Commit the new iPOJO version (0.7.6).

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@642265 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/examples/junit4osgi/felix-command/metadata.xml b/ipojo/examples/junit4osgi/felix-command/metadata.xml
new file mode 100644
index 0000000..87f7db1
--- /dev/null
+++ b/ipojo/examples/junit4osgi/felix-command/metadata.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<iPOJO>

+	<component

+		className="org.apache.felix.ipojo.junit4osgi.command.JunitCommand"

+		factory="false">

+		<requires field="runner" />

+		<provides />

+	</component>

+	<instance

+		component="org.apache.felix.ipojo.junit4osgi.command.JunitCommand" />

+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/examples/junit4osgi/felix-command/pom.xml b/ipojo/examples/junit4osgi/felix-command/pom.xml
new file mode 100644
index 0000000..f810d59
--- /dev/null
+++ b/ipojo/examples/junit4osgi/felix-command/pom.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.

+-->

+<project>

+	<parent>

+		<groupId>ipojo.examples</groupId>

+		<artifactId>Junit4Osgi</artifactId>

+		<version>0.7.6-SNAPSHOT</version>

+		<relativePath>../pom.xml</relativePath>

+	</parent>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<name>Junit4Osgi-Felix-Command</name>

+	<artifactId>

+		org.apache.felix.ipojo.junit4osgi.felix-command

+	</artifactId>

+	<dependencies>

+		<dependency>

+			<groupId>${pom.groupId}</groupId>

+			<artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.shell</artifactId>

+			<version>1.0.0</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>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-Name>

+							iPOJO OSGi Junit Runner - Felix Command

+						</Bundle-Name>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<Private-Package>

+							org.apache.felix.ipojo.junit4osgi.command

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>${pom.version}</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+						<configuration>

+							<ignoreAnnotations>true</ignoreAnnotations>

+						</configuration>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/junit4osgi/felix-command/src/main/java/org/apache/felix/ipojo/junit4osgi/command/JunitCommand.java b/ipojo/examples/junit4osgi/felix-command/src/main/java/org/apache/felix/ipojo/junit4osgi/command/JunitCommand.java
new file mode 100644
index 0000000..a217a9e
--- /dev/null
+++ b/ipojo/examples/junit4osgi/felix-command/src/main/java/org/apache/felix/ipojo/junit4osgi/command/JunitCommand.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.junit4osgi.command;

+

+import java.io.PrintStream;

+import java.util.ArrayList;

+import java.util.List;

+import java.util.ListIterator;

+

+import junit.framework.Test;

+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 {

+

+    private OSGiJunitRunner runner;

+

+    private List<String> getNamesFromTests(List<Test> list) {

+        List<String> names = new ArrayList<String>(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;

+    }

+

+    public void execute(String line, PrintStream out, PrintStream err) {

+        line = line.substring(getName().length()).trim();

+        List<TestResult> tr = null;

+        if (line.equals("all")) {

+            if (runner.getTests() == null) {

+                err.println("No tests to execute");

+                return;

+            } else {

+                out.println("Executing " + getNamesFromTests(runner.getTests()));

+                tr = runner.run();

+            }

+        } else {

+            try {

+                Long bundleId = new Long(line);

+                if (runner.getTests(bundleId) == null) {

+                    err.println("No tests to execute");

+                    return;

+                } else {

+                    out.println("Executing " + getNamesFromTests(runner.getTests(bundleId)));

+                    tr = runner.run(bundleId);

+                }

+            } catch (NumberFormatException e) {

+                err.println("Unable to parse id " + line);

+                return;

+            }

+        }

+

+        ListIterator<TestResult> it = tr.listIterator();

+        while (it.hasNext()) {

+            TestResult result = it.next();

+            if (result.failureCount() != 0) {

+                TestFailure fail = (TestFailure) result.failures().nextElement();

+                out.println(fail.trace());

+                return;

+            }

+        }

+

+    }

+

+    public String getName() {

+        return "junit";

+    }

+

+    public String getShortDescription() {

+        return "launch junit tests";

+    }

+

+    public String getUsage() {

+        return "junit";

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/immediate-launcher/metadata.xml b/ipojo/examples/junit4osgi/immediate-launcher/metadata.xml
new file mode 100644
index 0000000..648ab67
--- /dev/null
+++ b/ipojo/examples/junit4osgi/immediate-launcher/metadata.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<iPOJO>

+	<component

+		className="org.apache.felix.ipojo.junit4osgi.command.ImmediateRunner"

+		factory="false">

+		<requires field="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/examples/junit4osgi/immediate-launcher/pom.xml b/ipojo/examples/junit4osgi/immediate-launcher/pom.xml
new file mode 100644
index 0000000..18cfb31
--- /dev/null
+++ b/ipojo/examples/junit4osgi/immediate-launcher/pom.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.

+-->

+<project>

+	<parent>

+		<groupId>ipojo.examples</groupId>

+		<artifactId>Junit4Osgi</artifactId>

+		<version>0.7.6-SNAPSHOT</version>

+		<relativePath>../pom.xml</relativePath>

+	</parent>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<name>Junit4Osgi-Immediate-Runner</name>

+	<artifactId>

+		org.apache.felix.ipojo.junit4osgi.immediate-runner

+	</artifactId>

+	<dependencies>

+		<dependency>

+			<groupId>${pom.groupId}</groupId>

+			<artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.shell</artifactId>

+			<version>1.0.0</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>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-Name>

+							iPOJO OSGi Junit Runner - Immediate Runner

+						</Bundle-Name>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<Private-Package>

+							org.apache.felix.ipojo.junit4osgi.command

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>${pom.version}</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+						<configuration>

+							<ignoreAnnotations>true</ignoreAnnotations>

+						</configuration>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/junit4osgi/immediate-launcher/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ImmediateRunner.java b/ipojo/examples/junit4osgi/immediate-launcher/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ImmediateRunner.java
new file mode 100644
index 0000000..199cdf6
--- /dev/null
+++ b/ipojo/examples/junit4osgi/immediate-launcher/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ImmediateRunner.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.junit4osgi.command;

+

+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;

+

+/**

+ * Felix shell command. Allow to run tests.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class ImmediateRunner {

+

+    private OSGiJunitRunner runner;

+    

+    public void start() {

+        runner.run();

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/metadata.xml b/ipojo/examples/junit4osgi/junit4osgi/metadata.xml
new file mode 100644
index 0000000..83d84d3
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/metadata.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<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" />

+		<provides />

+	</Component>

+	<instance

+		component="org.apache.felix.ipojo.junit4osgi.impl.JunitExtender" />

+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/examples/junit4osgi/junit4osgi/pom.xml b/ipojo/examples/junit4osgi/junit4osgi/pom.xml
new file mode 100644
index 0000000..e4ffbf4
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/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>

+	<parent>

+		<groupId>ipojo.examples</groupId>

+		<artifactId>Junit4Osgi</artifactId>

+		<version>0.7.6-SNAPSHOT</version>

+		<relativePath>../pom.xml</relativePath>

+	</parent>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<name>Junit4Osgi</name>

+	<artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>

+	<dependencies>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.ipojo</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.ipojo.metadata</artifactId>

+			<version>${pom.version}</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>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-Name>

+							iPOJO OSGi Junit Runner

+						</Bundle-Name>

+						<Bundle-SymbolicName>

+							${pom.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, junit.*

+						</Export-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>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>${pom.version}</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+						<configuration>

+							<ignoreAnnotations>true</ignoreAnnotations>

+						</configuration>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiJunitRunner.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiJunitRunner.java
new file mode 100644
index 0000000..57a67d6
--- /dev/null
+++ b/ipojo/examples/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 : 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 : bundle containing the tests. 

+     * @return the list of the results.

+     */

+    List<TestResult> run(long bundleId);

+    

+    /**

+     * Get the list of available test suites.

+     * @return the list of test suites.

+     */

+    List<Test> getTests();

+    

+    /**

+     * Get the tests from the given bundle. 

+     * @param bundleId : bundle id.

+     * @return the list of test suites contained in the given bundle.

+     */

+    List<Test> getTests(long bundleId);

+    

+    /**

+     * Run the given test.

+     * @param test : test to execute.

+     * @return the result.

+     */

+    public TestResult run(Test test);

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestCase.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestCase.java
new file mode 100644
index 0000000..e10ad04
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestCase.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;

+

+import junit.framework.TestCase;

+

+import org.osgi.framework.BundleContext;

+

+/**

+ * OSGi Test Case. Allow the injection of the bundle context.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class OSGiTestCase extends TestCase {

+

+    protected BundleContext context;

+

+    public void setBundleContext(BundleContext bc) {

+        context = bc;

+    }

+

+    /**

+     * Asserts that two doubles are equal. If they are not an AssertionFailedError is thrown with the given message.

+     */

+    static public void assertEquals(String message, double expected, double actual) {

+        if (Double.compare(expected, actual) != 0) {

+            fail(formatEqualsMessage(message, expected, actual));

+        }

+    }

+

+    static String formatEqualsMessage(String message, Object expected, Object actual) {

+        String formatted = "";

+        if (message != null) {

+            formatted = message + " ";

+        }

+        return formatted + "expected:<" + expected + "> but was:<" + actual + ">";

+    }

+

+    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 + ">";

+    }

+

+    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 + ">";

+    }

+

+    static public void assertNotEquals(String message, Object o1, Object o2) {

+        if (o1.equals(o2)) {

+            fail(formatNotEqualsMessage(message, o1, o2));

+        }

+    }

+

+    static public 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));

+    }

+

+    static public void assertContains(String message, byte[] array, int txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+    static public void assertContains(String message, short[] array, int txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+    static public void assertContains(String message, int[] array, int txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+    static public void assertContains(String message, long[] array, long txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+    static public void assertContains(String message, float[] array, float txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+    static public void assertContains(String message, double[] array, double txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+    static public void assertContains(String message, char[] array, char txt) {

+        for (int i = 0; i < array.length; i++) {

+            if (array[i] == txt) {

+                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, txt));

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestSuite.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestSuite.java
new file mode 100644
index 0000000..8e7795a
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/OSGiTestSuite.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.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 {

+

+    protected BundleContext context;

+

+    public OSGiTestSuite(Class clazz, BundleContext bc) {

+        super(clazz);

+        context = bc;

+    }

+

+    public OSGiTestSuite(BundleContext bc) {

+        super();

+        context = bc;

+    }

+

+    public OSGiTestSuite(String name, BundleContext bc) {

+        super(name);

+        context = bc;

+    }

+

+    public OSGiTestSuite(Class clazz, String name, BundleContext bc) {

+        super(clazz, name);

+        context = bc;

+    }

+

+    public void setBundleContext(BundleContext bc) {

+        context = bc;

+    }

+

+    /**

+     * Adds the tests from the given class to the suite

+     */

+    public void addTestSuite(Class testClass) {

+        if (OSGiTestCase.class.isAssignableFrom(testClass)) {

+            addTest(new OSGiTestSuite(testClass, context));

+        } else if (TestCase.class.isAssignableFrom(testClass)) {

+            addTest(new TestSuite(testClass));

+        } else {

+            System.out.println("Error : the " + testClass + " is not a valid test class");

+        }

+    }

+

+    public void runTest(Test test, TestResult result) {

+        if (test instanceof OSGiTestSuite) {

+            ((OSGiTestSuite) test).context = context;

+            test.run(result);

+        } else if (test instanceof OSGiTestCase) {

+            ((OSGiTestCase) test).context = context;

+            test.run(result);

+        } else {

+            test.run(result);

+        }

+

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/JunitExtender.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/JunitExtender.java
new file mode 100644
index 0000000..34f0382
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/JunitExtender.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.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.osgi.framework.Bundle;

+import org.osgi.framework.BundleContext;

+

+/**

+ * Detect test suite from installed bundles.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class JunitExtender implements OSGiJunitRunner {

+

+    public static final String SUITE_METHODNAME = "suite";

+

+    private Map<Bundle, List<Class>> m_suites = new HashMap<Bundle, List<Class>>();

+

+    private ResultPrinter m_printer = new ResultPrinter(System.out);

+

+    void onBundleArrival(Bundle bundle, String header) {

+        String[] tss = header.split(",");

+        for (int i = 0; i < tss.length; i++) {

+            try {

+                if (tss[i].length() != 0) {

+                    System.out.println("Loading " + tss[i]);

+                    Class<? extends Test> clazz = bundle.loadClass(tss[i].trim());

+                    addTestSuite(bundle, clazz);

+                }

+            } catch (ClassNotFoundException e) {

+                System.err.println("The test suite " + tss[i] + " is not in the bundle " + bundle.getBundleId() + " : " + e.getMessage());

+            }

+        }

+    }

+

+    private synchronized void addTestSuite(Bundle bundle, Class<? extends Test> test) {

+        List<Class> list = m_suites.get(bundle);

+        if (list == null) {

+            list = new ArrayList<Class>();

+            list.add(test);

+            m_suites.put(bundle, list);

+        } else {

+            list.add(test);

+        }

+    }

+

+    private synchronized void removeTestSuites(Bundle bundle) {

+        m_suites.remove(bundle);

+    }

+

+    void onBundleDeparture(Bundle bundle) {

+        removeTestSuites(bundle);

+    }

+

+    public void setResultPrinter(PrintStream pw) {

+        m_printer = new ResultPrinter(pw);

+    }

+

+    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 = it.next();

+            Bundle bundle = entry.getKey();

+            List<Class> list = m_suites.get(bundle);

+            for (int i = 0; i < list.size(); i++) {

+                Test test = createTestFromClass(list.get(i), bundle);

+                TestResult tr = doRun(test);

+                results.add(tr);

+            }

+        }

+        return results;

+    }

+

+    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;

+    }

+

+    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())) {

+            System.err.println("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) {

+            System.err.println("Failed to invoke suite():" + e.getTargetException().toString());

+            return null;

+        } catch (IllegalAccessException e) {

+            System.err.println("Failed to invoke suite():" + e.toString());

+            return null;

+        }

+

+        return test;

+    }

+

+    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 = it.next();

+            Bundle bundle = entry.getKey();

+            List<Class> list = m_suites.get(bundle);

+            for (int i = 0; i < list.size(); i++) {

+                Test test = createTestFromClass(list.get(i), bundle);

+                results.add(test);

+            }

+        }

+        return results;

+    }

+

+    public TestResult run(Test test) {

+        return doRun(test);

+    }

+

+    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 = it.next();

+            Bundle bundle = entry.getKey();

+            if (bundle.getBundleId() == bundleId) {

+                List<Test> results = new ArrayList<Test>();

+                List<Class> list = m_suites.get(bundle);

+                for (int i = 0; i < list.size(); i++) {

+                    Test test = createTestFromClass(list.get(i), bundle);

+                    results.add(test);

+                }

+                return results;

+            }

+        }

+        return null;

+    }

+

+    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 = it.next();

+            Bundle bundle = entry.getKey();

+            if (bundle.getBundleId() == bundleId) {

+                List<TestResult> results = new ArrayList<TestResult>();

+                List<Class> list = m_suites.get(bundle);

+                for (int i = 0; i < list.size(); i++) {

+                    Test test = createTestFromClass(list.get(i), bundle);

+                    TestResult tr = doRun(test);

+                    results.add(tr);

+                }

+                return results;

+            }

+        }

+        return null;

+    }

+

+    public synchronized void stopping() {

+        System.out.println("Cleaning test suites ...");

+        m_suites.clear();

+    }

+    

+    public void starting() {

+        System.out.println("Junit Extender starting ...");

+    }

+

+    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) {

+                err("Cannot get the BundleContext by invoking " + meth.getName(), e);

+                return null;

+            } catch (IllegalAccessException e) {

+                err("Cannot get the BundleContext by invoking " + meth.getName(), e);

+                return null;

+            } catch (InvocationTargetException e) {

+                err("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) {

+                    err("Cannot get the BundleContext by invoking " + meth.getName(), e);

+                    return null;

+                } catch (IllegalAccessException e) {

+                    err("Cannot get the BundleContext by invoking " + meth.getName(), e);

+                    return null;

+                }

+            }

+        }

+        err("Cannot find the BundleContext for " + bundle.getSymbolicName(), null);

+        return null;

+    }

+

+    private void err(String s, Throwable e) {

+        System.err.println(s + " : " + e.getMessage());

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/ResultPrinter.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/ResultPrinter.java
new file mode 100644
index 0000000..4eb4e96
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/impl/ResultPrinter.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.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 {
+    PrintStream fWriter;
+
+    int fColumn = 0;
+
+    public ResultPrinter(PrintStream writer) {
+        fWriter = writer;
+    }
+
+    /*
+     * API for use by textui.TestRunner
+     */
+
+    synchronized void print(TestResult result, long runTime) {
+        printHeader(runTime);
+        printErrors(result);
+        printFailures(result);
+        printFooter(result);
+    }
+
+    void printWaitPrompt() {
+        getWriter().println();
+        getWriter().println("<RETURN> to continue");
+    }
+
+    /*
+     * Internal methods
+     */
+
+    protected void printHeader(long runTime) {
+        getWriter().println();
+        getWriter().println("Time: " + elapsedTimeAsString(runTime));
+    }
+
+    protected void printErrors(TestResult result) {
+        printDefects(result.errors(), result.errorCount(), "error");
+    }
+
+    protected void printFailures(TestResult result) {
+        printDefects(result.failures(), result.failureCount(), "failure");
+    }
+
+    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(booBoos.nextElement(), i);
+        }
+    }
+
+    public void printDefect(TestFailure booBoo, int count) { // only public for testing purposes
+        printDefectHeader(booBoo, count);
+        printDefectTrace(booBoo);
+    }
+
+    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());
+    }
+
+    protected void printDefectTrace(TestFailure booBoo) {
+        getWriter().print(BaseTestRunner.getFilteredTrace(booBoo.trace()));
+    }
+
+    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. Duplicated from BaseTestRunner. Fix it.
+     */
+    protected String elapsedTimeAsString(long runTime) {
+        return NumberFormat.getInstance().format((double) runTime / 1000);
+    }
+
+    public PrintStream getWriter() {
+        return fWriter;
+    }
+
+    /**
+     * @see junit.framework.TestListener#addError(Test, Throwable)
+     */
+    public void addError(Test test, Throwable t) {
+        getWriter().print("E");
+    }
+
+    /**
+     * @see junit.framework.TestListener#addFailure(Test, AssertionFailedError)
+     */
+    public void addFailure(Test test, AssertionFailedError t) {
+        getWriter().print("F");
+    }
+
+    /**
+     * @see junit.framework.TestListener#endTest(Test)
+     */
+    public void endTest(Test test) {
+    }
+
+    /**
+     * @see junit.framework.TestListener#startTest(Test)
+     */
+    public void startTest(Test test) {
+        getWriter().print(".");
+        if (fColumn++ >= 40) {
+            getWriter().println();
+            fColumn = 0;
+        }
+    }
+
+}
diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestCase.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestCase.java
new file mode 100644
index 0000000..2ee139e
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestCase.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.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 {

+    

+    public void test1() {

+        System.out.println("Test BC");

+        assertNotNull("Test bundle context", context);

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestSuite.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestSuite.java
new file mode 100644
index 0000000..c68f37c
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestOSGiTestSuite.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.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 {

+    

+    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/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestCase.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestCase.java
new file mode 100644
index 0000000..0e1527b
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestCase.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 junit.framework.TestCase;

+

+/**

+ * Simple Test Case.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class TestTestCase extends TestCase {

+    

+    public void test1() { }

+    

+    public void test2() { }

+    

+    public void test3() { }

+    

+    public void test4() { }

+

+}

diff --git a/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestSuite.java b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestSuite.java
new file mode 100644
index 0000000..6bd1bf1
--- /dev/null
+++ b/ipojo/examples/junit4osgi/junit4osgi/src/main/java/org/apache/felix/ipojo/junit4osgi/test/TestTestSuite.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 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 {

+    

+    public static Test suite() {

+        TestSuite ts = new TestSuite();

+        ts.setName("Test suite() method");

+        ts.addTestSuite(TestTestCase.class);

+        return ts;

+    }

+

+}

diff --git a/ipojo/examples/junit4osgi/metadata.xml b/ipojo/examples/junit4osgi/metadata.xml
new file mode 100644
index 0000000..29be5f3
--- /dev/null
+++ b/ipojo/examples/junit4osgi/metadata.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<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"/>

+		<provides/>

+	</Component>

+	<instance component="org.apache.felix.ipojo.junit4osgi.impl.JunitExtender"/>

+	

+	<component className="org.apache.felix.ipojo.junit4osgi.command.JunitCommand" factory="false">

+		<requires field="runner"/>

+		<provides/>

+	</component>

+	<instance component="org.apache.felix.ipojo.junit4osgi.command.JunitCommand"/>

+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/examples/junit4osgi/pom.xml b/ipojo/examples/junit4osgi/pom.xml
new file mode 100644
index 0000000..4e5a05e
--- /dev/null
+++ b/ipojo/examples/junit4osgi/pom.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<project>

+  <parent>

+    <groupId>ipojo.examples</groupId>

+  	<artifactId>ipojo.examples</artifactId>

+  	<version>0.7.6-SNAPSHOT</version>

+    <relativePath>../pom.xml</relativePath>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <artifactId>Junit4Osgi</artifactId>

+  <name>Apache Felix iPOJO Junit4OSGi</name>

+  <packaging>pom</packaging>

+

+  <profiles>

+	<profile>

+		<id>java5</id>

+		<activation>

+			<jdk>1.5</jdk>

+		</activation>

+		<modules>

+			<module>junit4osgi</module>

+			<module>felix-command</module>

+			<module>swing-runner</module>

+			<module>immediate-launcher</module>

+		</modules>

+	</profile>

+	<profile>

+		<id>java6</id>

+		<activation>

+			<jdk>1.6</jdk>

+		</activation>

+		<modules>

+			<module>junit4osgi</module>

+			<module>felix-command</module>

+			<module>swing-runner</module>

+			<module>immediate-launcher</module>

+		</modules>

+	</profile>

+  </profiles>

+</project>

diff --git a/ipojo/examples/junit4osgi/swing-runner/metadata.xml b/ipojo/examples/junit4osgi/swing-runner/metadata.xml
new file mode 100644
index 0000000..9251b6f
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/metadata.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<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/examples/junit4osgi/swing-runner/pom.xml b/ipojo/examples/junit4osgi/swing-runner/pom.xml
new file mode 100644
index 0000000..da9bae5
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/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>

+	<parent>

+		<groupId>ipojo.examples</groupId>

+		<artifactId>Junit4Osgi</artifactId>

+		<version>0.7.6-SNAPSHOT</version>

+		<relativePath>../pom.xml</relativePath>

+	</parent>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<name>Junit4Osgi-Swing-GUI</name>

+	<artifactId>org.apache.felix.ipojo.junit4osgi.swing-gui</artifactId>

+	<dependencies>

+		<dependency>

+			<groupId>${pom.groupId}</groupId>

+			<artifactId>org.apache.felix.ipojo.junit4osgi</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.shell</artifactId>

+			<version>1.0.0</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>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-Name>

+							iPOJO OSGi Junit Runner - Swing Gui

+						</Bundle-Name>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<Private-Package>

+							org.apache.felix.ipojo.junit4osgi.command

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>${pom.version}</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+						<configuration>

+							<ignoreAnnotations>true</ignoreAnnotations>

+						</configuration>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+	<repositories>

+		<repository>

+			<id>unknown-jars-temp-repo</id>

+			<name>

+				A temporary repository created by NetBeans for libraries

+				and jars it could not identify. Please replace the

+				dependencies in this repository with correct ones and

+				delete this repository.

+			</name>

+			<url>file:${project.basedir}/lib</url>

+		</repository>

+	</repositories>

+</project>

diff --git a/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultCellRenderer.java b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultCellRenderer.java
new file mode 100644
index 0000000..680ad32
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultCellRenderer.java
@@ -0,0 +1,75 @@
+/*
+ *  Copyright 2008 clement.
+ * 
+ *  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.
+ *  under the License.
+ */
+
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * 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;
+
+    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.SUCESS)) {
+            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/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultTableModel.java b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultTableModel.java
new file mode 100644
index 0000000..491f223
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/ResultTableModel.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.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 {
+
+    public static final String SUCESS = "success";
+
+    public static final String FAILURE = "failure";
+
+    public static final String ERROR = "error";
+
+    private static final long serialVersionUID = 1L;
+
+    private List<TestRecord> results = new ArrayList<TestRecord>();
+
+    public int getRowCount() {
+        return results.size();
+    }
+
+    public int getColumnCount() {
+        return 2;
+    }
+
+    public void addTest(Test t, AssertionFailedError e) {
+        TestRecord rec = new TestRecord(t, e);
+        results.add(rec);
+        fireTableDataChanged();
+    }
+
+    public void addTest(Test t, Throwable e) {
+        TestRecord rec = new TestRecord(t, e);
+        results.add(rec);
+        fireTableDataChanged();
+    }
+
+    public void addTest(Test t) {
+        if (!contains(t)) {
+            TestRecord rec = new TestRecord(t);
+            results.add(rec);
+            fireTableDataChanged();
+        }
+    }
+
+    public int getTestCount() {
+        return results.size();
+    }
+
+    public int getSucess() {
+        int count = 0;
+        for (TestRecord test : results) {
+            if (test.m_wasSucessFull) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public int getErrors() {
+        int count = 0;
+        for (TestRecord test : results) {
+            if (test.m_error != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    public int getFailures() {
+        int count = 0;
+        for (TestRecord test : results) {
+            if (test.m_failure != null) {
+                count++;
+            }
+        }
+        return count;
+    }
+
+    private boolean contains(Test t) {
+        for (TestRecord test : results) {
+            if (test.m_test.equals(t)) { return true; }
+        }
+        return false;
+    }
+
+    public void clear() {
+        results.clear();
+        fireTableDataChanged();
+    }
+
+    public Object getValueAt(int rowIndex, int columnIndex) {
+        if (columnIndex == 0) { return results.get(rowIndex).m_test; }
+        if (columnIndex == 1) {
+            TestRecord tr = results.get(rowIndex);
+            if (tr.m_wasSucessFull) { return SUCESS; }
+            if (tr.m_failure != null) { return FAILURE; }
+            if (tr.m_error != null) { return ERROR; }
+        }
+        return null;
+    }
+
+    public String getColumnName(int column) {
+        if (column == 0) { return "Test"; }
+
+        if (column == 1) { return "Status"; }
+
+        return null;
+    }
+
+    public String getMessage(int row, int column) {
+        if (row == -1) { return null; }
+        TestRecord rec = 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 {
+        private boolean m_wasSucessFull;
+
+        private Test m_test;
+
+        private AssertionFailedError m_failure;
+
+        private Throwable m_error;
+
+        public TestRecord(Test t, AssertionFailedError e) {
+            m_test = t;
+            m_wasSucessFull = false;
+            m_failure = e;
+        }
+
+        public TestRecord(Test t, Throwable e) {
+            m_test = t;
+            m_wasSucessFull = false;
+            m_error = e;
+        }
+
+        public TestRecord(Test t) {
+            m_test = t;
+            m_wasSucessFull = true;
+        }
+    }
+
+}
diff --git a/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.form b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.form
new file mode 100644
index 0000000..55cf564
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.form
@@ -0,0 +1,273 @@
+<?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="Junit Runner"/>
+    <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+      <Dimension value="[580, 580]"/>
+    </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_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"/>
+    <AuxValue name="designerSize" type="java.awt.Dimension" value="-84,-19,0,5,115,114,0,18,106,97,118,97,46,97,119,116,46,68,105,109,101,110,115,105,111,110,65,-114,-39,-41,-84,95,68,20,2,0,2,73,0,6,104,101,105,103,104,116,73,0,5,119,105,100,116,104,120,112,0,0,2,84,0,0,2,98"/>
+  </AuxValues>
+
+  <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+  <SubComponents>
+    <Container class="javax.swing.JPanel" name="m_panel">
+      <Properties>
+        <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[580, 560]"/>
+        </Property>
+        <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+          <Dimension value="[580, 566]"/>
+        </Property>
+      </Properties>
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="0" gridWidth="1" gridHeight="2" fill="1" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout"/>
+      <SubComponents>
+        <Container class="javax.swing.JScrollPane" name="m_suiteScroll">
+          <Properties>
+            <Property name="autoscrolls" type="boolean" value="true"/>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[400, 147]"/>
+            </Property>
+            <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[400, 147]"/>
+            </Property>
+          </Properties>
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+              <GridBagConstraints gridX="0" gridY="0" gridWidth="4" gridHeight="2" fill="1" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
+            </Constraint>
+          </Constraints>
+
+          <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="[250, 147]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[250, 147]"/>
+                </Property>
+                <Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[250, 147]"/>
+                </Property>
+              </Properties>
+            </Component>
+          </SubComponents>
+        </Container>
+        <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="[90, 23]"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="m_allButtonActionPerformed"/>
+          </Events>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+              <GridBagConstraints gridX="4" gridY="0" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="3" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="17" weightX="0.0" weightY="0.0"/>
+            </Constraint>
+          </Constraints>
+        </Component>
+        <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="[90, 23]"/>
+            </Property>
+          </Properties>
+          <Events>
+            <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="m_executeButtonActionPerformed"/>
+          </Events>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+              <GridBagConstraints gridX="4" gridY="1" gridWidth="1" gridHeight="1" fill="0" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="18" weightX="0.0" weightY="0.0"/>
+            </Constraint>
+          </Constraints>
+        </Component>
+        <Container class="javax.swing.JScrollPane" name="m_resultScroll">
+          <Properties>
+            <Property name="verticalScrollBarPolicy" type="int" value="22"/>
+            <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+              <Dimension value="[452, 402]"/>
+            </Property>
+          </Properties>
+          <AuxValues>
+            <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
+          </AuxValues>
+          <Constraints>
+            <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+              <GridBagConstraints gridX="0" gridY="2" gridWidth="5" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="2" insetsLeft="3" insetsBottom="3" insetsRight="3" anchor="10" weightX="0.0" weightY="0.0"/>
+            </Constraint>
+          </Constraints>
+
+          <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="[300, 400]"/>
+                </Property>
+                <Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
+                  <Dimension value="[300, 400]"/>
+                </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>
+      </SubComponents>
+    </Container>
+    <Container class="javax.swing.JPanel" name="m_statusBar">
+      <Constraints>
+        <Constraint layoutClass="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout" value="org.netbeans.modules.form.compat2.layouts.DesignGridBagLayout$GridBagConstraintsDescription">
+          <GridBagConstraints gridX="0" gridY="2" gridWidth="1" gridHeight="1" fill="2" ipadX="0" ipadY="0" insetsTop="0" insetsLeft="0" insetsBottom="0" insetsRight="0" anchor="10" weightX="0.0" weightY="0.0"/>
+        </Constraint>
+      </Constraints>
+
+      <Layout class="org.netbeans.modules.form.compat2.layouts.DesignBoxLayout"/>
+      <SubComponents>
+        <Component class="javax.swing.JProgressBar" name="m_progress">
+          <Properties>
+            <Property name="indeterminate" type="boolean" value="true"/>
+          </Properties>
+        </Component>
+        <Component class="javax.swing.JLabel" name="m_executedResults">
+          <Properties>
+            <Property name="text" type="java.lang.String" value="aaaaaaaaaaaaaaa"/>
+          </Properties>
+        </Component>
+      </SubComponents>
+    </Container>
+  </SubComponents>
+</Form>
diff --git a/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.java b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.java
new file mode 100644
index 0000000..82c4366
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/SwingRunner.java
@@ -0,0 +1,475 @@
+/* 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * 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.Cursor;
+import java.awt.Point;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.swing.JScrollBar;
+
+import javax.swing.table.TableColumn;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.apache.felix.ipojo.junit4osgi.OSGiJunitRunner;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+
+/**
+ * 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 {
+
+    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 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.JPanel m_panel;
+    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;
+    // End of variables declaration//GEN-END:variables
+
+    /**
+     * Constructor.
+     * @param bc : bundle context.
+     */
+    public SwingRunner(BundleContext bc) {
+        m_context = bc;
+    }
+
+    /**
+     * Start method.
+     */
+    public void start() {
+        initComponents();
+        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.
+     */
+    private void refreshSuites() {
+        List<Test> list = m_runner.getTests();
+        TestListModel lm = (TestListModel) m_suiteList.getModel();
+        lm.clear();
+        for (Test t : list) {
+            lm.addTest(t);
+        }
+    }
+
+    /** 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() {
+        java.awt.GridBagConstraints gridBagConstraints;
+
+        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_panel = new javax.swing.JPanel();
+        m_suiteScroll = new javax.swing.JScrollPane();
+        m_suiteList = new javax.swing.JList();
+        m_allButton = new javax.swing.JButton();
+        m_executeButton = new javax.swing.JButton();
+        m_resultScroll = new javax.swing.JScrollPane();
+        m_resultTable = new javax.swing.JTable();
+        m_statusBar = new javax.swing.JPanel();
+        m_progress = new javax.swing.JProgressBar();
+        m_executedResults = new javax.swing.JLabel();
+
+        m_resultDialog.setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
+        m_resultDialog.setMinimumSize(new java.awt.Dimension(320, 250));
+        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(new java.awt.Dimension(580, 580));
+        getContentPane().setLayout(new java.awt.GridBagLayout());
+
+        m_panel.setMinimumSize(new java.awt.Dimension(580, 560));
+        m_panel.setPreferredSize(new java.awt.Dimension(580, 566));
+        m_panel.setLayout(new java.awt.GridBagLayout());
+
+        m_suiteScroll.setAutoscrolls(true);
+        m_suiteScroll.setMinimumSize(new java.awt.Dimension(400, 147));
+        m_suiteScroll.setPreferredSize(new java.awt.Dimension(400, 147));
+
+        m_suiteList.setModel(new TestListModel());
+        m_suiteList.setMaximumSize(new java.awt.Dimension(250, 147));
+        m_suiteList.setMinimumSize(new java.awt.Dimension(250, 147));
+        m_suiteList.setPreferredSize(new java.awt.Dimension(250, 147));
+        m_suiteScroll.setViewportView(m_suiteList);
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.gridwidth = 4;
+        gridBagConstraints.gridheight = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
+        m_panel.add(m_suiteScroll, gridBagConstraints);
+
+        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(90, 23));
+        m_allButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                allButtonActionPerformed(evt);
+            }
+        });
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 4;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
+        gridBagConstraints.insets = new java.awt.Insets(3, 0, 0, 0);
+        m_panel.add(m_allButton, gridBagConstraints);
+
+        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(90, 23));
+        m_executeButton.addActionListener(new java.awt.event.ActionListener() {
+            public void actionPerformed(java.awt.event.ActionEvent evt) {
+                executeButtonActionPerformed(evt);
+            }
+        });
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 4;
+        gridBagConstraints.gridy = 1;
+        gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
+        gridBagConstraints.insets = new java.awt.Insets(2, 0, 0, 0);
+        m_panel.add(m_executeButton, gridBagConstraints);
+
+        m_resultScroll.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
+        m_resultScroll.setMinimumSize(new java.awt.Dimension(452, 402));
+
+        m_resultTable.setFont(new java.awt.Font("Tahoma", 0, 10));
+        m_resultTable.setModel(new ResultTableModel());
+        m_resultTable.setAutoResizeMode(javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS);
+        m_resultTable.setMaximumSize(new java.awt.Dimension(300, 400));
+        m_resultTable.setMinimumSize(new java.awt.Dimension(300, 400));
+        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);
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 2;
+        gridBagConstraints.gridwidth = 5;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        gridBagConstraints.insets = new java.awt.Insets(2, 3, 3, 3);
+        m_panel.add(m_resultScroll, gridBagConstraints);
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 0;
+        gridBagConstraints.gridheight = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
+        gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3);
+        getContentPane().add(m_panel, gridBagConstraints);
+
+        m_statusBar.setLayout(new javax.swing.BoxLayout(m_statusBar, javax.swing.BoxLayout.LINE_AXIS));
+
+        m_progress.setIndeterminate(true);
+        m_statusBar.add(m_progress);
+
+        m_executedResults.setText("aaaaaaaaaaaaaaa");
+        m_statusBar.add(m_executedResults);
+
+        gridBagConstraints = new java.awt.GridBagConstraints();
+        gridBagConstraints.gridx = 0;
+        gridBagConstraints.gridy = 2;
+        gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
+        getContentPane().add(m_statusBar, gridBagConstraints);
+
+        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) {//GEN-FIRST:event_onDialogClosed
+        m_resultDialog.setVisible(false);
+        setEnabled(true);
+    }//GEN-LAST:event_onDialogClosed
+
+    /**
+     * 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();
+    }
+    
+     private void computeExecutedTest() {
+        ResultTableModel results = (ResultTableModel) m_resultTable.getModel();
+        String m = " \t ";
+        m+= results.getTestCount() + " tests executed / ";
+        m+= results.getSucess() + " sucess / ";
+        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, java.lang.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, java.lang.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);
+            }
+        }
+
+    }
+
+    /**
+     * Bundle Changed callback method.
+     * @param arg0 : bundle event.
+     * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
+     */
+    public void bundleChanged(BundleEvent arg0) {
+        refreshSuites();
+    }
+
+}
diff --git a/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/TestListModel.java b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/TestListModel.java
new file mode 100644
index 0000000..4811c5e
--- /dev/null
+++ b/ipojo/examples/junit4osgi/swing-runner/src/main/java/org/apache/felix/ipojo/junit4osgi/command/TestListModel.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.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 {
+
+    private static final long serialVersionUID = 1L;
+
+    private List<TestRecord> list = new ArrayList<TestRecord>();
+
+    public Object getElementAt(int index) {
+        if (index >= list.size()) {
+            return null;
+        } else {
+            return list.get(index).name;
+        }
+    }
+
+    public Test getTestElementAt(int index) {
+        return list.get(index).test;
+    }
+
+    public void addTest(Test test) {
+        synchronized(this) {
+            TestRecord tr = new TestRecord();
+            tr.test = test;
+            tr.name = test.toString();
+            list.add(tr);
+        }
+        fireContentsChanged(this, list.size() - 1, list.size() - 1);
+    }
+
+    public void removeTest(Test test) {
+        int index = 1;
+        synchronized(this) {
+            for (TestRecord t : list) {
+                if (t.test.equals(test)) {
+                    index = list.indexOf(t);
+                    list.remove(t);
+                    return;
+                }
+            }
+        }
+        
+        if (index != -1) {
+            fireContentsChanged(this, index, index);
+        }
+    }
+
+    public void clear() {
+        list.clear();
+    }
+
+    private class TestRecord {
+        public Test test;
+
+        public String name;
+    }
+
+    public int getSize() {
+        return list.size();
+    }
+
+}
diff --git a/ipojo/examples/pom.xml b/ipojo/examples/pom.xml
new file mode 100644
index 0000000..0aef7eb
--- /dev/null
+++ b/ipojo/examples/pom.xml
@@ -0,0 +1,40 @@
+<project>

+  <parent>

+    <groupId>org.apache.felix</groupId>

+    <artifactId>iPOJO</artifactId>

+    <version>0.7.6-SNAPSHOT</version>

+    <relativePath>../pom.xml</relativePath>

+  </parent>

+

+  <modelVersion>4.0.0</modelVersion>

+  <groupId>ipojo.examples</groupId>

+  <artifactId>ipojo.examples</artifactId>

+  <name>Apache Felix iPOJO Examples</name>

+  <packaging>pom</packaging>

+  <modules>

+	<module>tutorial-maven</module>

+  </modules>

+  

+  <profiles>

+	<profile>

+		<id>java5</id>

+		<activation>

+			<jdk>1.5</jdk>

+		</activation>

+		<modules>

+			<module>junit4osgi</module>

+			<module>property-handler</module>

+		</modules>

+	</profile>

+	<profile>

+		<id>java6</id>

+		<activation>

+			<jdk>1.6</jdk>

+		</activation>

+		<modules>

+			<module>junit4osgi</module>

+			<module>property-handler</module>

+		</modules>

+	</profile>

+  </profiles>

+</project>
\ No newline at end of file
diff --git a/ipojo/examples/property-handler/PropertyHandler/metadata.xml b/ipojo/examples/property-handler/PropertyHandler/metadata.xml
new file mode 100644
index 0000000..48d7bef
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandler/metadata.xml
@@ -0,0 +1,9 @@
+<ipojo xmlns:props="example.handler.properties">

+

+	<!-- Declare the handler -->

+	<handler name="properties" namespace="example.handler.properties"

+		classname="org.apache.felix.ipojo.handler.properties.PropertiesHandler">

+		<!--  the properties handler does not use any other handler -->

+	</handler>

+

+</ipojo>

diff --git a/ipojo/examples/property-handler/PropertyHandler/pom.xml b/ipojo/examples/property-handler/PropertyHandler/pom.xml
new file mode 100644
index 0000000..d806ab9
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandler/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>ipojo.examples</groupId>

+		<artifactId>ipojo.examples.property.handler</artifactId>

+		<version>0.7.6-SNAPSHOT</version>

+		<relativePath>../pom.xml</relativePath>

+	</parent>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<name>Apache Felix iPOJO Property Handler</name>

+	<artifactId>

+		org.apache.felix.ipojo.example.handler.property

+	</artifactId>

+	<dependencies>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.ipojo</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.ipojo.metadata</artifactId>

+			<version>${pom.version}</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>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Private-Package>

+							org.apache.felix.ipojo.handler.properties,

+							example.handler.properties

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>${pom.version}</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+						<configuration>

+							<ignoreAnnotations>true</ignoreAnnotations>

+						</configuration>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/property-handler/PropertyHandler/src/main/java/example/handler/properties/Properties.java b/ipojo/examples/property-handler/PropertyHandler/src/main/java/example/handler/properties/Properties.java
new file mode 100644
index 0000000..9144bb8
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandler/src/main/java/example/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 example.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/examples/property-handler/PropertyHandler/src/main/java/org/apache/felix/ipojo/handler/properties/PropertiesHandler.java b/ipojo/examples/property-handler/PropertyHandler/src/main/java/org/apache/felix/ipojo/handler/properties/PropertiesHandler.java
new file mode 100644
index 0000000..abd3583
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandler/src/main/java/org/apache/felix/ipojo/handler/properties/PropertiesHandler.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.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.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 stopping the handler stores

+ * updated value inside the file. The properties file contains [field-name: field-value] (field-value are strings) Metadata :

+ * &lt;example.handler.properties:properties file="file-path"&gt; Instances can override file locations by setting the properties.file property.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class PropertiesHandler extends PrimitiveHandler {

+    

+    /** The Handler NAMESPACE. */

+    private final String NAMESPACE = "example.handler.properties";

+

+    /** Properties file. */

+    private Properties m_properties = new Properties();

+

+    /** File location. */

+    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

+     * description. The method parses given metadata and register field to listen. 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.

+     * @see org.apache.felix.ipojo.Handler#configure(org.apache.felix.ipojo.metadata.Element, java.util.Dictionary)

+     */

+    @SuppressWarnings("unchecked")

+    public void configure(Element metadata, Dictionary configuration) throws ConfigurationException {

+        // Parse metadata to get <properties file="$file"/>

+

+        Element[] elem = metadata.getElements("properties", NAMESPACE); // Get all example.handler.properties:properties element

+

+        switch (elem.length) {

+            case 0:

+                // No matching element in metadata, throw a configuration error.

+                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.

+     * @see org.apache.felix.ipojo.PrimitiveHandler#getterCallback(java.lang.String, java.lang.Object)

+     */

+    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

+     * @see org.apache.felix.ipojo.PrimitiveHandler#setterCallback(java.lang.String, java.lang.Object)

+     */

+    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

+            }

+            return;

+        }

+    }

+

+    /**

+     * 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/examples/property-handler/PropertyHandlerTest/metadata.xml b/ipojo/examples/property-handler/PropertyHandlerTest/metadata.xml
new file mode 100644
index 0000000..dcc9c16
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandlerTest/metadata.xml
@@ -0,0 +1,21 @@
+<ipojo xmlns:props="example.handler.properties">

+

+	<!-- Declare a component using your handler -->

+	<component

+		classname="org.apache.felix.ipojo.handler.properties.example.PropertiesTester">

+		<callback transition="validate" method="start" />

+		<callback transition="invalidate" method="stop" />

+		<!--  declare our handler -->

+		<props:properties file="props\properties.txt" />

+	</component>

+

+	<!-- Declare an instance -->

+	<instance component="annotationTester" />

+	<instance

+		component="org.apache.felix.ipojo.handler.properties.example.PropertiesTester"

+		name="i1">

+		<property name="properties.file"

+			value="props\properties-i1.txt" />

+	</instance>

+

+</ipojo>

diff --git a/ipojo/examples/property-handler/PropertyHandlerTest/pom.xml b/ipojo/examples/property-handler/PropertyHandlerTest/pom.xml
new file mode 100644
index 0000000..dc28218
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandlerTest/pom.xml
@@ -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.

+-->

+<project>

+	<parent>

+		<groupId>ipojo.examples</groupId>

+		<artifactId>ipojo.examples.property.handler</artifactId>

+		<version>0.7.6-SNAPSHOT</version>

+		<relativePath>../pom.xml</relativePath>

+	</parent>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<name>Apache Felix iPOJO Property Handler Test</name>

+	<artifactId>

+		org.apache.felix.ipojo.example.handler.property.test

+	</artifactId>

+	<dependencies>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.ipojo.annotations</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>ipojo.examples</groupId>

+			<artifactId>

+				org.apache.felix.ipojo.example.handler.property

+			</artifactId>

+			<version>${pom.version}</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>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Private-Package>

+							org.apache.felix.ipojo.handler.properties.example

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>${pom.version}</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/property-handler/PropertyHandlerTest/props/properties-i1.txt b/ipojo/examples/property-handler/PropertyHandlerTest/props/properties-i1.txt
new file mode 100644
index 0000000..7d688d2
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandlerTest/props/properties-i1.txt
@@ -0,0 +1,4 @@
+#

+#Sun Nov 18 20:33:54 CET 2007

+m_property2=foo - 18 nov. 2007 20\:32\:55 - 18 nov. 2007 20\:33\:51

+m_property1=bar - 18 nov. 2007 20\:32\:55 - 18 nov. 2007 20\:33\:51

diff --git a/ipojo/examples/property-handler/PropertyHandlerTest/props/properties.txt b/ipojo/examples/property-handler/PropertyHandlerTest/props/properties.txt
new file mode 100644
index 0000000..2d46de8
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandlerTest/props/properties.txt
@@ -0,0 +1,4 @@
+#

+#Sun Nov 18 20:33:54 CET 2007

+m_property2=prop2 - 18 nov. 2007 20\:32\:55 - 18 nov. 2007 20\:33\:51

+m_property1=prop1 - 18 nov. 2007 20\:32\:55 - 18 nov. 2007 20\:33\:51

diff --git a/ipojo/examples/property-handler/PropertyHandlerTest/src/main/java/org/apache/felix/ipojo/handler/properties/example/AnnotationPropertiesTester.java b/ipojo/examples/property-handler/PropertyHandlerTest/src/main/java/org/apache/felix/ipojo/handler/properties/example/AnnotationPropertiesTester.java
new file mode 100644
index 0000000..0f3df8d
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandlerTest/src/main/java/org/apache/felix/ipojo/handler/properties/example/AnnotationPropertiesTester.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.handler.properties.example;

+

+import java.text.DateFormat;

+import java.util.Date;

+

+import org.apache.felix.ipojo.annotations.Component;

+import org.apache.felix.ipojo.annotations.Invalidate;

+import org.apache.felix.ipojo.annotations.Validate;

+

+import example.handler.properties.Properties;

+

+/**

+ * A simple component implementation using the property handler.

+ *@author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+@Component(name = "annotationTester")

+@Properties(file = "props\\properties.txt")

+public class AnnotationPropertiesTester {

+ 

+    /**

+     * Property 1 : injected. 

+     */

+    private String m_property1;

+

+    /**

+     * Property 1 : injected. 

+     */

+    private String m_property2;

+

+    /**

+     * Start method : 

+     * displays loaded & injected properties before modifying them.

+     */

+    @Validate

+    public void start() {

+        System.out.println("AnnotationPropertiesTester is starting ...");

+        System.out.println("Property 1 : " + m_property1);

+        System.out.println("Property 2 : " + m_property2);

+

+        updateProperties();

+    }

+

+    /**

+     * Stop method :

+     * displays properties values.

+     */

+    @Invalidate

+    public void stop() {

+        System.out.println("AnnotationPropertiesTester is stopping ...");

+        System.out.println("Property 1 : " + m_property1);

+        System.out.println("Property 2 : " + m_property2);

+    }

+

+    /**

+     * Update property value.

+     */

+    private void updateProperties() {

+        System.out.println("Update properties");

+        Date date = new Date();

+        DateFormat df = DateFormat.getDateTimeInstance();

+        m_property1 = m_property1 + " - " + df.format(date);

+        m_property2 = m_property2 + " - " + df.format(date);

+

+    }

+}

diff --git a/ipojo/examples/property-handler/PropertyHandlerTest/src/main/java/org/apache/felix/ipojo/handler/properties/example/PropertiesTester.java b/ipojo/examples/property-handler/PropertyHandlerTest/src/main/java/org/apache/felix/ipojo/handler/properties/example/PropertiesTester.java
new file mode 100644
index 0000000..37872db
--- /dev/null
+++ b/ipojo/examples/property-handler/PropertyHandlerTest/src/main/java/org/apache/felix/ipojo/handler/properties/example/PropertiesTester.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.handler.properties.example;

+

+import java.text.DateFormat;

+import java.util.Date;

+

+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.

+     */

+    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.

+     */

+    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/examples/property-handler/pom.xml b/ipojo/examples/property-handler/pom.xml
new file mode 100644
index 0000000..2b9f2df
--- /dev/null
+++ b/ipojo/examples/property-handler/pom.xml
@@ -0,0 +1,36 @@
+<project>

+ <parent>

+    <groupId>ipojo.examples</groupId>

+  	<artifactId>ipojo.examples</artifactId>

+  	<version>0.7.6-SNAPSHOT</version>

+    <relativePath>../pom.xml</relativePath>

+  </parent>

+

+  <modelVersion>4.0.0</modelVersion>

+  <artifactId>ipojo.examples.property.handler</artifactId>

+  <name>Apache Felix iPOJO Property Handler</name>

+  <packaging>pom</packaging>

+

+  <profiles>

+	<profile>

+		<id>java5</id>

+		<activation>

+			<jdk>1.5</jdk>

+		</activation>

+		<modules>

+			<module>PropertyHandler</module>

+			<module>PropertyHandlerTest</module>

+		</modules>

+	</profile>

+	<profile>

+		<id>java6</id>

+		<activation>

+			<jdk>1.6</jdk>

+		</activation>

+		<modules>

+			<module>PropertyHandler</module>

+			<module>PropertyHandlerTest</module>

+		</modules>

+	</profile>

+  </profiles>

+</project>
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.client.annotation/metadata.xml b/ipojo/examples/tutorial-maven/hello.client.annotation/metadata.xml
new file mode 100644
index 0000000..134250d
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client.annotation/metadata.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<iPOJO>

+  <instance component="AnnotatedHelloClient" name="HelloClient"/>

+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.client.annotation/pom.xml b/ipojo/examples/tutorial-maven/hello.client.annotation/pom.xml
new file mode 100644
index 0000000..eee6444
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client.annotation/pom.xml
@@ -0,0 +1,66 @@
+<project>

+  <modelVersion>4.0.0</modelVersion>

+  <packaging>bundle</packaging>

+  <groupId>ipojo.examples</groupId>

+  <artifactId>hello.client.annotation</artifactId>

+   <version>0.7.6-SNAPSHOT</version>

+  <name>Hello Service Client using Annotations</name>

+  

+  <dependencies>

+    <dependency>

+      <groupId>ipojo.examples</groupId>

+      <artifactId>hello.service</artifactId>

+      <version>${pom.version}</version>

+    </dependency>

+    <dependency>

+      <groupId>org.apache.felix</groupId>

+      <artifactId>org.apache.felix.ipojo.annotations</artifactId>

+      <version>0.7.6-SNAPSHOT</version>

+    </dependency>

+  </dependencies>

+  

+  <pluginRepositories>

+    <pluginRepository>

+      <id>apache.snapshots</id>

+      <name>snapshot plugins</name>

+      <url>

+        http://people.apache.org/repo/m2-snapshot-repository

+      </url>

+    </pluginRepository>

+  </pluginRepositories>

+  

+  <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>

+        <extensions>true</extensions>

+        <configuration>

+          <instructions>

+            <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>

+            <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>

diff --git a/ipojo/examples/tutorial-maven/hello.client.annotation/src/main/java/ipojo/example/hello/client/HelloClient.java b/ipojo/examples/tutorial-maven/hello.client.annotation/src/main/java/ipojo/example/hello/client/HelloClient.java
new file mode 100644
index 0000000..2c3697c
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client.annotation/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;

+

+import org.apache.felix.ipojo.annotations.Component;

+import org.apache.felix.ipojo.annotations.Invalidate;

+import org.apache.felix.ipojo.annotations.Requires;

+import org.apache.felix.ipojo.annotations.Validate;

+

+/**

+ * A simple Hello service client. This client use annotation instead of XML metadata.

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+@Component(name = "AnnotatedHelloClient", architecture = true)

+public class HelloClient implements Runnable {

+    

+    /** Delay between two invocations. */

+    private static final int DELAY = 10000;

+

+    /**

+     * Hello services. Injected by the container.

+     */

+    @Requires

+    private Hello[] m_hello;

+

+    /**

+     *  End flag.

+     */

+    private boolean m_end;

+

+    /**

+     * Run method.

+     * @see java.lang.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() {

+        for (int i = 0; i < m_hello.length; i++) {

+            System.out.println(i + " :" + m_hello[i].sayHello("Clement"));

+        }

+    }

+

+    /**

+     * 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/examples/tutorial-maven/hello.client.annotation/src/main/java/ipojo/example/source.txt b/ipojo/examples/tutorial-maven/hello.client.annotation/src/main/java/ipojo/example/source.txt
new file mode 100644
index 0000000..0198756
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client.annotation/src/main/java/ipojo/example/source.txt
@@ -0,0 +1 @@
+PUT YOUR SOURCE FILES HERE
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.client/metadata.xml b/ipojo/examples/tutorial-maven/hello.client/metadata.xml
new file mode 100644
index 0000000..4141c34
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client/metadata.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<iPOJO>

+	<component className="ipojo.example.hello.client.HelloClient"

+		architecture="true">

+		<requires field="m_hello" />

+		<callback transition="validate" method="starting" />

+		<callback transition="invalidate" method="stopping" />

+		<properties>

+			<property field="m_name" name="name" />

+		</properties>

+	</component>

+	<instance component="ipojo.example.hello.client.HelloClient">

+		<property name="name" value="clement" />

+	</instance>

+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.client/pom.xml b/ipojo/examples/tutorial-maven/hello.client/pom.xml
new file mode 100644
index 0000000..91cbe69
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client/pom.xml
@@ -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.

+-->

+<project>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging><!-- Use the BND Maven plug-in -->

+	<groupId>ipojo.examples</groupId>

+	<artifactId>hello.client</artifactId>

+	<version>0.7.6-SNAPSHOT</version>

+	<name>Hello Service Client</name>

+	<dependencies>

+		<dependency>

+			<groupId>ipojo.examples</groupId>

+			<artifactId>hello.service</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+	</dependencies>

+

+	<pluginRepositories>

+		<pluginRepository>

+			<id>apache.snapshots</id>

+			<name>snapshot plugins</name>

+			<url>

+				http://people.apache.org/repo/m2-snapshot-repository

+			</url>

+			<releases>

+				<enabled>false</enabled>

+			</releases>

+			<snapshots>

+				<enabled>true</enabled>

+			</snapshots>

+		</pluginRepository>

+	</pluginRepositories>

+

+	<build>

+		<plugins>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-bundle-plugin</artifactId>

+				<extensions>true</extensions>

+				<version>1.4.0</version>

+				<configuration>

+					<instructions>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<Private-Package>

+							ipojo.example.hello.client

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>0.7.6-SNAPSHOT</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/tutorial-maven/hello.client/src/main/java/ipojo/example/hello/client/HelloClient.java b/ipojo/examples/tutorial-maven/hello.client/src/main/java/ipojo/example/hello/client/HelloClient.java
new file mode 100644
index 0000000..023db3f
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client/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[] m_hello; // Service Requirement

+

+    /** 

+     * End flag.

+     *  */

+    private boolean m_end;

+

+    /** 

+     * Name property.

+     * Injected by the container.

+     * */

+    private String m_name;

+

+    /**

+     * Run method.

+     * @see java.lang.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() {

+        for (int i = 0; i < m_hello.length; i++) {

+            System.out.println(m_hello[i].sayHello(m_name));

+        }

+    }

+

+    /**

+     * Starting.

+     */

+    public void starting() {

+        Thread thread = new Thread(this);

+        m_end = false;

+        thread.start();

+    }

+

+    /**

+     * Stopping.

+     */

+    public void stopping() {

+        m_end = true;

+    }

+}

diff --git a/ipojo/examples/tutorial-maven/hello.client/src/main/java/ipojo/example/source.txt b/ipojo/examples/tutorial-maven/hello.client/src/main/java/ipojo/example/source.txt
new file mode 100644
index 0000000..0198756
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.client/src/main/java/ipojo/example/source.txt
@@ -0,0 +1 @@
+PUT YOUR SOURCE FILES HERE
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.impl.annotation/pom.xml b/ipojo/examples/tutorial-maven/hello.impl.annotation/pom.xml
new file mode 100644
index 0000000..2281a57
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl.annotation/pom.xml
@@ -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.

+-->

+<project>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<groupId>ipojo.examples</groupId>

+	<artifactId>hello.impl.annotation</artifactId>

+	<version>0.7.6-SNAPSHOT</version>

+	<name>Hello Service Provider using Annotations</name>

+

+	<pluginRepositories>

+		<pluginRepository>

+			<id>apache.snapshots</id>

+			<name>snapshot plugins</name>

+			<url>

+				http://people.apache.org/repo/m2-snapshot-repository

+			</url>

+		</pluginRepository>

+	</pluginRepositories>

+

+	<dependencies>

+		<dependency>

+			<groupId>ipojo.examples</groupId>

+			<artifactId>hello.service</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+		<dependency>

+			<groupId>org.apache.felix</groupId>

+			<artifactId>org.apache.felix.ipojo.annotations</artifactId>

+			<version>0.7.6-SNAPSHOT</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>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<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>

diff --git a/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/java/ipojo/example/hello/impl/HelloImpl.java b/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/java/ipojo/example/hello/impl/HelloImpl.java
new file mode 100644
index 0000000..8b37c2f
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/java/ipojo/example/hello/impl/HelloImpl.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 ipojo.example.hello.impl;

+

+import ipojo.example.hello.Hello;

+

+import org.apache.felix.ipojo.annotations.Component;

+import org.apache.felix.ipojo.annotations.Provides;

+

+/**

+ * 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

+public class HelloImpl implements Hello {

+    

+    /**

+     * Returns an 'Hello' message.

+     * @param name : name

+     * @return Hello message

+     * @see ipojo.example.hello.Hello#sayHello(java.lang.String)

+     */

+    public String sayHello(String name) { return "hello " + name + " @";  }

+}

diff --git a/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/java/ipojo/example/hello/impl/source.txt b/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/java/ipojo/example/hello/impl/source.txt
new file mode 100644
index 0000000..0198756
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/java/ipojo/example/hello/impl/source.txt
@@ -0,0 +1 @@
+PUT YOUR SOURCE FILES HERE
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/resources/metadata.xml b/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/resources/metadata.xml
new file mode 100644
index 0000000..559b556
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl.annotation/src/main/resources/metadata.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<iPOJO>

+	<instance component="ipojo.example.hello.impl.HelloImpl"

+		name="HelloService2" />

+</iPOJO>
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.impl/metadata.xml b/ipojo/examples/tutorial-maven/hello.impl/metadata.xml
new file mode 100644
index 0000000..59d9666
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl/metadata.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<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/examples/tutorial-maven/hello.impl/pom.xml b/ipojo/examples/tutorial-maven/hello.impl/pom.xml
new file mode 100644
index 0000000..3cf4551
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl/pom.xml
@@ -0,0 +1,65 @@
+<project>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<groupId>ipojo.examples</groupId>

+	<artifactId>hello.impl</artifactId>

+	<version>0.7.6-SNAPSHOT</version>

+	<name>Hello Service Provider</name>

+

+	<pluginRepositories>

+		<pluginRepository>

+			<id>apache.snapshots</id>

+			<name>snapshot plugins</name>

+			<url>

+				http://people.apache.org/repo/m2-snapshot-repository

+			</url>

+			<releases>

+				<enabled>false</enabled>

+			</releases>

+			<snapshots>

+				<enabled>true</enabled>

+			</snapshots>

+		</pluginRepository>

+	</pluginRepositories>

+

+	<dependencies>

+		<dependency>

+			<groupId>ipojo.examples</groupId>

+			<artifactId>hello.service</artifactId>

+			<version>${pom.version}</version>

+		</dependency>

+	</dependencies>

+

+	<build>

+		<plugins>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-bundle-plugin</artifactId>

+				<version>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<Private-Package>

+							ipojo.example.hello.impl

+						</Private-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-ipojo-plugin</artifactId>

+				<version>0.7.6-SNAPSHOT</version>

+				<executions>

+					<execution>

+						<goals>

+							<goal>ipojo-bundle</goal>

+						</goals>

+					</execution>

+				</executions>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/tutorial-maven/hello.impl/src/main/java/ipojo/example/hello/impl/HelloImpl.java b/ipojo/examples/tutorial-maven/hello.impl/src/main/java/ipojo/example/hello/impl/HelloImpl.java
new file mode 100644
index 0000000..8008fa9
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl/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(java.lang.String)

+     */

+    public String sayHello(String name) { return "hello " + name;  }

+}

diff --git a/ipojo/examples/tutorial-maven/hello.impl/src/main/java/ipojo/example/hello/impl/source.txt b/ipojo/examples/tutorial-maven/hello.impl/src/main/java/ipojo/example/hello/impl/source.txt
new file mode 100644
index 0000000..0198756
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.impl/src/main/java/ipojo/example/hello/impl/source.txt
@@ -0,0 +1 @@
+PUT YOUR SOURCE FILES HERE
\ No newline at end of file
diff --git a/ipojo/examples/tutorial-maven/hello.service/metadata.xml b/ipojo/examples/tutorial-maven/hello.service/metadata.xml
new file mode 100644
index 0000000..89547bc
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.service/metadata.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>

+<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/examples/tutorial-maven/hello.service/pom.xml b/ipojo/examples/tutorial-maven/hello.service/pom.xml
new file mode 100644
index 0000000..084989d
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/hello.service/pom.xml
@@ -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.

+-->

+<project>

+	<modelVersion>4.0.0</modelVersion>

+	<packaging>bundle</packaging>

+	<groupId>ipojo.examples</groupId>

+	<artifactId>hello.service</artifactId>

+	<version>0.7.6-SNAPSHOT</version>

+	<name>Hello Service</name>

+

+	<pluginRepositories>

+		<pluginRepository>

+			<id>apache.snapshots</id>

+			<name>snapshot plugins</name>

+			<url>

+				http://people.apache.org/repo/m2-snapshot-repository

+			</url>

+			<releases>

+				<enabled>false</enabled>

+			</releases>

+			<snapshots>

+				<enabled>true</enabled>

+			</snapshots>

+		</pluginRepository>

+	</pluginRepositories>

+

+	<build>

+		<plugins>

+			<plugin>

+				<groupId>org.apache.felix</groupId>

+				<artifactId>maven-bundle-plugin</artifactId>

+				<version>1.4.0</version>

+				<extensions>true</extensions>

+				<configuration>

+					<instructions>

+						<Bundle-SymbolicName>

+							${pom.artifactId}

+						</Bundle-SymbolicName>

+						<Export-Package>

+							ipojo.example.hello

+						</Export-Package>

+					</instructions>

+				</configuration>

+			</plugin>

+		</plugins>

+	</build>

+</project>

diff --git a/ipojo/examples/tutorial-maven/hello.service/src/main/java/ipojo/example/hello/Hello.java b/ipojo/examples/tutorial-maven/hello.service/src/main/java/ipojo/example/hello/Hello.java
new file mode 100644
index 0000000..e0c25da
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/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/examples/tutorial-maven/pom.xml b/ipojo/examples/tutorial-maven/pom.xml
new file mode 100644
index 0000000..99d12ac
--- /dev/null
+++ b/ipojo/examples/tutorial-maven/pom.xml
@@ -0,0 +1,40 @@
+<project>

+  <parent>

+    <groupId>ipojo.examples</groupId>

+  	<artifactId>ipojo.examples</artifactId>

+  	<version>0.7.6-SNAPSHOT</version>

+    <relativePath>../pom.xml</relativePath>

+  </parent>

+  <modelVersion>4.0.0</modelVersion>

+  <artifactId>ipojo.tutorial</artifactId>

+  <name>Apache Felix iPOJO Tutorial</name>

+  <packaging>pom</packaging>

+  <modules>

+	<module>hello.service</module>

+	<module>hello.impl</module>

+	<module>hello.client</module>

+  </modules>

+  

+  <profiles>

+	<profile>

+		<id>java5</id>

+		<activation>

+			<jdk>1.5</jdk>

+		</activation>

+		<modules>

+			<module>hello.impl.annotation</module>

+			<module>hello.client.annotation</module>

+		</modules>

+	</profile>

+	<profile>

+		<id>java6</id>

+		<activation>

+			<jdk>1.6</jdk>

+		</activation>

+		<modules>

+			<module>hello.impl.annotation</module>

+			<module>hello.client.annotation</module>

+		</modules>

+	</profile>

+  </profiles>

+</project>
\ No newline at end of file