karaf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ioca...@apache.org
Subject svn commit: r1100302 [3/5] - in /karaf/cellar: ./ branches/ tags/ trunk/ trunk/config/ trunk/config/src/ trunk/config/src/main/ trunk/config/src/main/java/ trunk/config/src/main/java/org/ trunk/config/src/main/java/org/apache/ trunk/config/src/main/jav...
Date Fri, 06 May 2011 17:55:42 GMT
Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/Event.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/Event.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/Event.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/Event.java Fri May  6 17:55:35 2011
@@ -0,0 +1,94 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.Node;
+
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * Represents an event that is broadcasted to the cluster.
+ * The event is always generated by a single node (source) but can have none or multiple destinations.
+ *
+ * @author: iocanel
+ */
+public class Event implements Serializable {
+
+    protected String id;
+    protected Node sourceNode;
+    protected Group sourceGroup;
+    protected Set<Node> destination;
+    protected Boolean force = Boolean.FALSE;
+    protected Boolean postPublish = Boolean.FALSE;
+
+    /**
+     * Constructor
+     *
+     * @param id
+     */
+    public Event(String id) {
+        this.id = id;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Node getSourceNode() {
+        return sourceNode;
+    }
+
+    public void setSourceNode(Node sourceNode) {
+        this.sourceNode = sourceNode;
+    }
+
+    public Group getSourceGroup() {
+        return sourceGroup;
+    }
+
+    public void setSourceGroup(Group sourceGroup) {
+        this.sourceGroup = sourceGroup;
+    }
+
+    public Set<Node> getDestination() {
+        return destination;
+    }
+
+    public void setDestination(Set<Node> destination) {
+        this.destination = destination;
+    }
+
+    public Boolean getForce() {
+        return force;
+    }
+
+    public void setForce(Boolean force) {
+        this.force = force;
+    }
+
+    public Boolean getPostPublish() {
+        return postPublish;
+    }
+
+    public void setPostPublish(Boolean postPublish) {
+        this.postPublish = postPublish;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventConsumer.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventConsumer.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventConsumer.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventConsumer.java Fri May  6 17:55:35 2011
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.apache.karaf.cellar.core.Consumer;
+
+/**
+ * @author iocanel
+ */
+public interface EventConsumer<E extends Event> extends Consumer<E> {
+
+    /**
+     * Consumes {@code Event}s to the cluster.
+     *
+     * @param event
+     */
+    public void consume(E event);
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatchTask.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatchTask.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatchTask.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatchTask.java Fri May  6 17:55:35 2011
@@ -0,0 +1,106 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author iocanel
+ */
+public class EventDispatchTask<E extends Event> implements Runnable {
+
+    private Logger logger = LoggerFactory.getLogger(EventDispatchTask.class);
+    private E event;
+    private EventHandlerRegistry handlerRegistry;
+    private long timeout = 10000;
+    private long interval = 1000;
+
+    /**
+     * Constructor
+     *
+     * @param event
+     * @param handlerRegistry
+     */
+    public EventDispatchTask(E event, EventHandlerRegistry handlerRegistry) {
+        this.event = event;
+        this.handlerRegistry = handlerRegistry;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param event
+     * @param handlerRegistry
+     * @param timeout
+     */
+    public EventDispatchTask(E event, EventHandlerRegistry handlerRegistry, long timeout) {
+        this.event = event;
+        this.handlerRegistry = handlerRegistry;
+        this.timeout = timeout;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param handlerRegistry
+     * @param timeout
+     * @param interval
+     * @param event
+     */
+    public EventDispatchTask(EventHandlerRegistry handlerRegistry, long timeout, long interval, E event) {
+        this.handlerRegistry = handlerRegistry;
+        this.timeout = timeout;
+        this.interval = interval;
+        this.event = event;
+    }
+
+    public void run() {
+        boolean dispathced = false;
+
+        for (long delay = 0; delay < timeout && !dispathced; delay += interval) {
+            EventHandler handler = handlerRegistry.getHandler(event);
+            if (handler != null) {
+                handler.handle(event);
+                dispathced = true;
+            } else {
+                try {
+                    Thread.sleep(interval);
+                } catch (InterruptedException e) {
+                    logger.warn("Interupted while waiting for event handler", e);
+                }
+            }
+        }
+        if (!dispathced) {
+            logger.warn("Failed to retrieve handler for event {}", event.getClass());
+        }
+    }
+
+    public long getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(long timeout) {
+        this.timeout = timeout;
+    }
+
+    public long getInterval() {
+        return interval;
+    }
+
+    public void setInterval(long interval) {
+        this.interval = interval;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatcher.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatcher.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatcher.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventDispatcher.java Fri May  6 17:55:35 2011
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.apache.karaf.cellar.core.Dispatcher;
+
+/**
+ * A dispatcher which dispatches each event to the appropriate Handler.
+ *
+ * @author iocanel
+ */
+public interface EventDispatcher<E extends Event> extends Dispatcher<E> {
+
+
+    /**
+     * Dispatches the Event to the appropriate handler.
+     *
+     * @param event
+     */
+    public void dispatch(E event);
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandler.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandler.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandler.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandler.java Fri May  6 17:55:35 2011
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+
+import org.apache.karaf.cellar.core.Handler;
+
+public interface EventHandler<E extends Event> extends Handler<E> {
+
+    public static String MANAGED_FILTER = "(managed=true)";
+
+    /**
+     * Called to handle {@code Event}.
+     */
+    public void handle(E event);
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerRegistry.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerRegistry.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerRegistry.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerRegistry.java Fri May  6 17:55:35 2011
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.apache.karaf.cellar.core.Handler;
+import org.apache.karaf.cellar.core.HandlerRegistry;
+
+/**
+ * @author iocanel
+ */
+public interface EventHandlerRegistry<E extends Event> extends HandlerRegistry<E, Handler<E>> {
+
+    /**
+     * Returns the {@code EventHandler} for the given {@code Event}.
+     *
+     * @param event
+     * @return
+     */
+    public EventHandler<E> getHandler(E event);
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistry.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistry.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistry.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistry.java Fri May  6 17:55:35 2011
@@ -0,0 +1,63 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleReference;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author iocanel
+ */
+public class EventHandlerServiceRegistry<E extends Event> implements EventHandlerRegistry<E> {
+
+    private static final Logger logger = LoggerFactory.getLogger(EventHandlerServiceRegistryDispatcher.class);
+
+    /**
+     * Returns the appropriate {@code EventHandler} found inside the {@code HandlerRegistry}.
+     *
+     * @param event
+     * @return
+     */
+    public EventHandler<E> getHandler(E event) {
+        BundleContext bundleContext = ((BundleReference) getClass().getClassLoader()).getBundle().getBundleContext();
+
+        ServiceReference[] references = new ServiceReference[0];
+        try {
+            references = bundleContext.getServiceReferences("org.apache.karaf.cellar.core.event.EventHandler", null);
+            if (references != null && references.length > 0) {
+                for (int i = 0; i < references.length; i++) {
+                    ServiceReference ref = references[i];
+                    try {
+                        EventHandler handler = (EventHandler) bundleContext.getService(ref);
+                        if (handler.getType().equals(event.getClass())) {
+                            return handler;
+                        }
+                    } catch (Exception ex) {
+                        logger.error("Failed to get handler from Service Reference.", ex);
+                    } finally {
+                        bundleContext.ungetService(ref);
+                    }
+                }
+            }
+        } catch (InvalidSyntaxException e) {
+            logger.error("Failed to lookup Service Registry for Event Hanlders.", e);
+        }
+        return null;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistryDispatcher.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistryDispatcher.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistryDispatcher.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventHandlerServiceRegistryDispatcher.java Fri May  6 17:55:35 2011
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+/**
+ * @author iocanel
+ */
+public class EventHandlerServiceRegistryDispatcher<E extends Event> implements EventDispatcher<E> {
+
+    private static final Logger logger = LoggerFactory.getLogger(EventHandlerServiceRegistryDispatcher.class);
+
+    private ExecutorService threadPool;
+    private EventHandlerServiceRegistry handlerRegistry;
+
+    /**
+     * Initialization
+     */
+    public void init() {
+        if (threadPool == null) {
+            threadPool = Executors.newCachedThreadPool();
+        }
+    }
+
+    /**
+     * Dispatches an {@code Event} to the appropriate {@code EventHandler}.
+     *
+     * @param event
+     */
+    public void dispatch(E event) {
+        EventDispatchTask task = new EventDispatchTask(event, handlerRegistry);
+        threadPool.execute(task);
+    }
+
+    public EventHandlerServiceRegistry getHandlerRegistry() {
+        return handlerRegistry;
+    }
+
+    public void setHandlerRegistry(EventHandlerServiceRegistry handlerRegistry) {
+        this.handlerRegistry = handlerRegistry;
+    }
+
+    public ExecutorService getThreadPool() {
+        return threadPool;
+    }
+
+    public void setThreadPool(ExecutorService threadPool) {
+        this.threadPool = threadPool;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventProducer.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventProducer.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventProducer.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventProducer.java Fri May  6 17:55:35 2011
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+import org.apache.karaf.cellar.core.Producer;
+
+/**
+ * Transmits events to the cluster.
+ *
+ * @author iocanel
+ */
+public interface EventProducer<E extends Event> extends Producer<E> {
+
+    /**
+     * Produce {@code Event}s to the cluster.
+     *
+     * @param event
+     */
+    public void produce(E event);
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventTracker.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventTracker.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventTracker.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventTracker.java Fri May  6 17:55:35 2011
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+/**
+ * @author iocanel
+ */
+public interface EventTracker<E extends Event> {
+
+    /**
+     * Starts tracking the occurance of an {@code Event}.
+     *
+     * @param event
+     */
+    public void start(E event);
+
+    /**
+     * Stops tracking the occurance of an {@code Event}.
+     *
+     * @param event
+     */
+    public void stop(E event);
+
+    /**
+     * Returns true if the {@code Event} is being tracked.
+     *
+     * @param event
+     * @return
+     */
+    public Boolean isPending(E event);
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventType.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventType.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventType.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/event/EventType.java Fri May  6 17:55:35 2011
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.event;
+
+/**
+ * @author iocanel
+ */
+public enum EventType {
+    INBOUND,
+    OUTBOUND;
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/CellarCommandSupport.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/CellarCommandSupport.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/CellarCommandSupport.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/CellarCommandSupport.java Fri May  6 17:55:35 2011
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.shell;
+
+import org.apache.karaf.cellar.core.ClusterManager;
+import org.apache.karaf.cellar.core.GroupManager;
+import org.apache.karaf.shell.console.OsgiCommandSupport;
+
+/**
+ * @author: iocanel
+ */
+public abstract class CellarCommandSupport extends OsgiCommandSupport {
+
+    protected ClusterManager clusterManager;
+    protected GroupManager groupManager;
+
+
+    public ClusterManager getClusterManager() {
+        return clusterManager;
+    }
+
+    public void setClusterManager(ClusterManager clusterManager) {
+        this.clusterManager = clusterManager;
+    }
+
+    public GroupManager getGroupManager() {
+        return groupManager;
+    }
+
+    public void setGroupManager(GroupManager groupManager) {
+        this.groupManager = groupManager;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/AllGroupsCompleter.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/AllGroupsCompleter.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/AllGroupsCompleter.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/AllGroupsCompleter.java Fri May  6 17:55:35 2011
@@ -0,0 +1,27 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.shell.completers;
+
+import org.apache.karaf.cellar.core.Group;
+
+/**
+ * @author iocanel
+ */
+public class AllGroupsCompleter extends GroupCompleterSupport {
+    @Override
+    protected boolean acceptsGroup(Group group) {
+        return true;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/GroupCompleterSupport.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/GroupCompleterSupport.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/GroupCompleterSupport.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/GroupCompleterSupport.java Fri May  6 17:55:35 2011
@@ -0,0 +1,58 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.shell.completers;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.GroupManager;
+import org.apache.karaf.shell.console.Completer;
+import org.apache.karaf.shell.console.completer.StringsCompleter;
+
+import java.util.List;
+
+/**
+ * @author: iocanel
+ */
+public abstract class GroupCompleterSupport implements Completer {
+
+    protected GroupManager groupManager;
+
+    protected abstract boolean acceptsGroup(Group group);
+
+    public int complete(String buffer, int cursor, List<String> candidates) {
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (Group group : groupManager.listAllGroups()) {
+                if (acceptsGroup(group)) {
+                    String name = group.getName();
+                    if (delegate.getStrings() != null && !delegate.getStrings().contains(name)) {
+                        delegate.getStrings().add(name);
+                    }
+                }
+            }
+        } catch (Exception e) {
+            // Ignore
+        }
+        return delegate.complete(buffer, cursor, candidates);
+    }
+
+
+    public GroupManager getGroupManager() {
+        return groupManager;
+    }
+
+    public void setGroupManager(GroupManager groupManager) {
+        this.groupManager = groupManager;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/LocalGroupsCompleter.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/LocalGroupsCompleter.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/LocalGroupsCompleter.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/LocalGroupsCompleter.java Fri May  6 17:55:35 2011
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.shell.completers;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.Node;
+
+/**
+ * @author: iocanel
+ */
+public class LocalGroupsCompleter extends GroupCompleterSupport {
+    @Override
+    protected boolean acceptsGroup(Group group) {
+        Node node = groupManager.getNode();
+        if (group.getMembers().contains(node))
+            return true;
+        else return false;
+    }
+}

Added: karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/OtherGroupsCompleter.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/OtherGroupsCompleter.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/OtherGroupsCompleter.java (added)
+++ karaf/cellar/trunk/core/src/main/java/org/apache/karaf/cellar/core/shell/completers/OtherGroupsCompleter.java Fri May  6 17:55:35 2011
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.core.shell.completers;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.Node;
+
+/**
+ * @author: iocanel
+ */
+public class OtherGroupsCompleter extends GroupCompleterSupport {
+    @Override
+    protected boolean acceptsGroup(Group group) {
+        Node node = groupManager.getNode();
+        if (group.getMembers().contains(node))
+            return false;
+        else return true;
+    }
+}

Added: karaf/cellar/trunk/features/pom.xml
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/pom.xml?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/pom.xml (added)
+++ karaf/cellar/trunk/features/pom.xml Fri May  6 17:55:35 2011
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+   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.
+  -->
+
+<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.karaf.cellar</groupId>
+        <artifactId>karaf-cellar</artifactId>
+        <version>1.0.0-SNAPSHOT</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>features</artifactId>
+    <packaging>bundle</packaging>
+    <name>Apache Karaf :: Cellar :: Features</name>
+
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <osgi.import>
+            !org.apache.karaf.cellar.features*,
+            org.apache.karaf.cellar.core*;version=${project.version},
+            org.apache.karaf.cellar.common*;version=${project.version},
+            org.apache.karaf.features;version="[2,3)",
+            *
+        </osgi.import>
+        <osgi.dynamic.import>javax.*,org.w3c.*,org.xml.*</osgi.dynamic.import>
+        <osgi.export>
+            org.apache.karaf.cellar.features*;version=${project.version}
+        </osgi.export>
+    </properties>
+
+    <dependencies>
+        <!-- Internal Dependencies -->
+        <dependency>
+            <groupId>org.apache.karaf.cellar</groupId>
+            <artifactId>core</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Configuration Admin -->
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.configadmin</artifactId>
+        </dependency>
+
+        <!-- Karaf features -->
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.core</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.karaf.features</groupId>
+            <artifactId>org.apache.karaf.features.command</artifactId>
+        </dependency>
+
+
+        <!-- Logging -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-simple</artifactId>
+        </dependency>
+
+        <!-- Testing -->
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+        </dependency>
+    </dependencies>
+</project>
\ No newline at end of file

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/Constants.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/Constants.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/Constants.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/Constants.java Fri May  6 17:55:35 2011
@@ -0,0 +1,26 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+/**
+ * @author iocanel
+ */
+public class Constants {
+    public static final String REPOSITORIES = "org.apache.karaf.cellar.repositories";
+    public static final String FEATURES = "org.apache.karaf.cellar.features";
+    public static final String REPOSITORIES_CATEGORY = "repositories";
+    public static final String FEATURES_CATEGORY = "features";
+
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeatureInfo.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeatureInfo.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeatureInfo.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeatureInfo.java Fri May  6 17:55:35 2011
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import java.io.Serializable;
+
+/**
+ * @author iocanel
+ */
+public class FeatureInfo implements Serializable {
+
+    private String name;
+    private String version;
+
+    public FeatureInfo(String name, String version) {
+        this.name = name;
+        this.version = version;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        FeatureInfo info = (FeatureInfo) o;
+
+        if (name != null ? !name.equals(info.name) : info.name != null) return false;
+        if (version != null ? !version.equals(info.version) : info.version != null) return false;
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = name != null ? name.hashCode() : 0;
+        result = 31 * result + (version != null ? version.hashCode() : 0);
+        return result;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesEventHandler.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesEventHandler.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesEventHandler.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesEventHandler.java Fri May  6 17:55:35 2011
@@ -0,0 +1,83 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+
+import org.apache.karaf.cellar.core.control.BasicSwitch;
+import org.apache.karaf.cellar.core.control.Switch;
+import org.apache.karaf.cellar.core.event.EventHandler;
+import org.apache.karaf.cellar.core.event.EventType;
+import org.apache.karaf.features.FeatureEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author iocanel
+ */
+public class FeaturesEventHandler extends FeaturesSupport implements EventHandler<RemoteFeaturesEvent> {
+
+    private static Logger logger = LoggerFactory.getLogger(FeaturesSynchronizer.class);
+    public static final String SWITCH_ID = "org.apache.karaf.cellar.event.features.handler";
+
+    private final Switch eventSwitch = new BasicSwitch(SWITCH_ID);
+
+    @Override
+    public void init() {
+        super.init();
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+    }
+
+    /**
+     * Features Event.
+     *
+     * @param event
+     */
+    public void handle(RemoteFeaturesEvent event) {
+        String name = event.getName();
+        String version = event.getVersion();
+        if (isAllowed(event.getSourceGroup(), Constants.FEATURES_CATEGORY, name, EventType.INBOUND) || event.getForce()) {
+            logger.debug("Received features event {} version {} type {}.", new Object[]{event.getName(), event.getVersion(), event.getType()});
+            FeatureEvent.EventType type = event.getType();
+            Boolean isInstalled = isInstanlled(name, version);
+            try {
+                if (FeatureEvent.EventType.FeatureInstalled.equals(type) && !isInstalled) {
+                    logger.debug("Installing feature {} version {}", name, version);
+                    if (version != null) {
+                        featuresService.installFeature(name, version);
+                    } else featuresService.installFeature(name);
+                } else if (FeatureEvent.EventType.FeatureUninstalled.equals(type) && isInstalled) {
+                    logger.debug("Uninstalling feature {} version {}", name, version);
+                    if (version != null) {
+                        featuresService.uninstallFeature(name, version);
+                    } else featuresService.uninstallFeature(name);
+                }
+            } catch (Exception e) {
+                logger.error("Failed to process feature event.", e);
+            }
+        } else logger.debug("Feature with name {} is marked as BLOCKED INBOUND", name);
+    }
+
+    public Class<RemoteFeaturesEvent> getType() {
+        return RemoteFeaturesEvent.class;
+    }
+
+    public Switch getSwitch() {
+        return eventSwitch;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSupport.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSupport.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSupport.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSupport.java Fri May  6 17:55:35 2011
@@ -0,0 +1,139 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import org.apache.karaf.cellar.core.CellarSupport;
+import org.apache.karaf.cellar.core.Configurations;
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.event.EventType;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author iocanel
+ */
+public class FeaturesSupport extends CellarSupport {
+
+    private static Logger logger = LoggerFactory.getLogger(FeaturesSupport.class);
+
+    protected FeaturesService featuresService;
+
+
+    /**
+     * Initialization method
+     */
+    public void init() {
+    }
+
+    /**
+     * Destruction method
+     */
+    public void destroy() {
+
+    }
+
+    /**
+     * Returns true if the specified feature is installed.
+     *
+     * @param name
+     * @param version
+     * @return
+     */
+    public Boolean isInstanlled(String name, String version) {
+        if (featuresService != null) {
+            Feature[] features = featuresService.listInstalledFeatures();
+
+            if (features != null && features.length > 0) {
+                for (Feature feature : features) {
+                    if (feature.getName().equals(name) && (feature.getVersion().equals(version) || version == null))
+                        return true;
+                }
+            }
+        }
+        return false;
+    }
+
+
+    /**
+     * Pushes a {@code Feature} and its status to the distributed list of features.
+     *
+     * @param feature
+     */
+    public void pushFeature(Feature feature, Group group) {
+        if (feature != null) {
+            String groupName = group.getName();
+            Map<FeatureInfo, Boolean> features = clusterManager.getMap(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+
+            if (isAllowed(group, Constants.FEATURES_CATEGORY, feature.getName(), EventType.OUTBOUND)) {
+                if (featuresService != null && features != null) {
+                    FeatureInfo info = new FeatureInfo(feature.getName(), feature.getVersion());
+                    Boolean installed = featuresService.isInstalled(feature);
+                    features.put(info, installed);
+                }
+            } else logger.debug("Feature with name {} is marked as BLOCKED OUTBOUND");
+        } else logger.debug("Feature is null");
+    }
+
+    /**
+     * Pushes a {@code Feature} and its status to the distributed list of features.
+     * This version of the method force the bundle status, without looking the features service.
+     *
+     * @param feature
+     */
+    public void pushFeature(Feature feature, Group group, Boolean force) {
+        if (feature != null) {
+            String groupName = group.getName();
+            Map<FeatureInfo, Boolean> features = clusterManager.getMap(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+
+            if (isAllowed(group, Constants.FEATURES_CATEGORY, feature.getName(), EventType.OUTBOUND)) {
+                if (featuresService != null && features != null) {
+                    FeatureInfo info = new FeatureInfo(feature.getName(), feature.getVersion());
+                    features.put(info, force);
+                }
+            } else logger.debug("Feature with name {} is marked as BLOCKED OUTBOUND");
+        } else logger.debug("Feature is null");
+    }
+
+    /**
+     * Pushed a {@code Repository} to the distributed list of repositories.
+     *
+     * @param repository
+     */
+    public void pushRepository(Repository repository, Group group) {
+        String groupName = group.getName();
+        List<String> repositories = clusterManager.getList(Constants.REPOSITORIES + Configurations.SEPARATOR + groupName);
+
+        if (featuresService != null && repositories != null) {
+            URI uri = repository.getURI();
+            repositories.add(uri.toString());
+        }
+    }
+
+
+    public FeaturesService getFeaturesService() {
+        return featuresService;
+    }
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/FeaturesSynchronizer.java Fri May  6 17:55:35 2011
@@ -0,0 +1,216 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import org.apache.karaf.cellar.core.ClusterManager;
+import org.apache.karaf.cellar.core.Configurations;
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.Synchronizer;
+import org.apache.karaf.cellar.core.event.EventProducer;
+import org.apache.karaf.cellar.core.event.EventType;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.apache.karaf.features.Repository;
+import org.osgi.service.cm.Configuration;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.util.Dictionary;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author iocanel
+ */
+public class FeaturesSynchronizer extends FeaturesSupport implements Synchronizer {
+
+    private static Logger logger = LoggerFactory.getLogger(FeaturesSynchronizer.class);
+
+    private List<EventProducer> producerList;
+
+    /**
+     * Initialization method
+     */
+    public void init() {
+        super.init();
+        Set<Group> groups = groupManager.listLocalGroups();
+        if (groups != null && !groups.isEmpty()) {
+            for (Group group : groups) {
+                if (isSyncEnabled(group)) {
+                    pull(group);
+                    push(group);
+                }
+            }
+        }
+    }
+
+    /**
+     * Destruction method
+     */
+    public void destroy() {
+        super.destroy();
+    }
+
+    /**
+     * Pulls the features from the cluster.
+     */
+    public void pull(Group group) {
+        if (group != null) {
+            String groupName = group.getName();
+            List<String> repositories = clusterManager.getList(Constants.REPOSITORIES + Configurations.SEPARATOR + groupName);
+            Map<FeatureInfo, Boolean> features = clusterManager.getMap(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+            clusterManager.getList(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+            ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+                //Retrieve remote feautre URLs.
+                if (repositories != null && !repositories.isEmpty()) {
+                    for (String url : repositories) {
+                        try {
+                            logger.debug("Adding repository {}", url);
+                            featuresService.addRepository(new URI(url));
+                        } catch (MalformedURLException e) {
+                            logger.error("Failed to add features repository! Url {} is malformed", url);
+                        } catch (Exception e) {
+                            logger.error("Failed to add features repository.", e);
+                        }
+                    }
+                }
+
+                //Retrieve remote feautre status.
+                if (features != null && !features.isEmpty()) {
+                    for (FeatureInfo info : features.keySet()) {
+                        String name = info.getName();
+                        //Check if feature is blocked.
+                        if (isAllowed(group, Constants.FEATURES_CATEGORY, name, EventType.INBOUND)) {
+                            Boolean remotelyInstalled = features.get(info);
+                            Boolean localyInstalled = isInstanlled(info.getName(), info.getVersion());
+
+                            //If feature needs to be installed locally.
+                            if (remotelyInstalled && !localyInstalled) {
+                                try {
+                                    logger.debug("Installing feature {} version {}", info.getName(), info.getVersion());
+                                    featuresService.installFeature(info.getName(), info.getVersion());
+                                } catch (Exception e) {
+                                    logger.error("Failed to install feature {} {} ", info.getName(), info.getVersion());
+                                }
+                                //If feature needs to be localy uninstalled.
+                            } else if (!remotelyInstalled && localyInstalled) {
+                                try {
+                                    logger.debug("Uninstalling feature {} version {}", info.getName(), info.getVersion());
+                                    featuresService.uninstallFeature(info.getName(), info.getVersion());
+                                } catch (Exception e) {
+                                    logger.error("Failed to uninstall feature {} {} ", info.getName(), info.getVersion());
+                                }
+                            }
+                        } else logger.debug("Feature with name {} is marked as BLOCKED INBOUND");
+                    }
+                }
+            } finally {
+                Thread.currentThread().setContextClassLoader(originalClassLoader);
+            }
+        }
+    }
+
+    /**
+     * Pushes features to the cluster.
+     */
+    public void push(Group group) {
+        if (group != null) {
+            String groupName = group.getName();
+            List<String> repositories = clusterManager.getList(Constants.REPOSITORIES + Configurations.SEPARATOR + groupName);
+            Map<FeatureInfo, Boolean> features = clusterManager.getMap(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+            clusterManager.getList(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+
+            ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
+            try {
+                Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+
+                Repository[] repositoryList = new Repository[0];
+                Feature[] featuresList = new Feature[0];
+
+                try {
+                    repositoryList = featuresService.listRepositories();
+                    featuresList = featuresService.listFeatures();
+                } catch (Exception e) {
+                    logger.error("Error listing features.", e);
+                }
+
+                //Process repository list
+                if (repositoryList != null && repositoryList.length > 0) {
+                    for (Repository repository : repositoryList) {
+                        pushRepository(repository, group);
+                    }
+                }
+
+                //Process features list
+                if (featuresList != null && featuresList.length > 0) {
+                    for (Feature feature : featuresList) {
+                        pushFeature(feature, group);
+                    }
+                }
+            } finally {
+                Thread.currentThread().setContextClassLoader(originalClassLoader);
+            }
+        }
+    }
+
+
+    @Override
+    public Boolean isSyncEnabled(Group group) {
+        Boolean result = Boolean.FALSE;
+        String groupName = group.getName();
+
+        try {
+            Configuration configuration = configurationAdmin.getConfiguration(Configurations.GROUP);
+            Dictionary<String, String> properties = configuration.getProperties();
+            String propertyKey = groupName + Configurations.SEPARATOR + Constants.FEATURES_CATEGORY + Configurations.SEPARATOR + Configurations.SYNC;
+            String propertyValue = properties.get(propertyKey);
+            result = Boolean.parseBoolean(propertyValue);
+        } catch (IOException e) {
+            logger.error("Error while checking if sync is enabled.", e);
+        }
+        return result;
+    }
+
+    public List<EventProducer> getProducerList() {
+        return producerList;
+    }
+
+    public void setProducerList(List<EventProducer> producerList) {
+        this.producerList = producerList;
+    }
+
+
+    public ClusterManager getCollectionManager() {
+        return clusterManager;
+    }
+
+    public void setCollectionManager(ClusterManager clusterManager) {
+        this.clusterManager = clusterManager;
+    }
+
+    public FeaturesService getFeaturesService() {
+        return featuresService;
+    }
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/LocalFeaturesListener.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/LocalFeaturesListener.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/LocalFeaturesListener.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/LocalFeaturesListener.java Fri May  6 17:55:35 2011
@@ -0,0 +1,122 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.Node;
+import org.apache.karaf.cellar.core.event.EventProducer;
+import org.apache.karaf.cellar.core.event.EventType;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeatureEvent;
+import org.apache.karaf.features.RepositoryEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * @author iocanel
+ */
+public class LocalFeaturesListener extends FeaturesSupport implements org.apache.karaf.features.FeaturesListener {
+
+    private static Logger logger = LoggerFactory.getLogger(LocalFeaturesListener.class);
+    private List<EventProducer> producerList;
+
+    @Override
+    public void init() {
+        super.init();
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+    }
+
+    /**
+     * Called when a {@code FeatureEvent} occurs.
+     *
+     * @param event
+     */
+    public void featureEvent(FeatureEvent event) {
+        if (event != null) {
+            Set<Group> groups = groupManager.listLocalGroups();
+
+            if (groups != null && !groups.isEmpty()) {
+                for (Group group : groups) {
+
+                    Feature feature = event.getFeature();
+                    String name = feature.getName();
+                    String version = feature.getVersion();
+
+                    if (isAllowed(group, Constants.FEATURES_CATEGORY, name, EventType.OUTBOUND)) {
+                        FeatureEvent.EventType type = event.getType();
+
+                        //Check the event type.
+                        //This is required because upon reception of the even the feature service considers the feature uninstalled.
+                        if (FeatureEvent.EventType.FeatureInstalled.equals(event.getType())) {
+                            pushFeature(event.getFeature(), group, true);
+                        } else {
+                            pushFeature(event.getFeature(), group, false);
+                        }
+
+                        RemoteFeaturesEvent featureEvent = new RemoteFeaturesEvent(name, version, type);
+                        featureEvent.setSourceGroup(group);
+                        //TODO: Choose group producer.
+                        if (producerList != null && !producerList.isEmpty()) {
+                            for (EventProducer producer : producerList) {
+                                producer.produce(featureEvent);
+                            }
+                        }
+                    } else logger.debug("Feature with name {} is marked as local.", name);
+                }
+            }
+        }
+    }
+
+    /**
+     * Called when a {@code RepositoryEvent} occurs.
+     *
+     * @param event
+     */
+    public void repositoryEvent(RepositoryEvent event) {
+        if (event != null && event.getRepository() != null) {
+
+            Node node = clusterManager.getNode();
+            Set<Group> groups = groupManager.listLocalGroups();
+
+            if (groups != null && !groups.isEmpty()) {
+                for (Group group : groups) {
+                    RemoteRepositoryEvent repositoryEvent = new RemoteRepositoryEvent(event.getRepository().getURI().toString(), event.getType());
+                    repositoryEvent.setSourceGroup(group);
+                    pushRepository(event.getRepository(), group);
+                    if (producerList != null && !producerList.isEmpty()) {
+                        for (EventProducer producer : producerList) {
+                            producer.produce(repositoryEvent);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public List<EventProducer> getProducerList() {
+        return producerList;
+    }
+
+    public void setProducerList(List<EventProducer> producerList) {
+        this.producerList = producerList;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteFeaturesEvent.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteFeaturesEvent.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteFeaturesEvent.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteFeaturesEvent.java Fri May  6 17:55:35 2011
@@ -0,0 +1,49 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import org.apache.karaf.cellar.core.event.Event;
+import org.apache.karaf.features.FeatureEvent.EventType;
+
+/**
+ * @author iocanel
+ */
+public class RemoteFeaturesEvent extends Event {
+
+    private static final String separator = "/";
+
+    private String name;
+    private String version;
+    private EventType type;
+
+    public RemoteFeaturesEvent(String name, String version, EventType type) {
+        super(name + separator + version);
+        this.name = name;
+        this.version = version;
+        this.type = type;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteRepositoryEvent.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteRepositoryEvent.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteRepositoryEvent.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RemoteRepositoryEvent.java Fri May  6 17:55:35 2011
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import org.apache.karaf.cellar.core.event.Event;
+import org.apache.karaf.features.RepositoryEvent.EventType;
+
+/**
+ * @author iocanel
+ */
+public class RemoteRepositoryEvent extends Event {
+
+    private EventType type;
+
+    public RemoteRepositoryEvent(String id, EventType type) {
+        super(id);
+        this.type = type;
+    }
+
+    public EventType getType() {
+        return type;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RepositoryEventHandler.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RepositoryEventHandler.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RepositoryEventHandler.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/RepositoryEventHandler.java Fri May  6 17:55:35 2011
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features;
+
+import org.apache.karaf.cellar.core.control.BasicSwitch;
+import org.apache.karaf.cellar.core.control.Switch;
+import org.apache.karaf.cellar.core.event.EventHandler;
+import org.apache.karaf.features.RepositoryEvent;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.URI;
+
+/**
+ * @author iocanel
+ */
+public class RepositoryEventHandler extends FeaturesSupport implements EventHandler<RemoteRepositoryEvent> {
+
+    private static Logger logger = LoggerFactory.getLogger(RepositoryEventHandler.class);
+    public static final String SWITCH_ID = "org.apache.karaf.cellar.event.repository.handler";
+
+    private final Switch eventSwitch = new BasicSwitch(SWITCH_ID);
+
+    @Override
+    public void init() {
+        super.init();
+    }
+
+    @Override
+    public void destroy() {
+        super.destroy();
+    }
+
+    public void handle(RemoteRepositoryEvent event) {
+        String uri = event.getId();
+        RepositoryEvent.EventType type = event.getType();
+        try {
+            if (RepositoryEvent.EventType.RepositoryAdded.equals(type)) {
+                logger.debug("Adding repository url {}", uri);
+                featuresService.addRepository(new URI(uri));
+            } else {
+                logger.debug("Removing repository url {}", uri);
+                featuresService.removeRepository(new URI(uri));
+            }
+        } catch (Exception e) {
+            logger.error("Failed to add/remove repository {}", uri);
+        }
+    }
+
+    public Class<RemoteRepositoryEvent> getType() {
+        return RemoteRepositoryEvent.class;
+    }
+
+    public Switch getSwitch() {
+        return eventSwitch;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/FeatureCommandSupport.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/FeatureCommandSupport.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/FeatureCommandSupport.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/FeatureCommandSupport.java Fri May  6 17:55:35 2011
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features.shell;
+
+import org.apache.karaf.cellar.core.Configurations;
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.shell.CellarCommandSupport;
+import org.apache.karaf.cellar.features.Constants;
+import org.apache.karaf.cellar.features.FeatureInfo;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.features.Feature;
+import org.apache.karaf.features.FeaturesService;
+import org.osgi.framework.BundleContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+/**
+ * @author: iocanel
+ */
+@Command(scope = "cluster", name = "feature-install", description = "Installs a feature to all members of a group")
+public abstract class FeatureCommandSupport extends CellarCommandSupport {
+
+    protected static final Logger logger = LoggerFactory.getLogger(FeatureCommandSupport.class);
+
+    protected FeaturesService featuresService;
+    protected BundleContext bundleContext;
+
+
+    /**
+     * Forces the features status for a specific group.
+     * Why? Its required if no group member currently in the cluster.
+     * If a member of the group joins later, it won't find the change, unless we force it.
+     *
+     * @param groupName
+     * @param feature
+     * @param version
+     * @param status
+     */
+    public Boolean updateFeatureStatus(String groupName, String feature, String version, Boolean status) {
+        Boolean result = Boolean.FALSE;
+        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+            Group group = groupManager.findGroupByName(groupName);
+            if (group == null || group.getMembers().isEmpty()) {
+                FeatureInfo info = new FeatureInfo(feature, version);
+                Map<FeatureInfo, Boolean> features = clusterManager.getMap(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+                //1st check the existing configuration
+                if (version == null || version.isEmpty()) {
+                    for (FeatureInfo f : features.keySet()) {
+                        if (f.getName().equals(feature)) {
+                            version = f.getVersion();
+                            info.setVersion(version);
+                        }
+                    }
+                }
+
+                //2nd check the Features Service.
+                try {
+                    for (Feature f : featuresService.listFeatures()) {
+                        if (f.getName().equals(feature)) {
+                            version = f.getVersion();
+                            info.setVersion(version);
+                        }
+                    }
+                } catch (Exception e) {
+                    logger.error("Error while browsing features", e);
+                }
+
+                if (info.getVersion() != null && !info.getVersion().isEmpty()) {
+                    features.put(info, status);
+                    result = Boolean.TRUE;
+                }
+            }
+        } finally {
+            Thread.currentThread().setContextClassLoader(originalClassLoader);
+        }
+        return result;
+    }
+
+
+    public BundleContext getBundleContext() {
+        return bundleContext;
+    }
+
+    public void setBundleContext(BundleContext bundleContext) {
+        this.bundleContext = bundleContext;
+    }
+
+    public FeaturesService getFeaturesService() {
+        return featuresService;
+    }
+
+    public void setFeaturesService(FeaturesService featuresService) {
+        this.featuresService = featuresService;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/InstallFeatureCommand.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/InstallFeatureCommand.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/InstallFeatureCommand.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/InstallFeatureCommand.java Fri May  6 17:55:35 2011
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features.shell;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.event.EventProducer;
+import org.apache.karaf.cellar.features.RemoteFeaturesEvent;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.features.FeatureEvent;
+
+/**
+ * @author: iocanel
+ */
+@Command(scope = "cluster", name = "features-install", description = "Installs a feature to the group")
+public class InstallFeatureCommand extends FeatureCommandSupport {
+
+    @Argument(index = 0, name = "group", description = "The name of the group that will install the feature", required = true, multiValued = false)
+    String groupName;
+
+    @Argument(index = 1, name = "feature", description = "The name of the feature", required = true, multiValued = false)
+    String feature;
+
+    @Argument(index = 2, name = "version", description = "The version of the feature", required = false, multiValued = false)
+    String version;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        Group group = groupManager.findGroupByName(groupName);
+        EventProducer producer = clusterManager.getEventProducer(groupName);
+        RemoteFeaturesEvent event = new RemoteFeaturesEvent(feature, version, FeatureEvent.EventType.FeatureInstalled);
+        event.setForce(true);
+        event.setSourceGroup(group);
+        producer.produce(event);
+
+        updateFeatureStatus(groupName, feature, version, true);
+        return null;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/ListGroupFeatures.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/ListGroupFeatures.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/ListGroupFeatures.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/ListGroupFeatures.java Fri May  6 17:55:35 2011
@@ -0,0 +1,61 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features.shell;
+
+import org.apache.karaf.cellar.core.Configurations;
+import org.apache.karaf.cellar.features.Constants;
+import org.apache.karaf.cellar.features.FeatureInfo;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+
+import java.util.Map;
+
+/**
+ * iocanel iocanel
+ */
+@Command(scope = "cluster", name = "features-list", description = "List the features that are assigned to a group")
+public class ListGroupFeatures extends FeatureCommandSupport {
+
+    protected static final String OUTPUT_FORMAT = "%-40s %20s %-4s ";
+
+    @Argument(index = 0, name = "group", description = "The name of the group", required = true, multiValued = false)
+    String groupName;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        ClassLoader originalClassLoader = Thread.currentThread().getContextClassLoader();
+        try {
+            Thread.currentThread().setContextClassLoader(getClass().getClassLoader());
+
+            Map<FeatureInfo, Boolean> features = clusterManager.getMap(Constants.FEATURES + Configurations.SEPARATOR + groupName);
+            if (features != null && !features.isEmpty()) {
+                System.out.println(String.format("Features for group:" + groupName));
+                System.out.println(String.format(OUTPUT_FORMAT, "Name", "Version", "Status"));
+                for (FeatureInfo info : features.keySet()) {
+                    String name = info.getName();
+                    String version = info.getVersion();
+                    Boolean status = features.get(info);
+                    if (version == null)
+                        version = "";
+                    System.out.println(String.format(OUTPUT_FORMAT, name, version, status));
+                }
+            } else System.err.print("No features found for group:" + groupName);
+        } finally {
+            Thread.currentThread().setContextClassLoader(originalClassLoader);
+
+        }
+        return null;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/UninstallFeatureCommand.java
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/UninstallFeatureCommand.java?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/UninstallFeatureCommand.java (added)
+++ karaf/cellar/trunk/features/src/main/java/org/apache/karaf/cellar/features/shell/UninstallFeatureCommand.java Fri May  6 17:55:35 2011
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+package org.apache.karaf.cellar.features.shell;
+
+import org.apache.karaf.cellar.core.Group;
+import org.apache.karaf.cellar.core.event.EventProducer;
+import org.apache.karaf.cellar.features.RemoteFeaturesEvent;
+import org.apache.felix.gogo.commands.Argument;
+import org.apache.felix.gogo.commands.Command;
+import org.apache.karaf.features.FeatureEvent;
+
+/**
+ * @author: iocanel
+ */
+@Command(scope = "cluster", name = "features-uninstall", description = "Uninstalls a feature to the group")
+public class UninstallFeatureCommand extends FeatureCommandSupport {
+
+    @Argument(index = 0, name = "group", description = "The name of the group that will uninstall the feature", required = true, multiValued = false)
+    String groupName;
+
+    @Argument(index = 1, name = "feature", description = "The name of the feature", required = true, multiValued = false)
+    String feature;
+
+    @Argument(index = 2, name = "version", description = "The version of the feature", required = false, multiValued = false)
+    String version;
+
+    @Override
+    protected Object doExecute() throws Exception {
+        Group group = groupManager.findGroupByName(groupName);
+        EventProducer producer = clusterManager.getEventProducer(groupName);
+        RemoteFeaturesEvent event = new RemoteFeaturesEvent(feature, version, FeatureEvent.EventType.FeatureUninstalled);
+        event.setForce(true);
+        event.setSourceGroup(group);
+        producer.produce(event);
+
+        updateFeatureStatus(groupName, feature, version, true);
+        return null;
+    }
+}

Added: karaf/cellar/trunk/features/src/main/resources/OSGI-INF/blueprint/blueprint.xml
URL: http://svn.apache.org/viewvc/karaf/cellar/trunk/features/src/main/resources/OSGI-INF/blueprint/blueprint.xml?rev=1100302&view=auto
==============================================================================
--- karaf/cellar/trunk/features/src/main/resources/OSGI-INF/blueprint/blueprint.xml (added)
+++ karaf/cellar/trunk/features/src/main/resources/OSGI-INF/blueprint/blueprint.xml Fri May  6 17:55:35 2011
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+   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.
+  -->
+
+<blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
+
+    <!-- Cluster Configuration Listener -->
+    <bean id="featuresListener" class="org.apache.karaf.cellar.features.LocalFeaturesListener" init-method="init"
+          destroy-method="destroy">
+        <property name="featuresService" ref="featuresService"/>
+        <property name="producerList" ref="groupEventProducers"/>
+        <property name="clusterManager" ref="clusterManager"/>
+        <property name="groupManager" ref="groupManager"/>
+        <property name="configurationAdmin" ref="configurationAdmin"/>
+    </bean>
+
+    <!-- Features/Repositories Synchronizer -->
+    <bean id="synchronizer" class="org.apache.karaf.cellar.features.FeaturesSynchronizer"
+          init-method="init" destroy-method="destroy">
+        <property name="featuresService" ref="featuresService"/>
+        <property name="clusterManager" ref="clusterManager"/>
+        <property name="groupManager" ref="groupManager"/>
+        <property name="producerList" ref="groupEventProducers"/>
+        <property name="configurationAdmin" ref="configurationAdmin"/>
+    </bean>
+
+    <!-- Features Handler -->
+    <bean id="featuresHandler" class="org.apache.karaf.cellar.features.FeaturesEventHandler"
+          init-method="init" destroy-method="destroy">
+        <property name="featuresService" ref="featuresService"/>
+        <property name="clusterManager" ref="clusterManager"/>
+        <property name="configurationAdmin" ref="configurationAdmin"/>
+    </bean>
+
+    <!-- Repository Handler -->
+    <bean id="repositoryHandler" class="org.apache.karaf.cellar.features.RepositoryEventHandler"
+          init-method="init" destroy-method="destroy">
+        <property name="featuresService" ref="featuresService"/>
+        <property name="clusterManager" ref="clusterManager"/>
+        <property name="configurationAdmin" ref="configurationAdmin"/>
+    </bean>
+
+    <!-- OSGi Services  & References -->
+    <service ref="featuresListener" interface="org.apache.karaf.features.FeaturesListener"/>
+    <service ref="synchronizer" interface="org.apache.karaf.cellar.core.Synchronizer"/>
+    <service ref="featuresHandler" interface="org.apache.karaf.cellar.core.event.EventHandler">
+        <service-properties>
+            <entry key="managed" value="true"/>
+        </service-properties>
+    </service>
+
+    <service ref="repositoryHandler" interface="org.apache.karaf.cellar.core.event.EventHandler"/>
+    <reference id="clusterManager" interface="org.apache.karaf.cellar.core.ClusterManager"/>
+    <reference id="groupManager" interface="org.apache.karaf.cellar.core.GroupManager"/>
+    <reference id="eventProducer" interface="org.apache.karaf.cellar.core.event.EventProducer"/>
+    <reference id="featuresService" interface="org.apache.karaf.features.FeaturesService"/>
+    <reference id="configurationAdmin" interface="org.osgi.service.cm.ConfigurationAdmin"/>
+    <reference-list id="groupEventProducers" member-type="service-object"
+                    interface="org.apache.karaf.cellar.core.event.EventProducer" filter="(type=group)"/>
+
+</blueprint>



Mime
View raw message