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 2014/05/13 08:40:03 UTC
svn commit: r1594142 - in /sling/trunk/launchpad/base/src/main:
java/org/apache/sling/launchpad/base/impl/
java/org/apache/sling/launchpad/base/shared/ resources/
Author: cziegeler
Date: Tue May 13 06:40:03 2014
New Revision: 1594142
URL: http://svn.apache.org/r1594142
Log:
Revert SLING-3529 : Move startup handling to a separate bundle
Added:
sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/DefaultStartupHandler.java (with props)
Modified:
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/impl/StartupManager.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
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=1594142&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 Tue May 13 06:40:03 2014
@@ -0,0 +1,331 @@
+/*
+ * 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;
+
+ /** Use incremental start level handling. */
+ private final boolean useIncremental;
+
+ /**
+ * 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);
+
+ this.useIncremental = this.startupMode != StartupMode.RESTART && manager.isIncrementalStartupEnabled();
+
+ if ( !this.useIncremental ) {
+ final Bundle[] bundles = context.getBundles();
+ this.expectedBundlesCount = (bundles != null && bundles.length > 0 ? bundles.length : 10);
+
+ context.addBundleListener(this);
+ } else {
+ this.expectedBundlesCount = 10;
+ }
+
+ this.bundleContext.registerService(StartupHandler.class.getName(), this, null);
+ logger.log(Logger.LOG_INFO, "Started startup handler with target start level="
+ + String.valueOf(this.targetStartLevel) + ", and expected bundle count=" + String.valueOf(this.expectedBundlesCount));
+ 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() {
+ 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_DEBUG, "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.useIncremental ) {
+ // 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.useIncremental ) {
+ this.bundleContext.removeBundleListener(this);
+ }
+ this.bundleContext.removeFrameworkListener(this);
+ }
+
+ /**
+ * Notify startup progress
+ * @param ratio ratio
+ */
+ private void startupProgress(final float 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/Sling.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/Sling.java?rev=1594142&r1=1594141&r2=1594142&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 Tue May 13 06:40:03 2014
@@ -222,6 +222,8 @@ public class Sling {
init(tmpFramework);
}
+ new DefaultStartupHandler(tmpFramework.getBundleContext(), logger, startupManager);
+
// finally start
tmpFramework.start();
Modified: sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java
URL: http://svn.apache.org/viewvc/sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java?rev=1594142&r1=1594141&r2=1594142&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java (original)
+++ sling/trunk/launchpad/base/src/main/java/org/apache/sling/launchpad/base/impl/StartupManager.java Tue May 13 06:40:03 2014
@@ -29,6 +29,7 @@ import java.util.Map;
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.shared.SharedConstants;
import org.osgi.framework.Constants;
/**
@@ -60,6 +61,10 @@ public class StartupManager {
private final File confDir;
+ private final long targetStartLevel;
+
+ private final boolean incrementalStartupEnabled;
+
StartupManager(final Map<String, String> properties,
final Logger logger) {
this.logger = logger;
@@ -73,7 +78,16 @@ public class StartupManager {
} else {
this.mode = detectMode(properties.get(Constants.FRAMEWORK_STORAGE));
this.logger.log(Logger.LOG_INFO, "Detected startup mode. Starting in mode " + this.mode);
- properties.put(OVERRIDE_PROP, this.mode.toString());
+ }
+
+ this.targetStartLevel = Long.valueOf(properties.get(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
+
+ this.incrementalStartupEnabled = Boolean.valueOf(properties.get(SharedConstants.SLING_INSTALL_INCREMENTAL_START));
+
+ // if this is not a restart, reduce start level
+ if ( this.mode != StartupMode.RESTART && this.incrementalStartupEnabled ) {
+ final String startLevel = properties.get(SharedConstants.SLING_INSTALL_STARTLEVEL);
+ properties.put(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, startLevel != null ? startLevel : "10");
}
}
@@ -86,6 +100,21 @@ public class StartupManager {
}
/**
+ * Is the incremental startup enabled?
+ */
+ public boolean isIncrementalStartupEnabled() {
+ return this.incrementalStartupEnabled;
+ }
+
+ /**
+ * 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 String osgiStorageDir) {
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=1594142&r1=1594141&r2=1594142&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 Tue May 13 06:40:03 2014
@@ -125,9 +125,7 @@ public interface SharedConstants {
* the initial framework start level is reached (value is "sling.framework.install.incremental").
* The default value is false, disabling this feature.
* @since 2.4.0
- * @deprecated This property is not used anymore.
*/
- @Deprecated
public static final String SLING_INSTALL_INCREMENTAL_START = "sling.framework.install.incremental";
/**
@@ -138,8 +136,6 @@ public interface SharedConstants {
* This level is only used if {@link #SLING_INSTALL_INCREMENTAL_START} is
* enabled. Default value is 10.
* @since 2.4.0
- * @deprecated This property is not used anymore.
*/
- @Deprecated
public static final String SLING_INSTALL_STARTLEVEL = "sling.framework.install.startlevel";
}
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=1594142&r1=1594141&r2=1594142&view=diff
==============================================================================
--- sling/trunk/launchpad/base/src/main/resources/sling.properties (original)
+++ sling/trunk/launchpad/base/src/main/resources/sling.properties Tue May 13 06:40:03 2014
@@ -130,28 +130,13 @@ org.osgi.framework.storage = ${sling.lau
# Default initial framework start level
org.osgi.framework.startlevel.beginning=30
-#
-# By default the framework on startup tries to go straight to
-# the beginning start level (set above).
-# However, in the case of an install or update a slower startup
-# by increasing the level one by one and waiting for the OSGi
-# installer to finish might be more appropriate.
-# In this case, set org.osgi.framework.startlevel.beginning to
-# a lower start level and sling.framework.install.startlevel to
-# the final start level. The framework is then started with
-# the beginning start level and Sling's startup handler will
-# increase it to the sling.framework.startup.startlevel.
-# If sling.framework.startup.incremental is set to true for
-# an install and update this is done level by level.
-# If you use the below properties make sure to comment the above
-# definition for org.osgi.framework.startlevel out.
-#
+# 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.install.incremental=true
-# org.osgi.framework.startlevel.beginning=10
-# sling.framework.install.startlevel=30
-# sling.framework.startup.incremental=true
-# sling.framework.startup.startlevel
-
+# sling.framework.install.startlevel=10
#
# Default start level for newly installed bundles not explicitly assigned