ace-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j...@apache.org
Subject svn commit: r1307498 - in /ace/trunk: ./ ace-deployment-task-base/ ace-deployment-task-base/src/ ace-deployment-task-base/src/main/ ace-deployment-task-base/src/main/java/ ace-deployment-task-base/src/main/java/org/ ace-deployment-task-base/src/main/ja...
Date Fri, 30 Mar 2012 16:05:01 GMT
Author: jawi
Date: Fri Mar 30 16:04:59 2012
New Revision: 1307498

URL: http://svn.apache.org/viewvc?rev=1307498&view=rev
Log:
ACE-242: split off the deployment-task frontend service into a separate project.

Added:
    ace/trunk/ace-deployment-task-base/   (with props)
    ace/trunk/ace-deployment-task-base/pom.xml   (with props)
    ace/trunk/ace-deployment-task-base/src/
    ace/trunk/ace-deployment-task-base/src/main/
    ace/trunk/ace-deployment-task-base/src/main/java/
    ace/trunk/ace-deployment-task-base/src/main/java/org/
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/DeploymentService.java   (with props)
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/Activator.java   (with props)
    ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java   (with props)
    ace/trunk/ace-deployment-task-base/src/main/resources/
    ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/
    ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/
    ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.properties   (with props)
    ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.xml   (with props)
    ace/trunk/ace-deployment-task-base/src/test/
    ace/trunk/ace-deployment-task-base/src/test/java/
    ace/trunk/ace-deployment-task-base/src/test/java/org/
    ace/trunk/ace-deployment-task-base/src/test/java/org/apache/
    ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/
    ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/
    ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/
    ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/
    ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/DeploymentServiceImplTest.java   (with props)
Removed:
    ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/service/DeploymentService.java
    ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentTaskBase.java
    ace/trunk/ace-deployment-task/src/test/java/org/apache/ace/deployment/task/
Modified:
    ace/trunk/ace-deployment-task/pom.xml
    ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/Activator.java
    ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentCheckTask.java
    ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentUpdateTask.java
    ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.properties
    ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.xml
    ace/trunk/ace-integrationtests/pom.xml
    ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/Options.java
    ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/deployment/DeploymentIntegrationTest.java
    ace/trunk/ace-managementagent/pom.xml
    ace/trunk/ace-managementagent/src/main/java/org/apache/ace/managementagent/Activator.java
    ace/trunk/ace-target-devgateway/pom.xml
    ace/trunk/pom.xml
    ace/trunk/pom/pom.xml

Propchange: ace/trunk/ace-deployment-task-base/
------------------------------------------------------------------------------
--- svn:ignore (added)
+++ svn:ignore Fri Mar 30 16:04:59 2012
@@ -0,0 +1,11 @@
+.metadata
+.settings
+bin
+.classpath
+.project
+target
+*.ipr
+*.iws
+*.iml
+
+

Added: ace/trunk/ace-deployment-task-base/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/pom.xml?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/pom.xml (added)
+++ ace/trunk/ace-deployment-task-base/pom.xml Fri Mar 30 16:04:59 2012
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<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">
+
+    <!--
+
+        Licensed to the Apache Software Foundation (ASF) under one or more
+        contributor license agreements.  See the NOTICE file distributed with
+        this work for additional information regarding copyright ownership.
+        The ASF licenses this file to You under the Apache License, Version 2.0
+        (the "License"); you may not use this file except in compliance with
+        the License.  You may obtain a copy of the License at
+
+           http://www.apache.org/licenses/LICENSE-2.0
+
+        Unless required by applicable law or agreed to in writing, software
+        distributed under the License is distributed on an "AS IS" BASIS,
+        WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+        See the License for the specific language governing permissions and
+        limitations under the License.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.ace</groupId>
+        <artifactId>ace-pom</artifactId>
+        <version>0.8.1-SNAPSHOT</version>
+        <relativePath>../pom/pom.xml</relativePath>
+    </parent>
+
+    <version>0.8.1-SNAPSHOT</version>
+    <artifactId>org.apache.ace.deployment.task.base</artifactId>
+    <packaging>bundle</packaging>
+
+    <name>Apache ACE :: Deployment :: Task :: API</name>
+    <description>This bundle provides an API for checking the deployment server for updates and for synchronizing the local instance with the server.</description>
+
+    <scm>
+        <connection>scm:svn:http://svn.apache.org/repos/asf/ace/trunk/ace-deployment-task</connection>
+        <developerConnection>scm:svn:https://svn.apache.org/repos/asf/ace/trunk/ace-deployment-task</developerConnection>
+        <url>http://svn.apache.org/repos/asf/ace/trunk/ace-deployment-task</url>
+    </scm>
+
+    <properties>
+        <import.package>
+            org.apache.ace.deployment;version=${project.version},
+            org.apache.ace.discovery;version=${project.version},
+            org.apache.ace.identification;version=${project.version},
+            *
+        </import.package>
+        <export.package>
+            org.apache.ace.deployment.service;version=${project.version}
+        </export.package>
+        <private.package>
+            org.apache.ace.deployment.service.impl
+        </private.package>
+        <bundle.activator>
+            org.apache.ace.deployment.service.impl.Activator
+        </bundle.activator>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.deployment.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.discovery.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.scheduler.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.identification.api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.dependencymanager</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.gateway.log.store</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.util</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+</project>

Propchange: ace/trunk/ace-deployment-task-base/pom.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/DeploymentService.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/DeploymentService.java?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/DeploymentService.java (added)
+++ ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/DeploymentService.java Fri Mar 30 16:04:59 2012
@@ -0,0 +1,82 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.service;
+
+import java.io.IOException;
+import java.util.SortedSet;
+
+import org.osgi.framework.Version;
+
+/**
+ * Deployment service can be used to talk to the management agent about deployment packages,
+ * versions and updates, and to actually perform them. This interface coexists with the
+ * tasks that are also published by the management agent and that are probably more convenient
+ * if you just want to schedule (checks for) updates.
+ */
+public interface DeploymentService {
+
+    /**
+     * Returns the highest version that is available locally (already installed).
+     * 
+     * @return The highest installed version, can be <code>null</code> if no version is locally available.
+     */
+    Version getHighestLocalVersion();
+
+    /**
+     * Returns the highest version that is available remotely.
+     * 
+     * @param url The URL to be used to retrieve the versions available on the remote.
+     * @return The highest version available on the remote or <code>null</code> if no versions were available or the remote could not be reached.
+     * @throws IOException in case of I/O problems obtaining the remote version.
+     */
+    Version getHighestRemoteVersion() throws IOException;
+
+    /**
+     * Returns all versions that are available remotely.
+     * 
+     * @return the remote versions, sorted, can be <code>null</code>.
+     * @throws IOException in case of I/O problems obtaining the remote versions.
+     */
+    SortedSet<Version> getRemoteVersions() throws IOException;
+
+    /**
+     * Installs the version specified by the highestRemoteVersion.
+     * 
+     * @param remoteVersion the version to retrieve and install;
+     * @param localVersion the current (local) version, can be <code>null</code> in case of no version is yet installed.
+     * @throws IOException in case of I/O problems installing the version;
+     * @throws Exception in case of other problems installing the version.
+     */
+    void installVersion(Version remoteVersion, Version localVersion) throws IOException, Exception;
+
+    /**
+     * Updates from the current local version to the given remote version.
+     * <p>
+     * This method is the same as calling:
+     * <pre>
+     * installVersion(toVersion, getHighestLocalVersion());
+     * </pre>
+     * </p>
+     * 
+     * @param toVersion the (remote) version to update to, cannot be <code>null</code>.
+     * @throws Exception in case of other problems updating to the requested version.
+     */
+    void update(Version toVersion) throws Exception;
+
+}

Propchange: ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/DeploymentService.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/Activator.java?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/Activator.java (added)
+++ ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/Activator.java Fri Mar 30 16:04:59 2012
@@ -0,0 +1,152 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.service.impl;
+
+import java.util.Dictionary;
+import java.util.Map;
+import java.util.Properties;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.apache.ace.deployment.Deployment;
+import org.apache.ace.deployment.service.DeploymentService;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyActivatorBase;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.ConfigurationException;
+import org.osgi.service.cm.ManagedServiceFactory;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.log.LogService;
+
+/**
+ * Provides an activator for the deployment service.
+ */
+public class Activator extends DependencyActivatorBase implements ManagedServiceFactory {
+
+    private static final String PID_NAME = "org.apache.ace.deployment.task.base.factory";
+
+    private static final String MA_NAME = "ma";
+    private static final String DEFAULT_MA_NAME = null;
+
+    private final Map<String, Component> m_instances = new ConcurrentHashMap<String, Component>();
+
+    private volatile DependencyManager m_manager;
+
+    /**
+     * @see org.osgi.service.cm.ManagedServiceFactory#deleted(java.lang.String)
+     */
+    public void deleted(String pid) {
+        Component component;
+        synchronized (m_instances) {
+            component = m_instances.remove(pid);
+        }
+        
+        if (component != null) {
+            m_manager.remove(component);
+        }
+    }
+
+    /**
+     * @see org.apache.felix.dm.DependencyActivatorBase#destroy(org.osgi.framework.BundleContext, org.apache.felix.dm.DependencyManager)
+     */
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // do nothing
+    }
+
+    /**
+     * @see org.osgi.service.cm.ManagedServiceFactory#getName()
+     */
+    public String getName() {
+        return "Deployment Service - base";
+    }
+
+    /**
+     * @see org.apache.felix.dm.DependencyActivatorBase#init(org.osgi.framework.BundleContext, org.apache.felix.dm.DependencyManager)
+     */
+    public void init(BundleContext context, DependencyManager manager) throws Exception {
+        m_manager = manager;
+
+        // Create a default deployment service instance...
+        m_manager.add(createService(DEFAULT_MA_NAME));
+
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_PID, PID_NAME);
+
+        m_manager.add(createComponent()
+            .setInterface(ManagedServiceFactory.class.getName(), props)
+            .setImplementation(this)
+            );
+    }
+
+    /**
+     * @see org.osgi.service.cm.ManagedServiceFactory#updated(java.lang.String, java.util.Dictionary)
+     */
+    public void updated(String pid, Dictionary dict) throws ConfigurationException {
+        final String ma = (String) dict.get(MA_NAME);
+        
+        Component component = m_instances.get(pid);
+        if (component == null) {
+            component = createService(ma);
+            synchronized (m_instances) {
+                m_instances.put(pid, component);
+            }
+            m_manager.add(component);
+        }
+        else {
+            // TODO do we want to deal with changes here?
+        }
+    }
+
+    /**
+     * Creates the {@link DeploymentService} component for the given management agent name.
+     * 
+     * @param ma the name of the management agent to create the service for, can be <code>null</code>.
+     * @return a {@link Component} instance for the {@link DeploymentService}, never <code>null</code>.
+     */
+    private Component createService(String ma) {
+        Dictionary deploymentProperties = new Properties();
+
+        String identificationFilter = "(" + Constants.OBJECTCLASS + "=" + Identification.class.getName() + ")";
+        String discoveryFilter = "(" + Constants.OBJECTCLASS + "=" + Discovery.class.getName() + ")";
+
+        if (ma == null || "".equals(ma.trim())) {
+            identificationFilter = String.format("(&%s(!(%s=*)))", identificationFilter, MA_NAME);
+            discoveryFilter = String.format("(&%s(!(%s=*)))", discoveryFilter, MA_NAME); ;
+        }
+        else {
+            identificationFilter = String.format("(&%s(%s=%s))", identificationFilter, MA_NAME, ma);
+            discoveryFilter = String.format("(&%s(%s=%s))", discoveryFilter, MA_NAME, ma);
+            deploymentProperties.put(MA_NAME, ma);
+        }
+
+        DeploymentServiceImpl deploymentService = new DeploymentServiceImpl();
+
+        return createComponent()
+            .setInterface(DeploymentService.class.getName(), deploymentProperties)
+            .setImplementation(deploymentService)
+            .add(createServiceDependency().setService(Deployment.class).setRequired(true))
+            .add(createServiceDependency().setService(Identification.class, identificationFilter).setRequired(true))
+            .add(createServiceDependency().setService(Discovery.class, discoveryFilter).setRequired(true))
+            .add(createServiceDependency().setService(EventAdmin.class).setRequired(false))
+            .add(createServiceDependency().setService(LogService.class).setRequired(false));
+    }
+}
\ No newline at end of file

Propchange: ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/Activator.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java (added)
+++ ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java Fri Mar 30 16:04:59 2012
@@ -0,0 +1,285 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.service.impl;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Dictionary;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Properties;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.ace.deployment.Deployment;
+import org.apache.ace.deployment.service.DeploymentService;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.osgi.framework.Version;
+import org.osgi.service.event.Event;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.log.LogService;
+
+/**
+ * Provides an implementation for {@link DeploymentService}.
+ */
+public class DeploymentServiceImpl implements DeploymentService {
+    
+    private final String TOPIC_DEPLOYMENTPACKAGE_INSTALL = "org/apache/ace/deployment/INSTALL";
+
+    // injected by dependencymanager
+    protected volatile Deployment m_deployer;
+    protected volatile Identification m_identification;
+    protected volatile Discovery m_discovery;
+    protected volatile LogService m_log;
+    protected volatile EventAdmin m_eventAdmin;
+
+    /**
+     * @see org.apache.ace.deployment.service.DeploymentService#getHighestLocalVersion()
+     */
+    public Version getHighestLocalVersion() {
+        Object[] installedPackages = m_deployer.list();
+        List versions = new ArrayList();
+        for (int i = 0; i < installedPackages.length; i++) {
+            if (m_deployer.getName(installedPackages[i]).equals(m_identification.getID())) {
+                versions.add(m_deployer.getVersion(installedPackages[i]));
+            }
+        }
+        return getHighestVersion(versions);
+    }
+
+    /**
+     * @see org.apache.ace.deployment.service.DeploymentService#getHighestRemoteVersion()
+     */
+    public Version getHighestRemoteVersion() throws IOException {
+        SortedSet<Version> versions = getRemoteVersions(getURL());
+        return ((versions == null) || versions.isEmpty()) ? null : versions.last();
+    }
+
+    /**
+     * @see org.apache.ace.deployment.service.DeploymentService#getRemoteVersions()
+     */
+    public SortedSet<Version> getRemoteVersions() throws IOException {
+        return getRemoteVersions(getURL());
+    }
+
+    /**
+     * @see org.apache.ace.deployment.service.DeploymentService#installVersion(org.osgi.framework.Version, org.osgi.framework.Version)
+     */
+    public void installVersion(Version highestRemoteVersion, Version highestLocalVersion) throws IOException, Exception {
+        InputStream inputStream = null;
+        
+        m_log.log(LogService.LOG_INFO, "Installing version: " + highestRemoteVersion);
+        
+        try {
+            String version = highestRemoteVersion.toString();
+            if (highestLocalVersion != null) {
+                version += "?current=" + highestLocalVersion.toString();
+            }
+            URL dataURL = new URL(getURL(), version);
+            if ("file".equals(dataURL.getProtocol())) {
+                File file = urlToFile(dataURL);
+                inputStream = new FileInputStream(file);
+            }
+            else {
+                inputStream = dataURL.openStream();
+            }
+
+            // Post event for auditlog
+            m_eventAdmin.postEvent(createEvent(version, dataURL));
+
+            m_deployer.install(inputStream);
+        }
+        finally {
+            if (inputStream != null) {
+                try {
+                    inputStream.close();
+                }
+                catch (Exception ex) {
+                    // Not much we can do.
+                }
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.ace.deployment.service.DeploymentService#update(org.osgi.framework.Version)
+     */
+    public void update(Version toVersion) throws Exception {
+        installVersion(toVersion, getHighestLocalVersion());
+    }
+
+    /**
+     * @param url
+     * @return
+     * @throws IOException
+     */
+    final SortedSet<Version> getRemoteVersions(URL url) throws IOException {
+        if (url == null) {
+            return null;
+        }
+        
+        if ("file".equals(url.getProtocol())) {
+            return getVersionsFromDirectory(url);
+        }
+        else {
+            return getVersionsFromServer(url);
+        }
+    }
+
+    /**
+     * @param version
+     * @param dataURL
+     * @return
+     */
+    private Event createEvent(String version, URL dataURL) {
+        Dictionary properties = new Properties();
+        properties.put("deploymentpackage.url", dataURL.toString());
+        properties.put("deploymentpackage.version", version);
+        Event event = new Event(TOPIC_DEPLOYMENTPACKAGE_INSTALL, properties);
+        return event;
+    }
+
+    /**
+     * @param versions
+     * @return
+     */
+    private Version getHighestVersion(List versions) {
+        Version highestVersion = null;
+        for (Iterator i = versions.iterator(); i.hasNext();) {
+            Version version = (Version) i.next();
+            if (highestVersion == null) {
+                highestVersion = version;
+            }
+            else if (version.compareTo(highestVersion) > 0) {
+                highestVersion = version;
+            }
+        }
+        return highestVersion;
+    }
+
+    /**
+     * @return
+     */
+    private URL getURL() {
+        URL host = m_discovery.discover();
+        if (host == null) {
+            return null;
+        }
+        try {
+            return new URL(host, "deployment/" + m_identification.getID() + "/versions/");
+        }
+        catch (MalformedURLException e) {
+            m_log.log(LogService.LOG_WARNING, "Malformed URL", e);
+            return null;
+        }
+    }
+
+    /**
+     * @param url
+     * @return
+     */
+    private SortedSet<Version> getVersionsFromDirectory(URL url) {
+        File file = urlToFile(url);
+        if (!file.isDirectory()) {
+            return null;
+        }
+            
+        final File[] files = file.listFiles();
+        SortedSet<Version> versions = new TreeSet<Version>();
+        for (File f : files) {
+            try {
+                Version version = Version.parseVersion(f.getName());
+                if (version != Version.emptyVersion) {
+                    versions.add(version);
+                }
+            }
+            catch (IllegalArgumentException e) {
+                // if the file is not a valid version, we skip it
+            }
+        }
+        return versions;
+    }
+
+    /**
+     * @param url
+     * @return
+     */
+    private SortedSet<Version> getVersionsFromServer(URL url) {
+        BufferedReader bufReader = null;
+        try {
+            bufReader = new BufferedReader(new InputStreamReader(url.openStream()));
+            SortedSet<Version> versions = new TreeSet<Version>();
+            
+            String versionString;
+            while ((versionString = bufReader.readLine()) != null) {
+                try {
+                    Version version = Version.parseVersion(versionString);
+                    if (version != Version.emptyVersion) {
+                        versions.add(version);
+                    }
+                }
+                catch (IllegalArgumentException iae) {
+                    m_log.log(LogService.LOG_WARNING, "Received malformed version, ignoring: " + versionString);
+                }
+            }
+            
+            return versions;
+        }
+        catch (IOException ioe) {
+            return null;
+        }
+        finally {
+            if (bufReader != null) {
+                try {
+                    bufReader.close();
+                }
+                catch (Exception ex) {
+                    // not much we can do
+                }
+            }
+        }
+    }
+
+    /**
+     * @param url
+     * @return
+     */
+    private File urlToFile(URL url) {
+        File file;
+        // See: http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
+        // makes a best effort to convert a file URL to a File
+        try {
+            file = new File(url.toURI());
+        }
+        catch (URISyntaxException e) {
+            file = new File(url.getPath());
+        }
+        return file;
+    }
+
+}
\ No newline at end of file

Propchange: ace/trunk/ace-deployment-task-base/src/main/java/org/apache/ace/deployment/service/impl/DeploymentServiceImpl.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.properties (added)
+++ ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.properties Fri Mar 30 16:04:59 2012
@@ -0,0 +1,5 @@
+service.name=Apache ACE :: Deployment :: Task :: Base
+service.desc=This component provides an API for checking the deployment server for updates and for synchronizing the local instance with the server. A new configuration is only required if there are multiple management agents.
+
+ma.name=Management Agent Name
+ma.desc=The name of the management agent that the deployment should be synchronized with.

Propchange: ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.xml?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.xml (added)
+++ ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.xml Fri Mar 30 16:04:59 2012
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0" localization="OSGI-INF/metatype/metatype">
+	<metatype:OCD id="org.apache.ace.deployment" name="%service.name" description="%service.desc">
+		<metatype:AD id="ma" type="String" name="%ma.name" description="%ma.desc" required="false" />
+	</metatype:OCD>
+	<metatype:Designate factoryPid="org.apache.ace.deployment.task.base.factory">
+		<metatype:Object ocdref="org.apache.ace.deployment" />
+	</metatype:Designate>
+</metatype:MetaData>

Propchange: ace/trunk/ace-deployment-task-base/src/main/resources/OSGI-INF/metatype/metatype.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/DeploymentServiceImplTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/DeploymentServiceImplTest.java?rev=1307498&view=auto
==============================================================================
--- ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/DeploymentServiceImplTest.java (added)
+++ ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/DeploymentServiceImplTest.java Fri Mar 30 16:04:59 2012
@@ -0,0 +1,270 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.ace.deployment.service.impl;
+
+import static org.apache.ace.test.utils.TestUtils.UNIT;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.SortedSet;
+
+import org.apache.ace.deployment.Deployment;
+import org.apache.ace.discovery.Discovery;
+import org.apache.ace.identification.Identification;
+import org.apache.ace.test.utils.TestUtils;
+import org.osgi.framework.Version;
+import org.osgi.service.event.EventAdmin;
+import org.osgi.service.log.LogService;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+public class DeploymentServiceImplTest {
+    
+    private static final Version VERSION1 = new Version("1.0.0");
+    private static final Version VERSION2 = new Version("2.0.0");
+    private static final Version VERSION3 = new Version("3.0.0");
+    
+    private DeploymentServiceImpl m_service;
+    private MockDeployerService m_mockDeployerService;
+    private boolean m_correctVersionInstalled;
+    private boolean m_installCalled;
+
+    @BeforeMethod(alwaysRun = true)
+    protected void setUp() throws Exception {
+        m_mockDeployerService = new MockDeployerService();
+        
+        m_correctVersionInstalled = false;
+        m_installCalled = false;
+        m_service = new DeploymentServiceImpl();
+        
+        TestUtils.configureObject(m_service, LogService.class);
+        TestUtils.configureObject(m_service, EventAdmin.class);
+        TestUtils.configureObject(m_service, Identification.class, new Identification() {
+            public String getID() {
+                return "test";
+            }
+        });
+        TestUtils.configureObject(m_service, Discovery.class, new Discovery() {
+            public URL discover() {
+                try {
+                    return new URL("http://localhost/");
+                }
+                catch (MalformedURLException e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        });
+        TestUtils.configureObject(m_service, Deployment.class, m_mockDeployerService);
+    }
+
+    @Test(groups = { UNIT })
+    public void testGetHighestLocalVersion() {
+        prepareMockEnvironment(new Version[] {VERSION1, VERSION2, VERSION3}, null, null);
+        Version highestVersion = m_service.getHighestLocalVersion();
+        assert highestVersion.equals(VERSION3) : "Highest local version is incorrect, expected " + VERSION3.toString() + " but got " + highestVersion.toString();
+    }
+
+    @Test(groups = { UNIT })
+    public void testGetRemoteVersionsWithURL() throws MalformedURLException, IOException {
+        URL[] urls =  prepareMockEnvironment(null, new Version[] {VERSION1, VERSION2, VERSION3}, null);
+        SortedSet<Version> highestVersion = m_service.getRemoteVersions(urls[0]);
+        assert !highestVersion.isEmpty() : "Expected versions to return!";
+        assert highestVersion.last().equals(VERSION3) : "Highest remote version is incorrect, expected " + VERSION3.toString() + " but got " + highestVersion.toString();
+    }
+
+    @Test(groups = { UNIT })
+    public void testUpdateWithLatestVersion() throws Exception {
+        final URL[] urls=  prepareMockEnvironment(null, new Version[] {VERSION1, VERSION2, VERSION3}, VERSION3);
+
+        TestUtils.configureObject(m_service, Discovery.class, new Discovery() {
+            public URL discover() {
+                return urls[1];
+            }
+        });
+
+        m_service.update(VERSION3);
+        
+        assert m_installCalled : "Install not called?!";
+        assert m_correctVersionInstalled : "Wrong version installed?!";
+    }
+
+    @Test(groups = { UNIT })
+    public void testUpdateWithNonLatestVersion() throws Exception {
+        final URL[] urls=  prepareMockEnvironment(null, new Version[] {VERSION1, VERSION2, VERSION3}, VERSION2);
+
+        TestUtils.configureObject(m_service, Discovery.class, new Discovery() {
+            public URL discover() {
+                return urls[1];
+            }
+        });
+
+        m_service.update(VERSION2);
+        
+        assert m_installCalled : "Install not called?!";
+        assert m_correctVersionInstalled : "Wrong version installed?!";
+    }
+
+    /**
+     * Helper method to setup the correct endpoints and deploymentservice based on the appropriate mock classes.
+     *
+     * @param localVersions The versions that should appear to be installed.
+     * @param remoteVersions The versions that should appear to be available remotely.
+     * @param expectedInstallVersion The version that is expected to be installed.
+     * @return Array of two urls, element [0] is the controlEndpoint, element [1] is the dataEndpoint
+     */
+    private URL[] prepareMockEnvironment(Version[] localVersions, Version[] remoteVersions, Version expectedInstallVersion) {
+        if (localVersions == null) {
+            localVersions = new Version[0];
+        }
+        if (remoteVersions == null) {
+            remoteVersions = new Version[0];
+        }
+        if (expectedInstallVersion == null) {
+            expectedInstallVersion = Version.emptyVersion;
+        }
+        // mock installed versions
+        m_mockDeployerService.setList(localVersions);
+
+        // mock versions available remotely through the control channel
+        MockURLConnection controlURLConnection = new MockURLConnection();
+        controlURLConnection.setVersions(remoteVersions, null);
+
+        // mock version available remotely through the data channel
+        MockURLConnection dataURLConnection = new MockURLConnection();
+        dataURLConnection.setVersions(new Version[] {expectedInstallVersion}, null);
+
+        m_mockDeployerService.setExpectedInstallVersion(expectedInstallVersion);
+
+        final URL controlEndpoint;
+        URL dataEndpoint = null;
+        try {
+            // create endpoints based on mock classes
+            controlEndpoint = new URL(new URL("http://notmalformed"), "", new MockURLStreamHandler(controlURLConnection));
+            dataEndpoint = new URL(new URL("http://notmalformed"), "", new MockURLStreamHandler(dataURLConnection));
+        }
+        catch (MalformedURLException e) {
+            throw new RuntimeException(e);
+        }
+
+        return new URL[] {controlEndpoint, dataEndpoint};
+    }
+    
+    /**
+     * Mock implementation of <code>DeploymentService</code> that expects Version objects.
+     * The Version objects that are 'installed' can be mocked with the new <code>setList(Version[] objects)</code>
+     * method. The <code>install(Inputstream is)</code> method only checks if the call was expected by verifying the
+     * version matches the version set by the <code>setExpectedInstallVersion(Version v)</code> method. If so a boolean
+     * in the outer class is set to true.
+     */
+    private class MockDeployerService implements Deployment {
+        Object[] m_objects = new Object[]{};
+        Version m_expectedInstallVersion = Version.emptyVersion;
+
+        public String getName(Object object) throws IllegalArgumentException {
+            return "test";
+        }
+
+        public void setExpectedInstallVersion(Version version) {
+            m_expectedInstallVersion = version;
+        }
+
+        public Version getVersion(Object object) throws IllegalArgumentException {
+            return (Version) object;
+        }
+
+        public Object install(InputStream inputStream) throws Exception {
+            m_installCalled = true;
+            BufferedReader bufReader = new BufferedReader(new InputStreamReader(inputStream));
+            String versionString = bufReader.readLine();
+            if (m_expectedInstallVersion.equals(new Version(versionString))) {
+                m_correctVersionInstalled = true;
+            }
+            return new Version(versionString);
+        }
+
+        public Object[] list() {
+            return m_objects;
+        }
+
+        public void setList(Version[] objects) {
+            m_objects = objects;
+        }
+
+    }
+
+    /**
+     * Mock implementation of <code>URLStreamHandler</code>. Will return the <code>URLConnection</code>
+     * supplied in the constructor instead when <code>openConnection(URL url)</code> is called.
+     */
+    private static class MockURLStreamHandler extends URLStreamHandler {
+        private final URLConnection urlConn;
+
+        public MockURLStreamHandler(URLConnection urlConnection) {
+            this.urlConn = urlConnection;
+        }
+
+        @Override
+        protected URLConnection openConnection(URL url) throws IOException {
+            return urlConn;
+        }
+    }
+
+    /**
+     * Mock implementation of <code>URLConnection</code>. Instead of returning an inputstream
+     * based on the URL it will return an inputstream based on the versions specified by the
+     * new <code>setVersions(Version[] versions)</code> method.
+     */
+    private static class MockURLConnection extends URLConnection {
+        private ByteArrayInputStream m_inputStream = new ByteArrayInputStream(new byte[]{});
+
+        protected MockURLConnection() {
+            super(null);
+        }
+
+        @Override
+        public void connect() throws IOException {
+            // do nothing
+        }
+
+        @Override
+        public InputStream getInputStream() {
+            return m_inputStream;
+        }
+
+        public void setVersions(Version[] versions, String malformedVersion) {
+            String versionsString = "";
+            for(int i = 0; i < versions.length; i++) {
+                versionsString += versions[i] + "\n";
+            }
+            if (malformedVersion != null) {
+                versionsString += malformedVersion + "\n";
+            }
+            byte[] bytes = versionsString.getBytes();
+            m_inputStream = new ByteArrayInputStream(bytes);
+        }
+
+    }
+}

Propchange: ace/trunk/ace-deployment-task-base/src/test/java/org/apache/ace/deployment/service/impl/DeploymentServiceImplTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ace/trunk/ace-deployment-task/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task/pom.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-deployment-task/pom.xml (original)
+++ ace/trunk/ace-deployment-task/pom.xml Fri Mar 30 16:04:59 2012
@@ -46,11 +46,9 @@
             org.apache.ace.deployment;version=${project.version},
             org.apache.ace.discovery;version=${project.version},
             org.apache.ace.identification;version=${project.version},
+            org.apache.ace.deployment.service;version=${project.version},
             *
         </import.package>
-        <export.package>
-            org.apache.ace.deployment.service;version=${project.version}
-        </export.package>
         <private.package>
             org.apache.ace.deployment.task
         </private.package>
@@ -62,6 +60,10 @@
     <dependencies>
         <dependency>
             <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.deployment.task.base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
             <artifactId>org.apache.ace.deployment.api</artifactId>
         </dependency>
         <dependency>

Modified: ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/Activator.java?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/Activator.java (original)
+++ ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/Activator.java Fri Mar 30 16:04:59 2012
@@ -25,10 +25,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
-import org.apache.ace.deployment.Deployment;
 import org.apache.ace.deployment.service.DeploymentService;
-import org.apache.ace.discovery.Discovery;
-import org.apache.ace.identification.Identification;
 import org.apache.ace.scheduler.constants.SchedulerConstants;
 import org.apache.felix.dm.Component;
 import org.apache.felix.dm.DependencyActivatorBase;
@@ -41,134 +38,155 @@ import org.osgi.service.event.EventAdmin
 import org.osgi.service.log.LogService;
 
 public class Activator extends DependencyActivatorBase implements ManagedServiceFactory {
+
+    private static final String PID_NAME = "org.apache.ace.deployment.task.default.factory";
+
     private static final String MA_NAME = "ma";
-    private DependencyManager m_manager;
+    private static final String DEFAULT_INTERVAL = "5000";
+
     private final Map<String, List<Component>> m_instances = new HashMap<String, List<Component>>();
-    private BundleContext m_context;
 
-    
+    private volatile DependencyManager m_manager;
+
+    /**
+     * @see org.osgi.service.cm.ManagedServiceFactory#deleted(java.lang.String)
+     */
+    public void deleted(String pid) {
+        List<Component> components;
+        synchronized (m_instances) {
+            components = m_instances.remove(pid);
+        }
+        if (components != null) {
+            for (Component component : components) {
+                m_manager.remove(component);
+            }
+        }
+    }
+
+    /**
+     * @see org.apache.felix.dm.DependencyActivatorBase#destroy(org.osgi.framework.BundleContext, org.apache.felix.dm.DependencyManager)
+     */
+    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
+        // do nothing
+    }
+
+    /**
+     * @see org.osgi.service.cm.ManagedServiceFactory#getName()
+     */
+    public String getName() {
+        return "Deployment Service - default check/update tasks";
+    }
+
+    /**
+     * @see org.apache.felix.dm.DependencyActivatorBase#init(org.osgi.framework.BundleContext, org.apache.felix.dm.DependencyManager)
+     */
     public void init(BundleContext context, DependencyManager manager) throws Exception {
-        m_context = context;
         m_manager = manager;
+
         List<Component> components = createServices(null);
         for (Component component : components) {
             m_manager.add(component);
         }
+
+        Properties props = new Properties();
+        props.put(Constants.SERVICE_PID, PID_NAME);
+
         manager.add(createComponent()
-            .setInterface(ManagedServiceFactory.class.getName(), new Properties() {{ put(Constants.SERVICE_PID, "org.apache.ace.deployment.factory"); }} )
+            .setInterface(ManagedServiceFactory.class.getName(), props)
             .setImplementation(this)
-        );
+            );
     }
 
+    /**
+     * @see org.osgi.service.cm.ManagedServiceFactory#updated(java.lang.String, java.util.Dictionary)
+     */
+    public void updated(String pid, Dictionary dict) throws ConfigurationException {
+        String ma = (String) dict.get(MA_NAME);
+
+        List<Component> components = m_instances.get(pid);
+        if (components == null) {
+            components = createServices(ma);
+            synchronized (m_instances) {
+                m_instances.put(pid, components);
+            }
+            for (Component component : components) {
+                m_manager.add(component);
+            }
+        }
+        else {
+            // TODO do we want to deal with changes here?
+        }
+    }
+
+    /**
+     * Creates the check/update task components for the given management agent name.
+     * 
+     * @param ma the name of the management agent to create the service for, can be <code>null</code>.
+     * @return an array with {@link Component} instances for the different tasks, never <code>null</code>.
+     */
     private List<Component> createServices(String ma) {
-        List<Component> result = new ArrayList<Component>();
         Dictionary updateProperties = new Properties();
         Dictionary checkProperties = new Properties();
         Dictionary deploymentProperties = new Properties();
-        String updateSchedulerName;
-        String updateDescription;
-        String checkSchedulerName;
-        String checkDescription;
-        String identificationFilter;
-        String discoveryFilter;
-        String deploymentFilter;
+        
+        String updateSchedulerName = DeploymentUpdateTask.class.getName();
+        String updateDescription = "Task that synchronizes the artifacts (bundles, resources) installed on this target with the server.";
+        
+        String checkSchedulerName = DeploymentCheckTask.class.getName();
+        String checkDescription = "Task that checks for updates of artifacts installed on this target with the server.";
+        
+        String deploymentFilter = "(" + Constants.OBJECTCLASS + "=" + DeploymentService.class.getName() + ")";
 
         if (ma == null || "".equals(ma)) {
-            updateSchedulerName = DeploymentUpdateTask.class.getName();
-            updateDescription = "Task that synchronizes the artifacts (bundles, resources) installed on this target with the server.";
-            checkSchedulerName = DeploymentCheckTask.class.getName();
-            checkDescription = "Task that checks for updates of artifacts installed on this target with the server.";
-            identificationFilter = "(&("+Constants.OBJECTCLASS+"="+Identification.class.getName()+")(!(ma=*)))";
-            discoveryFilter = "(&("+Constants.OBJECTCLASS+"="+Discovery.class.getName()+")(!(ma=*)))";
-            deploymentFilter = "(&("+Constants.OBJECTCLASS+"="+DeploymentService.class.getName()+")(!(ma=*)))";
+            deploymentFilter = String.format("(&%s(!(%s=*)))", deploymentFilter, MA_NAME);
         }
         else {
-            updateSchedulerName = "ma=" + ma + ";name=" + DeploymentUpdateTask.class.getName();
+            updateSchedulerName = "ma=" + ma + ";name=" + updateSchedulerName;
             updateDescription = "Task that synchronizes the artifacts (bundles, resources) installed on this target with the server with ma=" + ma + ".";
-            checkSchedulerName = "ma=" + ma + ";name=" + DeploymentCheckTask.class.getName();
+            
+            checkSchedulerName = "ma=" + ma + ";name=" + checkSchedulerName;
             checkDescription = "Task that checks for updates of artifacts installed on this target with the server with ma=" + ma + ".";
-            identificationFilter = "(&("+Constants.OBJECTCLASS+"="+Identification.class.getName()+")(ma=" + ma + "))";
-            discoveryFilter = "(&("+Constants.OBJECTCLASS+"="+Discovery.class.getName()+")(ma=" + ma + "))";
-            deploymentFilter = "(&("+Constants.OBJECTCLASS+"="+DeploymentService.class.getName()+")(ma=" + ma + "))";
+            
+            deploymentFilter = String.format("(&%s(%s=%s))", deploymentFilter, MA_NAME, ma);
+            
             updateProperties.put(MA_NAME, ma);
             checkProperties.put(MA_NAME, ma);
             deploymentProperties.put(MA_NAME, ma);
         }
+
+        List<Component> result = new ArrayList<Component>();
+
         updateProperties.put(SchedulerConstants.SCHEDULER_NAME_KEY, updateSchedulerName);
         updateProperties.put(SchedulerConstants.SCHEDULER_DESCRIPTION_KEY, updateDescription);
-        updateProperties.put(SchedulerConstants.SCHEDULER_RECIPE, "5000");
+        updateProperties.put(SchedulerConstants.SCHEDULER_RECIPE, DEFAULT_INTERVAL);
+
+        DeploymentUpdateTask updateTask = new DeploymentUpdateTask();
+
+        Component updateTaskComponent =
+            createComponent()
+                .setInterface(Runnable.class.getName(), updateProperties)
+                .setImplementation(updateTask)
+                .add(createServiceDependency().setService(DeploymentService.class, deploymentFilter).setRequired(true))
+                .add(createServiceDependency().setService(LogService.class).setRequired(false));
 
         checkProperties.put(SchedulerConstants.SCHEDULER_NAME_KEY, checkSchedulerName);
         checkProperties.put(SchedulerConstants.SCHEDULER_DESCRIPTION_KEY, checkDescription);
-        checkProperties.put(SchedulerConstants.SCHEDULER_RECIPE, "5000");
-        
-        DeploymentTaskBase task = new DeploymentTaskBase();
-        DeploymentUpdateTask updateTask = new DeploymentUpdateTask(task);
-        DeploymentCheckTask checkTask = new DeploymentCheckTask(task);
-
-        Component deploymentServiceComponent = createComponent()
-            .setInterface(DeploymentService.class.getName(), deploymentProperties)
-            .setImplementation(task)
-            .add(createServiceDependency().setService(Deployment.class).setRequired(true))
-            .add(createServiceDependency().setService(Identification.class, identificationFilter).setRequired(true))
-            .add(createServiceDependency().setService(Discovery.class, discoveryFilter).setRequired(true))
-            .add(createServiceDependency().setService(EventAdmin.class).setRequired(false))
-            .add(createServiceDependency().setService(LogService.class).setRequired(false));
-
-        Component updateTaskComponent = createComponent()
-            .setInterface(Runnable.class.getName(), updateProperties)
-            .setImplementation(updateTask)
-            .add(createServiceDependency().setService(DeploymentService.class, deploymentFilter).setRequired(true).setAutoConfig(false))
-            .add(createServiceDependency().setService(LogService.class).setRequired(false));
-
-        Component checkTaskComponent = createComponent()
-            .setInterface(Runnable.class.getName(), checkProperties)
-            .setImplementation(checkTask)
-            .add(createServiceDependency().setService(DeploymentService.class, deploymentFilter).setRequired(true).setAutoConfig(false))
-            .add(createServiceDependency().setService(EventAdmin.class).setRequired(false))
-            .add(createServiceDependency().setService(LogService.class).setRequired(false));
+        checkProperties.put(SchedulerConstants.SCHEDULER_RECIPE, DEFAULT_INTERVAL);
 
-        result.add(deploymentServiceComponent);
         result.add(updateTaskComponent);
-        result.add(checkTaskComponent);
 
-        return result;
-    }
+        DeploymentCheckTask checkTask = new DeploymentCheckTask();
 
-    public void destroy(BundleContext context, DependencyManager manager) throws Exception {
-        // do nothing
-    }
-
-    public String getName() {
-        return "Deployment Service";
-    }
+        Component checkTaskComponent =
+            createComponent()
+                .setInterface(Runnable.class.getName(), checkProperties)
+                .setImplementation(checkTask)
+                .add(createServiceDependency().setService(DeploymentService.class, deploymentFilter).setRequired(true))
+                .add(createServiceDependency().setService(EventAdmin.class).setRequired(false))
+                .add(createServiceDependency().setService(LogService.class).setRequired(false));
 
-    public void updated(String pid, Dictionary dict) throws ConfigurationException {
-        String ma = (String) dict.get(MA_NAME);
-        List<Component> components = m_instances.get(pid);
-        if (components == null) {
-            components = createServices(ma);
-            synchronized (m_instances) {
-                m_instances.put(pid, components);
-            }
-            for (Component component : components) {
-                m_manager.add(component);
-            }
-        }
-        else {
-            // TODO do we want to deal with changes here?
-        }
-    }
+        result.add(checkTaskComponent);
 
-    public void deleted(String pid) {
-        List<Component> components;
-        synchronized (m_instances) {
-            components = m_instances.remove(pid);
-        }
-        if (components != null) {
-            for (Component component : components) {
-                m_manager.remove(component);
-            }
-        }
+        return result;
     }
 }
\ No newline at end of file

Modified: ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentCheckTask.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentCheckTask.java?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentCheckTask.java (original)
+++ ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentCheckTask.java Fri Mar 30 16:04:59 2012
@@ -22,6 +22,7 @@ import java.net.MalformedURLException;
 import java.util.Dictionary;
 import java.util.Properties;
 
+import org.apache.ace.deployment.service.DeploymentService;
 import org.osgi.framework.Version;
 import org.osgi.service.event.Event;
 import org.osgi.service.event.EventAdmin;
@@ -32,38 +33,33 @@ import org.osgi.service.log.LogService;
  * download or install it.
  */
 public class DeploymentCheckTask implements Runnable {
+
     private static final String TOPIC_UPDATE_AVAILABLE = "org/apache/ace/deployment/UPDATEAVAILABLE";
-    
-    private final DeploymentTaskBase m_task;
-    
+
     private volatile LogService m_log;
     private volatile EventAdmin m_eventAdmin;
-    
-    public DeploymentCheckTask(DeploymentTaskBase task) {
-        m_task = task;
-    }
+    private volatile DeploymentService m_service;
 
     /**
      * When run a check is made if a higher version is available on the remote. If so, send out an event.
      */
     public void run() {
         try {
-            Version highestLocalVersion = m_task.getHighestLocalVersion();
-            Version highestRemoteVersion = m_task.getHighestRemoteVersion();
-            if (highestRemoteVersion == null) {
-                //expected if there's no discovered ps or relay server
+            Version localVersion = m_service.getHighestLocalVersion();
+            Version remoteVersion = m_service.getHighestRemoteVersion();
+
+            if (remoteVersion == null) {
+                // expected if there's no discovered ps or relay server
                 // ACE-220: lower log level; not of real interest...
-                m_log.log(LogService.LOG_DEBUG, "Highest remote: unknown / Highest local: " + highestLocalVersion);
+                m_log.log(LogService.LOG_DEBUG, "Highest remote: unknown / Highest local: " + localVersion);
                 return;
             }
+
             // ACE-220: lower log level; not of real interest...
-            m_log.log(LogService.LOG_DEBUG, "Highest remote: " + highestRemoteVersion + " / Highest local: " + highestLocalVersion);
-            
-            if ((highestRemoteVersion != null) && ((highestLocalVersion == null) || (highestRemoteVersion.compareTo(highestLocalVersion) > 0))) {
-                Properties properties = new Properties();
-                properties.put("deploymentpackage.localversion", ((highestLocalVersion == null) ? Version.emptyVersion : highestLocalVersion));
-                properties.put("deploymentpackage.remoteversion", highestRemoteVersion);
-                m_eventAdmin.postEvent(new Event(TOPIC_UPDATE_AVAILABLE, (Dictionary) properties));
+            m_log.log(LogService.LOG_DEBUG, "Highest remote: " + remoteVersion + " / Highest local: " + localVersion);
+
+            if ((remoteVersion != null) && ((localVersion == null) || (remoteVersion.compareTo(localVersion) > 0))) {
+                m_eventAdmin.postEvent(createEvent(localVersion, remoteVersion));
             }
         }
         catch (MalformedURLException e) {
@@ -73,4 +69,19 @@ public class DeploymentCheckTask impleme
             m_log.log(LogService.LOG_ERROR, "Error checking for update", e);
         }
     }
+
+    /**
+     * Creates an event for notifying listeners that a new version can be installed.
+     * 
+     * @param localVersion the highest local version;
+     * @param remoteVersion the higest remote version.
+     * @return a new {@link Event} instance, never <code>null</code>.
+     */
+    private Event createEvent(Version localVersion, Version remoteVersion) {
+        Properties properties = new Properties();
+        properties.put("deploymentpackage.localversion", ((localVersion == null) ? Version.emptyVersion : localVersion));
+        properties.put("deploymentpackage.remoteversion", remoteVersion);
+
+        return new Event(TOPIC_UPDATE_AVAILABLE, (Dictionary) properties);
+    }
 }
\ No newline at end of file

Modified: ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentUpdateTask.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentUpdateTask.java?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentUpdateTask.java (original)
+++ ace/trunk/ace-deployment-task/src/main/java/org/apache/ace/deployment/task/DeploymentUpdateTask.java Fri Mar 30 16:04:59 2012
@@ -21,31 +21,28 @@ package org.apache.ace.deployment.task;
 import java.io.IOException;
 import java.net.MalformedURLException;
 
+import org.apache.ace.deployment.service.DeploymentService;
 import org.osgi.framework.Version;
 import org.osgi.service.log.LogService;
 
 /**
- * Implementation of the <code>Updater</code> interface that updates software configurations by using the
+ * Implementation of the <code>Runnable</code> interface that updates software configurations by using the
  * <code>DeploymentService</code> to determine the current local version and to actually install new versions.
  */
 public class DeploymentUpdateTask implements Runnable {
-    
-    private final DeploymentTaskBase m_task;
-    
+
+    private volatile DeploymentService m_service;
     private volatile LogService m_log;
-    
-    public DeploymentUpdateTask(DeploymentTaskBase task) {
-        m_task = task;
-    }
-    
+
     /**
      * When run a check is made if a higher version is available on the remote. If so, an attempt is made to install
      * this new version.
      */
     public void run() {
         try {
-            Version highestLocalVersion = m_task.getHighestLocalVersion();
-            Version highestRemoteVersion = m_task.getHighestRemoteVersion();
+            Version highestLocalVersion = m_service.getHighestLocalVersion();
+            Version highestRemoteVersion = m_service.getHighestRemoteVersion();
+
             if (highestRemoteVersion == null) {
                 // expected if there's no discovered ps or relay server
                 // ACE-220: lower log level; not of real interest...
@@ -54,10 +51,10 @@ public class DeploymentUpdateTask implem
             }
             // ACE-220: lower log level; not of real interest...
             m_log.log(LogService.LOG_DEBUG, "Highest remote: " + highestRemoteVersion + " / Highest local: " + highestLocalVersion);
-            
+
             if ((highestRemoteVersion != null) && ((highestLocalVersion == null) || (highestRemoteVersion.compareTo(highestLocalVersion) > 0))) {
                 // no local version or local version lower than remote, install the update
-                m_task.installVersion(highestRemoteVersion, highestLocalVersion);
+                m_service.installVersion(highestRemoteVersion, highestLocalVersion);
             }
         }
         catch (MalformedURLException e) {

Modified: ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.properties
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.properties?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.properties (original)
+++ ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.properties Fri Mar 30 16:04:59 2012
@@ -1,5 +1,5 @@
 service.name=Apache ACE :: Deployment :: Task
-service.desc=This component is responsible for checking the deployment server for updates and for synchronizing the local instance with the server. A new configuration is only required if there are multiple management agents.
+service.desc=This component provides a default implementation for checking the deployment server for updates and for synchronizing the local instance with the server. A new configuration is only required if there are multiple management agents.
 
 ma.name=Management Agent Name
 ma.desc=The name of the management agent that the deployment should be synchronized with.

Modified: ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.xml (original)
+++ ace/trunk/ace-deployment-task/src/main/resources/OSGI-INF/metatype/metatype.xml Fri Mar 30 16:04:59 2012
@@ -1,10 +1,9 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0"
-  localization="OSGI-INF/metatype/metatype">
-  <metatype:OCD id="org.apache.ace.deployment" name="%service.name" description="%service.desc">
-    <metatype:AD id="ma" type="String" name="%ma.name" description="%ma.desc" required="false"/>
-  </metatype:OCD>
-  <metatype:Designate pid="org.apache.ace.deployment.factory">
-    <metatype:Object ocdref="org.apache.ace.deployment"/>
-  </metatype:Designate>
+<metatype:MetaData xmlns:metatype="http://www.osgi.org/xmlns/metatype/v1.0.0" localization="OSGI-INF/metatype/metatype">
+	<metatype:OCD id="org.apache.ace.deployment" name="%service.name" description="%service.desc">
+		<metatype:AD id="ma" type="String" name="%ma.name" description="%ma.desc" required="false" />
+	</metatype:OCD>
+	<metatype:Designate factoryPid="org.apache.ace.deployment.task.default.factory">
+		<metatype:Object ocdref="org.apache.ace.deployment" />
+	</metatype:Designate>
 </metatype:MetaData>

Modified: ace/trunk/ace-integrationtests/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-integrationtests/pom.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-integrationtests/pom.xml (original)
+++ ace/trunk/ace-integrationtests/pom.xml Fri Mar 30 16:04:59 2012
@@ -191,6 +191,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.deployment.task.base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
             <artifactId>org.apache.ace.deployment.task</artifactId>
         </dependency>
         <dependency>

Modified: ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/Options.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/Options.java?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/Options.java (original)
+++ ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/Options.java Fri Mar 30 16:04:59 2012
@@ -142,6 +142,10 @@ public class Options {
             return maven("org.apache.ace.deployment.servlet");
         }
 
+        public static MavenArtifactProvisionOption deploymentTaskBase() {
+            return maven("org.apache.ace.deployment.task.base");
+        }
+
         public static MavenArtifactProvisionOption deploymentTask() {
             return maven("org.apache.ace.deployment.task");
         }

Modified: ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/deployment/DeploymentIntegrationTest.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/deployment/DeploymentIntegrationTest.java?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/deployment/DeploymentIntegrationTest.java (original)
+++ ace/trunk/ace-integrationtests/src/test/java/org/apache/ace/it/deployment/DeploymentIntegrationTest.java Fri Mar 30 16:04:59 2012
@@ -87,6 +87,7 @@ public class DeploymentIntegrationTest e
                 Ace.deploymentApi(),
                 Ace.deploymentDeploymentAdmin(),
                 Ace.deploymentServlet(),
+                Ace.deploymentTaskBase(),
                 Ace.deploymentTask(),
                 Ace.deploymentStreamgenerator()
             )

Modified: ace/trunk/ace-managementagent/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-managementagent/pom.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-managementagent/pom.xml (original)
+++ ace/trunk/ace-managementagent/pom.xml Fri Mar 30 16:04:59 2012
@@ -155,6 +155,10 @@
         </dependency>
         <dependency>
             <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.deployment.task.base</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
             <artifactId>org.apache.ace.deployment.task</artifactId>
         </dependency>
     </dependencies>

Modified: ace/trunk/ace-managementagent/src/main/java/org/apache/ace/managementagent/Activator.java
URL: http://svn.apache.org/viewvc/ace/trunk/ace-managementagent/src/main/java/org/apache/ace/managementagent/Activator.java?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-managementagent/src/main/java/org/apache/ace/managementagent/Activator.java (original)
+++ ace/trunk/ace-managementagent/src/main/java/org/apache/ace/managementagent/Activator.java Fri Mar 30 16:04:59 2012
@@ -2,7 +2,6 @@ package org.apache.ace.managementagent;
 
 import java.io.IOException;
 import java.net.URL;
-import java.util.ArrayList;
 import java.util.Dictionary;
 import java.util.Properties;
 
@@ -14,10 +13,10 @@ import org.osgi.service.cm.Configuration
 import org.osgi.service.cm.ConfigurationAdmin;
 
 public class Activator extends DependencyActivatorBase {
-    private static final String[] PROTOTYPE_ARRAY = new String[] {};
 
     private BundleActivator[] m_activators = new BundleActivator[] {
         new org.apache.ace.deployment.deploymentadmin.Activator(),
+        new org.apache.ace.deployment.service.impl.Activator(),
         new org.apache.ace.deployment.task.Activator(),
         new org.apache.ace.discovery.property.Activator(),
         new org.apache.ace.target.log.Activator(),
@@ -91,7 +90,8 @@ public class Activator extends Dependenc
                     if (!isFileUrl) {
                         configureFactory("org.apache.ace.target.log.sync.factory", "ma", ma, "name", "auditlog");
                     }
-                    configureFactory("org.apache.ace.deployment.factory", "ma", ma);
+                    configureFactory("org.apache.ace.deployment.task.base.factory", "ma", ma);
+                    configureFactory("org.apache.ace.deployment.task.default.factory", "ma", ma);
                     configure("org.apache.ace.scheduler", "ma=" + ma + ";name=auditlog", syncInterval);
                     instances.append(
                         "  Instance     : " + ma + "\n" +

Modified: ace/trunk/ace-target-devgateway/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/ace-target-devgateway/pom.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/ace-target-devgateway/pom.xml (original)
+++ ace/trunk/ace-target-devgateway/pom.xml Fri Mar 30 16:04:59 2012
@@ -178,6 +178,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.ace</groupId>
+            <artifactId>org.apache.ace.deployment.task.base</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.ace</groupId>
             <artifactId>org.apache.ace.deployment.task</artifactId>
             <scope>runtime</scope>
         </dependency>

Modified: ace/trunk/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/pom.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/pom.xml (original)
+++ ace/trunk/pom.xml Fri Mar 30 16:04:59 2012
@@ -79,6 +79,7 @@
 
         <module>ace-deployment-api</module>
         <module>ace-deployment-deploymentadmin</module>
+        <module>ace-deployment-task-base</module>
         <module>ace-deployment-task</module>
         <module>ace-deployment-verifier</module>
         <module>ace-deployment-verifier-ui</module>
@@ -188,6 +189,7 @@
                 <module>ace-scheduler-api</module>
                 <module>ace-scheduler</module>
                 <module>ace-deployment-api</module>
+                <module>ace-deployment-task-base</module>
                 <module>ace-deployment-task</module>
             </modules>
         </profile>

Modified: ace/trunk/pom/pom.xml
URL: http://svn.apache.org/viewvc/ace/trunk/pom/pom.xml?rev=1307498&r1=1307497&r2=1307498&view=diff
==============================================================================
--- ace/trunk/pom/pom.xml (original)
+++ ace/trunk/pom/pom.xml Fri Mar 30 16:04:59 2012
@@ -430,6 +430,11 @@
             </dependency>
             <dependency>
                 <groupId>org.apache.ace</groupId>
+                <artifactId>org.apache.ace.deployment.task.base</artifactId>
+                <version>${project.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.apache.ace</groupId>
                 <artifactId>org.apache.ace.deployment.task</artifactId>
                 <version>${project.version}</version>
             </dependency>



Mime
View raw message