karaf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jbono...@apache.org
Subject [karaf-cave] branch master updated: [KARAF-5188] Provide Cave Features Gateway feature
Date Mon, 18 Dec 2017 16:04:41 GMT
This is an automated email from the ASF dual-hosted git repository.

jbonofre pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/karaf-cave.git


The following commit(s) were added to refs/heads/master by this push:
     new 3a478cb  [KARAF-5188] Provide Cave Features Gateway feature
3a478cb is described below

commit 3a478cbc336a058374d2c68ada277796c684e4fc
Author: Jean-Baptiste Onofré <jbonofre@apache.org>
AuthorDate: Mon Dec 18 17:04:21 2017 +0100

    [KARAF-5188] Provide Cave Features Gateway feature
---
 manual/src/main/asciidoc/index.adoc                |  2 +
 .../main/asciidoc/user-guide/features-gateway.adoc | 84 +++++++++++++++++++++
 .../karaf/cave/server/api/CaveFeatureGateway.java  | 32 ++++++++
 .../cave/server/command/GatewayListCommand.java    | 40 ++++++++++
 .../server/command/GatewayRegisterCommand.java     | 42 +++++++++++
 .../cave/server/command/GatewayRemoveCommand.java  | 45 +++++++++++
 .../command/completers/GatewayCompleter.java       | 48 ++++++++++++
 .../karaf/cave/server/http/CaveHttpServlet.java    | 46 ++++++++----
 .../cave/server/management/CaveGatewayMBean.java   | 24 ++++++
 .../cave/server/management/internal/Activator.java | 39 +++++++---
 .../management/internal/CaveGatewayMBeanImpl.java  | 49 ++++++++++++
 .../internal/CaveRepositoryMBeanImpl.java          |  1 -
 server/storage/pom.xml                             | 13 +++-
 .../karaf/cave/server/storage/Activator.java       |  9 ++-
 .../server/storage/CaveFeatureGatewayImpl.java     | 86 ++++++++++++++++++++++
 .../server/storage/CaveFeatureGatewayImplTest.java | 79 ++++++++++++++++++++
 16 files changed, 609 insertions(+), 30 deletions(-)

diff --git a/manual/src/main/asciidoc/index.adoc b/manual/src/main/asciidoc/index.adoc
index c78f2d2..34026f4 100644
--- a/manual/src/main/asciidoc/index.adoc
+++ b/manual/src/main/asciidoc/index.adoc
@@ -39,3 +39,5 @@ include::user-guide/http-wrapper.adoc[]
 include::user-guide/maven-wrapper.adoc[]
 
 include::user-guide/administrate-cave.adoc[]
+
+include::user-guide/features-gateway.adoc[]
diff --git a/manual/src/main/asciidoc/user-guide/features-gateway.adoc b/manual/src/main/asciidoc/user-guide/features-gateway.adoc
new file mode 100644
index 0000000..b32602b
--- /dev/null
+++ b/manual/src/main/asciidoc/user-guide/features-gateway.adoc
@@ -0,0 +1,84 @@
+//
+// 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.
+//
+
+=== Cave Features Gateway
+
+Apache Karaf Cave can also act as a central Karaf Features gateway. For instance, you can
have an unique Cave server in your organization, providing
+a single features repository for your Karaf instances.
+
+Your Karaf instances on your ecosystem can connect to this unique Cave features gateway URL.
+
+Then, you manage your features repository on the "central" Cave server, and the Karaf instances
get the features (without knowing exactly where they come from).
+
+The Cave Features Gateway is automatically installed by the `cave-server` feature.
+
+==== Cave Features Gateway server
+
+You can manipulate the Features Gateway using specific shell commands or corresponding MBean.
+
+===== Shell commands
+
+You can register a features repository in the gateway using `cave:gateway-register` command.
For example, you can register
+Apache Camel feature in the gateway using:
+
+----
+karaf@root()> cave:gateway-register mvn:org.apache.camel.karaf/apache-camel/2.18.1/xml/features
+----
+
+Any URL (http, file, mvn, ...) supported by Apache Karaf is supported by Cave Features Gateway.
+
+You can see the features repository registered in the gateway using the `cave:gateway-register`
command:
+
+----
+karaf@root()> cave:gateway-list
+mvn:org.apache.camel.karaf/apache-camel/2.18.1/xml/features
+----
+
+You can also delete a features repository from the gateway using `cave:gateway-remove` command:
+
+----
+karaf@root()> cave:gateway-remove mvn:org.apache.camel.karaf/apache-camel/2.18.1/xml/features
+----
+
+===== MBean
+
+Similar to the `cave:gateway*` commands, you find similar operation on the CaveGatewayMBean.
+
+This MBean uses the following object name:
+
+----
+org.apache.karaf.cave:type=gateway,name=*
+----
+
+This MBean provides the following operations:
+
+* `List<String> list()`
+* `register(repository)`
+* `remove(repository)`
+
+==== Plugin your Karaf instances with the central gateway
+
+The Cave Features Gateway is available on the Cave HTTP service at the following URL:
+
+----
+http://localhost:8181/cave/http/gateway
+----
+
+Any Karaf instance can use the gateway using the regular `feature:repo-add` command:
+
+----
+karaf@root()> feature:repo-add http://cave_server:8181/cave/http/gateway
+----
+
+NB: the Karaf instances use a cache, so you have to flush the changes on the gateway using
the `feature:repo-refresh` command.
\ No newline at end of file
diff --git a/server/api/src/main/java/org/apache/karaf/cave/server/api/CaveFeatureGateway.java
b/server/api/src/main/java/org/apache/karaf/cave/server/api/CaveFeatureGateway.java
new file mode 100644
index 0000000..196dfe0
--- /dev/null
+++ b/server/api/src/main/java/org/apache/karaf/cave/server/api/CaveFeatureGateway.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.api;
+
+import java.io.File;
+import java.util.List;
+
+public interface CaveFeatureGateway {
+
+    String STORAGE = System.getProperty("karaf.data") + File.separator + "cave-features-gateway.xml";
+
+    void register(String url) throws Exception;
+
+    void remove(String id) throws Exception;
+
+    List<String> list() throws Exception;
+
+}
diff --git a/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayListCommand.java
b/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayListCommand.java
new file mode 100644
index 0000000..07c34b3
--- /dev/null
+++ b/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayListCommand.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.command;
+
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Service
+@Command(scope = "cave", name = "gateway-list", description = "List the features repositories
registered in the gateway")
+public class GatewayListCommand implements Action {
+
+    @Reference
+    private CaveFeatureGateway gateway;
+
+    @Override
+    public Object execute() throws Exception {
+        for (String repository : gateway.list()) {
+            System.out.println(repository);
+        }
+        return null;
+    }
+
+}
diff --git a/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayRegisterCommand.java
b/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayRegisterCommand.java
new file mode 100644
index 0000000..86c5f70
--- /dev/null
+++ b/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayRegisterCommand.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.command;
+
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Service
+@Command(scope = "cave", name = "gateway-register", description = "Register a features repository
in the gateway")
+public class GatewayRegisterCommand implements Action {
+
+    @Argument(name = "repository", description = "The features repository URL ", required
= true, multiValued = false)
+    String repository;
+
+    @Reference
+    CaveFeatureGateway gateway;
+
+    @Override
+    public Object execute() throws Exception {
+        gateway.register(repository);
+        return null;
+    }
+
+}
diff --git a/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayRemoveCommand.java
b/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayRemoveCommand.java
new file mode 100644
index 0000000..e2d64cf
--- /dev/null
+++ b/server/command/src/main/java/org/apache/karaf/cave/server/command/GatewayRemoveCommand.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.command;
+
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
+import org.apache.karaf.cave.server.command.completers.GatewayCompleter;
+import org.apache.karaf.shell.api.action.Action;
+import org.apache.karaf.shell.api.action.Argument;
+import org.apache.karaf.shell.api.action.Command;
+import org.apache.karaf.shell.api.action.Completion;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+
+@Service
+@Command(scope = "cave", name = "gateway-remove", description = "Remove a features repository
from the gateway")
+public class GatewayRemoveCommand implements Action {
+
+    @Argument(name = "repository", description = "The features repository URL", required
= true, multiValued = false)
+    @Completion(GatewayCompleter.class)
+    String repository;
+
+    @Reference
+    private CaveFeatureGateway gateway;
+
+    @Override
+    public Object execute() throws Exception {
+        gateway.remove(repository);
+        return null;
+    }
+
+}
diff --git a/server/command/src/main/java/org/apache/karaf/cave/server/command/completers/GatewayCompleter.java
b/server/command/src/main/java/org/apache/karaf/cave/server/command/completers/GatewayCompleter.java
new file mode 100644
index 0000000..7e85a37
--- /dev/null
+++ b/server/command/src/main/java/org/apache/karaf/cave/server/command/completers/GatewayCompleter.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.command.completers;
+
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
+import org.apache.karaf.shell.api.action.lifecycle.Reference;
+import org.apache.karaf.shell.api.action.lifecycle.Service;
+import org.apache.karaf.shell.api.console.CommandLine;
+import org.apache.karaf.shell.api.console.Completer;
+import org.apache.karaf.shell.api.console.Session;
+import org.apache.karaf.shell.support.completers.StringsCompleter;
+
+import java.util.List;
+
+@Service
+public class GatewayCompleter implements Completer {
+
+    @Reference
+    private CaveFeatureGateway gateway;
+
+    @Override
+    public int complete(Session session, CommandLine commandLine, List<String> list)
{
+        StringsCompleter delegate = new StringsCompleter();
+        try {
+            for (String repository : gateway.list()) {
+                delegate.getStrings().add(repository);
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+        return delegate.complete(session, commandLine, list);
+    }
+
+}
diff --git a/server/http/src/main/java/org/apache/karaf/cave/server/http/CaveHttpServlet.java
b/server/http/src/main/java/org/apache/karaf/cave/server/http/CaveHttpServlet.java
index 4fb2f0f..ff02500 100644
--- a/server/http/src/main/java/org/apache/karaf/cave/server/http/CaveHttpServlet.java
+++ b/server/http/src/main/java/org/apache/karaf/cave/server/http/CaveHttpServlet.java
@@ -16,10 +16,7 @@
  */
 package org.apache.karaf.cave.server.http;
 
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.io.PrintWriter;
+import java.io.*;
 import java.net.URI;
 import java.net.URL;
 import java.util.zip.GZIPOutputStream;
@@ -36,6 +33,7 @@ import javax.xml.transform.TransformerException;
 import javax.xml.transform.dom.DOMSource;
 import javax.xml.transform.stream.StreamResult;
 
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
 import org.apache.karaf.cave.server.api.CaveRepository;
 import org.apache.karaf.cave.server.api.CaveRepositoryService;
 import org.apache.karaf.util.XmlUtils;
@@ -85,17 +83,19 @@ public class CaveHttpServlet extends HttpServlet {
     protected long getLastModified(HttpServletRequest request) {
         String uri = request.getPathInfo();
         // remove the starting /
-        uri = uri.substring(1);
-        if (request.getPathInfo().endsWith("-repository.xml")) {
-            // the user wants to get the Cave repository repository.xml
-            // the expected format is {cave-repo-name}-repository.xml
-            int index = uri.indexOf("-repository.xml");
-            String caveRepositoryName = uri.substring(0, index);
-            CaveRepositoryService caveRepositoryService = tracker.getService();
-            if (caveRepositoryService != null) {
-                CaveRepository caveRepository = caveRepositoryService.getRepository(caveRepositoryName);
-                if (caveRepository != null) {
-                    return caveRepository.getIncrement();
+        if (uri != null) {
+            uri = uri.substring(1);
+            if (request.getPathInfo().endsWith("-repository.xml")) {
+                // the user wants to get the Cave repository repository.xml
+                // the expected format is {cave-repo-name}-repository.xml
+                int index = uri.indexOf("-repository.xml");
+                String caveRepositoryName = uri.substring(0, index);
+                CaveRepositoryService caveRepositoryService = tracker.getService();
+                if (caveRepositoryService != null) {
+                    CaveRepository caveRepository = caveRepositoryService.getRepository(caveRepositoryName);
+                    if (caveRepository != null) {
+                        return caveRepository.getIncrement();
+                    }
                 }
             }
         }
@@ -114,6 +114,22 @@ public class CaveHttpServlet extends HttpServlet {
 
         String uri = request.getPathInfo();
 
+        // Cave Feature gateway
+        if (uri.equals("/gateway")) {
+            response.setContentType("application/xml");
+            File file = new File(CaveFeatureGateway.STORAGE);
+            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
+                PrintWriter writer = response.getWriter();
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    writer.println(line);
+                }
+                writer.flush();
+                writer.close();
+            }
+            return;
+        }
+
         // remove the starting /
         uri = uri.substring(1);
 
diff --git a/server/management/src/main/java/org/apache/karaf/cave/server/management/CaveGatewayMBean.java
b/server/management/src/main/java/org/apache/karaf/cave/server/management/CaveGatewayMBean.java
new file mode 100644
index 0000000..fdca603
--- /dev/null
+++ b/server/management/src/main/java/org/apache/karaf/cave/server/management/CaveGatewayMBean.java
@@ -0,0 +1,24 @@
+/*
+ * 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.cave.server.management;
+
+import java.util.List;
+
+public interface CaveGatewayMBean {
+
+    List<String> list() throws Exception;
+    void register(String repository) throws Exception;
+    void remove(String repository) throws Exception;
+
+}
diff --git a/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/Activator.java
b/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/Activator.java
index 3d61032..7579caa 100644
--- a/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/Activator.java
+++ b/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/Activator.java
@@ -2,6 +2,7 @@ package org.apache.karaf.cave.server.management.internal;
 
 import java.util.Hashtable;
 
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
 import org.apache.karaf.cave.server.api.CaveRepositoryService;
 import org.apache.karaf.util.tracker.BaseActivator;
 import org.apache.karaf.util.tracker.annotation.RequireService;
@@ -23,28 +24,44 @@ import org.osgi.framework.ServiceRegistration;
  */
 
 @Services(
-        requires = { @RequireService(CaveRepositoryService.class) }
+        requires = {
+                @RequireService(CaveRepositoryService.class),
+                @RequireService(CaveFeatureGateway.class)
+        }
 )
 public class Activator extends BaseActivator {
 
-    private volatile ServiceRegistration registration;
+    private volatile ServiceRegistration repositoryRegistration;
+    private volatile ServiceRegistration gatewayRegistration;
 
     @Override
     protected void doStart() throws Exception {
-        CaveRepositoryService service = getTrackedService(CaveRepositoryService.class);
-        CaveRepositoryMBeanImpl mbean = new CaveRepositoryMBeanImpl();
-        mbean.setCaveRepositoryService(service);
+        CaveRepositoryService repositoryService = getTrackedService(CaveRepositoryService.class);
+        CaveRepositoryMBeanImpl repositoryMBean = new CaveRepositoryMBeanImpl();
+        repositoryMBean.setCaveRepositoryService(repositoryService);
+
+        Hashtable<String, Object> repositoryProps = new Hashtable<>();
+        repositoryProps.put("jmx.objectname", "org.apache.karaf.cave:type=repository,name="
+ System.getProperty("karaf.name"));
+        repositoryRegistration = this.bundleContext.registerService(getInterfaceNames(repositoryMBean),
repositoryMBean, repositoryProps);
 
-        Hashtable<String, Object> props = new Hashtable<>();
-        props.put("jmx.objectname", "org.apache.karaf.cave:type=repository,name=" + System.getProperty("karaf.name"));
-        registration = this.bundleContext.registerService(getInterfaceNames(mbean), mbean,
props);
+        CaveFeatureGateway gatewayService = getTrackedService(CaveFeatureGateway.class);
+        CaveGatewayMBeanImpl gatewayMBean = new CaveGatewayMBeanImpl();
+        gatewayMBean.setGateway(gatewayService);
+
+        Hashtable<String, Object> gatewayProps = new Hashtable<>();
+        gatewayProps.put("jmx.objectname", "org.apache.karaf.cave:type=gateway,name=" + System.getProperty("karaf.name"));
+        gatewayRegistration = this.bundleContext.registerService(getInterfaceNames(gatewayMBean),
gatewayMBean, gatewayProps);
     }
 
     @Override
     protected void doStop() {
-        if (registration != null) {
-            registration.unregister();
-            registration = null;
+        if (repositoryRegistration != null) {
+            repositoryRegistration.unregister();
+            repositoryRegistration = null;
+        }
+        if (gatewayRegistration != null) {
+            gatewayRegistration.unregister();
+            gatewayRegistration = null;
         }
         super.doStop();
     }
diff --git a/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveGatewayMBeanImpl.java
b/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveGatewayMBeanImpl.java
new file mode 100644
index 0000000..77d7bfc
--- /dev/null
+++ b/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveGatewayMBeanImpl.java
@@ -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.cave.server.management.internal;
+
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
+import org.apache.karaf.cave.server.management.CaveGatewayMBean;
+
+import javax.management.NotCompliantMBeanException;
+import javax.management.StandardMBean;
+import java.util.List;
+
+public class CaveGatewayMBeanImpl extends StandardMBean implements CaveGatewayMBean {
+
+    private CaveFeatureGateway gateway;
+
+    public CaveGatewayMBeanImpl() throws NotCompliantMBeanException {
+        super(CaveGatewayMBean.class);
+    }
+
+    public void setGateway(CaveFeatureGateway gateway) {
+        this.gateway = gateway;
+    }
+
+    @Override
+    public List<String> list() throws Exception {
+        return gateway.list();
+    }
+
+    @Override
+    public void register(String repository) throws Exception {
+
+    }
+
+    @Override
+    public void remove(String repository) throws Exception {
+
+    }
+}
diff --git a/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveRepositoryMBeanImpl.java
b/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveRepositoryMBeanImpl.java
index 39052cf..95f71aa 100644
--- a/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveRepositoryMBeanImpl.java
+++ b/server/management/src/main/java/org/apache/karaf/cave/server/management/internal/CaveRepositoryMBeanImpl.java
@@ -11,7 +11,6 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package org.apache.karaf.cave.server.management.internal;
 
 import java.io.FileInputStream;
diff --git a/server/storage/pom.xml b/server/storage/pom.xml
index cfccfe0..86cfe06 100644
--- a/server/storage/pom.xml
+++ b/server/storage/pom.xml
@@ -83,7 +83,14 @@
                     <instructions>
                         <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
                         <Import-Package>
-                            !org.apache.karaf.features.internal.*,
+                            !org.apache.karaf.features.internal.model,
+                            !org.apache.karaf.features.internal.resolver,
+                            !org.apache.karaf.features.internal.repository,
+                            !org.apache.karaf.features.internal.util,
+                            !org.apache.karaf.util*,
+                            !org.apache.felix.utils*,
+                            !org.apache.felix.resolver,
+                            !org.apache.felix.resolver.util,
                             org.apache.karaf.features;version="[2,5)",
                             *
                         </Import-Package>
@@ -91,9 +98,11 @@
                             org.apache.felix.utils*,
                             org.apache.felix.resolver,
                             org.apache.felix.resolver.util,
+                            org.apache.karaf.features.internal.model,
                             org.apache.karaf.features.internal.resolver,
                             org.apache.karaf.features.internal.repository,
-                            org.apache.karaf.util.tracker*
+                            org.apache.karaf.features.internal.util,
+                            org.apache.karaf.util*
                         </Private-Package>
                     </instructions>
                 </configuration>
diff --git a/server/storage/src/main/java/org/apache/karaf/cave/server/storage/Activator.java
b/server/storage/src/main/java/org/apache/karaf/cave/server/storage/Activator.java
index 379dc8f..43d2e39 100644
--- a/server/storage/src/main/java/org/apache/karaf/cave/server/storage/Activator.java
+++ b/server/storage/src/main/java/org/apache/karaf/cave/server/storage/Activator.java
@@ -18,6 +18,7 @@ package org.apache.karaf.cave.server.storage;
 
 import java.io.File;
 
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
 import org.apache.karaf.cave.server.api.CaveRepositoryService;
 import org.apache.karaf.util.tracker.BaseActivator;
 import org.apache.karaf.util.tracker.annotation.Managed;
@@ -27,7 +28,10 @@ import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.cm.ManagedService;
 
 @Services(
-        provides = { @ProvideService(CaveRepositoryService.class) }
+        provides = {
+                @ProvideService(CaveRepositoryService.class),
+                @ProvideService(CaveFeatureGateway.class)
+        }
 )
 @Managed("org.apache.karaf.cave.server.storage")
 public class Activator extends BaseActivator implements ManagedService {
@@ -39,6 +43,9 @@ public class Activator extends BaseActivator implements ManagedService {
         service.setStorageLocation(new File(getString("cave.storage.location", System.getProperty("karaf.data")
+ File.separator + "cave")));
         service.init();
         register(CaveRepositoryService.class, service);
+
+        CaveFeatureGatewayImpl gateway = new CaveFeatureGatewayImpl();
+        register(CaveFeatureGateway.class, gateway);
     }
 
 }
diff --git a/server/storage/src/main/java/org/apache/karaf/cave/server/storage/CaveFeatureGatewayImpl.java
b/server/storage/src/main/java/org/apache/karaf/cave/server/storage/CaveFeatureGatewayImpl.java
new file mode 100644
index 0000000..0d2bd76
--- /dev/null
+++ b/server/storage/src/main/java/org/apache/karaf/cave/server/storage/CaveFeatureGatewayImpl.java
@@ -0,0 +1,86 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.storage;
+
+import org.apache.karaf.cave.server.api.CaveFeatureGateway;
+import org.apache.karaf.features.internal.model.Features;
+import org.apache.karaf.features.internal.model.JaxbUtil;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.ArrayList;
+import java.util.List;
+
+public class CaveFeatureGatewayImpl implements CaveFeatureGateway {
+
+    @Override
+    public void register(String url) throws Exception {
+        File storage = new File(STORAGE);
+
+        Features features = new Features();
+        if (storage.exists()) {
+            features = JaxbUtil.unmarshal(storage.getAbsolutePath(), true);
+        } else {
+            storage.getParentFile().mkdirs();
+            storage.createNewFile();
+        }
+        features.setName("cave-gateway");
+        if (isFeaturesRepositoryRegistered(url, features.getRepository())) {
+            throw new IllegalArgumentException("Features repository " + url + " already registered
in the gateway");
+        }
+        features.getRepository().add(url);
+        JaxbUtil.marshal(features, new FileOutputStream(storage));
+    }
+
+    @Override
+    public void remove(String url) throws Exception {
+        File storage = new File(STORAGE);
+
+        if (!storage.exists()) {
+            return;
+        }
+
+        Features features = JaxbUtil.unmarshal(storage.getAbsolutePath(), true);
+        if (!isFeaturesRepositoryRegistered(url, features.getRepository())) {
+            throw new IllegalArgumentException("Features repository " + url + " is not registered
in the gateway");
+        }
+        features.getRepository().remove(url);
+        JaxbUtil.marshal(features, new FileOutputStream(storage));
+    }
+
+    @Override
+    public List<String> list() throws Exception {
+        List<String> repositories = new ArrayList<>();
+
+        File storage = new File(STORAGE);
+        if (storage.exists()) {
+            Features features = JaxbUtil.unmarshal(storage.getAbsolutePath(), true);
+            repositories = features.getRepository();
+        }
+
+        return repositories;
+    }
+
+    private boolean isFeaturesRepositoryRegistered(String url, List<String> repositories)
{
+        for (String repository : repositories) {
+            if (repository.equals(url)) {
+                return true;
+            }
+        }
+        return false;
+    }
+}
diff --git a/server/storage/src/test/java/org/apache/karaf/cave/server/storage/CaveFeatureGatewayImplTest.java
b/server/storage/src/test/java/org/apache/karaf/cave/server/storage/CaveFeatureGatewayImplTest.java
new file mode 100644
index 0000000..b6d8c7f
--- /dev/null
+++ b/server/storage/src/test/java/org/apache/karaf/cave/server/storage/CaveFeatureGatewayImplTest.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.server.storage;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+public class CaveFeatureGatewayImplTest {
+
+    private CaveFeatureGatewayImpl gateway;
+
+    @Before
+    public void setup() throws Exception {
+        System.setProperty("karaf.data", "target/test-classes");
+        File file = new File("target/test-classes/cave-features-gateway.xml");
+        if (file.exists()) {
+            file.delete();
+        }
+        gateway = new CaveFeatureGatewayImpl();
+    }
+
+    @Test
+    public void testRegister() throws Exception {
+        gateway.register("mvn:test/test/1.0-SNAPSHOT");
+        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+
+                "<features xmlns=\"http://karaf.apache.org/xmlns/features/v1.4.0\" name=\"cave-gateway\">"
+
+                "    <repository>mvn:test/test/1.0-SNAPSHOT</repository>" +
+                "</features>";
+        String result = readCaveFile();
+        Assert.assertEquals(expected, result);
+    }
+
+    @Test
+    public void testRemove() throws Exception {
+        gateway.register("mvn:test/second/1.0-SNAPSHOT");
+        String expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+
+                "<features xmlns=\"http://karaf.apache.org/xmlns/features/v1.4.0\" name=\"cave-gateway\">"
+
+                "    <repository>mvn:test/second/1.0-SNAPSHOT</repository>" +
+                "</features>";
+        String result = readCaveFile();
+        Assert.assertEquals(expected, result);
+        gateway.remove("mvn:test/second/1.0-SNAPSHOT");
+        expected = "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>"
+
+                "<features xmlns=\"http://karaf.apache.org/xmlns/features/v1.4.0\" name=\"cave-gateway\"/>";
+        result = readCaveFile();
+        Assert.assertEquals(expected, result);
+    }
+
+    private String readCaveFile() throws Exception {
+        File file = new File("target/test-classes/cave-features-gateway.xml");
+        StringBuilder builder = new StringBuilder();
+        BufferedReader reader = new BufferedReader(new FileReader(file));
+        String line;
+        while ((line = reader.readLine()) != null) {
+            builder.append(line);
+        }
+        return builder.toString();
+    }
+
+}

-- 
To stop receiving notification emails like this one, please contact
['"commits@karaf.apache.org" <commits@karaf.apache.org>'].

Mime
View raw message