You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:42:25 UTC
[sling-org-apache-sling-installer-factory-configuration] 01/11:
SLING-1999 : Split Installer Core and Configuration Support
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.installer.factory.configuration-1.0.0
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-factory-configuration.git
commit fc46c463f23d86b17170700789115c95150d0a19
Author: Carsten Ziegeler <cz...@apache.org>
AuthorDate: Tue Mar 1 09:48:27 2011 +0000
SLING-1999 : Split Installer Core and Configuration Support
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/installer/factories/configuration@1075751 13f79535-47bb-0310-9956-ffa450edef68
---
pom.xml | 83 ++++++++++
.../configuration/impl/AbstractConfigTask.java | 100 +++++++++++
.../factories/configuration/impl/Activator.java | 48 ++++++
.../configuration/impl/ConfigInstallTask.java | 81 +++++++++
.../configuration/impl/ConfigRemoveTask.java | 72 ++++++++
.../configuration/impl/ConfigTaskCreator.java | 182 +++++++++++++++++++++
.../factories/configuration/impl/ConfigUtil.java | 128 +++++++++++++++
.../configuration/impl/ServicesListener.java | 174 ++++++++++++++++++++
8 files changed, 868 insertions(+)
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..17a3d65
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,83 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>10</version>
+ <relativePath>../../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.sling.installer.factory.configuration</artifactId>
+ <version>0.9.0-SNAPSHOT</version>
+ <packaging>bundle</packaging>
+
+ <name>Apache Sling Configuration Admin Installer</name>
+ <description>
+ Provides support for configurations to the Apache Sling OSGi installer
+ </description>
+
+ <scm>
+ <connection>scm:svn:http://svn.apache.org/repos/asf/sling/trunk/installer/factories/configuration</connection>
+ <developerConnection> scm:svn:https://svn.apache.org/repos/asf/sling/trunk/installer/factories/configuration</developerConnection>
+ <url>http://svn.apache.org/viewvc/sling/trunk/installer/factories/configuration/</url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Activator>
+ org.apache.sling.installer.factories.configuration.impl.Activator
+ </Bundle-Activator>
+ <Private-Package>
+ org.apache.sling.installer.factories.configuration.impl.*
+ </Private-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-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.sling</groupId>
+ <artifactId>org.apache.sling.installer.core</artifactId>
+ <version>3.1.3-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ </dependencies>
+</project>
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/AbstractConfigTask.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/AbstractConfigTask.java
new file mode 100644
index 0000000..011e193
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/AbstractConfigTask.java
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.installer.factories.configuration.impl;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for configuration-related tasks
+ */
+abstract class AbstractConfigTask extends InstallTask {
+
+ /** Configuration PID */
+ protected final String configPid;
+
+ /** Factory PID or null */
+ protected final String factoryPid;
+
+ /** Configuration admin. */
+ private final ConfigurationAdmin configAdmin;
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ AbstractConfigTask(final TaskResourceGroup r, final ConfigurationAdmin configAdmin) {
+ super(r);
+ this.configAdmin = configAdmin;
+ this.configPid = (String)getResource().getAttribute(Constants.SERVICE_PID);
+ this.factoryPid = (String)getResource().getAttribute(ConfigurationAdmin.SERVICE_FACTORYPID);
+ }
+
+ protected Logger getLogger() {
+ return this.logger;
+ }
+
+ /**
+ * Get the configuration admin - if available
+ */
+ protected ConfigurationAdmin getConfigurationAdmin() {
+ return this.configAdmin;
+ }
+
+ protected String getCompositePid() {
+ return (factoryPid == null ? "" : factoryPid + ".") + configPid;
+ }
+
+ protected Dictionary<String, Object> getDictionary() {
+ // Copy dictionary and add pseudo-properties
+ final Dictionary<String, Object> d = this.getResource().getDictionary();
+ if ( d == null ) {
+ return null;
+ }
+
+ final Dictionary<String, Object> result = new Hashtable<String, Object>();
+ final Enumeration<String> e = d.keys();
+ while(e.hasMoreElements()) {
+ final String key = e.nextElement();
+ result.put(key, d.get(key));
+ }
+
+ result.put(ConfigTaskCreator.CONFIG_PATH_KEY, getResource().getURL());
+ if ( this.factoryPid != null ) {
+ result.put(ConfigTaskCreator.ALIAS_KEY, configPid);
+ }
+
+ return result;
+ }
+
+ protected Configuration getConfiguration(final ConfigurationAdmin ca,
+ final boolean createIfNeeded)
+ throws IOException, InvalidSyntaxException {
+ return ConfigUtil.getConfiguration(ca, this.factoryPid, this.configPid, createIfNeeded, true);
+ }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/Activator.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/Activator.java
new file mode 100644
index 0000000..ac16697
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/Activator.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.sling.installer.factories.configuration.impl;
+
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator registers the configuration support service.
+ */
+public class Activator implements BundleActivator {
+
+ /** Services listener. */
+ private ServicesListener listener;
+
+ /**
+ * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext)
+ */
+ public void start(final BundleContext context) throws Exception {
+ this.listener = new ServicesListener(context);
+ }
+
+ /**
+ * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(final BundleContext context) {
+ if ( this.listener != null ) {
+ this.listener.deactivate();
+ this.listener = null;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java
new file mode 100644
index 0000000..bc9308e
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigInstallTask.java
@@ -0,0 +1,81 @@
+/*
+ * 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.sling.installer.factories.configuration.impl;
+
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Task to install a configuration
+ */
+public class ConfigInstallTask extends AbstractConfigTask {
+
+ private static final String CONFIG_INSTALL_ORDER = "20-";
+
+ public ConfigInstallTask(final TaskResourceGroup r, final ConfigurationAdmin configAdmin) {
+ super(r, configAdmin);
+ }
+
+ @Override
+ public String getSortKey() {
+ return CONFIG_INSTALL_ORDER + getCompositePid();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public void execute(final InstallationContext ctx) {
+ final ConfigurationAdmin ca = this.getConfigurationAdmin();
+
+ // Get or create configuration, but do not
+ // update if the new one has the same values.
+ boolean created = false;
+ try {
+ Configuration config = getConfiguration(ca, false);
+ if (config == null) {
+ created = true;
+ config = getConfiguration(ca, true);
+ } else {
+ if (ConfigUtil.isSameData(config.getProperties(), getResource().getDictionary())) {
+ this.getLogger().debug("Configuration {} already installed with same data, update request ignored: {}",
+ config.getPid(), getResource());
+ config = null;
+ }
+ }
+
+ if (config != null) {
+ if (config.getBundleLocation() != null) {
+ config.setBundleLocation(null);
+ }
+ config.update(getDictionary());
+ ctx.log("Installed configuration {} from resource {}", config.getPid(), getResource());
+ this.setFinishedState(ResourceState.INSTALLED);
+ this.getLogger().debug("Configuration " + config.getPid()
+ + " " + (created ? "created" : "updated")
+ + " from " + getResource());
+ } else {
+ this.setFinishedState(ResourceState.IGNORED);
+ }
+ } catch (Exception e) {
+ this.getLogger().debug("Exception during installation of config " + this.getResource() + " : " + e.getMessage() + ". Retrying later.", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
new file mode 100644
index 0000000..78050b4
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigRemoveTask.java
@@ -0,0 +1,72 @@
+/*
+ * 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.sling.installer.factories.configuration.impl;
+
+import org.apache.sling.installer.api.tasks.InstallationContext;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/** Remove a Configuration */
+public class ConfigRemoveTask extends AbstractConfigTask {
+
+ private static final String CONFIG_REMOVE_ORDER = "10-";
+
+ public ConfigRemoveTask(final TaskResourceGroup r,
+ final ConfigurationAdmin configAdmin) {
+ super(r, configAdmin);
+ }
+
+ @Override
+ public String getSortKey() {
+ return CONFIG_REMOVE_ORDER + getCompositePid();
+ }
+
+ /**
+ * @see org.apache.sling.installer.api.tasks.InstallTask#execute(org.apache.sling.installer.api.tasks.InstallationContext)
+ */
+ @SuppressWarnings("unchecked")
+ public void execute(final InstallationContext ctx) {
+ final ConfigurationAdmin ca = this.getConfigurationAdmin();
+
+ try {
+ final Configuration cfg = getConfiguration(ca, false);
+ if (cfg == null) {
+ this.getLogger().debug("Cannot delete config , pid={} not found, ignored ({})", getCompositePid(), getResource());
+ this.setFinishedState(ResourceState.IGNORED);
+ } else {
+ if ( cfg.getProperties().get(ConfigTaskCreator.CONFIG_PATH_KEY) == null ) {
+ this.getLogger().debug("Configuration has not been installed by this resource. Not removing!");
+ this.setFinishedState(ResourceState.IGNORED);
+ } else if ( !ConfigUtil.isSameData(cfg.getProperties(), this.getResource().getDictionary()) ) {
+ this.getLogger().debug("Configuration has changed after it has been installed. Not removing!");
+ this.setFinishedState(ResourceState.IGNORED);
+ } else {
+ this.getLogger().debug("Deleting config {} ({})", getCompositePid(), getResource());
+ cfg.delete();
+ ctx.log("Deleted configuration {} from resource {}", getCompositePid(), getResource());
+ this.setFinishedState(ResourceState.UNINSTALLED);
+ }
+ }
+ } catch (Exception e) {
+ this.getLogger().debug("Exception during removal of config " + this.getResource() + " : " + e.getMessage() + ". Retrying later.", e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
new file mode 100644
index 0000000..535b5f8
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigTaskCreator.java
@@ -0,0 +1,182 @@
+/*
+ * 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.sling.installer.factories.configuration.impl;
+
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.sling.installer.api.InstallableResource;
+import org.apache.sling.installer.api.ResourceChangeListener;
+import org.apache.sling.installer.api.tasks.InstallTask;
+import org.apache.sling.installer.api.tasks.InstallTaskFactory;
+import org.apache.sling.installer.api.tasks.RegisteredResource;
+import org.apache.sling.installer.api.tasks.ResourceState;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.apache.sling.installer.api.tasks.TaskResource;
+import org.apache.sling.installer.api.tasks.TaskResourceGroup;
+import org.apache.sling.installer.api.tasks.TransformationResult;
+import org.osgi.framework.Constants;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationEvent;
+import org.osgi.service.cm.ConfigurationListener;
+
+/**
+ * Task creator for configurations.
+ */
+public class ConfigTaskCreator
+ implements InstallTaskFactory, ConfigurationListener, ResourceTransformer {
+
+ public static final String ALIAS_KEY = "org.apache.sling.installer.osgi.factoryaliaspid";
+ public static final String CONFIG_PATH_KEY = "org.apache.sling.installer.osgi.path";
+
+ /** Configuration admin. */
+ private ConfigurationAdmin configAdmin;
+
+ /** Resource change listener. */
+ private ResourceChangeListener changeListener;
+
+ public ConfigTaskCreator(final ResourceChangeListener listener, final ConfigurationAdmin configAdmin) {
+ this.changeListener = listener;
+ this.configAdmin = configAdmin;
+ }
+
+ /**
+ * Create a task to install or uninstall a configuration.
+ *
+ * @see org.apache.sling.installer.api.tasks.InstallTaskFactory#createTask(org.apache.sling.installer.api.tasks.TaskResourceGroup)
+ */
+ public InstallTask createTask(final TaskResourceGroup group) {
+ final TaskResource toActivate = group.getActiveResource();
+ if ( !toActivate.getType().equals(InstallableResource.TYPE_CONFIG) ) {
+ return null;
+ }
+
+ final InstallTask result;
+ if (toActivate.getState() == ResourceState.UNINSTALL) {
+ result = new ConfigRemoveTask(group, this.configAdmin);
+ } else {
+ result = new ConfigInstallTask(group, this.configAdmin);
+ }
+ return result;
+ }
+
+ /**
+ * @see org.osgi.service.cm.ConfigurationListener#configurationEvent(org.osgi.service.cm.ConfigurationEvent)
+ */
+ @SuppressWarnings("unchecked")
+ public void configurationEvent(final ConfigurationEvent event) {
+ final String id = (event.getFactoryPid() == null ? "" : event.getFactoryPid() + ".") + event.getPid();
+ if ( event.getType() == ConfigurationEvent.CM_DELETED ) {
+ this.changeListener.resourceRemoved(InstallableResource.TYPE_CONFIG, id);
+ } else {
+ try {
+ final Configuration config = ConfigUtil.getConfiguration(configAdmin,
+ event.getFactoryPid(),
+ event.getPid(),
+ false, false);
+ if ( config != null ) {
+ final Dictionary<String, Object> dict = ConfigUtil.cleanConfiguration(config.getProperties());
+ this.changeListener.resourceAddedOrUpdated(InstallableResource.TYPE_CONFIG, id, null, dict);
+ }
+ } catch ( final Exception ignore) {
+ // ignore for now (TODO)
+ }
+ }
+ }
+
+ /**
+ * @see org.apache.sling.installer.api.tasks.ResourceTransformer#transform(org.apache.sling.installer.api.tasks.RegisteredResource)
+ */
+ public TransformationResult[] transform(final RegisteredResource resource) {
+ if ( resource.getType().equals(InstallableResource.TYPE_PROPERTIES) ) {
+ return checkConfiguration(resource);
+ }
+ return null;
+ }
+
+ /**
+ * Check if the registered resource is a configuration
+ * @param resource The resource
+ */
+ private TransformationResult[] checkConfiguration(final RegisteredResource resource) {
+ final String url = resource.getURL();
+ String lastIdPart = url;
+ final int pos = lastIdPart.lastIndexOf('/');
+ if ( pos != -1 ) {
+ lastIdPart = lastIdPart.substring(pos + 1);
+ }
+
+ final String pid;
+ // remove extension if known
+ if ( isConfigExtension(getExtension(lastIdPart)) ) {
+ final int lastDot = lastIdPart.lastIndexOf('.');
+ pid = lastIdPart.substring(0, lastDot);
+ } else {
+ pid = lastIdPart;
+ }
+
+ // split pid and factory pid alias
+ final String factoryPid;
+ final String configPid;
+ int n = pid.indexOf('-');
+ if (n > 0) {
+ configPid = pid.substring(n + 1);
+ factoryPid = pid.substring(0, n);
+ } else {
+ factoryPid = null;
+ configPid = pid;
+ }
+
+ final Map<String, Object> attr = new HashMap<String, Object>();
+
+ attr.put(Constants.SERVICE_PID, configPid);
+ // Factory?
+ if (factoryPid != null) {
+ attr.put(ConfigurationAdmin.SERVICE_FACTORYPID, factoryPid);
+ }
+
+ final TransformationResult tr = new TransformationResult();
+ final String id = (factoryPid == null ? "" : factoryPid + ".") + configPid;
+ tr.setId(id);
+ tr.setResourceType(InstallableResource.TYPE_CONFIG);
+ tr.setAttributes(attr);
+
+ return new TransformationResult[] {tr};
+ }
+
+ /**
+ * Compute the extension
+ */
+ private static String getExtension(String url) {
+ final int pos = url.lastIndexOf('.');
+ return (pos < 0 ? "" : url.substring(pos+1));
+ }
+
+ private static boolean isConfigExtension(String extension) {
+ if ( extension.equals("cfg")
+ || extension.equals("config")
+ || extension.equals("xml")
+ || extension.equals("properties")) {
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java
new file mode 100644
index 0000000..321bdd9
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ConfigUtil.java
@@ -0,0 +1,128 @@
+/*
+ * 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.sling.installer.factories.configuration.impl;
+
+import java.io.IOException;
+import java.util.Dictionary;
+import java.util.Enumeration;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Set;
+
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.service.cm.Configuration;
+import org.osgi.service.cm.ConfigurationAdmin;
+
+/**
+ * Utilities for configuration handling
+ */
+abstract class ConfigUtil {
+
+ /** Configuration properties to ignore when comparing configs */
+ private static final Set<String> IGNORED_PROPERTIES = new HashSet<String>();
+ static {
+ IGNORED_PROPERTIES.add(Constants.SERVICE_PID);
+ IGNORED_PROPERTIES.add(ConfigTaskCreator.CONFIG_PATH_KEY);
+ IGNORED_PROPERTIES.add(ConfigTaskCreator.ALIAS_KEY);
+ }
+
+ private static Set<String> collectKeys(final Dictionary<String, Object>a) {
+ final Set<String> keys = new HashSet<String>();
+ final Enumeration<String> aI = a.keys();
+ while (aI.hasMoreElements() ) {
+ final String key = aI.nextElement();
+ if ( !IGNORED_PROPERTIES.contains(key) ) {
+ keys.add(key);
+ }
+ }
+ return keys;
+ }
+
+ /** True if a and b represent the same config data, ignoring "non-configuration" keys in the dictionaries */
+ public static boolean isSameData(Dictionary<String, Object>a, Dictionary<String, Object>b) {
+ boolean result = false;
+ if (a != null && b != null) {
+ final Set<String> keysA = collectKeys(a);
+ final Set<String> keysB = collectKeys(b);
+ if ( keysA.size() == keysB.size() && keysA.containsAll(keysB) ) {
+ for(final String key : keysA ) {
+ if ( !a.get(key).equals(b.get(key)) ) {
+ return result;
+ }
+ }
+ result = true;
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Remove all ignored properties
+ */
+ public static Dictionary<String, Object> cleanConfiguration(final Dictionary<String, Object> config) {
+ final Dictionary<String, Object> cleanedConfig = new Hashtable<String, Object>();
+ final Enumeration<String> e = config.keys();
+ while(e.hasMoreElements()) {
+ final String key = e.nextElement();
+ if ( !IGNORED_PROPERTIES.contains(key) ) {
+ cleanedConfig.put(key, config.get(key));
+ }
+ }
+
+ return cleanedConfig;
+ }
+
+ public static Configuration getConfiguration(final ConfigurationAdmin ca,
+ final String factoryPid,
+ final String configPid,
+ final boolean createIfNeeded,
+ final boolean useAliasForFactory)
+ throws IOException, InvalidSyntaxException {
+ Configuration result = null;
+
+ if (factoryPid == null) {
+ if (createIfNeeded) {
+ result = ca.getConfiguration(configPid, null);
+ } else {
+ String filter = "(" + Constants.SERVICE_PID + "=" + configPid
+ + ")";
+ Configuration[] configs = ca.listConfigurations(filter);
+ if (configs != null && configs.length > 0) {
+ result = configs[0];
+ }
+ }
+ } else {
+ Configuration configs[] = ca.listConfigurations("(&("
+ + ConfigurationAdmin.SERVICE_FACTORYPID + "=" + factoryPid
+ + ")(" + (useAliasForFactory ? ConfigTaskCreator.ALIAS_KEY : Constants.SERVICE_PID) + "=" + configPid
+ + "))");
+
+ if (configs == null || configs.length == 0) {
+ if (createIfNeeded) {
+ result = ca.createFactoryConfiguration(factoryPid, null);
+ }
+ } else {
+ result = configs[0];
+ }
+ }
+
+ return result;
+ }
+}
diff --git a/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java
new file mode 100644
index 0000000..ec987e3
--- /dev/null
+++ b/src/main/java/org/apache/sling/installer/factories/configuration/impl/ServicesListener.java
@@ -0,0 +1,174 @@
+/*
+ * 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.sling.installer.factories.configuration.impl;
+
+import java.util.Hashtable;
+
+import org.apache.sling.installer.api.ResourceChangeListener;
+import org.apache.sling.installer.api.tasks.InstallTaskFactory;
+import org.apache.sling.installer.api.tasks.ResourceTransformer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.cm.ConfigurationAdmin;
+import org.osgi.service.cm.ConfigurationListener;
+
+/**
+ * The <code>ServicesListener</code> listens for the required services
+ * and starts/stops the scanners based on the availability of the
+ * services.
+ */
+public class ServicesListener {
+
+ /** Vendor of all registered services. */
+ public static final String VENDOR = "The Apache Software Foundation";
+
+ /** The bundle context. */
+ private final BundleContext bundleContext;
+
+ /** The listener for the change list handler. */
+ private final Listener changeHandlerListener;
+
+ /** The listener for the configuration admin. */
+ private final Listener configAdminListener;
+
+ /** Registration the service. */
+ private ServiceRegistration configTaskCreatorRegistration;
+
+ private ConfigTaskCreator configTaskCreator;
+
+ public ServicesListener(final BundleContext bundleContext) {
+ this.bundleContext = bundleContext;
+ this.changeHandlerListener = new Listener(ResourceChangeListener.class.getName());
+ this.configAdminListener = new Listener(ConfigurationAdmin.class.getName());
+ this.changeHandlerListener.start();
+ this.configAdminListener.start();
+ }
+
+ public synchronized void notifyChange() {
+ // check if all services are available
+ final ResourceChangeListener listener = (ResourceChangeListener)this.changeHandlerListener.getService();
+ final ConfigurationAdmin configAdmin = (ConfigurationAdmin)this.configAdminListener.getService();
+
+ if ( configAdmin != null && listener != null ) {
+ if ( configTaskCreator == null ) {
+ final Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling Configuration Install Task Factory");
+ props.put(Constants.SERVICE_VENDOR, VENDOR);
+
+ this.configTaskCreator = new ConfigTaskCreator(listener, configAdmin);
+ // start and register osgi installer service
+ final String [] serviceInterfaces = {
+ InstallTaskFactory.class.getName(),
+ ConfigurationListener.class.getName(),
+ ResourceTransformer.class.getName()
+ };
+ configTaskCreatorRegistration = this.bundleContext.registerService(serviceInterfaces, configTaskCreator, props);
+ }
+ } else {
+ this.stop();
+ }
+ }
+
+ private void stop() {
+ // unregister
+ if ( this.configTaskCreatorRegistration != null ) {
+ this.configTaskCreatorRegistration.unregister();
+ this.configTaskCreatorRegistration = null;
+ }
+ this.configTaskCreator = null;
+ }
+
+ /**
+ * Deactivate this listener.
+ */
+ public void deactivate() {
+ this.changeHandlerListener.deactivate();
+ this.configAdminListener.deactivate();
+ this.stop();
+ }
+
+ protected final class Listener implements ServiceListener {
+
+ private final String serviceName;
+
+ private ServiceReference reference;
+ private Object service;
+
+ public Listener(final String serviceName) {
+ this.serviceName = serviceName;
+ }
+
+ public void start() {
+ this.retainService();
+ try {
+ bundleContext.addServiceListener(this, "("
+ + Constants.OBJECTCLASS + "=" + serviceName + ")");
+ } catch (final InvalidSyntaxException ise) {
+ // this should really never happen
+ throw new RuntimeException("Unexpected exception occured.", ise);
+ }
+ }
+
+ public void deactivate() {
+ bundleContext.removeServiceListener(this);
+ }
+
+ public synchronized Object getService() {
+ return this.service;
+ }
+ private synchronized void retainService() {
+ if ( this.reference == null ) {
+ this.reference = bundleContext.getServiceReference(this.serviceName);
+ if ( this.reference != null ) {
+ this.service = bundleContext.getService(this.reference);
+ if ( this.service == null ) {
+ this.reference = null;
+ } else {
+ notifyChange();
+ }
+ }
+ }
+ }
+
+ private synchronized void releaseService() {
+ if ( this.reference != null ) {
+ this.service = null;
+ bundleContext.ungetService(this.reference);
+ this.reference = null;
+ notifyChange();
+ }
+ }
+
+ /**
+ * @see org.osgi.framework.ServiceListener#serviceChanged(org.osgi.framework.ServiceEvent)
+ */
+ public void serviceChanged(ServiceEvent event) {
+ if (event.getType() == ServiceEvent.REGISTERED && this.service == null ) {
+ this.retainService();
+ } else if ( event.getType() == ServiceEvent.UNREGISTERING && this.service != null ) {
+ this.releaseService();
+ }
+ }
+ }
+}
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.