You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by cz...@apache.org on 2012/01/19 17:16:56 UTC
svn commit: r1233447 - in /sling/trunk/launchpad: api/
api/src/main/java/org/apache/sling/launchpad/api/ base/
base/src/main/java/org/apache/sling/launchpad/base/impl/
base/src/main/java/org/apache/sling/launchpad/base/shared/
base/src/main/resources/ ...
Author: cziegeler
Date: Thu Jan 19 16:16:55 2012
New Revision: 1233447
URL: http://svn.apache.org/viewvc?rev=1233447&view=rev
Log:
SLING-2376 : New Startup Features
Added:
sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java (with props)
sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java (with props)
sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java (with props)
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java (with props)
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java (contents, props changed)
- copied, changed from r1232820, sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupHandler.java
sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java (with props)
Removed:
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupHandler.java
Modified:
sling/trunk/launchpad/api/pom.xml
sling/trunk/launchpad/base/pom.xml
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DirectoryUtil.java
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java
sling/trunk/launchpad/base/src/main/resources/sling.properties
sling/trunk/launchpad/builder/src/main/bundles/list.xml
sling/trunk/launchpad/installer/pom.xml
sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java
Modified: sling/trunk/launchpad/api/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/api/pom.xml?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/api/pom.xml (original)
+++ sling/trunk/launchpad/api/pom.xml Thu Jan 19 16:16:55 2012
@@ -43,7 +43,7 @@
<extensions>true</extensions>
<configuration>
<instructions>
- <Export-Package>org.apache.sling.launchpad.api;version=1.0.0</Export-Package>
+ <Export-Package>org.apache.sling.launchpad.api;version=1.1.0</Export-Package>
</instructions>
</configuration>
</plugin>
Added: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java?rev=1233447&view=auto
==============================================================================
--- sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java (added)
+++ sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java Thu Jan 19 16:16:55 2012
@@ -0,0 +1,36 @@
+/*
+ * 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.launchpad.api;
+
+
+
+/**
+ * The <code>StartupHandler</code> tries to detect the startup mode:
+ * It distinguishes between an initial startup (INSTALL), an update (UPDATE)
+ * and a restart without a change (RESTART).
+ * @since 1.1.0
+ */
+public interface StartupHandler {
+
+ StartupMode getMode();
+
+ boolean isFinished();
+
+ void waitWithStartup(final boolean flag);
+}
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java?rev=1233447&view=auto
==============================================================================
--- sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java (added)
+++ sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java Thu Jan 19 16:16:55 2012
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.launchpad.api;
+
+
+/**
+ * A startup listener receives events about the startup.
+ *
+ * @since 1.1.0
+ */
+public interface StartupListener {
+
+ void inform(StartupMode mode, boolean finished);
+
+ /**
+ * Notify finished startup.
+ * @param The startup mode
+ */
+ void startupFinished(StartupMode mode);
+
+ /**
+ * Notify startup progress
+ * @param ratio The current ratio
+ */
+ void startupProgress(final float ratio);
+}
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupListener.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java?rev=1233447&view=auto
==============================================================================
--- sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java (added)
+++ sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java Thu Jan 19 16:16:55 2012
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.sling.launchpad.api;
+
+/**
+ * The <code>StartupMode</code>
+ * It distinguishes between an initial startup (INSTALL), an update (UPDATE)
+ * and a restart without a change (RESTART).
+ * @since 1.1.0
+ */
+public enum StartupMode {
+
+ INSTALL,
+ UPDATE,
+ RESTART
+}
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/launchpad/api/src/main/java/org/apache/sling/launchpad/api/StartupMode.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/launchpad/base/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/pom.xml?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/pom.xml (original)
+++ sling/trunk/launchpad/base/pom.xml Thu Jan 19 16:16:55 2012
@@ -270,7 +270,7 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.launchpad.api</artifactId>
- <version>1.0.0</version>
+ <version>1.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/BootstrapInstaller.java Thu Jan 19 16:16:55 2012
@@ -36,6 +36,7 @@ import java.util.jar.Manifest;
import org.apache.felix.framework.Logger;
import org.apache.sling.launchpad.api.LaunchpadContentProvider;
+import org.apache.sling.launchpad.api.StartupMode;
import org.apache.sling.launchpad.base.impl.bootstrapcommands.BootstrapCommandFile;
import org.apache.sling.launchpad.base.shared.SharedConstants;
import org.osgi.framework.Bundle;
@@ -72,11 +73,6 @@ class BootstrapInstaller {
private static final String PATH_RESOURCES = "resources/";
/**
- * The path of startup bundles in the sling home
- */
- private static final String PATH_STARTUP = "startup/";
-
- /**
* The location of the core Bundles (value is "resources/corebundles").
* These bundles are installed at startlevel
* {@link #STARTLEVEL_CORE_BUNDLES}.
@@ -135,7 +131,14 @@ class BootstrapInstaller {
/** The bundle context. */
private final BundleContext bundleContext;
- BootstrapInstaller(final BundleContext bundleContext, Logger logger, LaunchpadContentProvider resourceProvider) {
+ /** The startup mode. */
+ private final StartupMode startupMode;
+
+ BootstrapInstaller(final BundleContext bundleContext,
+ final Logger logger,
+ final LaunchpadContentProvider resourceProvider,
+ final StartupMode startupMode) {
+ this.startupMode = startupMode;
this.logger = logger;
this.resourceProvider = resourceProvider;
this.bundleContext = bundleContext;
@@ -166,8 +169,6 @@ class BootstrapInstaller {
}
final File slingStartupDir = getSlingStartupDir(launchpadHome);
- final StartupHandler startupHandler = new StartupHandler(this.bundleContext, this.logger, slingStartupDir);
-
// execute bootstrap commands, if needed
final BootstrapCommandFile cmd = new BootstrapCommandFile(logger,
new File(launchpadHome, BOOTSTRAP_CMD_FILENAME));
@@ -180,7 +181,7 @@ class BootstrapInstaller {
if (Boolean.valueOf(fpblString)) {
shouldInstall = true;
} else {
- shouldInstall = startupHandler.getMode() != StartupHandler.StartupMode.RESTART;
+ shouldInstall = this.startupMode != StartupMode.RESTART;
}
if (shouldInstall) {
@@ -235,9 +236,6 @@ class BootstrapInstaller {
// start all the newly installed bundles (existing bundles are not started if they are stopped)
startBundles(installed);
-
- // mark everything installed
- startupHandler.finished();
}
// due to the upgrade of a framework extension bundle, the framework
@@ -262,7 +260,7 @@ class BootstrapInstaller {
*/
private File getSlingStartupDir(String slingHome) {
final File slingHomeDir = new File(slingHome);
- final File slingHomeStartupDir = getOrCreateDirectory(slingHomeDir, PATH_STARTUP);
+ final File slingHomeStartupDir = getOrCreateDirectory(slingHomeDir, DirectoryUtil.PATH_STARTUP);
return slingHomeStartupDir;
}
@@ -280,7 +278,7 @@ class BootstrapInstaller {
|| ! parentDir.canRead()
|| ! parentDir.canWrite() ) {
throw new IllegalStateException("Fatal error in bootstrap: Cannot find accessible existing "
- +SharedConstants.SLING_HOME+PATH_STARTUP+" directory: " + slingHomeStartupDir);
+ +SharedConstants.SLING_HOME+DirectoryUtil.PATH_STARTUP+" directory: " + slingHomeStartupDir);
}
} else if (! slingHomeStartupDir.mkdirs() ) {
throw new IllegalStateException("Sling Home " + slingHomeStartupDir + " cannot be created as a directory");
Added: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java?rev=1233447&view=auto
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java (added)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java Thu Jan 19 16:16:55 2012
@@ -0,0 +1,327 @@
+/*
+ * 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.launchpad.base.impl;
+
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.apache.felix.framework.Logger;
+import org.apache.sling.launchpad.api.StartupHandler;
+import org.apache.sling.launchpad.api.StartupListener;
+import org.apache.sling.launchpad.api.StartupMode;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleEvent;
+import org.osgi.framework.BundleListener;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.startlevel.StartLevel;
+import org.osgi.util.tracker.ServiceTracker;
+import org.osgi.util.tracker.ServiceTrackerCustomizer;
+
+/**
+ * The installation listener is listening for
+ * - framework events
+ * - events from other services
+ *
+ * It notifies listeners about the finish of the startup and
+ * about an approximate progress.
+ *
+ * @see StartupHandler
+ * @see StartupListener
+ * @since 2.4.0
+ */
+public class DefaultStartupHandler
+ implements StartupHandler, BundleListener, FrameworkListener, Runnable {
+
+ /** Logger. */
+ private final Logger logger;
+
+ /** Marker for finished. */
+ private final AtomicBoolean finished = new AtomicBoolean(false);
+
+ /** Marker if startup should wait */
+ private final AtomicInteger startupShouldWait = new AtomicInteger(0);
+
+ /** The queue for increasing the start level. */
+ private final BlockingQueue<Boolean> queue = new LinkedBlockingQueue<Boolean>();
+
+ /** The start level service. */
+ private final StartLevel startLevelService;
+
+ /** The target start level. */
+ private final long targetStartLevel;
+
+ /** The startup mode. */
+ private final StartupMode startupMode;
+
+ /** Service tracker for startup listeners. */
+ private final ServiceTracker listenerTracker;
+
+ /** Expected bundle counts. */
+ private final int expectedBundlesCount;
+
+ /** Active bundle set. */
+ private final Set<String> activeBundles = new HashSet<String>();
+
+ /** Bundle Context. */
+ private final BundleContext bundleContext;
+
+ /**
+ * Constructor.
+ * @param context Bundle context
+ * @param logger Logger
+ * @param manager The startup manager
+ */
+ public DefaultStartupHandler(final BundleContext context, final Logger logger, final StartupManager manager) {
+ this.logger = logger;
+ this.bundleContext = context;
+ this.startupMode = manager.getMode();
+ this.targetStartLevel = manager.getTargetStartLevel();
+
+ this.listenerTracker = new ServiceTracker(context, StartupListener.class.getName(),
+ new ServiceTrackerCustomizer() {
+
+ public void removedService(final ServiceReference reference, final Object service) {
+ context.ungetService(reference);
+ }
+
+ public void modifiedService(final ServiceReference reference, final Object service) {
+ // nothing to do
+ }
+
+ public Object addingService(final ServiceReference reference) {
+ final StartupListener listener = (StartupListener) context.getService(reference);
+ if ( listener != null ) {
+ listener.inform(startupMode, finished.get());
+ }
+ return listener;
+ }
+ });
+ this.listenerTracker.open();
+ this.startLevelService = (StartLevel)context.getService(context.getServiceReference(StartLevel.class.getName()));
+ context.addFrameworkListener(this);
+
+ if ( this.startupMode == StartupMode.RESTART ) {
+ final Bundle[] bundles = context.getBundles();
+ this.expectedBundlesCount = (bundles != null ? bundles.length : 0);
+
+ context.addBundleListener(this);
+ } else {
+ this.expectedBundlesCount = 0;
+ }
+
+ final Thread t = new Thread(this);
+ t.start();
+ }
+
+ /**
+ * @see org.apache.sling.launchpad.api.StartupHandler#getMode()
+ */
+ public StartupMode getMode() {
+ return this.startupMode;
+ }
+
+ /**
+ * @see org.apache.sling.launchpad.api.StartupHandler#isFinished()
+ */
+ public boolean isFinished() {
+ return this.finished.get();
+ }
+
+ /**
+ * @see java.lang.Runnable#run()
+ */
+ public void run() {
+ this.bundleContext.registerService(StartupHandler.class.getName(), this, null);
+ logger.log(Logger.LOG_INFO, "Started startup listener with target start level="
+ + String.valueOf(this.targetStartLevel) + ", and expected bundle count=" + String.valueOf(this.expectedBundlesCount));
+ while ( !this.finished.get() ) {
+ Boolean doInc = null;
+ try {
+ doInc = this.queue.take();
+ } catch (final InterruptedException e) {
+ // ignore
+ }
+ if ( doInc != null && doInc ) {
+ // if the installer is idle we first wait
+ // we have to do this to give the installer or plugins for the installer,
+ // time to start after the start level has changed
+ if ( this.startupShouldWait.get() == 0 ) {
+ this.sleep(2000L);
+ }
+ // now we wait until the installer is idle
+ while ( this.startupShouldWait.get() != 0 ) {
+ this.sleep(50L);
+ }
+ this.incStartLevel();
+ }
+ }
+ }
+
+ /**
+ * Increment the current start level by one
+ */
+ private void incStartLevel() {
+ final int newLevel = this.startLevelService.getStartLevel() + 1;
+ logger.log(Logger.LOG_DEBUG, "Increasing start level to " + String.valueOf(newLevel));
+ this.startLevelService.setStartLevel(newLevel);
+ }
+
+ /**
+ * @see org.apache.sling.launchpad.api.StartupHandler#waitWithStartup(boolean)
+ */
+ public void waitWithStartup(final boolean flag) {
+ logger.log(Logger.LOG_INFO, "Wait with startup " + flag);
+ if ( flag ) {
+ this.startupShouldWait.incrementAndGet();
+ } else {
+ this.startupShouldWait.decrementAndGet();
+ }
+ }
+
+ /**
+ * Sleep a little bit
+ * @param time Sleeping time
+ */
+ private void sleep(final long time) {
+ try {
+ Thread.sleep(time);
+ } catch ( final InterruptedException e) {
+ // ignore
+ }
+ }
+
+ /**
+ * Put a task in the queue
+ * @param info Add new boolean information to queue
+ */
+ private void enqueue(final boolean info) {
+ try {
+ this.queue.put(info);
+ } catch (final InterruptedException e) {
+ // ignore
+ }
+ }
+
+ /**
+ * @see org.osgi.framework.FrameworkListener#frameworkEvent(org.osgi.framework.FrameworkEvent)
+ */
+ public void frameworkEvent(final FrameworkEvent event) {
+ if ( finished.get() ) {
+ return;
+ }
+ logger.log(Logger.LOG_DEBUG, "Received framework event " + event);
+
+ if ( this.startupMode == StartupMode.RESTART ) {
+ // restart
+ if ( event.getType() == FrameworkEvent.STARTED ) {
+ this.startupFinished();
+ }
+
+ } else {
+ // first startup or update
+ if ( event.getType() == FrameworkEvent.STARTED ) {
+ this.enqueue(true);
+
+ } else if ( event.getType() == FrameworkEvent.STARTLEVEL_CHANGED ) {
+ if ( this.startLevelService.getStartLevel() >= this.targetStartLevel ) {
+ this.startupFinished();
+ } else {
+ this.enqueue(true);
+ final int startLevel = this.startLevelService.getStartLevel();
+ logger.log(Logger.LOG_INFO, "Startup progress " + String.valueOf(startLevel) + '/' + String.valueOf(targetStartLevel));
+ final float ratio = (float) startLevel / (float) targetStartLevel;
+ this.startupProgress(ratio);
+ }
+ }
+ }
+ }
+
+ /**
+ * Notify finished startup
+ */
+ private void startupFinished() {
+ logger.log(Logger.LOG_INFO, "Startup finished.");
+ this.finished.set(true);
+
+ final Object[] listeners = this.listenerTracker.getServices();
+ if ( listeners != null ) {
+ for(final Object l : listeners) {
+ if ( l instanceof StartupListener ) {
+ ((StartupListener) l).startupFinished(this.startupMode);
+ }
+ }
+ }
+ // stop the queue
+ this.enqueue(false);
+
+ // clear bundle set
+ this.activeBundles.clear();
+
+ // unregister listeners
+ if ( this.startupMode == StartupMode.RESTART ) {
+ this.bundleContext.removeBundleListener(this);
+ }
+ this.bundleContext.removeFrameworkListener(this);
+ }
+
+ /**
+ * Notify startup progress
+ * @param ratio ratio
+ */
+ private void startupProgress(final float ratio) {
+ logger.log(Logger.LOG_INFO, "Startup progress " + String.valueOf(ratio));
+ final Object[] listeners = this.listenerTracker.getServices();
+ if ( listeners != null ) {
+ for(final Object l : listeners) {
+ if ( l instanceof StartupListener ) {
+ ((StartupListener) l).startupProgress(ratio);
+ }
+ }
+ }
+ }
+
+ /**
+ * @see org.osgi.framework.BundleListener#bundleChanged(org.osgi.framework.BundleEvent)
+ */
+ public void bundleChanged(final BundleEvent event) {
+ if (!finished.get()) {
+ logger.log(Logger.LOG_DEBUG, "Received bundle event " + event);
+
+ if (event.getType() == BundleEvent.RESOLVED || event.getType() == BundleEvent.STARTED) {
+ // Add (if not existing) bundle to active bundles and refresh progress bar
+ activeBundles.add(event.getBundle().getSymbolicName());
+
+ logger.log(Logger.LOG_INFO, "Startup progress " + String.valueOf(activeBundles.size()) + '/' + String.valueOf(expectedBundlesCount));
+ final float ratio = (float) activeBundles.size() / (float) expectedBundlesCount;
+ this.startupProgress(ratio);
+ } else if (event.getType() == BundleEvent.STOPPED) {
+ // Only remove bundle from active bundles,
+ // but do not refresh progress bar, to prevent progress bar from going back
+ activeBundles.remove(event.getBundle().getSymbolicName());
+ }
+ }
+ }
+}
Propchange: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DirectoryUtil.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DirectoryUtil.java?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DirectoryUtil.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DirectoryUtil.java Thu Jan 19 16:16:55 2012
@@ -18,6 +18,9 @@ package org.apache.sling.launchpad.base.
import java.io.File;
import java.io.FileFilter;
+import java.util.Map;
+
+import org.apache.sling.launchpad.base.shared.SharedConstants;
public class DirectoryUtil {
@@ -26,13 +29,23 @@ public class DirectoryUtil {
*/
private static final String[] BUNDLE_EXTENSIONS = { ".jar", ".war" };
+ /**
+ * The path of startup bundles in the sling home
+ */
+ public static final String PATH_STARTUP = "startup";
+
+ /**
+ * The path of startup bundles in the sling home
+ */
+ public static final String PATH_CONF = "conf";
+
//---------- FileFilter implementations to scan startup folders
/**
* Simple directory filter
*/
public static final FileFilter DIRECTORY_FILTER = new FileFilter() {
- public boolean accept(File f) {
+ public boolean accept(final File f) {
return f.isDirectory();
}
};
@@ -41,7 +54,7 @@ public class DirectoryUtil {
* Simple bundle file filter
*/
public static final FileFilter BUNDLE_FILE_FILTER = new FileFilter() {
- public boolean accept(File f) {
+ public boolean accept(final File f) {
return f.isFile() && isBundle(f.getName());
}
};
@@ -52,7 +65,7 @@ public class DirectoryUtil {
* @param path the path to the file
* @return true if the path could be a bundle
*/
- public static boolean isBundle(String path) {
+ public static boolean isBundle(final String path) {
for (String extension : BUNDLE_EXTENSIONS) {
if (path.endsWith(extension)) {
return true;
@@ -60,4 +73,26 @@ public class DirectoryUtil {
}
return false;
}
+
+ public static File getHomeDir(final Map<String, String> properties) {
+ String home = properties.get(SharedConstants.SLING_LAUNCHPAD);
+ if (home == null) {
+ home = properties.get(SharedConstants.SLING_HOME);
+ }
+ return new File(home);
+ }
+
+ /**
+ * Return the config dir.
+ */
+ public static File getConfigDir(final Map<String, String> properties) {
+ return new File(getHomeDir(properties), PATH_CONF);
+ }
+
+ /**
+ * Return the startup dir.
+ */
+ public static File getStartupDir(final Map<String, String> properties) {
+ return new File(getHomeDir(properties), PATH_STARTUP);
+ }
}
Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java Thu Jan 19 16:16:55 2012
@@ -220,25 +220,33 @@ public class Sling {
// create the framework and start it
try {
+ // initiate startup handler
+ final StartupManager startupManager = new StartupManager(props, logger);
+
Framework tmpFramework = createFramework(notifiable, logger, props);
init(tmpFramework);
- if (new BootstrapInstaller(tmpFramework.getBundleContext(), logger,
- resourceProvider).install()) {
+ final boolean restart = new BootstrapInstaller(tmpFramework.getBundleContext(), logger,
+ resourceProvider, startupManager.getMode()).install();
+ startupManager.markInstalled();
+
+ if (restart) {
stop(tmpFramework);
tmpFramework = createFramework(notifiable, logger, props);
init(tmpFramework);
}
+ new DefaultStartupHandler(tmpFramework.getBundleContext(), logger, startupManager);
+
// finally start
tmpFramework.start();
// only assign field if start succeeds
this.framework = tmpFramework;
- } catch (BundleException be) {
+ } catch (final BundleException be) {
throw be;
- } catch (Exception e) {
+ } catch (final Exception e) {
// thrown by SlingFelix constructor
throw new BundleException("Uncaught Instantiation Issue: " + e, e);
}
Copied: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java (from r1232820, sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupHandler.java)
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java?p2=sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java&p1=sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupHandler.java&r1=1232820&r2=1233447&rev=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupHandler.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java Thu Jan 19 16:16:55 2012
@@ -19,15 +19,18 @@
package org.apache.sling.launchpad.base.impl;
import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
+import java.util.Map;
import org.apache.felix.framework.Logger;
import org.apache.sling.launchpad.api.LaunchpadContentProvider;
-import org.osgi.framework.BundleContext;
+import org.apache.sling.launchpad.api.StartupMode;
+import org.apache.sling.launchpad.base.shared.SharedConstants;
+import org.osgi.framework.Constants;
/**
* The <code>StartupHandler</code> tries to detect the startup mode:
@@ -35,16 +38,10 @@ import org.osgi.framework.BundleContext;
* and a restart without a change (RESTART).
* @since 2.4.0
*/
-class StartupHandler {
-
- public enum StartupMode {
- INSTALL,
- UPDATE,
- RESTART
- }
+public class StartupManager {
/** The data file which works as a marker to detect the first startup. */
- private static final String DATA_FILE = "bootstrapinstaller.ser";
+ private static final String DATA_FILE = "launchpad-timestamp.txt";
/**
* The {@link Logger} use for logging messages during installation and
@@ -52,53 +49,69 @@ class StartupHandler {
*/
private final Logger logger;
- /** The bundle context. */
- private final BundleContext bundleContext;
-
private final StartupMode mode;
private final File startupDir;
- private final long selfStamp;
+ private final File confDir;
- StartupHandler(final BundleContext bundleContext,
- final Logger logger,
- final File slingStartupDir)
- throws IOException {
+ private final long targetStartLevel;
+
+ StartupManager(final Map<String, String> properties,
+ final Logger logger) {
this.logger = logger;
- this.bundleContext = bundleContext;
- this.startupDir = slingStartupDir;
- this.selfStamp = this.getSelfTimestamp();
+ this.startupDir = DirectoryUtil.getStartupDir(properties);
+ this.confDir = DirectoryUtil.getConfigDir(properties);
this.mode = detectMode();
this.logger.log(Logger.LOG_INFO, "Starting in mode " + this.mode);
+
+ this.targetStartLevel = Long.valueOf(properties.get(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
+
+ // if this is not a restart, reduce start level
+ if ( this.mode != StartupMode.RESTART ) {
+ final String startLevel = properties.get(SharedConstants.SLING_INSTALL_STARTLEVEL);
+ properties.put(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, startLevel);
+ }
}
+ /**
+ * Return the startup mode
+ * @return The startup mode
+ */
public StartupMode getMode() {
return this.mode;
}
- public void finished() {
- this.markInstalled();
+ /**
+ * Return the target start level.
+ * @return Target start level
+ */
+ public long getTargetStartLevel() {
+ return this.targetStartLevel;
}
+ /**
+ * Detect the startup mode by comparing time stamps
+ */
private StartupMode detectMode() {
- final File dataFile = this.bundleContext.getDataFile(DATA_FILE);
- if (dataFile != null && dataFile.exists()) {
+ final File dataFile = new File(this.confDir, DATA_FILE);
+ if (dataFile.exists()) {
- FileInputStream fis = null;
+ FileReader fis = null;
try {
- if (this.selfStamp > 0) {
+ final long selfStamp = this.getSelfTimestamp();
+ if (selfStamp > 0) {
- fis = new FileInputStream(dataFile);
- byte[] bytes = new byte[20];
- int len = fis.read(bytes);
- String value = new String(bytes, 0, len);
+ fis = new FileReader(dataFile);
+ final char[] txt = new char[128];
+ final int len = fis.read(txt);
+ final String value = new String(txt, 0, len);
- long storedStamp = Long.parseLong(value);
+ final long storedStamp = Long.parseLong(value);
logger.log(Logger.LOG_INFO, String.format("Stored timestamp: %s", storedStamp));
- return (storedStamp >= this.selfStamp ? StartupMode.RESTART : StartupMode.UPDATE);
+ return (storedStamp >= selfStamp ? StartupMode.RESTART : StartupMode.UPDATE);
}
} catch (final NumberFormatException nfe) {
@@ -120,8 +133,10 @@ class StartupHandler {
return StartupMode.INSTALL;
}
- private long getTimeStampOfClass(final Class<?> clazz)
- throws IOException {
+ /**
+ * Get the timestamp of a class through its url classloader (if possible)
+ */
+ private long getTimeStampOfClass(final Class<?> clazz) {
long selfStamp = -1;
final ClassLoader loader = clazz.getClassLoader();
if (loader instanceof URLClassLoader) {
@@ -130,7 +145,9 @@ class StartupHandler {
if (urls.length > 0) {
final URL url = urls[0];
logger.log(Logger.LOG_INFO, String.format("Using timestamp from %s.", url));
- selfStamp = urls[0].openConnection().getLastModified();
+ try {
+ selfStamp = urls[0].openConnection().getLastModified();
+ } catch (final IOException ignore) {}
}
}
return selfStamp;
@@ -152,7 +169,7 @@ class StartupHandler {
* @throws IOException If an error occurrs reading accessing the last
* modification time stampe.
*/
- private long getSelfTimestamp() throws IOException {
+ private long getSelfTimestamp() {
// the timestamp of the launcher jar and the bootstrap jar
long selfStamp = this.getTimeStampOfClass(this.getClass());
@@ -163,14 +180,18 @@ class StartupHandler {
// check whether any bundle is younger than the launcher jar
final File[] directories = this.startupDir.listFiles(DirectoryUtil.DIRECTORY_FILTER);
- for (final File levelDir : directories) {
+ if ( directories != null ) {
+ for (final File levelDir : directories) {
- // iterate through all files in the startlevel dir
- final File[] jarFiles = levelDir.listFiles(DirectoryUtil.BUNDLE_FILE_FILTER);
- for (final File bundleJar : jarFiles) {
- if (bundleJar.lastModified() > selfStamp) {
- logger.log(Logger.LOG_INFO, String.format("Using timestamp from %s.", bundleJar));
- selfStamp = bundleJar.lastModified();
+ // iterate through all files in the startlevel dir
+ final File[] jarFiles = levelDir.listFiles(DirectoryUtil.BUNDLE_FILE_FILTER);
+ if ( jarFiles != null ) {
+ for (final File bundleJar : jarFiles) {
+ if (bundleJar.lastModified() > selfStamp) {
+ logger.log(Logger.LOG_INFO, String.format("Using timestamp from %s.", bundleJar));
+ selfStamp = bundleJar.lastModified();
+ }
+ }
}
}
}
@@ -182,12 +203,16 @@ class StartupHandler {
return selfStamp;
}
- private void markInstalled() {
- final File dataFile = this.bundleContext.getDataFile(DATA_FILE);
+ /**
+ * Set the finished installation marker.
+ */
+ public void markInstalled() {
+ final File dataFile = new File(this.confDir, DATA_FILE);
try {
- final FileOutputStream fos = new FileOutputStream(dataFile);
+ this.confDir.mkdirs();
+ final FileWriter fos = new FileWriter(dataFile);
try {
- fos.write(String.valueOf(this.selfStamp).getBytes());
+ fos.write(String.valueOf(this.getSelfTimestamp()));
} finally {
try { fos.close(); } catch (final IOException ignore) {}
}
Propchange: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/shared/SharedConstants.java Thu Jan 19 16:16:55 2012
@@ -115,4 +115,13 @@ public interface SharedConstants {
* @since 2.4.0
*/
public static final String SLING_LAUNCHPAD = "sling.launchpad";
+
+ /**
+ * The name of the configuration property defining the startlevel
+ * for installs and updates. The framework starts with this start level
+ * and the startup manager increases the start level one by one until
+ * the initial framework start level is reached (value is "sling.framework.installstartlevel").
+ * @since 2.4.0
+ */
+ public static final String SLING_INSTALL_STARTLEVEL = "sling.framework.installstartlevel";
}
Modified: sling/trunk/launchpad/base/src/main/resources/sling.properties
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/resources/sling.properties?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/resources/sling.properties (original)
+++ sling/trunk/launchpad/base/src/main/resources/sling.properties Thu Jan 19 16:16:55 2012
@@ -127,9 +127,15 @@ org.osgi.framework.storage = ${sling.lau
#
-# Default initial Framework start level
+# Default initial framework start level
org.osgi.framework.startlevel.beginning=30
+# Install and update initial framework start level
+# This should be lower than the default initial framework start level
+# During an install or update, the framework starts with this level
+# and the startup manager increases the start level by one
+# until the initial framework start level is reached
+sling.framework.installstartlevel=10
#
# Default start level for newly installed bundles not explicitly assigned
@@ -158,7 +164,7 @@ org.osgi.framework.executionenvironment=
org.osgi.framework.system.packages= \
${osgi-core-packages}, \
${osgi-compendium-services}, \
- org.apache.sling.launchpad.api;version=1.0.0, \
+ org.apache.sling.launchpad.api;version=1.1.0, \
${jre-${java.specification.version}} \
${org.apache.sling.launcher.system.packages}
Modified: sling/trunk/launchpad/builder/src/main/bundles/list.xml
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/builder/src/main/bundles/list.xml?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/builder/src/main/bundles/list.xml (original)
+++ sling/trunk/launchpad/builder/src/main/bundles/list.xml Thu Jan 19 16:16:55 2012
@@ -223,7 +223,7 @@
<bundle>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.launchpad.installer</artifactId>
- <version>1.0.6</version>
+ <version>1.0.7-SNAPSHOT</version>
</bundle>
<bundle>
<groupId>org.apache.sling</groupId>
Modified: sling/trunk/launchpad/installer/pom.xml
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/installer/pom.xml?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/installer/pom.xml (original)
+++ sling/trunk/launchpad/installer/pom.xml Thu Jan 19 16:16:55 2012
@@ -55,13 +55,13 @@
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.launchpad.api</artifactId>
- <version>1.0.0</version>
+ <version>1.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.installer.core</artifactId>
- <version>3.2.2</version>
+ <version>3.3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
Added: sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java?rev=1233447&view=auto
==============================================================================
--- sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java (added)
+++ sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java Thu Jan 19 16:16:55 2012
@@ -0,0 +1,47 @@
+/*
+ * 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.launchpad.installer.impl;
+
+import org.apache.sling.installer.api.event.InstallationEvent;
+import org.apache.sling.installer.api.event.InstallationListener;
+import org.apache.sling.launchpad.api.StartupHandler;
+
+public class LaunchpadListener implements InstallationListener {
+
+ private final StartupHandler startupHandler;
+
+ private volatile boolean started = false;
+
+ public LaunchpadListener(final StartupHandler startupHandler) {
+ this.startupHandler = startupHandler;
+ }
+
+ /**
+ * @see org.apache.sling.installer.api.event.InstallationListener#onEvent(org.apache.sling.installer.api.event.InstallationEvent)
+ */
+ public void onEvent(final InstallationEvent event) {
+ if ( event.getType() == InstallationEvent.TYPE.STARTED ) {
+ this.startupHandler.waitWithStartup(true);
+ started = true;
+ } else if ( event.getType() == InstallationEvent.TYPE.SUSPENDED ) {
+ if ( started ) {
+ this.startupHandler.waitWithStartup(false);
+ }
+ }
+ }
+
+}
\ No newline at end of file
Propchange: sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java
------------------------------------------------------------------------------
svn:keywords = author date id revision rev url
Propchange: sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/LaunchpadListener.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java?rev=1233447&r1=1233446&r2=1233447&view=diff
==============================================================================
--- sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java (original)
+++ sling/trunk/launchpad/installer/src/main/java/org/apache/sling/launchpad/installer/impl/ServicesListener.java Thu Jan 19 16:16:55 2012
@@ -19,13 +19,16 @@
package org.apache.sling.launchpad.installer.impl;
import org.apache.sling.installer.api.OsgiInstaller;
+import org.apache.sling.installer.api.event.InstallationListener;
import org.apache.sling.launchpad.api.LaunchpadContentProvider;
+import org.apache.sling.launchpad.api.StartupHandler;
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
@@ -43,12 +46,21 @@ public class ServicesListener {
/** The listener for the provider. */
private final Listener providerListener;
+ /** The listener for the startup handler. */
+ private final Listener startupListener;
+
+ private ServiceRegistration launchpadListenerReg;
+
+ private volatile boolean installed = false;
+
public ServicesListener(final BundleContext bundleContext) {
this.bundleContext = bundleContext;
this.installerListener = new Listener(OsgiInstaller.class.getName());
this.providerListener = new Listener(LaunchpadContentProvider.class.getName());
+ this.startupListener = new Listener(StartupHandler.class.getName());
this.installerListener.start();
this.providerListener.start();
+ this.startupListener.start();
}
public synchronized void notifyChange() {
@@ -57,7 +69,22 @@ public class ServicesListener {
final LaunchpadContentProvider lcp = (LaunchpadContentProvider)this.providerListener.getService();
if ( installer != null && lcp != null ) {
- LaunchpadConfigInstaller.install(installer, lcp);
+ if ( !installed ) {
+ installed = true;
+ LaunchpadConfigInstaller.install(installer, lcp);
+ }
+ }
+ final StartupHandler handler = (StartupHandler)this.startupListener.getService();
+ if ( handler != null ) {
+ if ( launchpadListenerReg == null ) {
+ final LaunchpadListener launchpadListener = new LaunchpadListener(handler);
+ launchpadListenerReg = this.bundleContext.registerService(InstallationListener.class.getName(), launchpadListener, null);
+ }
+ } else {
+ if ( launchpadListenerReg != null ) {
+ launchpadListenerReg.unregister();
+ launchpadListenerReg = null;
+ }
}
}
@@ -67,6 +94,7 @@ public class ServicesListener {
public void deactivate() {
this.installerListener.deactivate();
this.providerListener.deactivate();
+ this.startupListener.deactivate();
}
protected final class Listener implements ServiceListener {