001: /**
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */package org.apache.openejb.tomcat.catalina;
017:
018: import org.apache.catalina.ContainerListener;
019: import org.apache.catalina.ContainerEvent;
020: import org.apache.catalina.core.StandardContext;
021: import org.apache.openejb.tomcat.common.LegacyAnnotationProcessor;
022:
023: import java.util.ArrayList;
024: import java.util.List;
025: import java.util.Arrays;
026: import java.util.Set;
027: import java.util.HashSet;
028:
029: /**
030: * The StandardContext only calls these events for the listeners in the
031: * getApplicationLifecycleListeners() list and not for any listeners in the
032: * getApplicationEventListeners() list. This is a big pain as we need to
033: * do annotation processing for both. The code gets a bit tricky as a result.
034: *
035: * Note this class only pertains to Tomcat 5.5.x and before, not 6.0.x and after.
036: *
037: * @version $Rev$ $Date$
038: */
039: public class ProcessAnnotatedListenersListener extends
040: LegacyAnnotationProcessorListener implements ContainerListener {
041: private Object[] applicationLifecycleListeners;
042: private Set<Object> destroyed;
043:
044: public ProcessAnnotatedListenersListener(
045: LegacyAnnotationProcessor annotationProcessor) {
046: super (annotationProcessor);
047: }
048:
049: public void containerEvent(ContainerEvent event) {
050: String type = event.getType();
051: if ("beforeContextInitialized".equals(type)) {
052: listenerStart(event);
053: } else if ("afterContextDestroyed".equals(type)) {
054: listenerStop(event);
055: }
056: }
057:
058: /**
059: * We must process all the listeners on the very first "beforeContextInitialized" event of this Container
060: * @param event
061: */
062: private void listenerStart(ContainerEvent event) {
063: if (!isFirstBeforeContextInitializedEvent(event))
064: return;
065:
066: StandardContext standardContext = (StandardContext) event
067: .getContainer();
068:
069: for (Object listener : getListeners(standardContext)) {
070: processAnnotations(listener);
071: postConstruct(listener);
072: }
073: }
074:
075: private boolean isFirstBeforeContextInitializedEvent(
076: ContainerEvent event) {
077: if (applicationLifecycleListeners != null)
078: return false;
079:
080: StandardContext standardContext = (StandardContext) event
081: .getContainer();
082: applicationLifecycleListeners = standardContext
083: .getApplicationLifecycleListeners();
084: destroyed = new HashSet<Object>();
085: return true;
086: }
087:
088: /**
089: * We must process all the listeners on the very last "afterContextDestroyed" event of this Container
090: *
091: * Looking at the code it's possible that if a ContainerListener threw an exception in the
092: * afterContextDestroyed event that the afterContextDestroyed will get fired again in the catch block,
093: * so we need to watch for that. We use a set to ensure we can track uniqe events.
094: * @param event
095: */
096: private void listenerStop(ContainerEvent event) {
097: if (!isLastAfterContextDestroyedEvent(event))
098: return;
099:
100: StandardContext standardContext = (StandardContext) event
101: .getContainer();
102:
103: for (Object listener : getListeners(standardContext)) {
104: preDestroy(listener);
105: }
106: }
107:
108: private boolean isLastAfterContextDestroyedEvent(
109: ContainerEvent event) {
110: // Something very strange is going on if either of these are null at this stage
111: if (destroyed == null || applicationLifecycleListeners == null)
112: return false;
113:
114: // We've already been called and processed our last event
115: if (destroyed.size() == applicationLifecycleListeners.length)
116: return false;
117:
118: Object listener = event.getData();
119: destroyed.add(listener);
120:
121: return (destroyed.size() == applicationLifecycleListeners.length);
122: }
123:
124: private List<Object> getListeners(StandardContext standardContext) {
125: ArrayList<Object> listeners = new ArrayList<Object>();
126: listeners.addAll(Arrays.asList(standardContext
127: .getApplicationEventListeners()));
128: listeners.addAll(Arrays.asList(standardContext
129: .getApplicationLifecycleListeners()));
130: return listeners;
131: }
132:
133: }
|