Java tutorial
/* * The contents of this file are subject to the Mozilla Public License Version 1.1 * (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.mozilla.org/MPL/>. * * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>, * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are * Copyright (C) 2002-03 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ package com.silverwrist.dynamo.app; import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.commons.collections.*; import org.apache.log4j.Logger; import org.w3c.dom.*; import com.silverwrist.util.*; import com.silverwrist.util.xml.*; import com.silverwrist.dynamo.DynamoVersion; import com.silverwrist.dynamo.Namespaces; import com.silverwrist.dynamo.event.*; import com.silverwrist.dynamo.except.*; import com.silverwrist.dynamo.iface.*; import com.silverwrist.dynamo.script.ScriptController; import com.silverwrist.dynamo.util.*; /** * The main "engine" class of the Dynamo framework, which holds most of the service providers and other * classes registered (usually by the defined {@link com.silverwrist.dynamo.iface.Application Application} class). * Exactly one of these is created per Dynamo instance; for Dynamo Web applications, a reference to it is saved * in the servlet context attributes. It is also responsible for reading and parsing the Dynamo XML configuration * file and instantiating components defined therein. * * @author Eric J. Bowersox <erbo@silcom.com> * @version X */ public class ApplicationContainer implements ResourceProvider, ResourceProviderManager, RendererRegistration, ObjectProvider, EventListenerRegistration, OutputObjectFilterRegistration, QueryRenderer, PostDynamicUpdate, RenderImmediate, RequestPreprocessorRegistration, ExceptionTranslatorRegistration, FinalStageRegistration { /*-------------------------------------------------------------------------------- * Internal class recording renderer registrations and providing a * "shutdown hook" *-------------------------------------------------------------------------------- */ private class RegisteredRenderer implements ComponentShutdown { /*==================================================================== * Attributes *==================================================================== */ private Renderer m_renderer; private HashSet m_known_classes; /*==================================================================== * Constructors *==================================================================== */ RegisteredRenderer(Class klass, Renderer renderer) { m_renderer = renderer; m_known_classes = new HashSet(); m_known_classes.add(klass); } // end constructor RegisteredRenderer(DynamicClass dclass, Renderer renderer) { m_renderer = renderer; m_known_classes = new HashSet(); m_known_classes.add(dclass); } // end constructor /*==================================================================== * Implementations from interface ComponentShutdown *==================================================================== */ public synchronized void shutdown() { Iterator it = m_known_classes.iterator(); while (it.hasNext()) { // remove all class rendering entries registered with this "event" Object obj = it.next(); if (obj instanceof Class) m_class_renderers.remove(obj); else if (obj instanceof DynamicClass) m_class_renderers.remove(obj); } // end while m_known_classes.clear(); } // end shutdown /*==================================================================== * External operations *==================================================================== */ public Renderer getRenderer() { return m_renderer; } // end getRenderer public synchronized void add(Class klass) { m_known_classes.add(klass); } // end add public synchronized void add(DynamicClass dclass) { m_known_classes.add(dclass); } // end add } // end class RegisteredRenderer /*-------------------------------------------------------------------------------- * Static data members *-------------------------------------------------------------------------------- */ private static Logger logger = Logger.getLogger(ApplicationContainer.class); private static final String[] SUBSTRATE_MAP_KEYS = { ApplicationSubstrate.OBJ_BASE_PATH, ApplicationSubstrate.OBJ_CODE_PATH, ApplicationSubstrate.OBJ_CLASSES_PATH, ApplicationSubstrate.OBJ_LIBS_PATH }; private static final ApplicationListener[] APP_LISTENER_TEMPLATE = new ApplicationListener[0]; private static final SessionInfoListener[] SESSION_LISTENER_TEMPLATE = new SessionInfoListener[0]; private static final String TEMPLATE_CLASSNAME = "$$$BLORT$$$"; /*-------------------------------------------------------------------------------- * Attributes *-------------------------------------------------------------------------------- */ private int m_refs; // reference count private ApplicationSubstrate m_substrate; // application substrate object private File m_resource_base; // base directory for resources private Vector m_resource_providers = new Vector(); // resource providers private LinkedList m_shutdown_list = new LinkedList(); // list of objects to shut down private HashMap m_connections = new HashMap(); // list of connection pools private HashMap m_objects = new HashMap(); // list of base objects private Application m_application = null; // the application object private Hashtable m_class_renderers = new Hashtable(); // renderers for static classes private Hashtable m_dclass_renderers = new Hashtable(); // renderers for dynamic classes private Vector m_application_listeners = new Vector(); // application event listeners private Vector m_session_listeners = new Vector(); // session event listeners private BackgroundProcessor m_background; // background processor private ScriptController m_script_ctrl; // script controller private ApplicationServiceManager m_app_sm; // application service manager private PropertySerializationSupport m_pss; // property serialization support private Set m_known_sessions; // known sessions private String m_identity; // server identity private Map m_rewrite_rules; // URL rewriting rules private Vector m_output_filters = new Vector(); // output filters private HashMap m_update_listeners = new HashMap(); // update listeners private Vector m_request_preprocessors = new Vector(); // request preprocessors private Vector m_exception_xlators = new Vector(); // exception translators private LinkedList m_final_stage_inits = new LinkedList(); // final-stage initialization hooks private LinkedList m_prestage_shutdown = new LinkedList(); // pre-stage shutdown hooks /*-------------------------------------------------------------------------------- * Constructor *-------------------------------------------------------------------------------- */ /** * Creates the application container. * * @param config_file A reference to the Dynamo XML configuration file. * @param substrate A reference to the {@link com.silverwrist.dynamo.iface.ApplicationSubstrate ApplicationSubstrate} * object, which provides certain services and object references to the * <CODE>ApplicationContainer</CODE>. (Usually, this will be specific to the Dynamo application * type, for example, Web application.) * @exception com.silverwrist.dynamo.except.ConfigException If there is an error in the configuration which will * not allow Dynamo to be initialized. */ public ApplicationContainer(File config_file, ApplicationSubstrate substrate) throws ConfigException { if (logger.isDebugEnabled()) logger.debug("new ApplicationContainer - config file is " + config_file.getAbsolutePath()); substrate.initialize(); m_substrate = substrate; m_refs = 1; m_app_sm = new ApplicationServiceManager(); m_pss = new PropertySerializationSupport(); m_known_sessions = Collections.synchronizedSet(new HashSet()); XMLLoader loader = XMLLoader.get(); // Initialize the init services and runtime services with defaults. m_app_sm.addInitService(ResourceProvider.class, (ResourceProvider) this); m_app_sm.addInitService(ResourceProviderManager.class, (ResourceProviderManager) this); m_app_sm.addInitService(RendererRegistration.class, (RendererRegistration) this); m_app_sm.addInitService(ObjectProvider.class, (ObjectProvider) this); m_app_sm.addInitService(EventListenerRegistration.class, (EventListenerRegistration) this); m_app_sm.addInitService(OutputObjectFilterRegistration.class, (OutputObjectFilterRegistration) this); m_app_sm.addInitService(PropertySerializer.class, (PropertySerializer) m_pss); m_app_sm.addInitService(PropertySerializerRegistration.class, (PropertySerializerRegistration) m_pss); m_app_sm.addInitService(PostDynamicUpdate.class, (PostDynamicUpdate) this); m_app_sm.addInitService(RequestPreprocessorRegistration.class, (RequestPreprocessorRegistration) this); m_app_sm.addInitService(ExceptionTranslatorRegistration.class, (ExceptionTranslatorRegistration) this); m_app_sm.addInitService(FinalStageRegistration.class, (FinalStageRegistration) this); m_app_sm.addRuntimeService(ResourceProvider.class, (ResourceProvider) this); m_app_sm.addRuntimeService(ObjectProvider.class, (ObjectProvider) this); m_app_sm.addRuntimeService(EventListenerRegistration.class, (EventListenerRegistration) this); m_app_sm.addRuntimeService(PropertySerializer.class, (PropertySerializer) m_pss); m_app_sm.addRuntimeService(PostDynamicUpdate.class, (PostDynamicUpdate) this); m_app_sm.addRuntimeService(RenderImmediate.class, (RenderImmediate) this); m_app_sm.addOutputService(ResourceProvider.class, (ResourceProvider) this); m_app_sm.addOutputService(ObjectProvider.class, (ObjectProvider) this); m_app_sm.addOutputService(QueryRenderer.class, (QueryRenderer) this); // Create initialization services interface object. ServiceProvider init_svcs = m_app_sm.createInitServices(); try { // load the configuration file Document config_doc = loader.load(config_file, false); Element root = loader.getRootElement(config_doc, "configuration"); // get the <control/> element and process it Element control = loader.getSubElement(root, "control"); processControlSection(control); m_shutdown_list.addFirst(m_background); m_app_sm.addInitService(BackgroundScheduler.class, m_background); m_app_sm.addRuntimeService(BackgroundScheduler.class, m_background); // initialize some default renderers m_shutdown_list.addFirst(registerRenderer(DataItem.class, new DataItemRenderer())); m_shutdown_list.addFirst(registerRenderer(java.util.List.class, new ListRenderer())); // initialize the scripting engine m_script_ctrl = new ScriptController(); m_script_ctrl.initialize(control, init_svcs); m_shutdown_list.addFirst(m_script_ctrl); // add the scripting engine's services so they can be used by external components m_app_sm.addInitService(ScriptEngineConfig.class, m_script_ctrl); m_app_sm.addRuntimeService(ScriptExecute.class, m_script_ctrl); // get all database connection configurations List l = loader.getMatchingSubElements(root, "dbconnection"); Iterator it = l.iterator(); Element elt; while (it.hasNext()) { // get each element in turn elt = (Element) (it.next()); DBConnectionPool pool = (DBConnectionPool) createNamedObject(elt, init_svcs, DBConnectionPool.class, "no.notDBPool"); m_connections.put(pool.getName(), pool); } // end while m_app_sm.addInitService(HookServiceProviders.class, m_app_sm); // Sort the "object" definitions by priority order to determine in what order to instantiate them. l = loader.getMatchingSubElements(root, "object"); if (!(l.isEmpty())) { // copy elements into binary heap it = l.iterator(); BinaryHeap prioheap = new BinaryHeap(l.size()); while (it.hasNext()) { // sort elements by priority elt = (Element) (it.next()); prioheap.insert(new HeapContents(elt)); } // end while while (prioheap.size() > 0) { // now remove and instantiate the elements HeapContents hc = (HeapContents) (prioheap.remove()); NamedObject nobj = createNamedObject(hc.getElement(), init_svcs, null, null); m_objects.put(nobj.getName(), nobj); } // end while } // end if // Find the application definition and initialize the application. elt = loader.getSubElement(root, "application"); m_application = (Application) createNamedObject(elt, init_svcs, Application.class, "no.notApp"); } // end try catch (IOException e) { // unable to read config file - send back a ConfigException logger.fatal("ApplicationContainer config read failed", e); ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "creation.ioError", e); ce.setParameter(0, config_file.getAbsolutePath()); throw ce; } // end catch catch (XMLLoadException e) { // XML loader failed - send back a ConfigException logger.fatal("ApplicationContainer config load failed", e); throw new ConfigException(e); } // end catch // Create the "server identity" string. StringBuffer buf = new StringBuffer(); String app_id = m_application.getIdentity(); if (app_id != null) buf.append(app_id).append(' '); buf.append("Dynamo/").append(DynamoVersion.VERSION); m_identity = buf.toString(); logger.info("Server: " + m_identity); try { // Call the "final stage" initialization hooks. logger.info(m_final_stage_inits.size() + " final-stage init hook(s) to call"); while (!(m_final_stage_inits.isEmpty())) { // call the hooks in FIFO order FinalStageInitHook hook = (FinalStageInitHook) (m_final_stage_inits.removeFirst()); hook.initialize(m_application, init_svcs); } // end while m_final_stage_inits = null; // done with this list } // end try catch (DynamoException e) { // final-stage initialization failed - post an error ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "finalinit.fail", e); ce.setParameter(0, e.getMessage()); throw ce; } // end catch // Fire the "application initialized" events. ApplicationListener[] listeners = (ApplicationListener[]) (m_application_listeners .toArray(APP_LISTENER_TEMPLATE)); if (listeners.length > 0) { // call the event handlers... if (logger.isDebugEnabled()) logger.debug("ApplicationContainer: " + listeners.length + " init handler(s) to call"); ApplicationEventRequest req = new ApplicationEventRequest(m_app_sm.createRuntimeServices(), true); ApplicationEvent evt = new ApplicationEvent(req, m_application); for (int i = 0; i < listeners.length; i++) listeners[i].applicationInitialized(evt); } // end if if (logger.isDebugEnabled()) logger.debug("ApplicationContainer initialization done"); } // end constructor /*-------------------------------------------------------------------------------- * Internal operations *-------------------------------------------------------------------------------- */ private static final Class getUltimateComponent(Class klass) { while (klass.isArray()) klass = klass.getComponentType(); return klass; } // end getUltimateComponent /** * Destroys all data associated with this <CODE>ApplicationContainer</CODE>. */ private final synchronized void destroy() { if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.destroy(): " + m_known_sessions.size() + " sessions to shutdown"); Iterator it = m_known_sessions.iterator(); while (it.hasNext()) { // shut down each session ComponentShutdown cs = (ComponentShutdown) (it.next()); cs.shutdown(); } // end while m_known_sessions.clear(); // Fire the "application exiting" events. ApplicationListener[] listeners = (ApplicationListener[]) (m_application_listeners .toArray(APP_LISTENER_TEMPLATE)); if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.destroy(): " + listeners.length + " exit handlers to call"); if (listeners.length > 0) { // call the event handlers... ApplicationEventRequest req = new ApplicationEventRequest(m_app_sm.createRuntimeServices(), false); ApplicationEvent evt = new ApplicationEvent(req, m_application); for (int i = 0; i < listeners.length; i++) listeners[i].applicationExiting(evt); } // end if if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.destroy(): " + m_prestage_shutdown.size() + " pre-stage shutdown hooks to call"); while (m_prestage_shutdown.size() > 0) { // call the appropriate pre-stage shutdown hooks ComponentShutdown sd = (ComponentShutdown) (m_prestage_shutdown.removeFirst()); sd.shutdown(); } // end while if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.destroy(): " + m_shutdown_list.size() + " objects to blow away"); while (m_shutdown_list.size() > 0) { // shut down all components in reverse order of creation ComponentShutdown sd = (ComponentShutdown) (m_shutdown_list.removeFirst()); sd.shutdown(); } // end while if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.destroy(): clearing internal data structures"); m_connections.clear(); m_objects.clear(); m_class_renderers.clear(); m_dclass_renderers.clear(); m_application = null; m_resource_providers.clear(); m_application_listeners.clear(); m_session_listeners.clear(); if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.destroy(): terminating substrate"); m_substrate.terminate(); m_substrate = null; } // end destroy private final Map getSubstrateReplaceMap() { HashMap rc = new HashMap(); for (int i = 0; i < SUBSTRATE_MAP_KEYS.length; i++) { // load the map with return values try { // get each object in turn from the substrate and add it to the map Object tmp = m_substrate.getObject(ApplicationSubstrate.NAMESPACE, SUBSTRATE_MAP_KEYS[i]); rc.put(SUBSTRATE_MAP_KEYS[i], tmp.toString()); } // end try catch (NoSuchObjectException e) { // skip this object and try the next one } // end catch } // end for return rc; } // end getSubstrateReplaceMap private final void processControlSection(Element control) throws ConfigException, XMLLoadException { Map replace_map = getSubstrateReplaceMap(); XMLLoader loader = XMLLoader.get(); DOMElementHelper control_h = new DOMElementHelper(control); // Get the thread counts and create the background processor. int num_norm = 2; int num_low = 2; Element elt = control_h.getSubElement("background-threads"); if (elt != null) { // read in the values num_norm = loader.getAttributeInt(elt, "normal", 2); num_low = loader.getAttributeInt(elt, "low", 2); } // end if // Create the background services and the background processor. SimpleServiceProvider bg_svcs = new SimpleServiceProvider("Background Services"); bg_svcs.addService(ResourceProvider.class, this); bg_svcs.addService(ObjectProvider.class, this); m_background = new BackgroundProcessor(num_norm, num_low, bg_svcs); // Get the resource root directory. String res_root = loader.getSubElementText(control_h, "resource-root"); m_resource_base = new File(StringUtils.replaceAllVariables(res_root, replace_map)); if (!(m_resource_base.isDirectory())) { // the resource base MUST be a directory! ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "resource.rootErr"); ce.setParameter(0, m_resource_base.getAbsolutePath()); throw ce; } // end if // Get the list of rewrite rules. Element rewrite_sect = loader.getSubElement(control_h, "url-rewrite-rules"); List rewrite_list = loader.getMatchingSubElements(rewrite_sect, "rule"); HashMap tmp_map = new HashMap(); Iterator it = rewrite_list.iterator(); while (it.hasNext()) { // get each rule and create corresponding object elt = (Element) (it.next()); RewriteRule rule = new RewriteRule(elt); tmp_map.put(rule.getName(), rule); } // end while m_rewrite_rules = Collections.unmodifiableMap(tmp_map); } // end processControlSection private final NamedObject createNamedObject(Element config_root, ServiceProvider services, Class extratest, String extratest_msg) throws ConfigException { NamedObject nobj = LoaderUtils.loadObject(config_root, services, extratest); synchronized (this) { // save its shutdown hook for later ComponentShutdown sd = (ComponentShutdown) (LoaderUtils.query(ComponentShutdown.class, nobj)); if (sd != null) m_shutdown_list.addFirst(sd); } // end synchronized block return nobj; } // end createNamedObject private final WrappedResourceProvider locateResourceProvider(ComponentResName crn) { WrappedResourceProvider wrp = null; synchronized (m_resource_providers) { // perform the "maximum munch" algorithm to try and find a provider int max_munch = 0; Iterator it = m_resource_providers.iterator(); while (it.hasNext()) { // look at each mounted provider and try to find a better possibility WrappedResourceProvider tmp = (WrappedResourceProvider) (it.next()); int test = tmp.getMatchCount(crn); if (test > max_munch) { // found one that munches more...save it wrp = tmp; max_munch = test; } // end if } // end while } // end synchronized block return wrp; } // end locateResourceProvider private final InputStream getResourceInternal(ComponentResName crn) throws IOException { File res_file = new File(m_resource_base, crn.getStringValue(0, false)); if (!(res_file.exists()) || res_file.isDirectory() || !(res_file.canRead())) throw new NoSuchResourceException(crn.getStringValue(0, true)); return new FileInputStream(res_file); } // end getResourceInternal private final long getResourceModTimeInternal(ComponentResName crn) { File res_file = new File(m_resource_base, crn.getStringValue(0, false)); if (!(res_file.exists()) || res_file.isDirectory() || !(res_file.canRead())) return 0; return res_file.lastModified(); } // end getResourceModTimeInternal private final RegisteredRenderer searchDClassRenderers(DynamicClass dclass) { return (RegisteredRenderer) (m_dclass_renderers.get(dclass)); } // end searchDClassRenderer private final RegisteredRenderer searchArrayRenderers(Class klass, String template) { if (klass.isPrimitive() || (klass == Object.class)) return null; // should have been picked up already // look at this level for the class member RegisteredRenderer rc = null; try { // load the array class corresponding to the right depth, then check the renderer map Class tmp = Class.forName(StringUtils.replace(template, TEMPLATE_CLASSNAME, klass.getName())); rc = (RegisteredRenderer) (m_class_renderers.get(tmp)); if (rc != null) return rc; } // end try catch (ClassNotFoundException e) { // this class was not found, so it can't be present rc = null; } // end catch // Try all interfaces implemented by the object. Class[] ifaces = klass.getInterfaces(); for (int i = 0; i < ifaces.length; i++) { // look for interfaces implemented by the object rc = searchArrayRenderers(ifaces[i], template); if (rc != null) return rc; } // end for Class superclass = klass.getSuperclass(); if (superclass != null) { // try the superclass now rc = searchArrayRenderers(superclass, template); if (rc != null) return rc; } // end if return null; // give up } // end searchArrayRenderers private final RegisteredRenderer searchClassRenderers(Class klass) { if (klass.isPrimitive() || (klass == Object.class)) return null; // should have been picked up already // look at this level for the class member RegisteredRenderer rc = (RegisteredRenderer) (m_class_renderers.get(klass)); if (rc != null) return rc; if (klass.isArray()) { // for arrays, use the parallel function to search back over the component // class's hierarchy Class component = getUltimateComponent(klass); if (component.isPrimitive() || (component == Object.class)) return null; // no chance this should have been picked up String template = StringUtils.replace(klass.getName(), component.getName(), TEMPLATE_CLASSNAME); return searchArrayRenderers(component, template); } // end if // Try all interfaces implemented by the object. Class[] ifaces = klass.getInterfaces(); for (int i = 0; i < ifaces.length; i++) { // look for interfaces implemented by the object rc = searchClassRenderers(ifaces[i]); if (rc != null) return rc; } // end for Class superclass = klass.getSuperclass(); if (superclass != null) { // try the superclass now rc = searchClassRenderers(superclass); if (rc != null) return rc; } // end if return null; // give up } // end searchClassRenderers /*-------------------------------------------------------------------------------- * Implementations from interface ResourceProvider *-------------------------------------------------------------------------------- */ public InputStream getResource(String resource_path) throws IOException { ComponentResName crn = new ComponentResName(resource_path); WrappedResourceProvider wrp = locateResourceProvider(crn); if (wrp == null) return getResourceInternal(crn); else return wrp.getResource(crn); } // end getResource public long getResourceModTime(String resource_path) { try { // build the resource name and return it ComponentResName crn = new ComponentResName(resource_path); WrappedResourceProvider wrp = locateResourceProvider(crn); if (wrp == null) return getResourceModTimeInternal(crn); else return wrp.getResourceModTime(crn); } // end try catch (NoSuchResourceException e) { // just deal with exceptions in here return 0; } // end catch } // end getResourceModTime /*-------------------------------------------------------------------------------- * Implementations from interface ResourceProviderManager *-------------------------------------------------------------------------------- */ public ComponentShutdown mountResourceProvider(String mount_path, ResourceProvider provider) throws ConfigException { ComponentResName crn = null; try { // create component name for mount path crn = new ComponentResName(mount_path); } // end try catch (NoSuchResourceException e) { // this is not a valid name - throw ConfigException ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "mountRP.badName"); ce.setParameter(0, mount_path); throw ce; } // end catch WrappedResourceProvider wrp = new WrappedResourceProvider(crn, provider); if (m_resource_providers.contains(wrp)) { // resource provider already mounted on this path - bogus! ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "mountRP.already"); ce.setParameter(0, mount_path); throw ce; } // end if m_resource_providers.add(wrp); return new ShutdownVectorRemove(m_resource_providers, wrp); } // end mountResourceProvider /*-------------------------------------------------------------------------------- * Implementations from interface RendererRegistration *-------------------------------------------------------------------------------- */ public ComponentShutdown registerRenderer(Class klass, Renderer renderer) throws ConfigException { if (m_class_renderers.containsKey(klass)) { // renderer already registered - bogus! ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "registerRenderer.already"); ce.setParameter(0, klass.getName()); throw ce; } // end if if (logger.isDebugEnabled()) logger.debug("Registering a new renderer for class " + klass.getName()); RegisteredRenderer rr = new RegisteredRenderer(klass, renderer); m_class_renderers.put(klass, rr); return rr; } // end registerRenderer public ComponentShutdown registerRenderer(DynamicClass dclass, Renderer renderer) throws ConfigException { if (m_dclass_renderers.containsKey(dclass)) { // renderer already registered - bogus! ConfigException ce = new ConfigException(ApplicationContainer.class, "ApplicationContainerMessages", "registerRenderer.already"); ce.setParameter(0, dclass.getName()); throw ce; } // end if if (logger.isDebugEnabled()) logger.debug("Registering a new renderer for dynamic class " + dclass.getName()); RegisteredRenderer rr = new RegisteredRenderer(dclass, renderer); m_class_renderers.put(dclass, rr); return rr; } // end if /*-------------------------------------------------------------------------------- * Implementations from interface ObjectProvider *-------------------------------------------------------------------------------- */ /** * Retrieves an object from this <CODE>ObjectProvider</CODE>. * * @param namespace The namespace to interpret the name relative to. * @param name The name of the object to be retrieved. * @return The object reference specified. */ public Object getObject(String namespace, String name) { if (namespace.equals(Namespaces.SUBSTRATE_NAMESPACE)) return m_substrate.getObject(namespace, name); if (namespace.equals(Namespaces.DATABASE_CONNECTIONS_NAMESPACE)) { // get a database connection Object rc = m_connections.get(name); if (rc != null) return rc; } // end if if (namespace.equals(Namespaces.DYNAMO_OBJECT_NAMESPACE)) { // get an object Object rc = m_objects.get(name); if (rc != null) return rc; } // end if if (namespace.equals(Namespaces.DYNAMO_APPLICATION_NAMESPACE)) { // return one of the application data elements if (name.equals("application")) return m_application; else if (name.equals("identity")) return m_identity; else if (name.equals("__container__")) return this; } // end if throw new NoSuchObjectException("ApplicationContainer", namespace, name); } // end getObject /*-------------------------------------------------------------------------------- * Implementations from interface EventListenerRegistration *-------------------------------------------------------------------------------- */ public ComponentShutdown registerApplicationListener(ApplicationListener listener) { m_application_listeners.add(listener); return new ShutdownVectorRemove(m_application_listeners, listener); } // end registerApplicationListener public ComponentShutdown registerSessionInfoListener(SessionInfoListener listener) { m_session_listeners.add(listener); return new ShutdownVectorRemove(m_session_listeners, listener); } // end registerSessionInfoListener public synchronized ComponentShutdown registerDynamicUpdateListener(Class event_type, DynamicUpdateListener listener) { if (!(DynamicUpdateEvent.class.isAssignableFrom(event_type))) throw new IllegalArgumentException("event type is not valid"); Vector vec = (Vector) (m_update_listeners.get(event_type)); if (vec == null) { // creatr vector for this event type vec = new Vector(); m_update_listeners.put(event_type, vec); } // end if vec.add(listener); return new ShutdownVectorRemove(vec, listener); } // end registerDynamicUpdateListener /*-------------------------------------------------------------------------------- * Implementations from interface OutputObjectFilterRegistration *-------------------------------------------------------------------------------- */ public ComponentShutdown registerOutputObjectFilter(OutputObjectFilter filter) { if (logger.isDebugEnabled()) logger.debug("Registering new OutputObjectFilter: " + filter); m_output_filters.add(filter); return new ShutdownVectorRemove(m_output_filters, filter); } // end registerOutputObjectFilter /*-------------------------------------------------------------------------------- * Implementations from interface QueryRenderer *-------------------------------------------------------------------------------- */ public Renderer getRendererForObject(Object obj) { RegisteredRenderer rc = null; if (obj instanceof DynamicObject) { // this is a dynamic object - search by its dynamic class first DynamicClass dclass = ((DynamicObject) obj).getDClass(); rc = (RegisteredRenderer) (m_dclass_renderers.get(dclass)); if (rc == null) { // search for ancestor class, "snap" reference if possible rc = searchDClassRenderers(dclass); if (rc != null) { // add this class to the mapping m_dclass_renderers.put(dclass, rc); rc.add(dclass); } // end if } // end if if (rc != null) return rc.getRenderer(); } // end if Class klass = obj.getClass(); rc = (RegisteredRenderer) (m_class_renderers.get(klass)); if (rc == null) { // search for ancestor class, "snap" reference if possible rc = searchClassRenderers(klass); if (rc != null) { // found it - add this class to the mapping m_class_renderers.put(klass, rc); rc.add(klass); } // end if } // end if return ((rc == null) ? null : rc.getRenderer()); } // end getRendererForObject /*-------------------------------------------------------------------------------- * Implementations from interface PostDynamicUpdate *-------------------------------------------------------------------------------- */ public void postUpdate(DynamicUpdateEvent event) { if (logger.isDebugEnabled()) logger.debug("PostDynamicUpdate: posting an event of type " + event.getClass().getName()); Class klass = event.getClass(); for (;;) { // get the event listeners Vector vec = (Vector) (m_update_listeners.get(klass)); if (vec != null) { // call the event handlers Iterator it = vec.iterator(); while (it.hasNext()) ((DynamicUpdateListener) (it.next())).updateReceived(event); } // end if if (klass == DynamicUpdateEvent.class) break; klass = klass.getSuperclass(); } // end for (ever) } // end postUpdate /*-------------------------------------------------------------------------------- * Implementations from interface RenderImmediate *-------------------------------------------------------------------------------- */ public String renderTextObject(Object obj) throws IOException, RenderingException { if (logger.isDebugEnabled()) logger.debug("RenderImmediate rendering an object of type " + obj.getClass().getName()); BufferTextRenderControl control = new BufferTextRenderControl(wrapOutputServices(null)); control.renderSubObject(obj); return control.getData(); } // end renderTextObject /*-------------------------------------------------------------------------------- * Implementations from interface RequestPreprocessorRegistration *-------------------------------------------------------------------------------- */ public ComponentShutdown registerRequestPreprocessor(RequestPreprocessor rp) { if (logger.isDebugEnabled()) logger.debug("Registering new RequestPreprocessor: " + rp); m_request_preprocessors.add(rp); return new ShutdownVectorRemove(m_request_preprocessors, rp); } // end registerRequestPreprocessor /*-------------------------------------------------------------------------------- * Implementations from interface ExceptionTranslatorRegistration *-------------------------------------------------------------------------------- */ public ComponentShutdown registerExceptionTranslator(ExceptionTranslator xlat) { if (logger.isDebugEnabled()) logger.debug("Registering new ExceptionTranslator: " + xlat); m_exception_xlators.add(xlat); return new ShutdownVectorRemove(m_exception_xlators, xlat); } // end registerExceptionTranslator /*-------------------------------------------------------------------------------- * Implementations from interface FinalStageRegistration *-------------------------------------------------------------------------------- */ public synchronized boolean registerFinalStageInitHook(FinalStageInitHook hook) { if ((m_final_stage_inits == null) || (m_application != null)) return false; // too late to register m_final_stage_inits.addLast(hook); return true; } // end registerFinalStageInitHook public synchronized void registerPreStageShutdown(ComponentShutdown cs) { m_prestage_shutdown.addFirst(cs); } // end registerPreStageShutdown /*-------------------------------------------------------------------------------- * External operations *-------------------------------------------------------------------------------- */ /** * Adds a reference to the reference count of the <CODE>ApplicationContainer</CODE>. Each servlet * or other initializing component that attempts to initialize the <CODE>ApplicationContainer</CODE> * increases its reference count by 1. */ public synchronized void addRef() { ++m_refs; if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.addRef(): refcount now " + m_refs); } // end addRef /** * Removes a reference from the reference count of the <CODE>ApplicationContainer</CODE>. Each servlet that * references the <CODE>ApplicationContainer</CODE> and is destroyed decreases the reference count by 1. * When the reference count reaches 0, the <CODE>ApplicationContainer</CODE> is destroyed. * * @return <CODE>true</CODE> if the <CODE>ApplicationContainer</CODE> was destroyed, <CODE>false</CODE> if not. */ public synchronized boolean release() { if (--m_refs == 0) { // clean up this stuff if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.release(): refcount now 0 - destroying!"); destroy(); return true; } // end if if (logger.isDebugEnabled()) logger.debug("ApplicationContainer.release(): refcount now " + m_refs); return false; } // end release /** * Returns the instance of the {@link com.silverwrist.dynamo.iface.Application Application} object defined in * the Dynamo XML configuration file and instantiated when the <CODE>ApplicationContainer</CODE> was created. * * @return The <CODE>Application</CODE> object. */ public Application getApplication() { return m_application; } // end getApplication public ServiceProvider getInitServices() { return m_app_sm.createInitServices(); } // end getInitServices public ServiceProvider wrapServices(ServiceProvider sp) { return m_app_sm.createRuntimeServices(sp); } // end wrapServices public ServiceProvider wrapOutputServices(ServiceProvider sp) { return m_app_sm.createOutputServices(sp); } // end wrapOutputServices /** * Returns a list of all registered {@link com.silverwrist.dynamo.event.SessionInfoListener SessionInfoListener} * objects. * * @return A list of all registered <CODE>SessionInfoListener</CODE> objects. */ public SessionInfoListener[] getSessionListeners() { return (SessionInfoListener[]) (m_session_listeners.toArray(SESSION_LISTENER_TEMPLATE)); } // end getSessionListeners /** * Adds a session to our list of known sessions, which will be shut down when the application container * is itself destroyed. * * @param link The link to the session. */ public void addSessionLink(ComponentShutdown link) { m_known_sessions.add(link); } // end addSessionLink /** * Removes a session from our list of known sessions, so it will no longer be automatically shut down * when the application container is itself destroyed. * * @param link The link to the session. */ public void removeSessionLink(ComponentShutdown link) { m_known_sessions.remove(link); } // end removeSessionLink public String getServerIdentity() { return m_identity; } // end getServerIdentity public void setServerHeader(HttpServletResponse resp) { resp.setHeader("Server", m_identity); } // end setServerHeader public Map getRewriteRuleMap() { return m_rewrite_rules; } // end getRewriteRuleMap public Object filterOutput(Object out, Request r) throws RenderingException { Object rc = out; for (int i = (m_output_filters.size() - 1); i >= 0; i--) { // look for new objects that filter this one OutputObjectFilter filt = (OutputObjectFilter) (m_output_filters.get(i)); Object tmp_rc = filt.filterObject(rc, r); if (tmp_rc != null) rc = tmp_rc; } // end for return rc; } // end filterOutput public void preprocessRequest(Request r) { for (int i = (m_request_preprocessors.size() - 1); i >= 0; i--) { // preprocess the request, if we have any preprocessors installed RequestPreprocessor rp = (RequestPreprocessor) (m_request_preprocessors.get(i)); rp.preprocessRequest(r); } // end for } // end preprocessRequest public Object translateException(Request r, Exception e) { for (int i = (m_exception_xlators.size() - 1); i >= 0; i--) { // try to translate exceptions ExceptionTranslator xlat = (ExceptionTranslator) (m_exception_xlators.get(i)); Object o = xlat.translateException(r, e); if (o != null) return o; // found a translation } // end for return e; // return the exception itself as a last resort } // end translateException public String translateSubstratePathName(String input) { return StringUtils.replaceAllVariables(input, getSubstrateReplaceMap()); } // end translateSubstratePathName } // end class ApplicationContainer