Package: StartupTracker

StartupTracker

nameinstructionbranchcomplexitylinemethod
StartupTracker(BundleContext, KernelConfiguration, int, BundleStartTracker, Shutdown, DumpGenerator)
M: 6 C: 30
83%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 6
100%
M: 0 C: 1
100%
registerKernelStatusMBean()
M: 13 C: 18
58%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 1 C: 5
83%
M: 0 C: 1
100%
start()
M: 6 C: 6
50%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 3
100%
M: 0 C: 1
100%
static {...}
M: 0 C: 4
100%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
M: 0 C: 1
100%
stop()
M: 6 C: 3
33%
M: 0 C: 0
100%
M: 0 C: 1
100%
M: 0 C: 2
100%
M: 0 C: 1
100%
unregisterKernelStatusMBean()
M: 13 C: 19
59%
M: 2 C: 2
50%
M: 2 C: 1
33%
M: 1 C: 6
86%
M: 0 C: 1
100%

Coverage

1: /*******************************************************************************
2: * Copyright (c) 2008, 2010 VMware Inc.
3: * All rights reserved. This program and the accompanying materials
4: * are made available under the terms of the Eclipse Public License v1.0
5: * which accompanies this distribution, and is available at
6: * http://www.eclipse.org/legal/epl-v10.html
7: *
8: * Contributors:
9: * VMware Inc. - initial contribution
10: *******************************************************************************/
11:
12: package org.eclipse.virgo.nano.core.internal;
13:
14: import java.lang.management.ManagementFactory;
15: import java.util.Map;
16: import java.util.concurrent.TimeUnit;
17:
18: import javax.management.JMException;
19: import javax.management.MBeanServer;
20: import javax.management.ObjectInstance;
21: import javax.management.ObjectName;
22:
23: import org.eclipse.virgo.nano.config.internal.KernelConfiguration;
24: import org.eclipse.virgo.nano.core.BlockingAbortableSignal;
25: import org.eclipse.virgo.nano.core.BundleUtils;
26: import org.eclipse.virgo.nano.core.FailureSignalledException;
27: import org.eclipse.virgo.nano.core.FatalKernelException;
28: import org.eclipse.virgo.nano.core.Shutdown;
29: import org.eclipse.virgo.nano.diagnostics.KernelLogEvents;
30: import org.eclipse.virgo.medic.dump.DumpGenerator;
31: import org.eclipse.virgo.medic.eventlog.EventLogger;
32: import org.osgi.framework.Bundle;
33: import org.osgi.framework.BundleContext;
34: import org.osgi.framework.ServiceReference;
35: import org.osgi.service.event.Event;
36: import org.osgi.service.event.EventAdmin;
37: import org.slf4j.Logger;
38: import org.slf4j.LoggerFactory;
39:
40: /**
41: * <code>StartupTracker</code> tracks the startup of the Kernel and produces event log entries, and
42: * {@link EventAdmin} events as the kernel starts.
43: * <p />
44: *
45: * <strong>Concurrent Semantics</strong><br />
46: *
47: * Thread-safe.
48: *
49: */
50: final class StartupTracker {
51:
52: private static final String THREAD_NAME_STARTUP_TRACKER = "startup-tracker";
53:
54:         static final String APPLICATION_CONTEXT_FILTER = "(objectClass=org.springframework.context.ApplicationContext)";
55:
56: private static final String KERNEL_EVENT_TOPIC = "org/eclipse/virgo/kernel/";
57:
58: private static final String KERNEL_EVENT_STARTING = KERNEL_EVENT_TOPIC + "STARTING";
59:
60: private static final String KERNEL_EVENT_STARTED = KERNEL_EVENT_TOPIC + "STARTED";
61:
62: private static final String KERNEL_EVENT_START_TIMED_OUT = KERNEL_EVENT_TOPIC + "START_TIMED_OUT";
63:
64: private static final String KERNEL_EVENT_START_ABORTED = KERNEL_EVENT_TOPIC + "START_ABORTED";
65:
66: private static final String KERNEL_EVENT_START_FAILED = KERNEL_EVENT_TOPIC + "START_FAILED";
67:
68: private static final String KERNEL_BSN_PREFIX = "org.eclipse.virgo.kernel";
69:
70: private static final String NANO_CORE_BSN_PREFIX = "org.eclipse.virgo.nano.core";
71:
72: private static final String NANO_AUTH_BSN_PREFIX = "org.eclipse.virgo.nano.authentication";
73:
74: private static final Logger LOGGER = LoggerFactory.getLogger(StartupTracker.class);
75:
76: private final KernelStatus status = new KernelStatus();
77:
78: private final KernelConfiguration configuration;
79:
80: private final Thread startupTrackingThread;
81:
82: private volatile ObjectInstance statusInstance;
83:
84: StartupTracker(BundleContext context, KernelConfiguration configuration, int startupWaitTime, BundleStartTracker asyncBundleStartTracker, Shutdown shutdown, DumpGenerator dumpGenerator) {
85:         Runnable startupTrackingRunnable = new StartupTrackingRunnable(context, startupWaitTime, asyncBundleStartTracker, this.status, shutdown, dumpGenerator);
86: this.startupTrackingThread = new Thread(startupTrackingRunnable, THREAD_NAME_STARTUP_TRACKER);
87: this.configuration = configuration;
88: }
89:
90: void start() {
91: registerKernelStatusMBean();
92: this.startupTrackingThread.start();
93: }
94:
95: void stop() {
96: unregisterKernelStatusMBean();
97: }
98:
99: private void registerKernelStatusMBean() {
100: MBeanServer server = ManagementFactory.getPlatformMBeanServer();
101: try {
102: ObjectName name = ObjectName.getInstance(StartupTracker.this.configuration.getDomain(), "type", "KernelStatus");
103: this.statusInstance = server.registerMBean(this.status, name);
104: } catch (JMException e) {
105: throw new FatalKernelException("Unable to register KernelStatus MBean", e);
106: }
107: }
108:
109: private void unregisterKernelStatusMBean() {
110: MBeanServer server = ManagementFactory.getPlatformMBeanServer();
111: try {
112: ObjectInstance instance = this.statusInstance;
113:• if (instance != null && server.isRegistered(instance.getObjectName())) {
114: server.unregisterMBean(this.statusInstance.getObjectName());
115: }
116: } catch (JMException e) {
117: throw new FatalKernelException("Unable to unregister KernelStatus MBean", e);
118: }
119: }
120:
121: private final static class StartupTrackingRunnable implements Runnable {
122:
123: private final BundleContext context;
124:
125: private final int startupWaitTime;
126:
127: private final BundleStartTracker asyncBundleStartTracker;
128:
129: private final KernelStatus kernelStatus;
130: private final Shutdown shutdown;
131: private final DumpGenerator dumpGenerator;
132:
133: private final ServiceReferenceTracker serviceReferenceTracker;
134:
135: private EventLogger eventLogger = null;
136: private EventAdmin eventAdmin = null;
137:
138: private StartupTrackingRunnable(BundleContext context, int startupWaitTime, BundleStartTracker asyncBundleStartTracker, KernelStatus kernelStatus, Shutdown shutdown, DumpGenerator dumpGenerator) {
139: this.context = context;
140: this.startupWaitTime = startupWaitTime;
141: this.asyncBundleStartTracker = asyncBundleStartTracker;
142: this.kernelStatus = kernelStatus;
143: this.shutdown = shutdown;
144: this.dumpGenerator = dumpGenerator;
145: this.serviceReferenceTracker = new ServiceReferenceTracker(context);
146: }
147:
148: public void run() {
149: this.eventLogger = getEventLoggerService();
150: this.eventAdmin = getEventAdminService();
151:
152: try {
153: kernelStarting();
154:
155: Bundle[] bundles = this.context.getBundles();
156:
157: try {
158: long waitTime = TimeUnit.SECONDS.toMillis(this.startupWaitTime);
159:
160: for (Bundle bundle : bundles) {
161:
162: if (!BundleUtils.isFragmentBundle(bundle) && isKernelBundle(bundle)) {
163: BlockingAbortableSignal signal = new BlockingAbortableSignal();
164:
165: this.asyncBundleStartTracker.trackStart(bundle, signal);
166:
167: LOGGER.debug("Awaiting startup of bundle {} for up to {} milliseconds with signal {}.", new Object[]{bundle, waitTime, signal});
168:
169: long startTime = System.currentTimeMillis();
170: boolean bundleStarted = signal.awaitCompletion(waitTime, TimeUnit.MILLISECONDS);
171: waitTime -= System.currentTimeMillis() - startTime;
172:
173: if (!bundleStarted) {
174: if(signal.isAborted()){
175: LOGGER.error("Bundle {} aborted before the Kernel timeout of {} seconds with {} seconds remaining.", new Object[]{bundle, this.startupWaitTime, TimeUnit.MILLISECONDS.toSeconds(waitTime)});
176: kernelStartAborted(bundle);
177: } else if (waitTime <= 0) {
178: LOGGER.error("Kernel has failed to start before the timeout of {} seconds.", this.startupWaitTime);
179: kernelStartTimedOut();
180: } else {
181: LOGGER.error("Bundle {} did not start within the Kernel timeout of {} seconds.", bundle, this.startupWaitTime);
182: kernelStartTimedOut();
183: }
184: return;
185: }
186: }
187: }
188: } catch (FailureSignalledException fse) {
189: kernelStartFailed(fse.getCause());
190: return;
191: } catch (Exception e) {
192: kernelStartFailed(e);
193: return;
194: }
195:
196: kernelStarted();
197: } finally {
198: this.serviceReferenceTracker.ungetAll();
199: }
200: }
201:
202: @SuppressWarnings("unchecked")
203: private EventLogger getEventLoggerService() {
204: EventLogger eventLogger = null;
205: ServiceReference<EventLogger> eventLoggerServiceReference = (ServiceReference<EventLogger>) this.context.getServiceReference(EventLogger.class.getName());
206: if (eventLoggerServiceReference != null) {
207: eventLogger = (EventLogger) this.context.getService(this.serviceReferenceTracker.track(eventLoggerServiceReference));
208: }
209: return eventLogger;
210: }
211:
212: @SuppressWarnings("unchecked")
213: private EventAdmin getEventAdminService() {
214: EventAdmin eventAdmin = null;
215: ServiceReference<EventAdmin> eventAdminServiceReference = (ServiceReference<EventAdmin>) this.context.getServiceReference(EventAdmin.class.getName());
216: if (eventAdminServiceReference != null) {
217: eventAdmin = (EventAdmin) this.context.getService(this.serviceReferenceTracker.track(eventAdminServiceReference));
218: }
219: return eventAdmin;
220: }
221:
222: private boolean isKernelBundle(Bundle bundle) {
223:         String symbolicName = bundle.getSymbolicName();
224:                         return symbolicName != null && (symbolicName.startsWith(KERNEL_BSN_PREFIX) ||
225:                                                                                         symbolicName.startsWith(NANO_AUTH_BSN_PREFIX) ||
226:                                                                                         symbolicName.startsWith(NANO_CORE_BSN_PREFIX));
227: }
228:
229: private void kernelStarting() {
230: postEvent(KERNEL_EVENT_STARTING);
231: logEvent(KernelLogEvents.KERNEL_STARTING);
232: }
233:
234: private void kernelStarted() {
235: this.kernelStatus.setStarted();
236: postEvent(KERNEL_EVENT_STARTED);
237: logEvent(KernelLogEvents.KERNEL_STARTED);
238: }
239:
240: private void kernelStartAborted(Bundle bundle) {
241: postEvent(KERNEL_EVENT_START_ABORTED);
242: logEvent(KernelLogEvents.KERNEL_EVENT_START_ABORTED, bundle.getSymbolicName(), bundle.getVersion());
243: generateDumpAndShutdown("startupTimedOut", null);
244: }
245:
246: private void kernelStartTimedOut() {
247: postEvent(KERNEL_EVENT_START_TIMED_OUT);
248: logEvent(KernelLogEvents.KERNEL_START_TIMED_OUT, this.startupWaitTime);
249: generateDumpAndShutdown("startupTimedOut", null);
250: }
251:
252: private void kernelStartFailed(Throwable failure) {
253: postEvent(KERNEL_EVENT_START_FAILED);
254: logEvent(KernelLogEvents.KERNEL_START_FAILED, failure);
255: generateDumpAndShutdown("startupFailed", failure);
256: }
257:
258: private void generateDumpAndShutdown(String cause, Throwable failure) {
259: if (failure != null) {
260: this.dumpGenerator.generateDump(cause, failure);
261: } else {
262: this.dumpGenerator.generateDump(cause);
263: }
264: this.shutdown.immediateShutdown();
265: }
266:
267: private void logEvent(KernelLogEvents event, Throwable throwable, Object...args) {
268: if (this.eventLogger != null) {
269: this.eventLogger.log(event, throwable, args);
270: }
271: }
272:
273: private void logEvent(KernelLogEvents event, Object... args) {
274: this.logEvent(event, null, args);
275: }
276:
277: private void postEvent(String topic) {
278: if (this.eventAdmin != null) {
279: this.eventAdmin.postEvent(new Event(topic, (Map<String, ?>)null));
280: }
281: }
282: }
283: }