This is an automated email from the ASF dual-hosted git repository. rombert pushed a commit to annotated tag org.apache.sling.settings-1.2.2 in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-settings.git
commit 7c677f21f70af1b2259bf7261ba3063cd1286b5d Author: Carsten Ziegeler <[email protected]> AuthorDate: Mon Nov 26 10:14:09 2012 +0000 SLING-2674 : SlingSettingsServiceImpl should detect and handle upgrades git-svn-id: https://svn.apache.org/repos/asf/sling/trunk/bundles/extensions/settings@1413541 13f79535-47bb-0310-9956-ffa450edef68 --- .../org/apache/sling/settings/impl/Activator.java | 43 +---- .../sling/settings/impl/ServicesListener.java | 199 +++++++++++++++++++++ .../settings/impl/SlingSettingsServiceImpl.java | 28 +-- .../sling/settings/impl/RunModeImplTest.java | 61 +++++-- 4 files changed, 257 insertions(+), 74 deletions(-) diff --git a/src/main/java/org/apache/sling/settings/impl/Activator.java b/src/main/java/org/apache/sling/settings/impl/Activator.java index 2d1c2a8..91781f2 100644 --- a/src/main/java/org/apache/sling/settings/impl/Activator.java +++ b/src/main/java/org/apache/sling/settings/impl/Activator.java @@ -18,14 +18,8 @@ */ package org.apache.sling.settings.impl; -import java.util.Dictionary; -import java.util.Hashtable; - -import org.apache.sling.settings.SlingSettingsService; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; -import org.osgi.framework.Constants; -import org.osgi.framework.ServiceRegistration; /** * This is the bundle activator. @@ -34,48 +28,23 @@ import org.osgi.framework.ServiceRegistration; */ public class Activator implements BundleActivator { - /** The service registration */ - private ServiceRegistration serviceRegistration; + /** The service listener */ + private ServicesListener servicesListener; /** * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) */ public void start(final BundleContext bundleContext) throws Exception { - final SlingSettingsService settingsService = new SlingSettingsServiceImpl(bundleContext); - - final Dictionary<String, String> props = new Hashtable<String, String>(); - props.put(Constants.SERVICE_PID, settingsService.getClass().getName()); - props.put(Constants.SERVICE_DESCRIPTION, - "Apache Sling Settings Service"); - props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); - serviceRegistration = bundleContext.registerService(new String[] { - SlingSettingsService.class.getName()}, - settingsService, props); - SlingPropertiesPrinter.initPlugin(bundleContext); - SlingSettingsPrinter.initPlugin(bundleContext, settingsService); - try { - RunModeCommand.initPlugin(bundleContext, settingsService.getRunModes()); - } catch (Throwable ignore) { - // we just ignore this - } - + this.servicesListener = new ServicesListener(bundleContext); } /** * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(final BundleContext context) throws Exception { - try { - RunModeCommand.destroyPlugin(); - } catch (Throwable ignore) { - // we just ignore this - } - SlingSettingsPrinter.destroyPlugin(); - SlingPropertiesPrinter.destroyPlugin(); - - if ( serviceRegistration != null ) { - serviceRegistration.unregister(); - serviceRegistration = null; + if ( this.servicesListener != null ) { + this.servicesListener.deactivate(); + this.servicesListener = null; } } } diff --git a/src/main/java/org/apache/sling/settings/impl/ServicesListener.java b/src/main/java/org/apache/sling/settings/impl/ServicesListener.java new file mode 100644 index 0000000..77b8045 --- /dev/null +++ b/src/main/java/org/apache/sling/settings/impl/ServicesListener.java @@ -0,0 +1,199 @@ +/* + * 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.settings.impl; + +import java.util.Dictionary; +import java.util.Hashtable; + +import org.apache.sling.launchpad.api.StartupHandler; +import org.apache.sling.settings.SlingSettingsService; +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; + +/** + * The <code>ServicesListener</code> listens for the required services + * and registers the settings service once all required services are + * available + */ +public class ServicesListener { + + /** The bundle context. */ + private final BundleContext bundleContext; + + /** The listener for the startup handler. */ + private final Listener startupListener; + + /** The registration of the settings service. */ + private ServiceRegistration settingsReg; + + /** + * Start listeners + */ + public ServicesListener(final BundleContext bundleContext) { + this.bundleContext = bundleContext; + this.startupListener = new Listener(StartupHandler.class.getName()); + this.startupListener.start(); + } + + /** + * Notify of service changes from the listeners. + * If all services are available, register listener and pass resources + * to the OSGi installer. + */ + public synchronized void notifyChange() { + // check if all services are available + final StartupHandler handler = (StartupHandler)this.startupListener.getService(); + if ( handler != null && this.settingsReg == null ) { + this.activate(handler); + } + } + + private void activate(final StartupHandler handler) { + final SlingSettingsService settingsService = new SlingSettingsServiceImpl(bundleContext, handler); + + final Dictionary<String, String> props = new Hashtable<String, String>(); + props.put(Constants.SERVICE_PID, settingsService.getClass().getName()); + props.put(Constants.SERVICE_DESCRIPTION, + "Apache Sling Settings Service"); + props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation"); + this.settingsReg = bundleContext.registerService(new String[] { + SlingSettingsService.class.getName()}, + settingsService, props); + SlingPropertiesPrinter.initPlugin(bundleContext); + SlingSettingsPrinter.initPlugin(bundleContext, settingsService); + try { + RunModeCommand.initPlugin(bundleContext, settingsService.getRunModes()); + } catch (Throwable ignore) { + // we just ignore this + } + } + /** + * Deactivate this listener. + */ + public void deactivate() { + this.startupListener.deactivate(); + if ( this.settingsReg != null ) { + this.settingsReg.unregister(); + this.settingsReg = null; + } + try { + RunModeCommand.destroyPlugin(); + } catch (Throwable ignore) { + // we just ignore this + } + SlingSettingsPrinter.destroyPlugin(); + SlingPropertiesPrinter.destroyPlugin(); + } + + /** + * Helper class listening for service events for a defined service. + */ + protected final class Listener implements ServiceListener { + + /** The name of the service. */ + private final String serviceName; + + /** The service reference. */ + private volatile ServiceReference reference; + + /** The service. */ + private volatile Object service; + + /** + * Constructor + */ + public Listener(final String serviceName) { + this.serviceName = serviceName; + } + + /** + * Start the listener. + * First register a service listener and then check for the service. + */ + public void start() { + try { + bundleContext.addServiceListener(this, "(" + + Constants.OBJECTCLASS + "=" + serviceName + ")"); + } catch (final InvalidSyntaxException ise) { + // this should really never happen + throw new RuntimeException("Unexpected exception occured.", ise); + } + this.retainService(); + } + + /** + * Unregister the listener. + */ + public void deactivate() { + bundleContext.removeServiceListener(this); + } + + /** + * Return the service (if available) + */ + public synchronized Object getService() { + return this.service; + } + + /** + * Try to get the service and notify the change. + */ + 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(); + } + } + } + } + + /** + * Try to release the service and notify the change. + */ + 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.retainService(); + } else if ( event.getType() == ServiceEvent.UNREGISTERING ) { + this.releaseService(); + } + } + } +} diff --git a/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java b/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java index 4ab883c..8836a57 100644 --- a/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java +++ b/src/main/java/org/apache/sling/settings/impl/SlingSettingsServiceImpl.java @@ -34,6 +34,7 @@ import java.util.List; import java.util.Set; import java.util.UUID; +import org.apache.sling.launchpad.api.StartupHandler; import org.apache.sling.launchpad.api.StartupMode; import org.apache.sling.settings.SlingSettingsService; import org.osgi.framework.BundleContext; @@ -72,24 +73,13 @@ public class SlingSettingsServiceImpl * Setup run modes * @param context The bundle context */ - public SlingSettingsServiceImpl(final BundleContext context) { + public SlingSettingsServiceImpl(final BundleContext context, + final StartupHandler handler) { this.setupSlingHome(context); - final boolean isInstall = this.setupSlingId(context); - - // Detect if upgrading from a previous version (where OPTIONS_FILE did not exist), - // as in terms of run modes this needs to be handled like an install - final File options = context.getDataFile(OPTIONS_FILE); - final boolean isUpdate = !isInstall && !options.exists(); - - final String startupModeObj = context.getProperty(StartupMode.class.getName()); - final StartupMode mode; - if ( startupModeObj != null ) { - mode = StartupMode.valueOf(startupModeObj); - logger.debug("Settings: Using startup mode : {}", mode); - } else { - logger.debug("Settings: Startup mode detection: isInstall={}, isUpdate={}", isInstall, isUpdate); - mode = isInstall ? StartupMode.INSTALL : (isUpdate ? StartupMode.UPDATE : StartupMode.RESTART); - } + this.setupSlingId(context); + + final StartupMode mode = handler.getMode(); + logger.debug("Settings: Using startup mode : {}", mode); this.setupRunModes(context, mode); @@ -113,7 +103,7 @@ public class SlingSettingsServiceImpl /** * Get / create sling id */ - private boolean setupSlingId(final BundleContext context) { + private void setupSlingId(final BundleContext context) { // try to read the id from the id file first final File idFile = context.getDataFile(DATA_FILE); if ( idFile == null ) { @@ -126,9 +116,7 @@ public class SlingSettingsServiceImpl if (slingId == null) { slingId = UUID.randomUUID().toString(); this.writeSlingId(idFile, this.slingId); - return true; } - return false; } private static final class Options implements Serializable { diff --git a/src/test/java/org/apache/sling/settings/impl/RunModeImplTest.java b/src/test/java/org/apache/sling/settings/impl/RunModeImplTest.java index 36a2954..658fad5 100644 --- a/src/test/java/org/apache/sling/settings/impl/RunModeImplTest.java +++ b/src/test/java/org/apache/sling/settings/impl/RunModeImplTest.java @@ -30,6 +30,8 @@ import java.util.HashMap; import java.util.Map; import java.util.Set; +import org.apache.sling.launchpad.api.StartupHandler; +import org.apache.sling.launchpad.api.StartupMode; import org.apache.sling.settings.SlingSettingsService; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; @@ -44,8 +46,33 @@ import org.osgi.framework.ServiceRegistration; public class RunModeImplTest { + private final class StartupHandlerImpl implements StartupHandler { + + private final StartupMode mode; + + public StartupHandlerImpl() { + this(StartupMode.INSTALL); + } + + public StartupHandlerImpl(final StartupMode mode) { + this.mode = mode; + } + + public void waitWithStartup(final boolean flag) { + // nothing to do + } + + public boolean isFinished() { + return false; + } + + public StartupMode getMode() { + return this.mode; + } + }; + private void assertParse(String str, String [] expected) { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock(str, null, null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock(str, null, null), new StartupHandlerImpl()); final Set<String> modes = rm.getRunModes(); final String[] actual = modes.toArray(new String[modes.size()]); assertArrayEquals("Parsed runModes match for '" + str + "'", expected, actual); @@ -57,7 +84,7 @@ public class RunModeImplTest { assertParse(" foo \t", new String[] { "foo" }); assertParse(" foo \t, bar\n", new String[] { "foo", "bar" }); } - + private void assertActive(SlingSettingsService s, boolean active, String ...modes) { for(String mode : modes) { if(active) { @@ -69,77 +96,77 @@ public class RunModeImplTest { } @org.junit.Test public void testMatchesNotEmpty() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar", null, null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar", null, null), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar"); assertActive(rm, false, "wiz", "bah", ""); } @org.junit.Test public void testOptions() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar", "a,b,c|d,e,f", null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar", "a,b,c|d,e,f", null), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "d"); assertActive(rm, false, "b", "c", "e", "f"); } @org.junit.Test public void testEmptyRunModesWithOptions() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("", "a,b,c|d,e,f", null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("", "a,b,c|d,e,f", null), new StartupHandlerImpl()); assertActive(rm, true, "a", "d"); assertActive(rm, false, "b", "c", "e", "f"); } @org.junit.Test public void testOptionsSelected() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e", "a,b,c|d,e,f", null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e", "a,b,c|d,e,f", null), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "c", "e"); assertActive(rm, false, "a", "b", "d", "f"); } @org.junit.Test public void testOptionsMultipleSelected() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e,f,a", "a,b,c|d,e,f", null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e,f,a", "a,b,c|d,e,f", null), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "e"); assertActive(rm, false, "b", "c", "d", "f"); } @org.junit.Test public void testOptionsMultipleSelected2() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,f,a,d", "a,b,c|d,e,f", null)); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,f,a,d", "a,b,c|d,e,f", null), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "d"); assertActive(rm, false, "b", "c", "e", "f"); } @org.junit.Test public void testInstallOptions() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar", null, "a,b,c|d,e,f")); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar", null, "a,b,c|d,e,f"), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "d"); assertActive(rm, false, "b", "c", "e", "f"); } @org.junit.Test public void testInstallOptionsSelected() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e", null , "a,b,c|d,e,f")); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e", null , "a,b,c|d,e,f"), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "c", "e"); assertActive(rm, false, "a", "b", "d", "f"); } @org.junit.Test public void testInstallOptionsMultipleSelected() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e,f,a", null, "a,b,c|d,e,f")); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,e,f,a", null, "a,b,c|d,e,f"), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "e"); assertActive(rm, false, "b", "c", "d", "f"); } @org.junit.Test public void testInstallOptionsMultipleSelected2() { - final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,d,f,a", null, "a,b,c|d,e,f")); + final SlingSettingsService rm = new SlingSettingsServiceImpl(new BundleContextMock("foo,bar,c,d,f,a", null, "a,b,c|d,e,f"), new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "d"); assertActive(rm, false, "b", "c", "e", "f"); } @org.junit.Test public void testInstallOptionsRestart() { final BundleContextMock bc = new BundleContextMock("foo,bar,c,e,f,a", null, "a,b,c|d,e,f"); - + { // create first context to simulate install - final SlingSettingsService rm = new SlingSettingsServiceImpl(bc); + final SlingSettingsService rm = new SlingSettingsServiceImpl(bc, new StartupHandlerImpl()); assertActive(rm, true, "foo", "bar", "a", "e"); assertActive(rm, false, "b", "c", "d", "f"); } - + { - final SlingSettingsService rm = new SlingSettingsServiceImpl(bc); + final SlingSettingsService rm = new SlingSettingsServiceImpl(bc, new StartupHandlerImpl(StartupMode.RESTART)); assertActive(rm, true, "foo", "bar", "a", "e"); assertActive(rm, false, "b", "c", "d", "f"); } @@ -148,7 +175,7 @@ public class RunModeImplTest { // mentioned in the .options properties are ignored bc.update("foo,doo,a,b,c,d,e,f,waa"); { - final SlingSettingsService rm = new SlingSettingsServiceImpl(bc); + final SlingSettingsService rm = new SlingSettingsServiceImpl(bc, new StartupHandlerImpl(StartupMode.RESTART)); assertActive(rm, true, "foo", "doo", "a", "e", "waa"); assertActive(rm, false, "bar", "b", "c", "d", "f"); } -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
