blob: 9ab6180c89e1574638881d4ce70a53e671da2ccd [file] [log] [blame]
Felix Meschbergerd25a63d2007-11-23 13:02:49 +00001/*
Richard S. Halle449eca2006-09-28 20:00:47 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
Richard S. Hall323d9712006-09-22 18:55:50 +00009 *
Richard S. Halle449eca2006-09-28 20:00:47 +000010 * http://www.apache.org/licenses/LICENSE-2.0
Richard S. Hall323d9712006-09-22 18:55:50 +000011 *
Richard S. Halle449eca2006-09-28 20:00:47 +000012 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
Richard S. Hall323d9712006-09-22 18:55:50 +000018 */
Felix Meschbergerd25a63d2007-11-23 13:02:49 +000019package org.apache.felix.scr.impl;
Richard S. Hall323d9712006-09-22 18:55:50 +000020
Felix Meschberger29e04e32007-08-30 14:53:12 +000021
Felix Meschbergerd468b352007-05-15 10:38:24 +000022import java.io.PrintStream;
David Jencks77ef1fc2013-08-19 23:10:49 +000023import java.text.MessageFormat;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000024import java.util.HashMap;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000025import java.util.Map;
Guillaume Nodet6574df22013-11-13 07:42:20 +000026import java.util.concurrent.CountDownLatch;
Guillaume Nodet6574df22013-11-13 07:42:20 +000027import java.util.concurrent.TimeUnit;
Richard S. Hall323d9712006-09-22 18:55:50 +000028
Felix Meschberger2136bed2009-11-26 10:08:12 +000029import org.apache.felix.scr.impl.config.ScrConfiguration;
Guillaume Nodetd767b212013-08-02 13:22:32 +000030import org.apache.felix.utils.extender.AbstractExtender;
31import org.apache.felix.utils.extender.Extension;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000032import org.osgi.framework.Bundle;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000033import org.osgi.framework.BundleContext;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000034import org.osgi.framework.Constants;
Felix Meschbergerba3da7a2009-07-09 12:26:58 +000035import org.osgi.service.component.ComponentConstants;
Richard S. Hall323d9712006-09-22 18:55:50 +000036import org.osgi.service.log.LogService;
Felix Meschbergerc90e3162007-03-28 14:34:01 +000037import org.osgi.util.tracker.ServiceTracker;
Richard S. Hall323d9712006-09-22 18:55:50 +000038
Felix Meschberger29e04e32007-08-30 14:53:12 +000039
Richard S. Hall323d9712006-09-22 18:55:50 +000040/**
41 * This activator is used to cover requirement described in section 112.8.1 @@ -27,14
42 * 37,202 @@ in active bundles.
Felix Meschbergerd25a63d2007-11-23 13:02:49 +000043 *
Richard S. Hall323d9712006-09-22 18:55:50 +000044 */
Guillaume Nodetd767b212013-08-02 13:22:32 +000045public class Activator extends AbstractExtender
Richard S. Hall323d9712006-09-22 18:55:50 +000046{
Felix Meschbergerd468b352007-05-15 10:38:24 +000047 // name of the LogService class (this is a string to not create a reference to the class)
Felix Meschberger29e04e32007-08-30 14:53:12 +000048 static final String LOGSERVICE_CLASS = "org.osgi.service.log.LogService";
49
Felix Meschberger08aaff62010-08-05 13:26:31 +000050 // name of the PackageAdmin class (this is a string to not create a reference to the class)
51 static final String PACKAGEADMIN_CLASS = "org.osgi.service.packageadmin.PackageAdmin";
52
Felix Meschberger2136bed2009-11-26 10:08:12 +000053 // Our configuration from bundle context properties and Config Admin
David Jencks2d3a00a2014-04-27 06:58:04 +000054 private static ScrConfiguration m_configuration;
Richard S. Hall323d9712006-09-22 18:55:50 +000055
Richard S. Hall323d9712006-09-22 18:55:50 +000056 // this bundle's context
Felix Meschberger08aaff62010-08-05 13:26:31 +000057 private static BundleContext m_context;
Felix Meschberger29e04e32007-08-30 14:53:12 +000058
Guillaume Nodet2241a5f2013-11-20 10:10:20 +000059 // this bundle
60 private static Bundle m_bundle;
61
Richard S. Hall323d9712006-09-22 18:55:50 +000062 // the log service to log messages to
David Jencks081fa832013-05-09 05:50:38 +000063 private static volatile ServiceTracker m_logService;
Felix Meschberger29e04e32007-08-30 14:53:12 +000064
Felix Meschberger08aaff62010-08-05 13:26:31 +000065 // the package admin service (see BindMethod.getParameterClass)
David Jencks081fa832013-05-09 05:50:38 +000066 private static volatile ServiceTracker m_packageAdmin;
Felix Meschberger08aaff62010-08-05 13:26:31 +000067
Felix Meschberger64e99f92009-10-11 08:35:25 +000068 // map of BundleComponentActivator instances per Bundle indexed by Bundle id
David Jenckseeb03d22012-11-29 23:53:21 +000069 private Map<Long, BundleComponentActivator> m_componentBundles;
Richard S. Hall323d9712006-09-22 18:55:50 +000070
Felix Meschbergerc90e3162007-03-28 14:34:01 +000071 // registry of managed component
72 private ComponentRegistry m_componentRegistry;
Richard S. Hall323d9712006-09-22 18:55:50 +000073
Felix Meschbergerd468b352007-05-15 10:38:24 +000074 // thread acting upon configurations
75 private ComponentActorThread m_componentActor;
Felix Meschberger29e04e32007-08-30 14:53:12 +000076
Guillaume Nodetd767b212013-08-02 13:22:32 +000077 public Activator() {
David Jencks2d3a00a2014-04-27 06:58:04 +000078 m_configuration = new ScrConfiguration( this );
Guillaume Nodetd767b212013-08-02 13:22:32 +000079 setSynchronous(true);
80 }
81
Richard S. Hall323d9712006-09-22 18:55:50 +000082 /**
83 * Registers this instance as a (synchronous) bundle listener and loads the
84 * components of already registered bundles.
Felix Meschbergerd25a63d2007-11-23 13:02:49 +000085 *
Richard S. Hall323d9712006-09-22 18:55:50 +000086 * @param context The <code>BundleContext</code> of the SCR implementation
87 * bundle.
88 */
Felix Meschberger29e04e32007-08-30 14:53:12 +000089 public void start( BundleContext context ) throws Exception
Richard S. Hall323d9712006-09-22 18:55:50 +000090 {
91 m_context = context;
Guillaume Nodet2241a5f2013-11-20 10:10:20 +000092 m_bundle = context.getBundle();
Richard S. Hall323d9712006-09-22 18:55:50 +000093 // require the log service
Guillaume Nodetd767b212013-08-02 13:22:32 +000094 m_logService = new ServiceTracker( m_context, LOGSERVICE_CLASS, null );
Felix Meschbergerc90e3162007-03-28 14:34:01 +000095 m_logService.open();
David Jencks2d3a00a2014-04-27 06:58:04 +000096 // get the configuration
97 m_configuration.start( m_context ); //this will call restart, which calls super.start.
98 }
99
100 public void restart( boolean globalExtender )
101 {
102 BundleContext context;
103 if ( globalExtender )
104 {
105 context = m_context.getBundle( 0 ).getBundleContext();
106 }
107 else
108 {
109 context = m_context;
110 }
111 if ( m_packageAdmin != null )
112 {
113 //this really is a restart, not the initial start
114 try
115 {
116 super.stop(context);
117 }
118 catch ( Exception e )
119 {
120 log( LogService.LOG_ERROR, m_bundle, "Exception stopping during restart", e );
121 }
122 }
123 try
124 {
125 super.start( context );
126 }
127 catch ( Exception e )
128 {
129 log( LogService.LOG_ERROR, m_bundle, "Exception starting during restart", e );
130 }
131
132 }
133
134 protected void doStart() throws Exception {
Felix Meschberger29e04e32007-08-30 14:53:12 +0000135
Felix Meschbergerfb1ce2f2011-02-04 10:49:51 +0000136 // prepare component registry
David Jenckseeb03d22012-11-29 23:53:21 +0000137 m_componentBundles = new HashMap<Long, BundleComponentActivator>();
Guillaume Nodetd767b212013-08-02 13:22:32 +0000138 m_componentRegistry = new ComponentRegistry( m_context );
Felix Meschbergerfb1ce2f2011-02-04 10:49:51 +0000139
Felix Meschberger2136bed2009-11-26 10:08:12 +0000140
141 // log SCR startup
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000142 log( LogService.LOG_INFO, m_bundle, " Version = {0}",
143 new Object[] {m_bundle.getHeaders().get( Constants.BUNDLE_VERSION )}, null );
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000144
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000145 // create and start the component actor
Felix Meschbergerd468b352007-05-15 10:38:24 +0000146 m_componentActor = new ComponentActorThread();
Felix Meschbergerf7dfd272009-10-30 17:26:25 +0000147 Thread t = new Thread(m_componentActor, "SCR Component Actor");
148 t.setDaemon( true );
149 t.start();
Felix Meschbergerd468b352007-05-15 10:38:24 +0000150
Guillaume Nodetd767b212013-08-02 13:22:32 +0000151 super.doStart();
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000152
Felix Meschberger44add772010-12-23 18:13:24 +0000153 // register the Gogo and old Shell commands
Guillaume Nodetd767b212013-08-02 13:22:32 +0000154 ScrCommand scrCommand = ScrCommand.register(m_context, m_componentRegistry, m_configuration);
David Jenckscb9f9422013-02-04 02:16:11 +0000155 m_configuration.setScrCommand( scrCommand );
Richard S. Hall323d9712006-09-22 18:55:50 +0000156 }
David Jencks2d3a00a2014-04-27 06:58:04 +0000157
158 public void stop(BundleContext context) throws Exception
159 {
160 super.stop(context);
161 m_configuration.stop();
162 m_configuration = null;
163 }
Richard S. Hall323d9712006-09-22 18:55:50 +0000164
Felix Meschberger29e04e32007-08-30 14:53:12 +0000165
Richard S. Hall323d9712006-09-22 18:55:50 +0000166 /**
167 * Unregisters this instance as a bundle listener and unloads all components
168 * which have been registered during the active life time of the SCR
169 * implementation bundle.
Richard S. Hall323d9712006-09-22 18:55:50 +0000170 */
Guillaume Nodetd767b212013-08-02 13:22:32 +0000171 public void doStop() throws Exception
Richard S. Hall323d9712006-09-22 18:55:50 +0000172 {
Guillaume Nodetd767b212013-08-02 13:22:32 +0000173 // stop tracking
174 super.doStop();
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000175
Felix Meschberger689e5f42009-07-28 14:06:58 +0000176 // dispose component registry
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000177 m_componentRegistry.dispose();
Felix Meschbergerd468b352007-05-15 10:38:24 +0000178
Felix Meschbergerf7dfd272009-10-30 17:26:25 +0000179 // terminate the actor thread
Felix Meschbergerd468b352007-05-15 10:38:24 +0000180 if ( m_componentActor != null )
181 {
Felix Meschbergerd468b352007-05-15 10:38:24 +0000182 m_componentActor.terminate();
Felix Meschbergerf7dfd272009-10-30 17:26:25 +0000183 m_componentActor = null;
Felix Meschbergerd468b352007-05-15 10:38:24 +0000184 }
Felix Meschberger08aaff62010-08-05 13:26:31 +0000185
186 // close the LogService tracker now
187 if ( m_logService != null )
188 {
189 m_logService.close();
190 m_logService = null;
191 }
192
193 // close the PackageAdmin tracker now
194 if ( m_packageAdmin != null )
195 {
196 m_packageAdmin.close();
197 m_packageAdmin = null;
198 }
199
200 // remove the reference to the component context
201 m_context = null;
Richard S. Hall323d9712006-09-22 18:55:50 +0000202 }
203
Felix Meschberger29e04e32007-08-30 14:53:12 +0000204
Felix Meschbergerc90e3162007-03-28 14:34:01 +0000205 //---------- Component Management -----------------------------------------
Richard S. Hall323d9712006-09-22 18:55:50 +0000206
Guillaume Nodetd767b212013-08-02 13:22:32 +0000207
208 @Override
209 protected Extension doCreateExtension(final Bundle bundle) throws Exception
Richard S. Hall323d9712006-09-22 18:55:50 +0000210 {
Guillaume Nodet6574df22013-11-13 07:42:20 +0000211 return new ScrExtension(bundle);
212 }
Richard S. Hall323d9712006-09-22 18:55:50 +0000213
Guillaume Nodet6574df22013-11-13 07:42:20 +0000214 protected class ScrExtension implements Extension {
215
216 private final Bundle bundle;
217 private final CountDownLatch started;
218
219 public ScrExtension(Bundle bundle) {
220 this.bundle = bundle;
221 this.started = new CountDownLatch(1);
222 }
223
224 public void start() {
225 try {
226 loadComponents( ScrExtension.this.bundle );
227 } finally {
228 started.countDown();
Guillaume Nodetd767b212013-08-02 13:22:32 +0000229 }
Guillaume Nodet6574df22013-11-13 07:42:20 +0000230 }
231
232 public void destroy() {
233 try {
Guillaume Nodet36518142013-11-20 09:17:46 +0000234 this.started.await(m_configuration.stopTimeout(), TimeUnit.MILLISECONDS);
Guillaume Nodet6574df22013-11-13 07:42:20 +0000235 } catch (InterruptedException e) {
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000236 log( LogService.LOG_WARNING, m_bundle, "The wait for bundle {0}/{1} being started before destruction has been interrupted.",
Guillaume Nodet6574df22013-11-13 07:42:20 +0000237 new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, e );
238 }
239 disposeComponents( this.bundle );
240 }
Guillaume Nodetd767b212013-08-02 13:22:32 +0000241 }
Felix Meschberger29e04e32007-08-30 14:53:12 +0000242
Richard S. Hall323d9712006-09-22 18:55:50 +0000243 /**
244 * Loads the components of the given bundle. If the bundle has no
245 * <i>Service-Component</i> header, this method has no effect. The
246 * fragments of a bundle are not checked for the header (112.4.1).
247 * <p>
Felix Meschbergera4b12bd2012-05-31 13:06:30 +0000248 * This method calls the {@link Bundle#getBundleContext()} method to find
Richard S. Hall323d9712006-09-22 18:55:50 +0000249 * the <code>BundleContext</code> of the bundle. If the context cannot be
250 * found, this method does not load components for the bundle.
251 */
Felix Meschberger29e04e32007-08-30 14:53:12 +0000252 private void loadComponents( Bundle bundle )
Richard S. Hall323d9712006-09-22 18:55:50 +0000253 {
Felix Meschberger29e04e32007-08-30 14:53:12 +0000254 if ( bundle.getHeaders().get( "Service-Component" ) == null )
Richard S. Hall323d9712006-09-22 18:55:50 +0000255 {
256 // no components in the bundle, abandon
257 return;
258 }
259
260 // there should be components, load them with a bundle context
Felix Meschberger8a8c6332009-10-29 13:48:37 +0000261 BundleContext context = bundle.getBundleContext();
Felix Meschberger29e04e32007-08-30 14:53:12 +0000262 if ( context == null )
Richard S. Hall323d9712006-09-22 18:55:50 +0000263 {
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000264 log( LogService.LOG_ERROR, m_bundle, "Cannot get BundleContext of bundle {0}/{1}",
David Jencks77ef1fc2013-08-19 23:10:49 +0000265 new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, null );
Richard S. Hall323d9712006-09-22 18:55:50 +0000266 return;
267 }
268
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000269 // FELIX-1666 method is called for the LAZY_ACTIVATION event and
270 // the started event. Both events cause this method to be called;
271 // so we have to make sure to not load components twice
272 // FELIX-2231 Mark bundle loaded early to prevent concurrent loading
273 // if LAZY_ACTIVATION and STARTED event are fired at the same time
274 final boolean loaded;
David Jenckseeb03d22012-11-29 23:53:21 +0000275 final Long bundleId = bundle.getBundleId();
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000276 synchronized ( m_componentBundles )
277 {
278 if ( m_componentBundles.containsKey( bundleId ) )
279 {
280 loaded = true;
281 }
282 else
283 {
David Jenckseeb03d22012-11-29 23:53:21 +0000284 m_componentBundles.put( bundleId, null );
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000285 loaded = false;
286 }
287 }
288
289 // terminate if already loaded (or currently being loaded)
290 if ( loaded )
291 {
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000292 log( LogService.LOG_DEBUG, m_bundle, "Components for bundle {0}/{1} already loaded. Nothing to do.",
David Jencks77ef1fc2013-08-19 23:10:49 +0000293 new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, null );
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000294 return;
295 }
296
Richard S. Hall323d9712006-09-22 18:55:50 +0000297 try
298 {
Felix Meschberger29e04e32007-08-30 14:53:12 +0000299 BundleComponentActivator ga = new BundleComponentActivator( m_componentRegistry, m_componentActor, context,
Felix Meschberger2136bed2009-11-26 10:08:12 +0000300 m_configuration );
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000301
302 // replace bundle activator in the map
303 synchronized ( m_componentBundles )
304 {
305 m_componentBundles.put( bundleId, ga );
306 }
Richard S. Hall323d9712006-09-22 18:55:50 +0000307 }
Felix Meschberger29e04e32007-08-30 14:53:12 +0000308 catch ( Exception e )
Richard S. Hall323d9712006-09-22 18:55:50 +0000309 {
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000310 // remove the bundle id from the bundles map to ensure it is
311 // not marked as being loaded
312 synchronized ( m_componentBundles )
313 {
314 m_componentBundles.remove( bundleId );
315 }
316
Felix Meschbergerf9b73362008-08-25 06:58:56 +0000317 if ( e instanceof IllegalStateException && bundle.getState() != Bundle.ACTIVE )
318 {
319 log(
Felix Meschberger9cb29722011-02-03 22:50:27 +0000320 LogService.LOG_DEBUG,
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000321 m_bundle,
David Jencks77ef1fc2013-08-19 23:10:49 +0000322 "Bundle {0}/{1} has been stopped while trying to activate its components. Trying again when the bundles gets started again.",
323 new Object[] {bundle.getSymbolicName(), bundle.getBundleId()},
Felix Meschbergerf9b73362008-08-25 06:58:56 +0000324 e );
325 }
326 else
327 {
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000328 log( LogService.LOG_ERROR, m_bundle, "Error while loading components of bundle {0}/{1}",
David Jencks77ef1fc2013-08-19 23:10:49 +0000329 new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, e );
Felix Meschbergerf9b73362008-08-25 06:58:56 +0000330 }
Richard S. Hall323d9712006-09-22 18:55:50 +0000331 }
332 }
333
Felix Meschberger29e04e32007-08-30 14:53:12 +0000334
Richard S. Hall323d9712006-09-22 18:55:50 +0000335 /**
336 * Unloads components of the given bundle. If no components have been loaded
337 * for the bundle, this method has no effect.
338 */
Felix Meschberger29e04e32007-08-30 14:53:12 +0000339 private void disposeComponents( Bundle bundle )
Richard S. Hall323d9712006-09-22 18:55:50 +0000340 {
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000341 final Object ga;
342 synchronized ( m_componentBundles )
343 {
David Jenckseeb03d22012-11-29 23:53:21 +0000344 ga = m_componentBundles.remove( bundle.getBundleId() );
Felix Meschberger99d5fba2010-03-24 09:22:39 +0000345 }
346
Guillaume Nodetd767b212013-08-02 13:22:32 +0000347 if ( ga != null )
Richard S. Hall323d9712006-09-22 18:55:50 +0000348 {
349 try
350 {
Guillaume Nodetd767b212013-08-02 13:22:32 +0000351 int reason = isStopping()
352 ? ComponentConstants.DEACTIVATION_REASON_DISPOSED
353 : ComponentConstants.DEACTIVATION_REASON_BUNDLE_STOPPED;
354 ( ( BundleComponentActivator ) ga ).dispose( reason );
Richard S. Hall323d9712006-09-22 18:55:50 +0000355 }
Felix Meschberger29e04e32007-08-30 14:53:12 +0000356 catch ( Exception e )
Richard S. Hall323d9712006-09-22 18:55:50 +0000357 {
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000358 log( LogService.LOG_ERROR, m_bundle, "Error while disposing components of bundle {0}/{1}",
David Jencks77ef1fc2013-08-19 23:10:49 +0000359 new Object[] {bundle.getSymbolicName(), bundle.getBundleId()}, e );
Richard S. Hall323d9712006-09-22 18:55:50 +0000360 }
361 }
362 }
363
Guillaume Nodetd767b212013-08-02 13:22:32 +0000364 @Override
365 protected void debug(Bundle bundle, String msg) {
366 log( LogService.LOG_DEBUG, bundle, msg, null );
Richard S. Hall323d9712006-09-22 18:55:50 +0000367 }
368
Guillaume Nodetd767b212013-08-02 13:22:32 +0000369 @Override
370 protected void warn(Bundle bundle, String msg, Throwable t) {
371 log( LogService.LOG_WARNING, bundle, msg, t );
372 }
373
374 @Override
375 protected void error(String msg, Throwable t) {
Guillaume Nodet2241a5f2013-11-20 10:10:20 +0000376 log( LogService.LOG_DEBUG, m_bundle, msg, t );
Guillaume Nodetd767b212013-08-02 13:22:32 +0000377 }
Felix Meschberger29e04e32007-08-30 14:53:12 +0000378
David Jencks77ef1fc2013-08-19 23:10:49 +0000379 public static void log( int level, Bundle bundle, String pattern, Object[] arguments, Throwable ex )
380 {
381 if ( isLogEnabled( level ) )
382 {
383 final String message = MessageFormat.format( pattern, arguments );
384 log( level, bundle, message, ex );
385 }
386 }
387
388 /**
389 * Returns <code>true</code> if logging for the given level is enabled.
390 */
391 public static boolean isLogEnabled( int level )
392 {
David Jencks2d3a00a2014-04-27 06:58:04 +0000393 return m_configuration == null || m_configuration.getLogLevel() >= level;
David Jencks77ef1fc2013-08-19 23:10:49 +0000394 }
395
Felix Meschbergerd468b352007-05-15 10:38:24 +0000396 /**
397 * Method to actually emit the log message. If the LogService is available,
398 * the message will be logged through the LogService. Otherwise the message
399 * is logged to stdout (or stderr in case of LOG_ERROR level messages),
Felix Meschbergerd25a63d2007-11-23 13:02:49 +0000400 *
Felix Meschbergerd468b352007-05-15 10:38:24 +0000401 * @param level The log level to log the message at
402 * @param message The message to log
403 * @param ex An optional <code>Throwable</code> whose stack trace is written,
404 * or <code>null</code> to not log a stack trace.
405 */
Felix Meschberger689e5f42009-07-28 14:06:58 +0000406 public static void log( int level, Bundle bundle, String message, Throwable ex )
Felix Meschbergerd468b352007-05-15 10:38:24 +0000407 {
David Jencks77ef1fc2013-08-19 23:10:49 +0000408 if ( isLogEnabled( level ) )
Felix Meschbergerd468b352007-05-15 10:38:24 +0000409 {
David Jencks88cf57e2012-10-25 17:59:55 +0000410 ServiceTracker t = m_logService;
411 Object logger = ( t != null ) ? t.getService() : null;
Felix Meschberger29e04e32007-08-30 14:53:12 +0000412 if ( logger == null )
Felix Meschbergerd468b352007-05-15 10:38:24 +0000413 {
Felix Meschberger29e04e32007-08-30 14:53:12 +0000414 // output depending on level
415 PrintStream out = ( level == LogService.LOG_ERROR ) ? System.err : System.out;
416
417 // level as a string
418 StringBuffer buf = new StringBuffer();
419 switch ( level )
420 {
421 case ( LogService.LOG_DEBUG ):
422 buf.append( "DEBUG: " );
423 break;
424 case ( LogService.LOG_INFO ):
425 buf.append( "INFO : " );
426 break;
427 case ( LogService.LOG_WARNING ):
428 buf.append( "WARN : " );
429 break;
430 case ( LogService.LOG_ERROR ):
431 buf.append( "ERROR: " );
432 break;
433 default:
434 buf.append( "UNK : " );
435 break;
436 }
437
438 // bundle information
439 if ( bundle != null )
440 {
441 buf.append( bundle.getSymbolicName() );
442 buf.append( " (" );
443 buf.append( bundle.getBundleId() );
444 buf.append( "): " );
445 }
446
447 // the message
448 buf.append( message );
449
450 // keep the message and the stacktrace together
451 synchronized ( out)
452 {
453 out.println( buf );
454 if ( ex != null )
455 {
456 ex.printStackTrace( out );
457 }
458 }
Felix Meschbergerd468b352007-05-15 10:38:24 +0000459 }
Felix Meschberger29e04e32007-08-30 14:53:12 +0000460 else
461 {
462 ( ( LogService ) logger ).log( level, message, ex );
463 }
Felix Meschbergerd468b352007-05-15 10:38:24 +0000464 }
Richard S. Hall323d9712006-09-22 18:55:50 +0000465 }
Felix Meschberger08aaff62010-08-05 13:26:31 +0000466
467
468 public static Object getPackageAdmin()
469 {
470 if ( m_packageAdmin == null )
471 {
472 synchronized ( Activator.class )
473 {
474 if ( m_packageAdmin == null )
475 {
476 m_packageAdmin = new ServiceTracker( m_context, PACKAGEADMIN_CLASS, null );
477 m_packageAdmin.open();
478 }
479 }
480 }
481
482 return m_packageAdmin.getService();
483 }
Richard S. Hall7bd86ce2006-09-06 19:04:29 +0000484}