001: // ***************************************************************
002: // * *
003: // * File:ServiceContextImpl.java *
004: // * *
005: // * Copyright (c) 2002 Sun Microsystems, Inc. *
006: // * All rights reserved. *
007: // * *
008: // * *
009: // * Date - Jul/16/2002 *
010: // * Author - alejandro.abdelnur@sun.com *
011: // * *
012: // ***************************************************************
013:
014: package com.sun.portal.common.service.impl;
015:
016: import java.util.Iterator;
017: import java.util.Map;
018: import java.util.HashMap;
019: import java.util.Set;
020: import java.util.Collections;
021: import java.util.logging.Level;
022: import java.util.logging.Logger;
023:
024: import com.sun.portal.common.service.ServiceContext;
025: import com.sun.portal.common.service.Service;
026: import com.sun.portal.common.service.ServiceConfig;
027: import com.sun.portal.common.service.ServiceException;
028:
029: import com.sun.portal.common.util.TimeBoundRunnable;
030: import com.sun.portal.common.util.TimeBoundRunnableException;
031: import com.sun.portal.common.util.TimeBoundExecutor;
032: import com.sun.portal.common.util.TimeoutException;
033:
034: import com.sun.portal.log.common.PortalLogger;
035:
036: /**
037: * Defines a set of methods that a services uses to communicate with
038: * its service container.
039: * <P>
040: * A ServiceContext groups a set of services.
041: * <P>
042: * The ServiceContext object is contained within the ServiceConfig
043: * object, which the service container provides the service when the
044: * service is initialized.
045: *
046: * @author <A HREF="mailto:tucu@sun.com">Alejandro Abdelnur</A>
047: *
048: */
049: public class ServiceContextImpl implements ServiceContext {
050: public static final int EXCO_OFFSET = 100;
051: public static final int EXCO_SERVICE_INIT = EXCO_OFFSET + 0;
052: public static final int EXCO_SERVICE_INIT_EXCEPTION = EXCO_OFFSET + 1;
053: public static final int EXCO_SERVICE_INIT_TIMEOUT = EXCO_OFFSET + 2;
054: public static final int EXCO_SERVICE_DESTROY = EXCO_OFFSET + 3;
055: public static final int EXCO_SERVICE_DESTROY_EXCEPTION = EXCO_OFFSET + 4;
056: public static final int EXCO_SERVICE_DESTROY_TIMEOUT = EXCO_OFFSET + 5;
057:
058: private String _contextName;
059: private Map _initParams;
060: private Set _initParamNames;
061: private Map _attributes;
062: private Set _attributeNames;
063: private ServiceData[] _servicesData;
064: private Map _services;
065: private static Logger _logger = PortalLogger
066: .getLogger(ServiceContextImpl.class);
067:
068: // used by the ServiceContainerImpl to store the info read from the DD
069: //
070: static class ServiceData {
071: private String _name;
072: private String _className;
073: private Map _initParams;
074: private int _initTimeout;
075: private int _destroyTimeout;
076:
077: public ServiceData(String name, String className,
078: Map initParams, int initTimeout, int destroyTimeout) {
079: _name = name;
080: _className = className;
081: _initParams = initParams;
082: _initTimeout = initTimeout;
083: _destroyTimeout = destroyTimeout;
084: }
085: }
086:
087: /**
088: * Creates a ServiceContext object.
089: * <P>
090: *
091: * @param initParams Map containing all the context initialization
092: * parameters
093: *
094: * @param servicesData array containing all the information necessary
095: * to manage the defined services.
096: *
097: */
098: ServiceContextImpl(String name, Map initParams,
099: ServiceData[] servicesData) {
100: _contextName = name;
101: _initParams = initParams;
102: _initParamNames = Collections.unmodifiableSet(_initParams
103: .keySet());
104: _attributes = Collections.synchronizedMap(new HashMap());
105: _attributeNames = Collections.unmodifiableSet(_attributes
106: .keySet());
107: _servicesData = servicesData;
108: }
109:
110: // This TimeBoundRunnable allows a timeout when initializing services.
111: // Useful when a service stales during initialization to avoid the
112: // system from halting.
113: private class ServiceInitTimeBoundRunner implements
114: TimeBoundRunnable {
115: private Service _service;
116: private ServiceConfig _config;
117:
118: public ServiceInitTimeBoundRunner(Service service,
119: ServiceConfig config) {
120: _service = service;
121: _config = config;
122: }
123:
124: public void run() throws TimeBoundRunnableException {
125: try {
126: _service.init(_config);
127: } catch (Exception ex) {
128: throw new TimeBoundRunnableException(ex);
129: }
130: }
131:
132: }
133:
134: /**
135: * Initializes all the services specified in the constructor.
136: * <P>
137: *
138: * @throws ServiceException if any of the services fails the initialization
139: *
140: */
141: synchronized void init() throws ServiceException {
142: if (getLogger().isLoggable(Level.FINER)) {
143: getLogger().finer(
144: "ServiceContext[" + _contextName
145: + "], initializing");
146: }
147:
148: _services = new HashMap();
149: for (int i = 1; i < _servicesData.length; i++) {
150: String name = _servicesData[i]._name;
151: Service service = initService(_servicesData[i], false);
152: _services.put(name, service);
153: }
154:
155: if (getLogger().isLoggable(Level.INFO)) {
156: getLogger()
157: .info(
158: "ServiceContext[" + _contextName
159: + "], initialized");
160: }
161: }
162:
163: /**
164: * Initializes a service, if service is logger does not log.
165: */
166: private Service initService(ServiceData serviceData,
167: boolean isLogger) throws ServiceException {
168: TimeBoundExecutor tbExecutor = new TimeBoundExecutor();
169: Service service = null;
170: String name = serviceData._name;
171: try {
172: if (!isLogger && getLogger().isLoggable(Level.FINEST)) {
173: getLogger().log(Level.FINEST,
174: "Service[" + name + "], initializing");
175: }
176: Class clazz = Class.forName(serviceData._className);
177: service = (Service) clazz.newInstance();
178: ServiceConfig serviceConfig = new ServiceConfigImpl(name,
179: this , serviceData._initParams);
180:
181: ServiceInitTimeBoundRunner runner = new ServiceInitTimeBoundRunner(
182: service, serviceConfig);
183: tbExecutor.run(runner, serviceData._initTimeout);
184:
185: if (!isLogger && getLogger().isLoggable(Level.FINER)) {
186: getLogger().log(Level.FINER,
187: "Service[" + name + "], initialized");
188: }
189:
190: } catch (TimeoutException tex) {
191: String msg = "Service[" + name
192: + "] initialization timed out";
193: if (!isLogger) {
194: getLogger().log(Level.SEVERE, msg, tex);
195: }
196: throw new ServiceException(EXCO_SERVICE_INIT_TIMEOUT,
197: "Service[" + name + "]", tex);
198: } catch (TimeBoundRunnableException tbrex) {
199: Throwable t = tbrex.getCause();
200: String msg = "Service[" + name + "] initialization failed";
201: if (!isLogger) {
202: getLogger().log(Level.SEVERE, msg, t);
203: }
204: if (t instanceof ServiceException) {
205: throw (ServiceException) t;
206: } else {
207: throw new ServiceException(EXCO_SERVICE_INIT_EXCEPTION,
208: "Service[" + name + "]", t);
209: }
210: } catch (Exception ex) {
211: String msg = "Service[" + name + "] instantiation failed";
212: if (!isLogger) {
213: getLogger().log(Level.SEVERE, msg, ex);
214: }
215: destroy();
216: throw new ServiceException(EXCO_SERVICE_INIT, msg, ex);
217: }
218: tbExecutor.destroy();
219: return service;
220: }
221:
222: // This TimeBoundRunnable allows a timeout when destroying services.
223: // Useful when a service stales during destruction to avoid the
224: // system from halting.
225: private class ServiceDestroyTimeBoundRunner implements
226: TimeBoundRunnable {
227: private Service _service;
228:
229: public ServiceDestroyTimeBoundRunner(Service service) {
230: _service = service;
231: }
232:
233: public void run() throws TimeBoundRunnableException {
234: String name = null;
235: try {
236: name = _service.getConfig().getServiceName();
237: _service.destroy();
238: } catch (Exception ex) {
239: throw new TimeBoundRunnableException(ex);
240: }
241: }
242: }
243:
244: /**
245: * Destroys all the services in the context.
246: * <P>
247: *
248: */
249: synchronized void destroy() {
250: if (getLogger().isLoggable(Level.FINER)) {
251: getLogger().finer(
252: "ServiceContext[" + _contextName + "], destroying");
253: }
254:
255: for (int i = _servicesData.length - 1; i >= 1; i--) {
256: String name = _servicesData[i]._name;
257: Service service = (Service) _services.get(name);
258: destroyService(_servicesData[i], service, false);
259: }
260: _services = null;
261:
262: if (getLogger().isLoggable(Level.INFO)) {
263: getLogger().info(
264: "ServiceContext[" + _contextName + "], destroyed");
265: }
266: }
267:
268: /**
269: * Destroys a service, if service is logger does not log.
270: */
271: private void destroyService(ServiceData serviceData,
272: Service service, boolean isLogger) {
273: String name = serviceData._name;
274: TimeBoundExecutor tbExecutor = new TimeBoundExecutor();
275: try {
276: if (!isLogger && getLogger().isLoggable(Level.FINEST)) {
277: getLogger().log(Level.FINEST,
278: "Service[" + name + "], destroying");
279: }
280:
281: ServiceDestroyTimeBoundRunner runner = new ServiceDestroyTimeBoundRunner(
282: service);
283: tbExecutor.run(runner, serviceData._destroyTimeout);
284:
285: if (!isLogger && getLogger().isLoggable(Level.FINER)) {
286: getLogger().log(Level.FINER,
287: "Service[" + name + "], destroyed");
288: }
289:
290: } catch (TimeoutException tex) {
291: if (!isLogger) {
292: String msg = "Service[" + name
293: + "] destruction timed out";
294: getLogger().log(Level.SEVERE, msg, tex);
295: }
296: } catch (TimeBoundRunnableException tbrex) {
297: if (!isLogger) {
298: Throwable t = tbrex.getCause();
299: String msg = "Service[" + name + "] destruction failed";
300: getLogger().log(Level.SEVERE, msg, t);
301: }
302: } catch (Exception ex) {
303: if (!isLogger) {
304: String msg = "Service[" + name + "] destruction failed";
305: getLogger().log(Level.SEVERE, msg, ex);
306: }
307: }
308: tbExecutor.destroy();
309: }
310:
311: /**
312: * Returns a service from a ServiceContext.
313: * <P>
314: *
315: * @param name a String with the name ofthe service to retrieve
316: *
317: * @return the service with the specified name or null if the
318: * service does not exist
319: *
320: */
321: public Service getService(String name) {
322: return (Service) _services.get(name);
323: }
324:
325: /**
326: * Returns a String containing the value of the named context-wide
327: * initialization parameter, or null if the parameter does not exist.
328: * <P>
329: *
330: * @param name a String containing the name of the parameter whose
331: * value is requested
332: *
333: * @return a String containing at value of the specified parameter
334: *
335: */
336: public String getInitParameter(String name) {
337: return (String) _initParams.get(name);
338: }
339:
340: /**
341: * Returns the names of the context's initialization parameters as
342: * an Iterator of String objects, or an empty Iterator if the context
343: * has no initialization parameters.
344: * <P>
345: *
346: * @return an Iterator of String objects containing the names of the
347: * context's initialization parameters
348: *
349: */
350: public Iterator getInitParameterNames() {
351: return _initParamNames.iterator();
352: }
353:
354: /**
355: * Returns an Iterator containing the attribute names available within
356: * this service context. Use the getAttribute(java.lang.String) method
357: * with an attribute name to get the value of an attribute.
358: * <P>
359: *
360: * @return an Iterator of attribute names
361: *
362: */
363: public Iterator getAttributeNames() {
364: return _attributeNames.iterator();
365: }
366:
367: /**
368: * Returns the service container attribute with the given name, or null
369: * if there is no attribute by that name.
370: * <P>
371: *
372: * @param name a String specifying the name of the attribute
373: *
374: * @return an Object containing the value of the attribute, or null
375: * if no attribute exists matching the given name
376: *
377: */
378: public Object getAttribute(String name) {
379: return _attributes.get(name);
380: }
381:
382: /**
383: * Removes the attribute with the given name from the service context.
384: * After removal, subsequent calls to getAttribute(java.lang.String)
385: * to retrieve the attribute's value will return null.
386: * <P>
387: *
388: * @param name a String specifying the name of the attribute
389: *
390: */
391: public void removeAttribute(String name) {
392: _attributes.remove(name);
393: }
394:
395: /**
396: * Binds an object to a given attribute name in this service context.
397: * If the name specified is already used for an attribute, this method
398: * will replace the attribute with the new to the new attribute.
399: * <P>
400: *
401: * @param name a String specifying the name of the attribute
402: *
403: * @return value an Object representing the attribute to be bound
404: *
405: */
406: public void setAttribute(String name, Object value) {
407: _attributes.put(name, value);
408: }
409:
410: /**
411: * Returns the context's logger object.
412: * <P>
413: *
414: * @return the Logger object associated with the context.
415: *
416: *
417: */
418: public Logger getLogger() {
419: return _logger;
420: }
421:
422: }
|