This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.installer.provider.file-1.0.2 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-installer-provider-file.git
commit 7654827e1968049b46c352cfcb8ba1cf457e3a51 Author: Carsten Ziegeler <[email protected]> AuthorDate: Fri Jul 29 07:40:55 2011 +0000 SLING-2162 : Support write back of configurations git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/installer/providers/file@1152133 13f79535-47bb-0310-9956-ffa450edef68 --- pom.xml | 13 +- .../installer/provider/file/impl/Activator.java | 12 +- .../provider/file/impl/FileChangesListener.java | 2 + .../provider/file/impl/FileInstaller.java | 228 +++++++++++++++++++++ .../installer/provider/file/impl/FileMonitor.java | 8 + .../installer/provider/file/impl/Installer.java | 15 +- .../provider/file/impl/ServicesListener.java | 65 +++--- 7 files changed, 298 insertions(+), 45 deletions(-) diff --git a/pom.xml b/pom.xml index a921f79..d0ee922 100644 --- a/pom.xml +++ b/pom.xml @@ -57,6 +57,9 @@ <Private-Package> org.apache.sling.installer.provider.file.impl.* </Private-Package> + <Embed-Dependency> + org.apache.felix.configadmin;inline="org/apache/felix/cm/file/ConfigurationHandler.*" + </Embed-Dependency> </instructions> </configuration> </plugin> @@ -79,7 +82,15 @@ <dependency> <groupId>org.apache.sling</groupId> <artifactId>org.apache.sling.installer.core</artifactId> - <version>3.0.0</version> + <version>3.2.0</version> + <scope>provided</scope> + </dependency> + <!-- We use a class from the config admin implementation to read config files --> + <dependency> + <groupId>org.apache.felix</groupId> + <artifactId>org.apache.felix.configadmin</artifactId> + <version>1.2.8</version> + <scope>provided</scope> </dependency> </dependencies> </project> diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java b/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java index 32c707b..2b06592 100644 --- a/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java +++ b/src/main/java/org/apache/sling/installer/provider/file/impl/Activator.java @@ -32,6 +32,7 @@ public class Activator implements BundleActivator { public static final String KEY_DIR = "sling.fileinstall.dir"; public static final String KEY_DELAY = "sling.fileinstall.interval"; + public static final String KEY_WRITEBACK = "sling.fileinstall.writeback"; /** The services listener will activate the installer. */ private ServicesListener servicesListener; @@ -42,10 +43,10 @@ public class Activator implements BundleActivator { public void start(final BundleContext context) { // read initial scan configurations final List<ScanConfiguration> configs = new ArrayList<ScanConfiguration>(); - final Object dir = this.getProp(context, KEY_DIR); + final Object dir = getProp(context, KEY_DIR); if ( dir != null ) { Long delay = null; - final Object interval = this.getProp(context, KEY_DELAY); + final Object interval = getProp(context, KEY_DELAY); if ( interval != null ) { if ( interval instanceof Number ) { delay = ((Number)interval).longValue(); @@ -73,10 +74,13 @@ public class Activator implements BundleActivator { this.servicesListener = null; } - private Object getProp(final BundleContext bundleContext, final String key) { + public static Object getProp(final BundleContext bundleContext, final String key) { Object o = bundleContext.getProperty(key); if (o == null) { - o = System.getProperty(key.toUpperCase().replace('.', '_')); + o = System.getProperty(key); + if ( o == null ) { + o = System.getProperty(key.toUpperCase().replace('.', '_')); + } } return o; } diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java b/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java index b9c16f2..2fd34d5 100644 --- a/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java +++ b/src/main/java/org/apache/sling/installer/provider/file/impl/FileChangesListener.java @@ -26,4 +26,6 @@ public interface FileChangesListener { void initialSet(List<File> files); void updated(List<File> added, List<File> changed, List<File> removed); + + String getScheme(); } diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java b/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java new file mode 100644 index 0000000..3726746 --- /dev/null +++ b/src/main/java/org/apache/sling/installer/provider/file/impl/FileInstaller.java @@ -0,0 +1,228 @@ +/* + * 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.provider.file.impl; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.math.BigInteger; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Dictionary; +import java.util.List; +import java.util.Map; + +import org.apache.felix.cm.file.ConfigurationHandler; +import org.apache.sling.installer.api.InstallableResource; +import org.apache.sling.installer.api.OsgiInstaller; +import org.apache.sling.installer.api.UpdateHandler; +import org.apache.sling.installer.api.UpdateResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The <code>FileInstaller</code> manages the file installers and + * handles updates. + * + */ +public class FileInstaller + implements UpdateHandler { + + /** The scheme we use to register our resources. */ + public static final String SCHEME_PREFIX = "fileinstall"; + + /** Logger. */ + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + /** All active scan configurations. */ + private final List<ScanConfiguration> scanConfigurations = new ArrayList<ScanConfiguration>(); + + /** All monitors. */ + private final List<FileMonitor> monitors = new ArrayList<FileMonitor>(); + + private final boolean writeBack; + + public FileInstaller(final List<ScanConfiguration> configs, final boolean writeBack) { + this.writeBack = writeBack; + if ( configs != null ) { + scanConfigurations.addAll(configs); + } + } + + public boolean hasConfigurations() { + return !this.scanConfigurations.isEmpty(); + } + + public void start(final OsgiInstaller installer) { + for(final ScanConfiguration config : this.scanConfigurations) { + logger.debug("Starting monitor for {}", config.directory); + this.monitors.add(new FileMonitor(new File(config.directory), + config.scanInterval, new Installer(installer, hash(config.directory)))); + } + } + + public void stop() { + for(final FileMonitor monitor : this.monitors) { + monitor.stop(); + } + this.monitors.clear(); + + } + + public String[] getSchemes() { + final String[] schemes = new String[this.monitors.size()]; + int index = 0; + + for(final FileMonitor m : this.monitors) { + schemes[index] = m.getListener().getScheme(); + index++; + } + + return schemes; + } + + /** + * @see org.apache.sling.installer.api.UpdateHandler#handleRemoval(java.lang.String, java.lang.String, java.lang.String) + */ + public UpdateResult handleRemoval(final String resourceType, + final String id, + final String url) { + if ( !this.writeBack ) { + return null; + } + final int pos = url.indexOf(':'); + final String path = url.substring(pos + 1); + // remove + logger.debug("Removal of {}", path); + final File file = new File(path); + if ( file.exists() ) { + file.delete(); + } + return new UpdateResult(url); + } + + /** + * @see org.apache.sling.installer.api.UpdateHandler#handleUpdate(java.lang.String, java.lang.String, java.lang.String, java.util.Dictionary, Map) + */ + public UpdateResult handleUpdate(final String resourceType, + final String id, + final String url, + final Dictionary<String, Object> dict, + final Map<String, Object> attributes) { + return this.handleUpdate(resourceType, id, url, null, dict, attributes); + } + + /** + * @see org.apache.sling.installer.api.UpdateHandler#handleUpdate(java.lang.String, java.lang.String, java.lang.String, java.io.InputStream, Map) + */ + public UpdateResult handleUpdate(final String resourceType, + final String id, + final String url, + final InputStream is, + final Map<String, Object> attributes) { + return this.handleUpdate(resourceType, id, url, is, null, attributes); + } + + /** + * Internal implementation of update handling + */ + private UpdateResult handleUpdate(final String resourceType, + final String id, + final String url, + final InputStream is, + final Dictionary<String, Object> dict, + final Map<String, Object> attributes) { + if ( !this.writeBack ) { + return null; + } + + // we only handle add/update of configs for now + if ( !resourceType.equals(InstallableResource.TYPE_CONFIG) ) { + return null; + } + + try { + final String path; + final String prefix; + if ( url != null ) { + // update + final int pos = url.indexOf(':'); + final String oldPath = url.substring(pos + 1); + prefix = url.substring(0, pos); + // ensure extension 'config' + if ( !oldPath.endsWith(".config") ) { + final File file = new File(oldPath); + if ( file.exists() ) { + file.delete(); + } + final int lastDot = oldPath.lastIndexOf('.'); + final int lastSlash = oldPath.lastIndexOf('/'); + if ( lastDot <= lastSlash ) { + path = oldPath + ".config"; + } else { + path = oldPath.substring(0, lastDot) + ".config"; + } + } else { + path = oldPath; + } + logger.debug("Update of {} at {}", resourceType, path); + } else { + // add + final FileMonitor first = this.monitors.get(0); + path = first.getRoot().getAbsolutePath() + '/' + id + ".config"; + prefix = first.getListener().getScheme(); + logger.debug("Add of {} at {}", resourceType, path); + } + + final File file = new File(path); + file.getParentFile().mkdirs(); + final FileOutputStream fos = new FileOutputStream(file); + try { + ConfigurationHandler.write(fos, dict); + } finally { + try { + fos.close(); + } catch (final IOException ignore) {} + } + + final UpdateResult result = new UpdateResult(prefix + ':' + path); + result.setResourceIsMoved(true); + return result; + } catch (final IOException e) { + logger.error("Unable to add/update resource " + resourceType + ':' + id, e); + return null; + } + } + + /** + * Hash the string + */ + private static String hash(String value) { + try { + final MessageDigest d = MessageDigest.getInstance("MD5"); + d.update(value.getBytes("UTF-8")); + final BigInteger bigInt = new BigInteger(1, d.digest()); + return new String(bigInt.toString(16)); + } catch (Exception ignore) { + // if anything goes wrong we just return the value + return value; + } + } +} diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java b/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java index 0c16ce7..085d07e 100644 --- a/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java +++ b/src/main/java/org/apache/sling/installer/provider/file/impl/FileMonitor.java @@ -59,6 +59,14 @@ public class FileMonitor extends TimerTask { timer.schedule(this, 0, (interval != null ? interval : 5000)); } + public File getRoot() { + return this.root.file; + } + + public FileChangesListener getListener() { + return this.listener; + } + private void collect(final File file, final List<File> files) { if ( file.exists() ) { if ( file.isDirectory() ) { diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java b/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java index 3113208..80ce7c2 100644 --- a/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java +++ b/src/main/java/org/apache/sling/installer/provider/file/impl/Installer.java @@ -37,10 +37,8 @@ import org.slf4j.LoggerFactory; * OSGi installer * */ -public class Installer implements FileChangesListener { - - /** The scheme we use to register our resources. */ - private static final String SCHEME_PREFIX = "fileinstall"; +public class Installer + implements FileChangesListener { /** Logger. */ private final Logger logger = LoggerFactory.getLogger(this.getClass()); @@ -53,11 +51,18 @@ public class Installer implements FileChangesListener { public Installer(final OsgiInstaller installer, final String id) { - this.scheme = SCHEME_PREFIX + id; + this.scheme = FileInstaller.SCHEME_PREFIX + id; this.installer = installer; } /** + * @see org.apache.sling.installer.provider.file.impl.FileChangesListener#getScheme() + */ + public String getScheme() { + return this.scheme; + } + + /** * @see org.apache.sling.installer.provider.file.impl.FileChangesListener#initialSet(java.util.List) */ public void initialSet(final List<File> files) { diff --git a/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java b/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java index 01e3c58..c71bfca 100644 --- a/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java +++ b/src/main/java/org/apache/sling/installer/provider/file/impl/ServicesListener.java @@ -18,19 +18,19 @@ */ package org.apache.sling.installer.provider.file.impl; -import java.io.File; -import java.math.BigInteger; -import java.security.MessageDigest; -import java.util.ArrayList; +import java.util.Dictionary; +import java.util.Hashtable; import java.util.List; import org.apache.sling.installer.api.OsgiInstaller; +import org.apache.sling.installer.api.UpdateHandler; 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.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -53,26 +53,29 @@ public class ServicesListener { /** The listener for the installer. */ private final Listener installerListener; - /** All active scan configurations. */ - private final List<ScanConfiguration> scanConfigurations = new ArrayList<ScanConfiguration>(); + /** The file installer. */ + private final FileInstaller installer; - /** All monitors. */ - private final List<FileMonitor> monitors = new ArrayList<FileMonitor>(); + /** Service registration. */ + private ServiceRegistration registration; private boolean running = false; public ServicesListener(final BundleContext bundleContext, final List<ScanConfiguration> configs) { - if ( configs != null ) { - scanConfigurations.addAll(configs); - } this.bundleContext = bundleContext; + boolean writeBack = true; + final Object writeBackObj = Activator.getProp(this.bundleContext, Activator.KEY_WRITEBACK); + if ( writeBackObj != null && "false".equalsIgnoreCase(writeBackObj.toString())) { + writeBack = false; + } + this.installer = new FileInstaller(configs, writeBack); this.installerListener = new Listener(INSTALLER_SERVICE_NAME); this.installerListener.start(); } public synchronized void notifyChange() { - final boolean shouldRun = !this.scanConfigurations.isEmpty(); + final boolean shouldRun = this.installer.hasConfigurations(); if ( (shouldRun && !running) || (!shouldRun && running) ) { final OsgiInstaller installer = (OsgiInstaller)this.installerListener.getService(); @@ -94,23 +97,30 @@ public class ServicesListener { this.stopScanner(); } + /** Vendor of all registered services. */ + public static final String VENDOR = "The Apache Software Foundation"; + private void startScanner(final OsgiInstaller installer) { if ( !running ) { - for(final ScanConfiguration config : this.scanConfigurations) { - logger.debug("Starting monitor for {}", config.directory); - this.monitors.add(new FileMonitor(new File(config.directory), - config.scanInterval, new Installer(installer, hash(config.directory)))); - } + this.installer.start(installer); + final Dictionary<String, Object> props = new Hashtable<String, Object>(); + props.put(Constants.SERVICE_DESCRIPTION, "Apache Sling File Installer Controller Service"); + props.put(Constants.SERVICE_VENDOR, VENDOR); + props.put(UpdateHandler.PROPERTY_SCHEMES, this.installer.getSchemes()); + + this.registration = this.bundleContext.registerService(UpdateHandler.class.getName(), + this.installer, props); running = true; } } private void stopScanner() { if ( running ) { - for(final FileMonitor monitor : this.monitors) { - monitor.stop(); + if ( this.registration != null ) { + this.registration.unregister(); + this.registration = null; } - this.monitors.clear(); + this.installer.stop(); running = false; } } @@ -178,19 +188,4 @@ public class ServicesListener { } } } - - /** - * Hash the string - */ - private static String hash(String value) { - try { - final MessageDigest d = MessageDigest.getInstance("MD5"); - d.update(value.getBytes("UTF-8")); - final BigInteger bigInt = new BigInteger(1, d.digest()); - return new String(bigInt.toString(16)); - } catch (Exception ignore) { - // if anything goes wrong we just return the value - return value; - } - } } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
