You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by jb...@apache.org on 2017/12/21 08:10:55 UTC
[karaf-cave] 02/02: [KARAF-5108] Add Deployer MBean
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
commit 92789311c77423da741b429eacab718c28eb5b09
Author: Jean-Baptiste Onofré <jb...@apache.org>
AuthorDate: Wed Dec 20 13:57:18 2017 +0100
[KARAF-5108] Add Deployer MBean
---
assembly/src/main/resources/features.xml | 14 +-
deployer/management/pom.xml | 77 ++++++
.../deployer/management/CaveDeployerMBean.java | 67 +++++
.../deployer/management/internal/Activator.java | 53 ++++
.../management/internal/CaveDeployerMBeanImpl.java | 283 +++++++++++++++++++++
deployer/pom.xml | 1 +
.../cave/server/management/internal/Activator.java | 21 +-
7 files changed, 504 insertions(+), 12 deletions(-)
diff --git a/assembly/src/main/resources/features.xml b/assembly/src/main/resources/features.xml
index 82e5529..40a8d87 100644
--- a/assembly/src/main/resources/features.xml
+++ b/assembly/src/main/resources/features.xml
@@ -69,6 +69,7 @@
<feature name="cave-deployer" version="${project.version}">
<feature version="${project.version}">cave-deployer-rest</feature>
<feature version="${project.version}">cave-deployer-command</feature>
+ <feature version="${project.version}">cave-deployer-management</feature>
</feature>
<feature name="cave-deployer-service" version="${project.version}">
@@ -93,7 +94,18 @@
<feature name="cave-deployer-command" version="${project.version}">
<feature version="${project.version}">cave-deployer-service</feature>
- <bundle>mvn:org.apache.karaf.cave.deployer/org.apache.karaf.cave.deployer.command/${project.version}</bundle>
+ <conditional>
+ <condition>shell</condition>
+ <bundle>mvn:org.apache.karaf.cave.deployer/org.apache.karaf.cave.deployer.command/${project.version}</bundle>
+ </conditional>
+ </feature>
+
+ <feature name="cave-deployer-management" version="${project.version}">
+ <feature version="${project.version}">cave-deployer-service</feature>
+ <conditional>
+ <condition>management</condition>
+ <bundle>mvn:org.apache.karaf.cave.deployer/org.apache.karaf.cave.deployer.management/${project.version}</bundle>
+ </conditional>
</feature>
</features>
\ No newline at end of file
diff --git a/deployer/management/pom.xml b/deployer/management/pom.xml
new file mode 100644
index 0000000..1e11e91
--- /dev/null
+++ b/deployer/management/pom.xml
@@ -0,0 +1,77 @@
+<?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.karaf.cave</groupId>
+ <artifactId>org.apache.karaf.cave.deployer</artifactId>
+ <version>4.1.0-SNAPSHOT</version>
+ <relativePath>../pom.xml</relativePath>
+ </parent>
+
+ <groupId>org.apache.karaf.cave.deployer</groupId>
+ <artifactId>org.apache.karaf.cave.deployer.management</artifactId>
+ <packaging>bundle</packaging>
+ <name>Apache Karaf :: Cave :: Deployer :: Management</name>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.karaf.cave.deployer</groupId>
+ <artifactId>org.apache.karaf.cave.deployer.api</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.karaf</groupId>
+ <artifactId>org.apache.karaf.util</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.core</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.karaf.tooling</groupId>
+ <artifactId>karaf-services-maven-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <configuration>
+ <instructions>
+ <Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
+ <Export-Package>
+ org.apache.karaf.cave.deployer.management
+ </Export-Package>
+ <Private-Package>
+ org.apache.karaf.cave.server.deployer.internal,
+ org.apache.karaf.util.tracker*
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
\ No newline at end of file
diff --git a/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/CaveDeployerMBean.java b/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/CaveDeployerMBean.java
new file mode 100644
index 0000000..cc573ff
--- /dev/null
+++ b/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/CaveDeployerMBean.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.karaf.cave.deployer.management;
+
+import javax.management.openmbean.TabularData;
+import java.util.List;
+import java.util.Map;
+
+public interface CaveDeployerMBean {
+
+ void registerConnection(String name, String jmxUrl, String karafName, String user, String password) throws Exception;
+ void deleteConnection(String name) throws Exception;
+ TabularData getConnections() throws Exception;
+
+ void explode(String url, String repository) throws Exception;
+ void extract(String url, String directory) throws Exception;
+ void download(String url, String directory) throws Exception;
+ void upload(String groupId, String artifactId, String version, String artifactUrl, String repositoryUrl) throws Exception;
+
+ void assembleFeature(String groupId, String artifactId, String version, String repositoryUrl, String feature,
+ List<String> repositories, List<String> features, List<String> bundles) throws Exception;
+
+ void installBundle(String url, String connection) throws Exception;
+ void uninstallBundle(String id, String connection) throws Exception;
+ void startBundle(String id, String connection) throws Exception;
+ void stopBundle(String id, String connection) throws Exception;
+ TabularData getBundles(String connection) throws Exception;
+
+ void installKar(String url, String connection) throws Exception;
+ void uninstallKar(String id, String connection) throws Exception;
+ List<String> getKars(String connection) throws Exception;
+
+ void addFeatureRepository(String url, String connection) throws Exception;
+ void removeFeatureRepository(String repository, String connection) throws Exception;
+ TabularData getFeatureRepositories(String connection) throws Exception;
+
+ void installFeature(String feature, String connection) throws Exception;
+ void uninstallFeature(String feature, String connection) throws Exception;
+ TabularData getFeatures(String connection) throws Exception;
+
+ void createConfig(String pid, String connection) throws Exception;
+ Map<String, String> getConfigProperties(String pid, String connection) throws Exception;
+ void deleteConfig(String pid, String connection) throws Exception;
+ void appendConfigProperty(String pid, String key, String value, String connection) throws Exception;
+ void setConfigProperty(String pid, String key, String value, String connection) throws Exception;
+ String getConfigProperty(String pid, String key, String connection) throws Exception;
+ void deleteConfigProperty(String pid, String key, String connection) throws Exception;
+
+ List<String> getClusterNodes(String connection) throws Exception;
+ Map<String, List<String>> getClusterGroups(String connection) throws Exception;
+ void clusterFeatureRepositoryAdd(String url, String clusterGroup, String connection) throws Exception;
+ void clusterFeatureRepositoryRemove(String url, String clusterGroup, String connection) throws Exception;
+ void clusterFeatureInstall(String feature, String clusterGroup, String connection) throws Exception;
+ void clusterFeatureUninstall(String feature, String clusterGroup, String connection) throws Exception;
+
+}
diff --git a/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/internal/Activator.java b/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/internal/Activator.java
new file mode 100644
index 0000000..4daf8a0
--- /dev/null
+++ b/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/internal/Activator.java
@@ -0,0 +1,53 @@
+/*
+ * 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.deployer.management.internal;
+
+import org.apache.karaf.cave.deployer.api.Deployer;
+import org.apache.karaf.util.tracker.BaseActivator;
+import org.apache.karaf.util.tracker.annotation.RequireService;
+import org.apache.karaf.util.tracker.annotation.Services;
+import org.osgi.framework.ServiceRegistration;
+
+import java.util.Hashtable;
+
+@Services(
+ requires = {
+ @RequireService(Deployer.class)
+ }
+)
+public class Activator extends BaseActivator {
+
+ private volatile ServiceRegistration mbeanRegistration;
+
+ @Override
+ protected void doStart() throws Exception {
+ Deployer deployer = getTrackedService(Deployer.class);
+ CaveDeployerMBeanImpl mbean = new CaveDeployerMBeanImpl();
+ mbean.setDeployer(deployer);
+
+ Hashtable<String, Object> props = new Hashtable<>();
+ props.put("jmx.objectname", "org.apache.karaf.cave:type=deployer,name=" + System.getProperty("karaf.name"));
+ mbeanRegistration = this.bundleContext.registerService(getInterfaceNames(mbean), mbean, props);
+ }
+
+ @Override
+ protected void doStop() {
+ if (mbeanRegistration != null) {
+ mbeanRegistration.unregister();
+ mbeanRegistration = null;
+ }
+ super.doStop();
+ }
+
+}
diff --git a/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/internal/CaveDeployerMBeanImpl.java b/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/internal/CaveDeployerMBeanImpl.java
new file mode 100644
index 0000000..2fa006b
--- /dev/null
+++ b/deployer/management/src/main/java/org/apache/karaf/cave/deployer/management/internal/CaveDeployerMBeanImpl.java
@@ -0,0 +1,283 @@
+/*
+ * 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.deployer.management.internal;
+
+import org.apache.karaf.cave.deployer.api.*;
+import org.apache.karaf.cave.deployer.management.CaveDeployerMBean;
+
+import javax.management.NotCompliantMBeanException;
+import javax.management.StandardMBean;
+import javax.management.openmbean.*;
+import java.util.List;
+import java.util.Map;
+
+public class CaveDeployerMBeanImpl extends StandardMBean implements CaveDeployerMBean {
+
+ private Deployer deployer;
+
+ public CaveDeployerMBeanImpl() throws NotCompliantMBeanException {
+ super(CaveDeployerMBean.class);
+ }
+
+ public Deployer getDeployer() {
+ return deployer;
+ }
+
+ public void setDeployer(Deployer deployer) {
+ this.deployer = deployer;
+ }
+
+
+ @Override
+ public void registerConnection(String name, String jmxUrl, String karafName, String user, String password) throws Exception {
+ Connection connection = new Connection();
+ connection.setName(name);
+ connection.setJmxUrl(jmxUrl);
+ connection.setKarafName(karafName);
+ connection.setUser(user);
+ connection.setPassword(password);
+ deployer.registerConnection(connection);
+ }
+
+ @Override
+ public void deleteConnection(String name) throws Exception {
+ deployer.deleteConnection(name);
+ }
+
+ @Override
+ public TabularData getConnections() throws Exception {
+ List<Connection> connections = deployer.connections();
+
+ CompositeType connectionType = new CompositeType("Connection", "Connection to a Karaf instance",
+ new String[]{"Name", "JMX URL", "Karaf Name", "User", "Password"},
+ new String[]{"Name of the connection", "JMX URL of the Karaf instance", "Karaf instance name", "Username to connect", "Password of the user" },
+ new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.STRING});
+ TabularType tabularType = new TabularType("Connections", "Table of all Cave Deployer connections", connectionType, new String[]{"Name"});
+ TabularData table = new TabularDataSupport(tabularType);
+ for (Connection connection : connections) {
+ CompositeData data = new CompositeDataSupport(connectionType,
+ new String[]{"Name", "JMX URL", "Karaf Name", "User", "Password"},
+ new Object[]{connection.getName(), connection.getJmxUrl(), connection.getKarafName(), connection.getUser(), connection.getPassword()});
+ table.put(data);
+ }
+ return table;
+ }
+
+ @Override
+ public void explode(String url, String repository) throws Exception {
+ deployer.explode(url, repository);
+ }
+
+ @Override
+ public void extract(String url, String directory) throws Exception {
+ deployer.extract(url, directory);
+ }
+
+ @Override
+ public void download(String url, String directory) throws Exception {
+ deployer.download(url, directory);
+ }
+
+ @Override
+ public void upload(String groupId, String artifactId, String version, String artifactUrl, String repositoryUrl) throws Exception {
+ deployer.upload(groupId, artifactId, version, artifactUrl, repositoryUrl);
+ }
+
+ @Override
+ public void assembleFeature(String groupId, String artifactId, String version, String repositoryUrl, String feature, List<String> repositories, List<String> features, List<String> bundles) throws Exception {
+ deployer.assembleFeature(groupId, artifactId, version, repositoryUrl, feature, repositories, features, bundles, null);
+ }
+
+ @Override
+ public void installBundle(String url, String connection) throws Exception {
+ deployer.installBundle(url, connection);
+ }
+
+ @Override
+ public void uninstallBundle(String id, String connection) throws Exception {
+ deployer.uninstallBundle(id, connection);
+ }
+
+ @Override
+ public void startBundle(String id, String connection) throws Exception {
+ deployer.startBundle(id, connection);
+ }
+
+ @Override
+ public void stopBundle(String id, String connection) throws Exception {
+ deployer.stopBundle(id, connection);
+ }
+
+ @Override
+ public TabularData getBundles(String connection) throws Exception {
+ CompositeType bundleType = new CompositeType("Bundle", "A bundle on the remote instance",
+ new String[]{"ID", "Name", "Version", "Start Level", "State"},
+ new String[]{"Bundle ID", "Bundle Name", "Bundle Version", "Bundle Start Level", "Bundle State"},
+ new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.STRING, SimpleType.INTEGER, SimpleType.STRING});
+ TabularType tableType = new TabularType("Bundles", "Table of bundles", bundleType, new String[]{"ID"});
+ TabularData table = new TabularDataSupport(tableType);
+
+ List<Bundle> bundles = deployer.bundles(connection);
+
+ for (Bundle bundle : bundles) {
+ CompositeData data = new CompositeDataSupport(bundleType,
+ new String[]{"ID", "Name", "Version", "Start Level", "State"},
+ new Object[]{bundle.getId(), bundle.getName(), bundle.getVersion(), bundle.getStartLevel(), bundle.getState()});
+ table.put(data);
+ }
+
+ return table;
+ }
+
+ @Override
+ public void installKar(String url, String connection) throws Exception {
+ deployer.installKar(url, connection);
+ }
+
+ @Override
+ public void uninstallKar(String id, String connection) throws Exception {
+ deployer.uninstallKar(id, connection);
+ }
+
+ @Override
+ public List<String> getKars(String connection) throws Exception {
+ return deployer.kars(connection);
+ }
+
+ @Override
+ public void addFeatureRepository(String url, String connection) throws Exception {
+ deployer.addFeaturesRepository(url, connection);
+ }
+
+ @Override
+ public void removeFeatureRepository(String repository, String connection) throws Exception {
+ deployer.removeFeaturesRepository(repository, connection);
+ }
+
+ @Override
+ public TabularData getFeatureRepositories(String connection) throws Exception {
+ List<FeaturesRepository> repositories = deployer.featuresRepositories(connection);
+
+ CompositeType repositoryType = new CompositeType("Features Repository", "Features Repository",
+ new String[]{"Name", "URL"},
+ new String[]{"The features repository name", "The location of the features repository"},
+ new OpenType[]{SimpleType.STRING, SimpleType.STRING});
+ TabularType tableType = new TabularType("Features Repositories", "Table of features repositories", repositoryType, new String[]{"Name"});
+ TabularData table = new TabularDataSupport(tableType);
+
+ for (FeaturesRepository repository : repositories) {
+ CompositeData data = new CompositeDataSupport(repositoryType,
+ new String[]{"Name", "URL"},
+ new Object[]{repository.getName(), repository.getUri()});
+ table.put(data);
+ }
+ return table;
+ }
+
+ @Override
+ public void installFeature(String feature, String connection) throws Exception {
+ deployer.installFeature(feature, connection);
+ }
+
+ @Override
+ public void uninstallFeature(String feature, String connection) throws Exception {
+ deployer.uninstallFeature(feature, connection);
+ }
+
+ @Override
+ public TabularData getFeatures(String connection) throws Exception {
+ List<Feature> features = deployer.features(connection);
+
+ CompositeType featureType = new CompositeType("Feature", "Feature",
+ new String[]{"Name", "Version", "State"},
+ new String[]{"Name of the feature", "Version of the feature", "State of the feature"},
+ new OpenType[]{SimpleType.STRING, SimpleType.STRING, SimpleType.STRING});
+ TabularType tableType = new TabularType("Features", "Table of features",
+ featureType, new String[]{"Name", "Version"});
+ TabularData table = new TabularDataSupport(tableType);
+ for (Feature feature : features) {
+ CompositeData data = new CompositeDataSupport(featureType,
+ new String[]{"Name", "Version", "State"},
+ new Object[]{feature.getName(), feature.getVersion(), feature.getState()});
+ table.put(data);
+ }
+
+ return table;
+ }
+
+ @Override
+ public void createConfig(String pid, String connection) throws Exception {
+ deployer.createConfig(pid, connection);
+ }
+
+ @Override
+ public Map<String, String> getConfigProperties(String pid, String connection) throws Exception {
+ return deployer.configProperties(pid, connection);
+ }
+
+ @Override
+ public void deleteConfig(String pid, String connection) throws Exception {
+ deployer.deleteConfig(pid, connection);
+ }
+
+ @Override
+ public void appendConfigProperty(String pid, String key, String value, String connection) throws Exception {
+ deployer.appendConfigProperty(pid, key, value, connection);
+ }
+
+ @Override
+ public void setConfigProperty(String pid, String key, String value, String connection) throws Exception {
+ deployer.setConfigProperty(pid, key, value, connection);
+ }
+
+ @Override
+ public String getConfigProperty(String pid, String key, String connection) throws Exception {
+ return deployer.configProperty(pid, key, connection);
+ }
+
+ @Override
+ public void deleteConfigProperty(String pid, String key, String connection) throws Exception {
+ deployer.deleteConfigProperty(pid, key, connection);
+ }
+
+ @Override
+ public List<String> getClusterNodes(String connection) throws Exception {
+ return deployer.clusterNodes(connection);
+ }
+
+ @Override
+ public Map<String, List<String>> getClusterGroups(String connection) throws Exception {
+ return deployer.clusterGroups(connection);
+ }
+
+ @Override
+ public void clusterFeatureRepositoryAdd(String url, String clusterGroup, String connection) throws Exception {
+ deployer.clusterAddFeaturesRepository(url, clusterGroup, connection);
+ }
+
+ @Override
+ public void clusterFeatureRepositoryRemove(String url, String clusterGroup, String connection) throws Exception {
+ deployer.clusterRemoveFeaturesRepository(url, clusterGroup, connection);
+ }
+
+ @Override
+ public void clusterFeatureInstall(String feature, String clusterGroup, String connection) throws Exception {
+ deployer.clusterFeatureInstall(feature, clusterGroup, connection);
+ }
+
+ @Override
+ public void clusterFeatureUninstall(String feature, String clusterGroup, String connection) throws Exception {
+ deployer.clusterFeatureUninstall(feature, clusterGroup, connection);
+ }
+}
diff --git a/deployer/pom.xml b/deployer/pom.xml
index 9663f47..976cc09 100644
--- a/deployer/pom.xml
+++ b/deployer/pom.xml
@@ -37,6 +37,7 @@
<module>api</module>
<module>service</module>
<module>command</module>
+ <module>management</module>
<module>rest</module>
</modules>
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 7579caa..092b2f5 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
@@ -1,14 +1,3 @@
-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;
-import org.apache.karaf.util.tracker.annotation.Services;
-import org.osgi.framework.ServiceRegistration;
-
/*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -22,6 +11,16 @@ import org.osgi.framework.ServiceRegistration;
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+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;
+import org.apache.karaf.util.tracker.annotation.Services;
+import org.osgi.framework.ServiceRegistration;
@Services(
requires = {
--
To stop receiving notification emails like this one, please contact
"commits@karaf.apache.org" <co...@karaf.apache.org>.