FELIX-4419 Open access to InstanceDeclaration and TypeDeclaration

* Added DeclarationBuilderService interface
* InstanceBuilder produces DeclarationHandle to XYZDeclaration
* Declarations now also implements DeclarationHandle
* Added some core-it tests to show typical service usage

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1571275 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/pom.xml b/ipojo/runtime/core-it/ipojo-core-declaration-test/pom.xml
new file mode 100644
index 0000000..e1df065
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/pom.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+     http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+  -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+
+  <parent>
+    <groupId>org.apache.felix</groupId>
+    <artifactId>org.apache.felix.ipojo.runtime.core-it</artifactId>
+    <version>1.11.2-SNAPSHOT</version>
+  </parent>
+
+  <modelVersion>4.0.0</modelVersion>
+
+  <artifactId>ipojo-core-declaration-test</artifactId>
+
+  <name>${project.artifactId}</name>
+
+  <dependencies>
+    <dependency>
+      <groupId>org.apache.felix</groupId>
+      <artifactId>org.apache.felix.ipojo.api</artifactId>
+      <version>1.11.2-SNAPSHOT</version>
+      <exclusions>
+        <exclusion>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>org.osgi.core</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.osgi</groupId>
+          <artifactId>org.osgi.core</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>org.apache.felix</groupId>
+          <artifactId>org.apache.felix.ipojo</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>asm</groupId>
+          <artifactId>asm-all</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+  </dependencies>
+</project>
\ No newline at end of file
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService.java
new file mode 100644
index 0000000..9668318
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+@Component(name = "hello-service", version = "2.0")
+@Provides
+public class EnglishHelloService implements HelloService {
+
+    @Property("Hello2")
+    private String message;
+
+    @Override
+    public String hello(final String name) {
+        return message + " " + name;
+    }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService2.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService2.java
new file mode 100644
index 0000000..6d986d2
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/EnglishHelloService2.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+@Component(name = "hello-service")
+@Provides
+public class EnglishHelloService2 implements HelloService {
+
+    @Property("Hello")
+    private String message;
+
+    @Override
+    public String hello(final String name) {
+        return message + " " + name;
+    }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FrenchHelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FrenchHelloService.java
new file mode 100644
index 0000000..57ca670
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/FrenchHelloService.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+@Component
+@Provides
+public class FrenchHelloService implements HelloService {
+
+    @Property("Bonjour")
+    private String message;
+
+    @Override
+    public String hello(final String name) {
+        return message + " " + name;
+    }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/GermanHelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/GermanHelloService.java
new file mode 100644
index 0000000..fe9db64
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/components/GermanHelloService.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.components;
+
+import org.apache.felix.ipojo.annotations.Component;
+import org.apache.felix.ipojo.annotations.Property;
+import org.apache.felix.ipojo.annotations.Provides;
+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;
+
+/**
+ * I intentionally left empty the component name plus the @Provides annotation.
+ * This is just to trigger the component manipulation
+ */
+@Component
+public class GermanHelloService implements HelloService {
+
+    @Override
+    public String hello(final String name) {
+        return "Hallo " + name;
+    }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java
new file mode 100644
index 0000000..abfff19
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/main/java/org/apache/felix/ipojo/runtime/core/test/services/HelloService.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.services;
+
+/**
+ * User: guillaume
+ * Date: 20/02/2014
+ * Time: 13:29
+ */
+public interface HelloService {
+    String hello(String name);
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/Common.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/Common.java
new file mode 100644
index 0000000..198ab5c
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/Common.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.runtime.core.test.declaration;
+
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.options.CompositeOption;
+import org.ops4j.pax.exam.options.DefaultCompositeOption;
+import org.ow2.chameleon.testing.helpers.BaseTest;
+
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+
+/**
+ * Bootstrap the test from this project
+ */
+public class Common extends BaseTest {
+    @Override
+    public boolean quiet() {
+        return false;
+    }
+}
diff --git a/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/TestDeclarationBuilderService.java b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/TestDeclarationBuilderService.java
new file mode 100644
index 0000000..ec97f01
--- /dev/null
+++ b/ipojo/runtime/core-it/ipojo-core-declaration-test/src/test/java/org/apache/felix/ipojo/runtime/core/test/declaration/TestDeclarationBuilderService.java
@@ -0,0 +1,216 @@
+/*

+ * Licensed to the Apache Software Foundation (ASF) under one

+ * or more contributor license agreements.  See the NOTICE file

+ * distributed with this work for additional information

+ * regarding copyright ownership.  The ASF licenses this file

+ * to you under the Apache License, Version 2.0 (the

+ * "License"); you may not use this file except in compliance

+ * with the License.  You may obtain a copy of the License at

+ *

+ *    http://www.apache.org/licenses/LICENSE-2.0

+ *

+ * Unless required by applicable law or agreed to in writing,

+ * software distributed under the License is distributed on an

+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY

+ * KIND, either express or implied.  See the License for the

+ * specific language governing permissions and limitations

+ * under the License.

+ */

+

+package org.apache.felix.ipojo.runtime.core.test.declaration;

+

+import org.apache.felix.ipojo.IPojoFactory;

+//import org.apache.felix.ipojo.api.PrimitiveComponentType;

+//import org.apache.felix.ipojo.api.Service;

+import org.apache.felix.ipojo.extender.DeclarationBuilderService;

+import org.apache.felix.ipojo.extender.DeclarationHandle;

+import org.apache.felix.ipojo.extender.ExtensionDeclaration;

+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;

+import org.apache.felix.ipojo.extender.builder.FactoryBuilderException;

+import org.apache.felix.ipojo.metadata.Attribute;

+import org.apache.felix.ipojo.metadata.Element;

+import org.apache.felix.ipojo.runtime.core.test.services.HelloService;

+import org.junit.After;

+import org.junit.Before;

+import org.junit.Test;

+import org.osgi.framework.BundleContext;

+

+import static java.lang.String.format;

+import static junit.framework.Assert.assertEquals;

+import static junit.framework.Assert.assertFalse;

+import static junit.framework.Assert.assertTrue;

+

+import java.util.Arrays;

+import java.util.List;

+

+public class TestDeclarationBuilderService extends Common {

+

+    private DeclarationBuilderService builder;

+    private DeclarationHandle handle;

+

+    @Override

+    protected List<String> getExtraExports() {

+        // The important thing here is to make sure that this package is in the bundle

+        return Arrays.asList("org.apache.felix.ipojo.runtime.core.test.components");

+    }

+

+    @Before

+    public void setUp() {

+        builder = osgiHelper.getServiceObject(DeclarationBuilderService.class);

+    }

+

+    @After

+    public void tearDown() {

+        if (handle != null) {

+            handle.retract();

+        }

+    }

+

+    @Test

+    public void testAnonymousInstanceCreation() {

+        handle = builder.newInstance("org.apache.felix.ipojo.runtime.core.test.components.FrenchHelloService")

+                .build();

+

+        // When a  service is registered, all events are fired synchronously, we

+        // can safely test the declaration binding

+        assertFalse(handle.getStatus().isBound());

+        handle.publish();

+

+        osgiHelper.waitForService(HelloService.class, null, 1000);

+

+        assertTrue(handle.getStatus().isBound());

+        handle.retract();

+        assertFalse(handle.getStatus().isBound());

+    }

+

+    @Test

+    public void testNamedInstanceCreation() {

+        handle = builder.newInstance("org.apache.felix.ipojo.runtime.core.test.components.FrenchHelloService")

+                .name("bonjour-service")

+                .build();

+

+        handle.publish();

+        assertTrue(ipojoHelper.isServiceAvailableByName(HelloService.class.getName(), "bonjour-service"));

+    }

+

+    @Test

+    public void testConfiguredInstanceCreation() {

+        handle = builder.newInstance("org.apache.felix.ipojo.runtime.core.test.components.FrenchHelloService")

+                .name("bonjour-service")

+                .configure()

+                .property("message", "Salut")

+                .build();

+

+        handle.publish();

+        assertTrue(ipojoHelper.isServiceAvailableByName(HelloService.class.getName(), "bonjour-service"));

+

+        HelloService service = osgiHelper.getServiceObject(HelloService.class, format("(instance.name=%s)", "bonjour-service"));

+        assertEquals(service.hello("Guillaume"), "Salut Guillaume");

+    }

+

+    @Test

+    public void testVersionedTypeInstanceCreation() {

+        handle = builder.newInstance("hello-service")

+                .version("2.0")

+                .name("hello2")

+                .build();

+

+        handle.publish();

+

+        String filter = format("(instance.name=%s)", "hello2");

+        osgiHelper.waitForService(HelloService.class, filter, 1000);

+        HelloService service = osgiHelper.getServiceObject(HelloService.class, filter);

+        assertEquals(service.hello("Guillaume"), "Hello2 Guillaume");

+    }

+

+    @Test

+    public void testExtensionCreation() {

+        handle = builder.newExtension("test", new EmptyFactoryBuilder());

+

+        handle.publish();

+

+        osgiHelper.waitForService(ExtensionDeclaration.class, null, 1000);

+    }

+

+    @Test

+    public void testTypeCreation() throws Exception {

+

+        handle = builder.newType(germanComponent());

+        handle.publish();

+

+        DeclarationHandle instance = builder.newInstance("german-service")

+                .name("german-hello")

+                .build();

+        instance.publish();

+

+        String filter = format("(instance.name=%s)", "german-hello");

+        osgiHelper.waitForService(HelloService.class, filter, 1000);

+        HelloService service = osgiHelper.getServiceObject(HelloService.class, filter);

+        assertEquals(service.hello("Guillaume"), "Hallo Guillaume");

+

+        instance.retract();

+

+    }

+

+    /*

+    @Test

+    public void testTypeCreationFromAPI() throws Exception {

+        PrimitiveComponentType type = new PrimitiveComponentType()

+                .setClassName("org.apache.felix.ipojo.runtime.core.test.components.GermanHelloService")

+                .setComponentTypeName("german-service")

+                .addService(new Service());

+

+        Element description = type.getFactory().getComponentMetadata();

+        handle = builder.newType(description);

+        handle.publish();

+

+        DeclarationHandle instance = builder.newInstance("german-service")

+                .name("german-hello")

+                .build();

+        instance.publish();

+

+        String filter = format("(instance.name=%s)", "german-hello");

+        osgiHelper.waitForService(HelloService.class, filter, 1000);

+        HelloService service = osgiHelper.getServiceObject(HelloService.class, filter);

+        assertEquals(service.hello("Guillaume"), "Hallo Guillaume");

+

+        instance.retract();

+

+    }

+    */

+

+    private Element germanComponent() {

+        Element component = new Element("component", null);

+        component.addAttribute(new Attribute("name", "german-service"));

+        component.addAttribute(new Attribute("classname", "org.apache.felix.ipojo.runtime.core.test.components.GermanHelloService"));

+        component.addElement(new Element("provides", null));

+        component.addElement(manipulation());

+        return component;

+    }

+

+    private Element manipulation() {

+        Element manipulation = new Element("manipulation", null);

+        manipulation.addAttribute(new Attribute("classname", "org.apache.felix.ipojo.runtime.core.test.components.GermanHelloService"));

+        manipulation.addAttribute(new Attribute("super", "java.lang.Object"));

+

+        Element itf = new Element("interface", null);

+        itf.addAttribute(new Attribute("name", "org.apache.felix.ipojo.runtime.core.test.services.HelloService"));

+        manipulation.addElement(itf);

+

+        Element method = new Element("method", null);

+        method.addAttribute(new Attribute("name", "hello"));

+        method.addAttribute(new Attribute("return", "java.lang.String"));

+        method.addAttribute(new Attribute("arguments", "{java.lang.String}"));

+        method.addAttribute(new Attribute("names", "{name}"));

+        manipulation.addElement(method);

+

+        return manipulation;

+    }

+

+    private static class EmptyFactoryBuilder implements FactoryBuilder {

+        @Override

+        public IPojoFactory build(final BundleContext bundleContext, final Element metadata) throws FactoryBuilderException {

+            return null;

+        }

+    }

+}

diff --git a/ipojo/runtime/core-it/pom.xml b/ipojo/runtime/core-it/pom.xml
index 70758cc..35dfbf5 100644
--- a/ipojo/runtime/core-it/pom.xml
+++ b/ipojo/runtime/core-it/pom.xml
@@ -46,11 +46,15 @@
     </properties>
 
     <modules>
+<!--
         <module>ipojo-core-annotations-test</module>
         <module>ipojo-core-bad-configuration-test</module>
         <module>ipojo-core-configuration-admin-test</module>
         <module>ipojo-core-configuration-processor-test</module>
         <module>ipojo-core-configuration-test</module>
+-->
+        <module>ipojo-core-declaration-test</module>
+<!--
         <module>ipojo-core-external-handlers-test</module>
         <module>ipojo-core-factory-test</module>
         <module>ipojo-core-factory-version-test</module>
@@ -67,6 +71,7 @@
         <module>ipojo-core-service-providing-test</module>
         <module>ipojo-api-test</module>
         <module>ipojo-compatibility-test</module>
+-->
     </modules>
 
     <build>
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ConfigurationBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ConfigurationBuilder.java
new file mode 100644
index 0000000..b3c2537
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/ConfigurationBuilder.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender;
+
+/**
+ * Support class for fluent instance declaration building.
+ * This class can be used to provide values for instance configuration.
+ * Any object can be used as configuration values (List and Maps are accepted for example).
+ *
+ * @since 1.12
+ */
+public interface ConfigurationBuilder {
+
+    /**
+     * Provide a property value.
+     * @param name property name
+     * @param value property value
+     * @return this builder
+     */
+    ConfigurationBuilder property(String name, Object value);
+
+    /**
+     * Remove a property from the configuration.
+     * This does not affect already created declarations (from this builder).
+     * @param name property name
+     * @return this builder
+     */
+    ConfigurationBuilder remove(String name);
+
+    /**
+     * Remove all properties from the configuration.
+     * This does not affect already created declarations (from this builder).
+     * @return this builder
+     */
+    ConfigurationBuilder clear();
+
+    /**
+     * Build the declaration handle (contains the instance configuration).
+     * Notice that the declaration is not yet published (no automatic activation).
+     * The client has to do it through {@link DeclarationHandle#publish()}
+     * @return the handle to the configured declaration
+     */
+    DeclarationHandle build();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationBuilderService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationBuilderService.java
new file mode 100644
index 0000000..731acff
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationBuilderService.java
@@ -0,0 +1,127 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender;
+
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.metadata.Element;
+
+/**
+ * This service provides a way for users to manage declarations through code.
+ *
+ * Notice that produced declarations are immutable once build. But it is possible to re-use a
+ * builder to share some configuration through instances.
+ *
+ * <pre>
+ *     // Obtain the service through the service registry
+ *     DeclarationBuilderService service = ...
+ *
+ *     // Get a fresh instance builder
+ *     DeclarationBuilder builder = service.newInstance("the.full.name.of.the.component.to.instantiate");
+ *
+ *     DeclarationHandle handle = builder.name("a-unique-name") // Make sure name is unique for the expected type
+ *                                       .configure()
+ *                                           .property("a-property", "a-value")
+ *                                           .property("another-property", "another-value")
+ *                                           .build();
+ *
+ *     // Push the InstanceDeclaration service in the registry
+ *     handle.publish();
+ * </pre>
+ *
+ * Except the {@link InstanceBuilder#build()} call, all methods are optional:
+ * <ul>
+ *     <li>{@link InstanceBuilder#name(String)}: if no name is provided,
+ *     a default one will be generated by iPOJO.</li>
+ *     <li>{@link InstanceBuilder#version(String)}: if no version is provided,
+ *     the first un-versioned type will be used.</li>
+ *     <li>{@link InstanceBuilder#configure()}: if no configuration is required, can be omitted.</li>
+ *     <li>{@link InstanceBuilder#type(String)}: can be used to change the <bold>required</bold> component type.</li>
+ *     <li>{@link InstanceBuilder#context(org.osgi.framework.BundleContext)}: by default, the bundle context
+ *     used to register the created {@link org.apache.felix.ipojo.extender.Declaration} is the one of the
+ *     caller. It can be changed though this method.</li>
+ * </ul>
+ *
+ * Once an instance handle has been created, its configuration (name, type, version and properties) is immutable. It can
+ * only be {@linkplain DeclarationHandle#publish() published} (so that the framework will try to instantiate the
+ * instance) or {@linkplain DeclarationHandle#retract() retracted} (framework will remove the instance).
+ *
+ * Notice that all created instances will appear as "coming from" the bundle that requires the
+ * {@link DeclarationBuilderService} service. Just like having a {@literal metadata.xml} file in your
+ * bundle that declares your instances. It is possible to override this default behavior using
+ * {@link InstanceBuilder#context(org.osgi.framework.BundleContext)}.
+ *
+ * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+ * @see org.apache.felix.ipojo.extender.TypeDeclaration
+ * @see org.apache.felix.ipojo.extender.ExtensionDeclaration
+ * @see org.apache.felix.ipojo.extender.InstanceBuilder
+ * @see org.apache.felix.ipojo.extender.ConfigurationBuilder
+ * @see org.apache.felix.ipojo.extender.DeclarationHandle
+ *
+ * @since 1.12
+ */
+public interface DeclarationBuilderService {
+
+    /**
+     * Declares a new anonymous instance of a given type.
+     * Invoking this method is equivalent to invoking <code>{@linkplain #newInstance(String, String) newInstance(type, null)}</code>.
+     * @param type name of the component to be instantiated (cannot be null).
+     * @return a handle usable to publish / retract the declaration.
+     * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+     */
+    InstanceBuilder newInstance(String type);
+
+    /**
+     * Declares a new instance of a given type.
+     * Invoking this method is equivalent to invoking <code>{@linkplain #newInstance(String, String, String) newInstance(type, name, null)}</code>.
+     * @param type name of the component to be instantiated.
+     * @param name name of the new instance (can be null)
+     * @return a handle usable to publish / retract the declaration.
+     * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+     */
+    InstanceBuilder newInstance(String type, String name);
+
+    /**
+     * Declares a new instance of a given type.
+     * @param type name of the component to be instantiated.
+     * @param name name of the new instance (can be null)
+     * @param version version of the expected type (can be null)
+     * @return a handle usable to publish / retract the declaration.
+     * @see org.apache.felix.ipojo.extender.InstanceDeclaration
+     */
+    InstanceBuilder newInstance(String type, String name, String version);
+
+    /**
+     * Declares a new extension (supports new types like {@literal component}, {@literal composite}, {@literal handler}).
+     * @param name name of the type to support (no namespace to be provided)
+     * @param builder associated factory builder
+     * @return a handle usable to publish / retract the declaration.
+     * @see org.apache.felix.ipojo.IPojoFactory
+     * @see org.apache.felix.ipojo.extender.ExtensionDeclaration
+     */
+    DeclarationHandle newExtension(String name, FactoryBuilder builder);
+
+    /**
+     * Declares a new type using the given element description.
+     * @param description description of the component type
+     * @return a handle usable to publish / retract the declaration.
+     * @see org.apache.felix.ipojo.extender.TypeDeclaration
+     */
+    DeclarationHandle newType(Element description);
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationHandle.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationHandle.java
new file mode 100644
index 0000000..1c0d044
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/DeclarationHandle.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender;
+
+/**
+ * Handle on the associated {@link org.apache.felix.ipojo.extender.Declaration} service.
+ * It can be used to start and/or stop the underlying declaration as well as retrieving its
+ * {@linkplain org.apache.felix.ipojo.extender.Status status} (bound or not).
+ *
+ * @since 1.12
+ */
+public interface DeclarationHandle {
+
+    /**
+     * Publish the {@link org.apache.felix.ipojo.extender.Declaration}. If the declaration
+     * is already registered, it's a no-op operation.
+     */
+    void publish();
+
+    /**
+     * Retract the {@link org.apache.felix.ipojo.extender.Declaration} service. If the
+     * declaration is not registered, it's a no-op operation.
+     */
+    void retract();
+
+    /**
+     * Return the current (instant) status of the declaration. Remember that
+     * {@link org.apache.felix.ipojo.extender.Status} is immutable (status does not change over time).
+     * If you want an updated status, call again the {@link #getStatus()} method.
+     * @return the instant status of the {@link org.apache.felix.ipojo.extender.Declaration}
+     */
+    Status getStatus();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceBuilder.java
new file mode 100644
index 0000000..69d7021
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/InstanceBuilder.java
@@ -0,0 +1,105 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender;
+
+import org.osgi.framework.BundleContext;
+
+/**
+ * Support class for fluent instance declaration building.
+ * This class can be used to specify instance details like naming, component's type, component's version.
+ * The {@link #context(org.osgi.framework.BundleContext)} method can be used to override the default
+ * {@link org.osgi.framework.BundleContext} used for declaration service registration.
+ *
+ * @since 1.12
+ */
+public interface InstanceBuilder {
+
+    /**
+     * Specify the instance name. Using {@literal null} will result in an anonymous instance.
+     * @param name instance name or {@literal null}
+     * @return this builder
+     */
+    InstanceBuilder name(String name);
+
+    /**
+     * Specify the component's type of this instance.
+     * @param type type of the instance (cannot be {@literal null}).
+     * @return this builder
+     */
+    InstanceBuilder type(String type);
+
+    /**
+     * Specify the component's type of this instance.
+     * @param type type of the instance (cannot be {@literal null}).
+     * @return this builder
+     */
+    InstanceBuilder type(Class<?> type);
+
+    /**
+     * Specify the component's version of this instance. If {@literal null} is used,
+     * the factory without any version attribute will be used.
+     * @param version component's version (can be {@literal null}).
+     * @return this builder
+     */
+    InstanceBuilder version(String version);
+
+    /**
+     * Override the default BundleContext used for declaration service registration.
+     * Use this with <bold>caution</bold>, for example, if the bundle does not import the
+     * <code>{@link org.apache.felix.ipojo.extender}</code> package, declarations may not be
+     * linked and activated properly.
+     * @param context new context to be used.
+     * @return this builder
+     */
+    InstanceBuilder context(BundleContext context);
+
+    /**
+     * Access the dedicated builder for configuration (properties).
+     * Notice that when this method is used, the called must use {@link ConfigurationBuilder#build()}
+     * to build the instance declaration configured with the right set of properties. Any attempt
+     * to use {@link #build()} will result in a new declaration with no properties associated.
+     *
+     * Good usage (produced declaration has the associated properties):
+     * <pre>
+     *     DeclarationHandle handle = builder.configure()
+     *                                            .property("hello", "world")
+     *                                            .build();
+     * </pre>
+     *
+     * Bad usage (produced declaration does not have the associated properties):
+     * <pre>
+     *     builder.configure()
+     *                .property("hello", "world");
+     *
+     *     DeclarationHandle handle = builder.build();
+     * </pre>
+     *
+     * @return the instance configuration builder
+     */
+    ConfigurationBuilder configure();
+
+    /**
+     * Build the declaration handle (never contains any configuration).
+     * Notice that the declaration is not yet published (no automatic activation).
+     * The client has to do it through {@link DeclarationHandle#publish()}
+     * @return the handle to the declaration
+     */
+    DeclarationHandle build();
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java
index 7fa1084..9f0a9b2 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/AbstractService.java
@@ -94,4 +94,11 @@
     protected ServiceRegistration<?> getRegistration() {
         return m_registration;
     }
+
+    /**
+     * Is this service registered or not ?
+     */
+    public boolean isRegistered() {
+        return m_registration != null;
+    }
 }
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java
index ddac180..492a31d 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/Extender.java
@@ -23,6 +23,7 @@
 
 import org.apache.felix.ipojo.ConfigurationTracker;
 import org.apache.felix.ipojo.EventDispatcher;
+import org.apache.felix.ipojo.extender.internal.declaration.service.DeclarationServiceFactory;
 import org.apache.felix.ipojo.extender.internal.linker.DeclarationLinker;
 import org.apache.felix.ipojo.extender.internal.processor.*;
 import org.apache.felix.ipojo.extender.internal.queue.ExecutorQueueService;
@@ -107,6 +108,11 @@
     private BundleTracker m_tracker;
 
     /**
+     * Service provided to build declarations through code.
+     */
+    private DeclarationServiceFactory m_declarationService;
+
+    /**
      * The iPOJO bundle is starting.
      * This method configures the iPOJO system (internal dispatcher and bundle processing). Then it initiates the
      * bundle processing.
@@ -211,6 +217,9 @@
 
         m_tracker.open();
 
+        m_declarationService = new DeclarationServiceFactory(context);
+        m_declarationService.start();
+
         m_logger.log(Logger.INFO, "iPOJO Main Extender started");
     }
 
@@ -221,6 +230,9 @@
      * @throws Exception something terrible happen
      */
     public void stop(BundleContext context) throws Exception {
+
+        m_declarationService.stop();
+
         m_tracker.close();
 
         m_processor.deactivate(m_bundle);
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java
index acca635..69197e8 100644
--- a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/AbstractDeclaration.java
@@ -20,6 +20,7 @@
 package org.apache.felix.ipojo.extender.internal.declaration;
 
 import org.apache.felix.ipojo.extender.Declaration;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
 import org.apache.felix.ipojo.extender.Status;
 import org.apache.felix.ipojo.extender.internal.AbstractService;
 import org.osgi.framework.BundleContext;
@@ -27,7 +28,7 @@
 /**
  * Common code to all Declaration objects.
  */
-public abstract class AbstractDeclaration extends AbstractService implements Declaration, Status {
+public abstract class AbstractDeclaration extends AbstractService implements Declaration, DeclarationHandle, Status {
 
     /**
      * The message used when a declaration is bound.
@@ -132,4 +133,16 @@
         m_message = message;
         m_throwable = throwable;
     }
+
+    public void publish() {
+        if (!isRegistered()) {
+            start();
+        }
+    }
+
+    public void retract() {
+        if (isRegistered()) {
+            stop();
+        }
+    }
 }
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DeclarationServiceFactory.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DeclarationServiceFactory.java
new file mode 100644
index 0000000..5682f65
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DeclarationServiceFactory.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import org.apache.felix.ipojo.extender.DeclarationBuilderService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * {@link org.osgi.framework.ServiceFactory} for {@link org.apache.felix.ipojo.extender.DeclarationBuilderService}.
+ * It avoids to explicitly gives a {@link org.osgi.framework.BundleContext} for each service method.
+ * The {@link org.osgi.framework.BundleContext} of the client is used.
+ */
+public class DeclarationServiceFactory implements ServiceFactory<DeclarationBuilderService> {
+
+    private final BundleContext bundleContext;
+    private ServiceRegistration<?> registration;
+
+    public DeclarationServiceFactory(final BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public void start() {
+        if (registration == null) {
+            registration = bundleContext.registerService(DeclarationBuilderService.class.getName(), this, null);
+        }
+    }
+
+    public void stop() {
+        if (registration != null) {
+            registration.unregister();
+            registration = null;
+        }
+    }
+
+    public DeclarationBuilderService getService(final Bundle bundle, final ServiceRegistration<DeclarationBuilderService> registration) {
+        return new DefaultDeclarationBuilderService(bundle.getBundleContext());
+    }
+
+    public void ungetService(final Bundle bundle, final ServiceRegistration<DeclarationBuilderService> registration, final DeclarationBuilderService service) {
+        // Nothing to do, built declarations will be kept
+        // It's the client responsibility to dispose its declarations
+    }
+
+
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilder.java
new file mode 100644
index 0000000..ee3f823
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilder.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import java.util.Hashtable;
+import java.util.Map;
+
+import org.apache.felix.ipojo.extender.ConfigurationBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+
+/**
+ * Declares a configuration and build the immutable {@link org.apache.felix.ipojo.extender.DeclarationHandle}
+ * containing that configuration.
+ */
+public class DefaultConfigurationBuilder implements ConfigurationBuilder {
+
+    private final DefaultInstanceBuilder builder;
+    private Map<String, Object> configuration = new Hashtable<String, Object>();
+
+    public DefaultConfigurationBuilder(final DefaultInstanceBuilder builder) {
+        this.builder = builder;
+    }
+
+    public ConfigurationBuilder property(final String name, final Object value) {
+        configuration.put(name, value);
+        return this;
+    }
+
+    public ConfigurationBuilder remove(final String name) {
+        configuration.remove(name);
+        return this;
+    }
+
+    public ConfigurationBuilder clear() {
+        configuration.clear();
+        return this;
+    }
+
+    public DeclarationHandle build() {
+        // Make a fresh dictionary instance, needed for immutable instance declarations
+        return builder.build(new Hashtable<String, Object>(configuration));
+    }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderService.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderService.java
new file mode 100644
index 0000000..a27ddbe
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderService.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationBuilderService;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultExtensionDeclaration;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultTypeDeclaration;
+import org.apache.felix.ipojo.metadata.Element;
+import org.osgi.framework.BundleContext;
+
+public class DefaultDeclarationBuilderService implements DeclarationBuilderService {
+
+    private final BundleContext context;
+
+    public DefaultDeclarationBuilderService(final BundleContext context) {
+        this.context = context;
+    }
+
+    public InstanceBuilder newInstance(final String type) {
+        return newInstance(type, null);
+    }
+
+    public InstanceBuilder newInstance(final String type, final String name) {
+        return newInstance(type, name, null);
+    }
+
+    public InstanceBuilder newInstance(final String type, final String name, final String version) {
+        return new DefaultInstanceBuilder(context, type)
+                .version(version)
+                .name(name);
+    }
+
+    public DeclarationHandle newExtension(final String name, final FactoryBuilder builder) {
+        return new DefaultExtensionDeclaration(context, builder, name);
+    }
+
+    public DeclarationHandle newType(final Element description) {
+        return new DefaultTypeDeclaration(context, description);
+    }
+}
diff --git a/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilder.java b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilder.java
new file mode 100644
index 0000000..d9d6655
--- /dev/null
+++ b/ipojo/runtime/core/src/main/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilder.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import static java.lang.String.format;
+
+import java.util.Dictionary;
+import java.util.Hashtable;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.extender.ConfigurationBuilder;
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultInstanceDeclaration;
+import org.osgi.framework.BundleContext;
+
+/**
+ * User: guillaume
+ * Date: 13/02/2014
+ * Time: 09:36
+ */
+public class DefaultInstanceBuilder implements InstanceBuilder {
+
+    private BundleContext context;
+    private String name;
+    private String type;
+    private String version;
+
+    public DefaultInstanceBuilder(final BundleContext context, final String type) {
+        this.context(context);
+        this.type(type);
+    }
+
+    public InstanceBuilder name(final String name) {
+        this.name = name;
+        return this;
+    }
+
+    public InstanceBuilder type(final String type) {
+        if (type == null) {
+            throw new IllegalArgumentException(format("'type' parameter cannot be null (instance must be of a given type)"));
+        }
+        this.type = type;
+        return this;
+    }
+
+    public InstanceBuilder type(final Class<?> type) {
+        if (type == null) {
+            throw new IllegalArgumentException(format("'type' parameter cannot be null (instance must be of a given type)"));
+        }
+        return type(type.getName());
+    }
+
+    public InstanceBuilder version(final String version) {
+        this.version = version;
+        return this;
+    }
+
+    public InstanceBuilder context(final BundleContext context) {
+        if (context == null) {
+            throw new IllegalArgumentException(format("'context' parameter cannot be null"));
+        }
+        this.context = context;
+        return this;
+    }
+
+    public ConfigurationBuilder configure() {
+        return new DefaultConfigurationBuilder(this);
+    }
+
+    /**
+     * Only called through ConfigurationBuilder to apply the created configuration to this instance
+     * @param configuration
+     */
+    public DeclarationHandle build(Dictionary<String, Object> configuration) {
+
+        // Prepare the instance configuration
+        if (configuration == null) {
+            configuration = new Hashtable<String, Object>();
+        }
+
+        if (name != null) {
+            configuration.put(Factory.INSTANCE_NAME_PROPERTY, name);
+        }
+
+        if (version != null) {
+            configuration.put(Factory.FACTORY_VERSION_PROPERTY, version);
+        }
+
+        return new DefaultInstanceDeclaration(context, type, configuration);
+
+    }
+
+    public DeclarationHandle build() {
+        return build(new Hashtable<String, Object>());
+    }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java
index e372f00..cc81f0d 100644
--- a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/DefaultInstanceDeclarationTestCase.java
@@ -19,20 +19,23 @@
 
 package org.apache.felix.ipojo.extender.internal.declaration;
 
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import java.util.Dictionary;
 import java.util.Hashtable;
 
 import org.apache.felix.ipojo.Factory;
 import org.apache.felix.ipojo.extender.InstanceDeclaration;
-import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.mockito.runners.MockitoJUnitRunner;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.ServiceRegistration;
 
 import junit.framework.TestCase;
 
@@ -44,12 +47,22 @@
     @Mock
     private BundleContext m_bundleContext;
 
+    @Mock
+    private ServiceRegistration<?> m_registration;
+
     @Captor
     private ArgumentCaptor<Hashtable<String, Object>> argument;
 
     @Override
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        doReturn(m_registration)
+                .when(m_bundleContext)
+                .registerService(
+                        eq(InstanceDeclaration.class.getName()),
+                        anyObject(),
+                        any(Dictionary.class));
+
     }
 
     public void testRegistrationWithEmptyConfiguration() throws Exception {
@@ -82,4 +95,38 @@
         assertEquals(argument.getValue().get(InstanceDeclaration.COMPONENT_VERSION_PROPERTY), "1.0.0");
 
     }
+
+    public void testHandlePublication() throws Exception {
+        DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+        declaration.publish();
+        assertTrue(declaration.isRegistered());
+    }
+
+    public void testHandleMultiplePublication() throws Exception {
+        DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+        declaration.publish();
+        assertTrue(declaration.isRegistered());
+        declaration.publish();
+        assertTrue(declaration.isRegistered());
+    }
+
+    public void testHandleRetraction() throws Exception {
+        DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+        declaration.publish();
+        assertTrue(declaration.isRegistered());
+        declaration.retract();
+        assertFalse(declaration.isRegistered());
+        verify(m_registration).unregister();
+    }
+
+    public void testHandleMultipleRetraction() throws Exception {
+        DefaultInstanceDeclaration declaration = new DefaultInstanceDeclaration(m_bundleContext, "component.Hello");
+        declaration.publish();
+        assertTrue(declaration.isRegistered());
+        declaration.retract();
+        assertFalse(declaration.isRegistered());
+        declaration.retract();
+        assertFalse(declaration.isRegistered());
+        verify(m_registration).unregister();
+    }
 }
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilderTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilderTestCase.java
new file mode 100644
index 0000000..3edb304
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultConfigurationBuilderTestCase.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 13/02/2014
+ * Time: 11:33
+ */
+public class DefaultConfigurationBuilderTestCase extends TestCase {
+
+    @Mock
+    private BundleContext m_bundleContext;
+    private DefaultInstanceBuilder parent;
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+        parent = new DefaultInstanceBuilder(m_bundleContext, "type");
+    }
+
+    public void testPropertyAddition() throws Exception {
+        DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+        builder.property("a", "b");
+        InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+        assertEquals(declaration.getConfiguration().get("a"), "b");
+    }
+
+    public void testPropertyAdditionReUse() throws Exception {
+        DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+        builder.property("a", "b");
+
+        // First built instance
+        InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+        assertEquals(declaration.getConfiguration().get("a"), "b");
+
+        // Second built instance
+        builder.property("c", "d");
+        InstanceDeclaration declaration2 = (InstanceDeclaration) builder.build();
+        assertEquals(declaration2.getConfiguration().get("a"), "b");
+        assertEquals(declaration2.getConfiguration().get("c"), "d");
+
+        // Verify that first instance is not modified
+        assertNull(declaration.getConfiguration().get("c"));
+
+    }
+
+    public void testPropertyRemoval() throws Exception {
+        DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+        builder.property("a", "b");
+
+        InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+        assertEquals(declaration.getConfiguration().get("a"), "b");
+
+        builder.remove("a");
+
+        InstanceDeclaration declaration2 = (InstanceDeclaration) builder.build();
+        assertNull(declaration2.getConfiguration().get("a"));
+
+    }
+
+    public void testClear() throws Exception {
+        DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder(parent);
+        builder.property("a", "b");
+        builder.property("c", "d");
+
+        InstanceDeclaration declaration = (InstanceDeclaration) builder.build();
+        assertEquals(declaration.getConfiguration().get("a"), "b");
+
+        builder.clear();
+
+        InstanceDeclaration declaration2 = (InstanceDeclaration) builder.build();
+        assertTrue(declaration2.getConfiguration().isEmpty());
+
+    }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderServiceTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderServiceTestCase.java
new file mode 100644
index 0000000..87bf9c4
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultDeclarationBuilderServiceTestCase.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.verify;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.ExtensionDeclaration;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.TypeDeclaration;
+import org.apache.felix.ipojo.extender.builder.FactoryBuilder;
+import org.apache.felix.ipojo.metadata.Element;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 10/02/2014
+ * Time: 15:41
+ */
+public class DefaultDeclarationBuilderServiceTestCase extends TestCase {
+
+    @Mock
+    private BundleContext m_bundleContext;
+
+    @Mock
+    private FactoryBuilder m_factoryBuilder;
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testNewInstance() throws Exception {
+        DefaultDeclarationBuilderService service = new DefaultDeclarationBuilderService(m_bundleContext);
+        assertNotNull(service.newInstance("type.of.component"));
+        assertNotNull(service.newInstance("type.of.component", "instance.name"));
+        InstanceBuilder builder = service.newInstance("type.of.component", "instance.name", "component.version");
+        assertNotNull(builder);
+        DeclarationHandle instance = builder.build();
+        instance.publish();
+        verify(m_bundleContext).registerService(
+                eq(InstanceDeclaration.class.getName()),
+                anyObject(),
+                any(Dictionary.class));
+    }
+
+    public void testNewExtension() throws Exception {
+        DefaultDeclarationBuilderService service = new DefaultDeclarationBuilderService(m_bundleContext);
+        DeclarationHandle extension = service.newExtension("test", m_factoryBuilder);
+        assertNotNull(extension);
+        extension.publish();
+        verify(m_bundleContext).registerService(
+                eq(ExtensionDeclaration.class.getName()),
+                anyObject(),
+                any(Dictionary.class));
+    }
+
+    public void testNewType() throws Exception {
+        DefaultDeclarationBuilderService service = new DefaultDeclarationBuilderService(m_bundleContext);
+        DeclarationHandle type = service.newType(new Element("component", null));
+        assertNotNull(type);
+        type.publish();
+        verify(m_bundleContext).registerService(
+                eq(TypeDeclaration.class.getName()),
+                anyObject(),
+                isNull(Dictionary.class));
+    }
+}
diff --git a/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilderTestCase.java b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilderTestCase.java
new file mode 100644
index 0000000..abc5c73
--- /dev/null
+++ b/ipojo/runtime/core/src/test/java/org/apache/felix/ipojo/extender/internal/declaration/service/DefaultInstanceBuilderTestCase.java
@@ -0,0 +1,111 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.felix.ipojo.extender.internal.declaration.service;
+
+import java.util.Dictionary;
+
+import org.apache.felix.ipojo.Factory;
+import org.apache.felix.ipojo.extender.InstanceBuilder;
+import org.apache.felix.ipojo.extender.DeclarationHandle;
+import org.apache.felix.ipojo.extender.InstanceDeclaration;
+import org.apache.felix.ipojo.extender.internal.declaration.DefaultInstanceDeclaration;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.osgi.framework.BundleContext;
+
+import junit.framework.TestCase;
+
+/**
+ * User: guillaume
+ * Date: 13/02/2014
+ * Time: 10:32
+ */
+public class DefaultInstanceBuilderTestCase extends TestCase {
+
+    @Mock
+    private BundleContext m_bundleContext;
+
+    @Override
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    public void testNoConfiguration() throws Exception {
+        InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+        DeclarationHandle handle = builder.build();
+        InstanceDeclaration did = (InstanceDeclaration) handle;
+
+        assertEquals("type", did.getComponentName());
+        assertEquals(InstanceDeclaration.UNNAMED_INSTANCE, did.getInstanceName());
+        assertNull(did.getComponentVersion());
+
+        Dictionary<String,Object> configuration = did.getConfiguration();
+        assertTrue(configuration.isEmpty());
+    }
+
+    public void testNameConfiguration() throws Exception {
+        InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type").name("John");
+
+        DeclarationHandle handle = builder.build();
+        InstanceDeclaration did = (InstanceDeclaration) handle;
+
+        assertEquals("type", did.getComponentName());
+        assertEquals("John", did.getInstanceName());
+        assertNull(did.getComponentVersion());
+
+        Dictionary<String,Object> configuration = did.getConfiguration();
+        assertEquals("John", configuration.get(Factory.INSTANCE_NAME_PROPERTY));
+    }
+
+    public void testVersionConfiguration() throws Exception {
+        InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type").name("John").version("1.0");
+
+        DeclarationHandle handle = builder.build();
+        InstanceDeclaration did = (InstanceDeclaration) handle;
+
+        assertEquals("type", did.getComponentName());
+        assertEquals("John", did.getInstanceName());
+        assertEquals("1.0", did.getComponentVersion());
+
+        Dictionary<String,Object> configuration = did.getConfiguration();
+        assertEquals("John", configuration.get(Factory.INSTANCE_NAME_PROPERTY));
+        assertEquals("1.0", configuration.get(Factory.FACTORY_VERSION_PROPERTY));
+    }
+
+    public void testBuilderReUseProvidesDifferentInstances() throws Exception {
+        InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+        assertNotSame(builder.build(), builder.build());
+    }
+
+
+    public void testDeclarationIsNotAutomaticallyStarted() throws Exception {
+        InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+        DeclarationHandle handle = builder.build();
+        DefaultInstanceDeclaration did = (DefaultInstanceDeclaration) handle;
+
+        assertFalse(did.isRegistered());
+    }
+
+    public void testDeepConfiguration() throws Exception {
+        InstanceBuilder builder = new DefaultInstanceBuilder(m_bundleContext, "type");
+        assertNotNull(builder.configure());
+    }
+}
+