001: /*
002: * BEGIN_HEADER - DO NOT EDIT
003: *
004: * The contents of this file are subject to the terms
005: * of the Common Development and Distribution License
006: * (the "License"). You may not use this file except
007: * in compliance with the License.
008: *
009: * You can obtain a copy of the license at
010: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
011: * See the License for the specific language governing
012: * permissions and limitations under the License.
013: *
014: * When distributing Covered Code, include this CDDL
015: * HEADER in each file and include the License file at
016: * https://open-esb.dev.java.net/public/CDDLv1.0.html.
017: * If applicable add the following below this CDDL HEADER,
018: * with the fields enclosed by brackets "[]" replaced with
019: * your own identifying information: Portions Copyright
020: * [year] [name of copyright owner]
021: */
022:
023: /*
024: * @(#)ServiceUnitFramework.java
025: * Copyright 2004-2007 Sun Microsystems, Inc. All Rights Reserved.
026: *
027: * END_HEADER - DO NOT EDIT
028: */
029: package com.sun.jbi.framework;
030:
031: import com.sun.jbi.ServiceUnitState;
032: import com.sun.jbi.management.system.DeploymentService;
033: import com.sun.jbi.management.system.ManagementContext;
034: import com.sun.jbi.management.registry.Registry;
035:
036: import java.util.HashMap;
037: import java.util.Iterator;
038: import java.util.List;
039: import java.util.Set;
040: import java.util.logging.Logger;
041:
042: import javax.jbi.component.ServiceUnitManager;
043:
044: /**
045: * This is the implementation of the Service Unit Framework, which provides
046: * an interface to the Service Unit Manager of all components. This class is
047: * used solely by the Component Framework during startup and shutdown of
048: * components.
049: *
050: * @author Sun Microsystems, Inc.
051: */
052: public class ServiceUnitFramework {
053: /**
054: * Local handle to EnvironmentContext
055: */
056: private EnvironmentContext mContext;
057:
058: /**
059: * Local handle to ComponentRegistry
060: */
061: private ComponentRegistry mCompReg;
062:
063: /**
064: * Local handle to Logger
065: */
066: private Logger mLog;
067:
068: /**
069: * Local handle to StringTranslator
070: */
071: private StringTranslator mTranslator;
072:
073: /**
074: * Timeout limit for heuristic decision on failure limits
075: */
076: private static final int TIMEOUT_LIMIT = 3;
077:
078: /**
079: * Default timeout interval for Service Unit operations. The
080: * value is in milliseconds and is set to 2 minutes.
081: */
082: private static final long TIMEOUT_DEFAULT = 1200000;
083:
084: /**
085: * Constructor.
086: * @param env the EnvironmentContext for JBI.
087: */
088: ServiceUnitFramework(EnvironmentContext env) {
089: mContext = env;
090: mCompReg = env.getComponentRegistry();
091: mLog = env.getLogger();
092: mTranslator = (StringTranslator) env
093: .getStringTranslatorFor(this );
094: }
095:
096: /**
097: * Initialize one Service Unit for a component. After initialization, if the
098: * the desired state of this Service Unit is <CODE>SHUTDOWN</CODE>, shut
099: * down the Service Unit to reach the desired state.
100: * @param comp the Component instance for this component.
101: * @param suMgr the ServiceUnitManager instance for this component.
102: * @param su the ServiceUnit instance for this Service Unit.
103: * @throws javax.jbi.JBIException if any error occurs.
104: */
105: private void initializeServiceUnit(Component comp,
106: ServiceUnitManager suMgr, ServiceUnit su)
107: throws javax.jbi.JBIException {
108: mLog.finer("Initializing Service Unit " + su.getName()
109: + " for " + comp.getComponentTypeAsString() + " "
110: + comp.getName());
111: if (su.isStopped()) {
112: return;
113: }
114: ComponentStatistics stats = comp.getStatisticsInstance();
115: try {
116: if (stats.isEnabled()) {
117: stats.incrementInitSURequests();
118: }
119: performServiceUnitOperation(ServiceUnitOperation.INIT,
120: "init", su, suMgr, comp);
121: mLog.finer("Setting Service Unit " + su.getName()
122: + " to STOPPED state");
123: su.setStopped();
124: if (ServiceUnitState.SHUTDOWN == su.getDesiredState()) {
125: mLog.finest("Returning Service Unit " + su.getName()
126: + " to shutdown state");
127: if (stats.isEnabled()) {
128: stats.incrementShutDownSURequests();
129: }
130: performServiceUnitOperation(
131: ServiceUnitOperation.SHUTDOWN, "init", su,
132: suMgr, comp);
133: mLog.finer("Setting Service Unit " + su.getName()
134: + " to SHUTDOWN state");
135: su.setShutdown();
136: }
137: } catch (javax.jbi.JBIException ex) {
138: String m = ex.getMessage();
139: mLog.warning(mTranslator.getString(
140: LocalStringKeys.SUM_EXCEPTION, comp
141: .getComponentTypeAsString(),
142: comp.getName(), m));
143: if (!(ex.getCause() instanceof javax.jbi.JBIException)) {
144: mLog.warning(mTranslator.getString(
145: LocalStringKeys.SUM_STACK_TRACE,
146: stackTraceToString(ex)));
147: }
148: throw ex;
149: } finally {
150: persistState(su, "init");
151: }
152: }
153:
154: /**
155: * Initialize all Service Units for a component. This is required in order
156: * to ensure that a component knows about all of its Service Units after it
157: * has been shut down and restarted.
158: *
159: * Each initialization call is done under a time limit. There is the danger
160: * that a hung component could have many Service Units deployed to it, and
161: * this could result in a very long time period waiting for each of those
162: * initialization calls to time out. Therefore, a heuristic check is used
163: * here; if 3 consecutive calls time out, no more calls are made. Note
164: * that this happens only if the 3 timeouts are on consecutive calls. Each
165: * time a call completes (successfully or not) before the timeout interval
166: * expires, the timeout count is reset.
167: *
168: * @param comp the Component instance for this component.
169: */
170: void initializeServiceUnits(Component comp) {
171: // Don't allow if the component is not started
172: if (!comp.isStarted()) {
173: return;
174: }
175: mLog.finest("Initializing Service Units for "
176: + comp.getComponentTypeAsString() + " "
177: + comp.getName());
178: ServiceUnitManager suMgr = comp.getServiceUnitManager();
179: if (null == suMgr) {
180: return;
181: }
182: List sus = comp.getServiceUnitList();
183: Iterator suIter = sus.iterator();
184: int timeouts = 0;
185: while (suIter.hasNext()) {
186: try {
187: initializeServiceUnit(comp, suMgr, (ServiceUnit) suIter
188: .next());
189: } catch (Throwable ex) {
190: if (ex instanceof com.sun.jbi.framework.TimeOutException) {
191: if (++timeouts >= TIMEOUT_LIMIT) {
192: mLog.warning(mTranslator.getString(
193: LocalStringKeys.SUM_INIT_TIMEOUT_LIMIT,
194: new Long(TIMEOUT_LIMIT), comp
195: .getComponentTypeAsString(),
196: comp.getName()));
197: break;
198: }
199: } else {
200: timeouts = 0;
201: }
202: }
203: }
204: mLog.finest("Initialized Service Units for "
205: + comp.getComponentTypeAsString() + " "
206: + comp.getName());
207: }
208:
209: /**
210: * Shut down one Service Unit for a component. Any failure is just logged
211: * so as not to terminate other processing.
212: * @param comp the Component instance for this component.
213: * @param suMgr the ServiceUnitManager instance for this component.
214: * @param su the ServiceUnit instance for this Service Unit.
215: * @throws javax.jbi.JBIException if any error occurs.
216: */
217: private void shutDownServiceUnit(Component comp,
218: ServiceUnitManager suMgr, ServiceUnit su)
219: throws javax.jbi.JBIException {
220: mLog.finest("Shutting down Service Unit " + su.getName()
221: + " for " + comp.getComponentTypeAsString() + " "
222: + comp.getName());
223: if (su.isShutdown()) {
224: return;
225: }
226: ComponentStatistics stats = comp.getStatisticsInstance();
227: try {
228: if (stats.isEnabled()) {
229: stats.incrementShutDownSURequests();
230: }
231: performServiceUnitOperation(ServiceUnitOperation.SHUTDOWN,
232: "shutDown", su, suMgr, comp);
233: mLog.finer("Setting Service Unit " + su.getName()
234: + " to SHUTDOWN state");
235: su.setShutdown();
236: mContext.getNotifier().emitServiceUnitNotification(
237: EventNotifier.EventType.ShutDown,
238: su.getName(),
239: comp.getName(),
240: su.getServiceAssemblyName(),
241: mTranslator.getString(
242: LocalStringKeys.SUF_SHUT_DOWN,
243: su.getName(), comp.getName(), su
244: .getServiceAssemblyName()));
245: } catch (javax.jbi.JBIException ex) {
246: String m = ex.getMessage();
247: mLog.warning(mTranslator.getString(
248: LocalStringKeys.SUM_EXCEPTION, comp
249: .getComponentTypeAsString(),
250: comp.getName(), m));
251: if (!(ex.getCause() instanceof javax.jbi.JBIException)) {
252: mLog.warning(mTranslator.getString(
253: LocalStringKeys.SUM_STACK_TRACE,
254: stackTraceToString(ex)));
255: }
256: throw ex;
257: } finally {
258: persistState(su, "shutDown");
259: }
260: }
261:
262: /**
263: * Shut down all active Service Units for a component.
264: * @param comp the Component instance for this component.
265: */
266: void shutDownServiceUnits(Component comp) {
267: mLog.finest("Shutting down Service Units for "
268: + comp.getComponentTypeAsString() + " "
269: + comp.getName());
270: ServiceUnitManager suMgr = comp.getServiceUnitManager();
271: if (null == suMgr) {
272: return;
273: }
274: List sus = comp.getServiceUnitList();
275: Iterator suIter = sus.iterator();
276: int timeouts = 0;
277: while (suIter.hasNext()) {
278: ServiceUnit su = (ServiceUnit) suIter.next();
279: if (su.isStopped()) {
280: try {
281: shutDownServiceUnit(comp, suMgr, su);
282: } catch (Throwable ex) {
283: if (ex instanceof com.sun.jbi.framework.TimeOutException) {
284: if (++timeouts >= TIMEOUT_LIMIT) {
285: mLog
286: .warning(mTranslator
287: .getString(
288: LocalStringKeys.SUM_SHUTDOWN_TIMEOUT_LIMIT,
289: new Long(
290: TIMEOUT_LIMIT),
291: comp
292: .getComponentTypeAsString(),
293: comp.getName()));
294: break;
295: }
296: } else {
297: timeouts = 0;
298: }
299: }
300: } else {
301: mLog.finest("Skipping Service Unit " + su.getName()
302: + ": was not started");
303: }
304: }
305: mLog.finest("Shut down Service Units for "
306: + comp.getComponentTypeAsString() + " "
307: + comp.getName());
308: }
309:
310: /*
311: * Start one Service Unit for a component. Any failure is just logged
312: * so as not to terminate other processing.
313: * @param comp the Component instance for this component.
314: * @param suMgr the ServiceUnitManager instance for this component.
315: * @param su the ServiceUnit instance for this Service Unit.
316: * @throws javax.jbi.JBIException if any error occurs.
317: */
318: private void startServiceUnit(Component comp,
319: ServiceUnitManager suMgr, ServiceUnit su)
320: throws javax.jbi.JBIException {
321: mLog.finest("Starting Service Unit " + su.getName() + " for "
322: + comp.getComponentTypeAsString() + " "
323: + comp.getName());
324: ComponentStatistics stats = comp.getStatisticsInstance();
325: try {
326: if (stats.isEnabled()) {
327: stats.incrementStartSURequests();
328: }
329: performServiceUnitOperation(ServiceUnitOperation.START,
330: "start", su, suMgr, comp);
331: mLog.finer("Setting Service Unit " + su.getName()
332: + " to STARTED state");
333: su.setStarted();
334: mContext.getNotifier().emitServiceUnitNotification(
335: EventNotifier.EventType.Started,
336: su.getName(),
337: comp.getName(),
338: su.getServiceAssemblyName(),
339: mTranslator.getString(LocalStringKeys.SUF_STARTED,
340: su.getName(), comp.getName(), su
341: .getServiceAssemblyName()));
342: } catch (javax.jbi.JBIException ex) {
343: try {
344: if (stats.isEnabled()) {
345: stats.incrementShutDownSURequests();
346: }
347: performServiceUnitOperation(
348: ServiceUnitOperation.SHUTDOWN, "start", su,
349: suMgr, comp);
350: mLog.finer("Setting Service Unit " + su.getName()
351: + " to SHUTDOWN state");
352: su.setShutdown();
353: } catch (javax.jbi.JBIException e) {
354: String em = e.getMessage();
355: mLog.warning(mTranslator.getString(
356: LocalStringKeys.SUM_EXCEPTION, comp
357: .getComponentTypeAsString(), comp
358: .getName(), em));
359: if (!(e.getCause() instanceof javax.jbi.JBIException)) {
360: mLog.warning(mTranslator.getString(
361: LocalStringKeys.SUM_STACK_TRACE,
362: stackTraceToString(e)));
363: }
364: }
365: String m = ex.getMessage();
366: mLog.warning(mTranslator.getString(
367: LocalStringKeys.SUM_EXCEPTION, comp
368: .getComponentTypeAsString(),
369: comp.getName(), m));
370: if (!(ex.getCause() instanceof javax.jbi.JBIException)) {
371: mLog.warning(mTranslator.getString(
372: LocalStringKeys.SUM_STACK_TRACE,
373: stackTraceToString(ex)));
374: }
375: throw ex;
376: } finally {
377: persistState(su, "start");
378: }
379: }
380:
381: /**
382: * Start Service Units for a component, based on their desired states at
383: * the last shutdown of the component.
384: * @param comp the Component instance for this component.
385: */
386: void startServiceUnits(Component comp) {
387: // Don't allow if the component is not started
388: if (!comp.isStarted()) {
389: return;
390: }
391: mLog.finest("Starting Service Units for "
392: + comp.getComponentTypeAsString() + " "
393: + comp.getName());
394: ServiceUnitManager suMgr = comp.getServiceUnitManager();
395: if (null == suMgr) {
396: return;
397: }
398: List sus = comp.getServiceUnitList();
399: Iterator suIter = sus.iterator();
400: int timeouts = 0;
401: while (suIter.hasNext()) {
402: ServiceUnit su = (ServiceUnit) suIter.next();
403: if (ServiceUnitState.STARTED == su.getDesiredState()
404: && su.isStopped()) {
405: try {
406: startServiceUnit(comp, suMgr, su);
407: } catch (Throwable ex) {
408: if (ex instanceof com.sun.jbi.framework.TimeOutException) {
409: if (++timeouts >= TIMEOUT_LIMIT) {
410: mLog
411: .warning(mTranslator
412: .getString(
413: LocalStringKeys.SUM_START_TIMEOUT_LIMIT,
414: new Long(
415: TIMEOUT_LIMIT),
416: comp
417: .getComponentTypeAsString(),
418: comp.getName()));
419: break;
420: }
421: } else {
422: timeouts = 0;
423: }
424: }
425: } else {
426: mLog.finest("Skipping Service Unit " + su.getName()
427: + ": was not started at last shutdown");
428: }
429: }
430: mLog.finest("Started Service Units for "
431: + comp.getComponentTypeAsString() + " "
432: + comp.getName());
433: }
434:
435: /**
436: * Stop one Service Unit for a component. Any failure is just logged
437: * so as not to terminate other processing.
438: * @param comp the Component instance for this component.
439: * @param suMgr the ServiceUnitManager instance for this component.
440: * @param su the ServiceUnit instance for this Service Unit.
441: * @throws javax.jbi.JBIException if any error occurs.
442: */
443: private void stopServiceUnit(Component comp,
444: ServiceUnitManager suMgr, ServiceUnit su)
445: throws javax.jbi.JBIException {
446: mLog.finest("Stopping Service Unit " + su.getName() + " for "
447: + comp.getComponentTypeAsString() + " "
448: + comp.getName());
449: ComponentStatistics stats = comp.getStatisticsInstance();
450: try {
451: if (stats.isEnabled()) {
452: stats.incrementStopSURequests();
453: }
454: performServiceUnitOperation(ServiceUnitOperation.STOP,
455: "stop", su, suMgr, comp);
456: mLog.finer("Setting Service Unit " + su.getName()
457: + " to STOPPED state");
458: su.setStopped();
459: mContext.getNotifier().emitServiceUnitNotification(
460: EventNotifier.EventType.Stopped,
461: su.getName(),
462: comp.getName(),
463: su.getServiceAssemblyName(),
464: mTranslator.getString(LocalStringKeys.SUF_STOPPED,
465: su.getName(), comp.getName(), su
466: .getServiceAssemblyName()));
467: } catch (javax.jbi.JBIException ex) {
468: String m = ex.getMessage();
469: mLog.warning(mTranslator.getString(
470: LocalStringKeys.SUM_EXCEPTION, comp
471: .getComponentTypeAsString(),
472: comp.getName(), m));
473: if (!(ex.getCause() instanceof javax.jbi.JBIException)) {
474: mLog.warning(mTranslator.getString(
475: LocalStringKeys.SUM_STACK_TRACE,
476: stackTraceToString(ex)));
477: }
478: throw ex;
479: } finally {
480: persistState(su, "stop");
481: }
482: }
483:
484: /**
485: * Stop all active Service Units for a component, after checkpointing
486: * their states.
487: * @param comp the Component instance for this component.
488: */
489: void stopServiceUnits(Component comp) {
490: // Don't allow if the component is not started
491: if (!comp.isStarted()) {
492: return;
493: }
494: mLog.finest("Stopping Service Units for "
495: + comp.getComponentTypeAsString() + " "
496: + comp.getName());
497: ServiceUnitManager suMgr = comp.getServiceUnitManager();
498: if (null == suMgr) {
499: return;
500: }
501: List sus = comp.getServiceUnitList();
502: Iterator suIter = sus.iterator();
503: int timeouts = 0;
504: while (suIter.hasNext()) {
505: ServiceUnit su = (ServiceUnit) suIter.next();
506: if (su.isStarted()) {
507: try {
508: stopServiceUnit(comp, suMgr, su);
509: } catch (Throwable ex) {
510: if (ex instanceof com.sun.jbi.framework.TimeOutException) {
511: if (++timeouts >= TIMEOUT_LIMIT) {
512: mLog
513: .warning(mTranslator
514: .getString(
515: LocalStringKeys.SUM_STOP_TIMEOUT_LIMIT,
516: new Long(
517: TIMEOUT_LIMIT),
518: comp
519: .getComponentTypeAsString(),
520: comp.getName()));
521: break;
522: }
523: } else {
524: timeouts = 0;
525: }
526: }
527: } else {
528: mLog.finest("Skipping Service Unit " + su.getName()
529: + ": was not started");
530: }
531: }
532: mLog.finest("Stopped Service Units for "
533: + comp.getComponentTypeAsString() + " "
534: + comp.getName());
535: }
536:
537: /**
538: * Update the state of Service Assemblies. For each Service Assembly whose
539: * name is in the provided list, set the state, and also start any service
540: * connections that need to be started.
541: *
542: * @param saNames The list of Service Assembly names to update.
543: */
544: void updateServiceAssemblies(Set<String> saNames) {
545: if (saNames.isEmpty()) {
546: mLog.finer("No Service Assemblies to be updated");
547: return;
548: }
549: mLog.finer("Updating Service Assemblies...");
550: String result;
551:
552: for (String saName : saNames) {
553: mLog.finer("Updating Service Assembly " + saName + "...");
554: result = ManagementContext.getDeploymentServiceHandle()
555: .updateSAState(saName);
556: mLog.finer("Updated Service Assembly state to " + result);
557: }
558: mLog.finer("Updated Service Assemblies");
559: }
560:
561: /**
562: * Perform the specified operation on a Service Unit and wait for it to
563: * complete or time out.
564: * @param operation the operation to be performed.
565: * @param task the task being executed.
566: * @param su the Service Unit to be operated upon.
567: * @param suMgr the SU manager of the owning component.
568: * @param comp the owning Component.
569: * @throws javax.jbi.JBIException if any runtime error
570: * or timeout occurs.
571: */
572: private void performServiceUnitOperation(int operation,
573: String task, ServiceUnit su, ServiceUnitManager suMgr,
574: Component comp) throws javax.jbi.JBIException {
575: String suName = su.getName();
576: String msg;
577: Object args[] = { suName, su.getFilePath() };
578: OperationCounter oc = new OperationCounter();
579: ServiceUnitOperation suOper = new ServiceUnitOperation(oc, comp
580: .getName(), suMgr, operation, args);
581: long timeout = mContext.getServiceUnitTimeout();
582: ComponentStatistics stats = comp.getStatisticsInstance();
583:
584: new Thread(suOper, suName).start();
585: synchronized (oc) {
586: try {
587: if (0 < oc.getValue()) {
588: oc.wait(timeout);
589: }
590: } catch (java.lang.InterruptedException iEx) {
591: suOper.getThread().interrupt();
592: msg = mTranslator.getString(
593: LocalStringKeys.DMB_SU_OPERATION_INTERRUPTED,
594: task, suName);
595: throw new javax.jbi.JBIException(msg, iEx);
596: }
597: }
598: if (suOper.completed()) {
599: Throwable ex = suOper.getException();
600: if (null != ex) {
601: if (stats.isEnabled()) {
602: stats.incrementFailedSURequests();
603: }
604: if (ex instanceof javax.jbi.management.DeploymentException) {
605: throw (javax.jbi.management.DeploymentException) ex;
606: } else {
607: String exMsg = ex.getMessage();
608: if (null == exMsg) {
609: msg = mTranslator
610: .getString(
611: LocalStringKeys.DMB_SU_OPERATION_EXCEPTION_NO_MSG,
612: ex.getClass().getName(), task,
613: suName);
614: } else {
615: msg = mTranslator
616: .getString(
617: LocalStringKeys.DMB_SU_OPERATION_EXCEPTION,
618: ex.getClass().getName(), task,
619: suName, exMsg);
620: }
621: throw new javax.jbi.JBIException(msg, ex);
622: }
623: }
624: } else {
625: if (stats.isEnabled()) {
626: stats.incrementTimedOutSURequests();
627: }
628: suOper.getThread().interrupt();
629: msg = mTranslator.getString(
630: LocalStringKeys.DMB_SU_OPERATION_TIMEOUT, task,
631: suName, new Long(timeout));
632: throw new com.sun.jbi.framework.TimeOutException(msg);
633: }
634: }
635:
636: /**
637: * Force the state of an SU to be persisted after a change.
638: * @param su the SU being processed.
639: * @param task the task being executed.
640: * @deprecated
641: */
642: private void persistState(ServiceUnit su, String task) {
643: try {
644: com.sun.jbi.management.registry.Updater updater = ((Registry) mContext
645: .getRegistry()).getUpdater();
646: updater.setServiceUnitState(su.getDesiredState(), su
647: .getTargetComponent(), su.getName());
648: } catch (com.sun.jbi.management.registry.RegistryException rex) {
649: String msg = mTranslator.getString(
650: LocalStringKeys.DMB_SU_STATE_PERSIST_FAILURE, su
651: .getName(), task, rex.getMessage());
652: mLog.warning(msg);
653: }
654: }
655:
656: /**
657: * Return an exception's stack trace as a String. If the trace cannot
658: * be produced, returns an error message in the string.
659: * @param exception the exception to process.
660: * @return the stack trace for the exception.
661: */
662: private String stackTraceToString(Throwable exception) {
663: try {
664: java.io.StringWriter sw = new java.io.StringWriter();
665: java.io.PrintWriter pw = new java.io.PrintWriter(sw);
666: exception.printStackTrace(pw);
667: return sw.toString();
668: } catch (Exception ex) {
669: return mTranslator
670: .getString(LocalStringKeys.STACK_TRACE_PRINT_FAILED);
671: }
672: }
673: }
|