KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > go > teaservlet > MergedApplication


1 /* ====================================================================
2  * TeaServlet - Copyright (c) 1999-2000 Walt Disney Internet Group
3  * ====================================================================
4  * The Tea Software License, Version 1.1
5  *
6  * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Walt Disney Internet Group (http://opensource.go.com/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact opensource@dig.com.
31  *
32  * 5. Products derived from this software may not be called "Tea",
33  * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34  * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35  * written permission of the Walt Disney Internet Group.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * For more information about Tea, please see http://opensource.go.com/.
51  */

52
53 package com.go.teaservlet;
54
55 import java.util.*;
56 import java.lang.reflect.*;
57 import javax.servlet.ServletContext JavaDoc;
58 import javax.servlet.ServletException JavaDoc;
59 import com.go.trove.log.Log;
60 import com.go.trove.util.IdentityMap;
61 import com.go.trove.util.MapBackedSet;
62 import com.go.trove.util.ClassInjector;
63 import com.go.trove.util.DelegateClassLoader;
64 import com.go.trove.util.MergedClass;
65 import com.go.trove.util.PropertyMap;
66 import com.go.trove.util.plugin.Plugin;
67
68 /******************************************************************************
69  *
70  * @author Brian S O'Neill
71  * @version
72  * <!--$$Revision:--> 29 <!-- $-->, <!--$$JustDate:--> 01/04/10 <!-- $-->
73  */

74 class MergedApplication implements Application {
75     /**
76      * Ensures that name only contains valid Java identifiers by converting
77      * non identifier characters to '$' characters. If name begins with a
78      * numeral, name is prefixed with an underscore. The returned name is also
79      * trimmed at the first hyphen character, if there is one. This allows
80      * multiple applications to appear to provide a unified set of functions.
81      */

82     private static String JavaDoc cleanName(String JavaDoc name) {
83         int index = name.indexOf('-');
84         if (index > 0) {
85             name = name.substring(0, index);
86         }
87
88         int length = name.length();
89         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(length + 1);
90
91         if (!Character.isJavaIdentifierStart(name.charAt(0))) {
92             buf.append('_');
93         }
94         else if (Character.isJavaIdentifierPart(name.charAt(0))) {
95             buf.append(name.charAt(0));
96         }
97
98         for (int i=1; i<length; i++) {
99             char c = name.charAt(i);
100             if (Character.isJavaIdentifierPart(c)) {
101                 buf.append(c);
102             }
103             else {
104                 buf.append('$');
105             }
106         }
107
108         return buf.toString();
109     }
110
111     private ApplicationConfig mBaseConfig;
112     private ServletContext JavaDoc mServletContext;
113     private Log mLog;
114     private PropertyMap mProperties;
115
116     // All the loaded applications that are merged together into this one.
117
private Application[] mApps;
118
119     // All the loaded applications that produce a context object.
120
private Application[] mAppsWithContexts;
121
122     // Maps Application instances to their names.
123
private Map mAppNameMap;
124
125     private Constructor mContextConstructor;
126
127     public void init(ApplicationConfig config) throws ServletException JavaDoc {
128         mBaseConfig = config;
129         mServletContext = config.getServletContext();
130         mLog = config.getLog();
131         mProperties = config.getProperties().subMap("applications");
132
133         // Load and init each application.
134
mLog.debug("Loading Applications");
135         Set appNames = mProperties.subMapKeySet();
136         List apps = new ArrayList(appNames.size());
137         List appsWithContexts = new ArrayList(appNames.size());
138         Map appNameMap = new IdentityMap(appNames.size() * 2 + 1);
139
140         if (appNames.size() == 0) {
141             mLog.warn("No Applications specified");
142         }
143
144         Set contextCLSet = new MapBackedSet(new IdentityMap());
145         List contextCLList = new ArrayList();
146
147         Iterator it = appNames.iterator();
148         while (it.hasNext()) {
149             String JavaDoc name = (String JavaDoc)it.next();
150             Application app = loadApplication(name, config.getPlugins());
151             if (app != null) {
152                 apps.add(app);
153                 appNameMap.put(app, name);
154
155                 Class JavaDoc contextType = app.getContextType();
156                 if (contextType != null) {
157                     appsWithContexts.add(app);
158
159                     // Allow applications to use their own ClassLoaders.
160
ClassLoader JavaDoc contextCL = contextType.getClassLoader();
161                     if (contextCL != null) {
162                         contextCLSet.add(contextCL);
163                         contextCLList.add(contextCL);
164                     }
165                 }
166             }
167         }
168
169         mApps = (Application[])apps.toArray(new Application[apps.size()]);
170         mAppsWithContexts = (Application[])appsWithContexts.toArray
171             (new Application[appsWithContexts.size()]);
172         mAppNameMap = appNameMap;
173
174         ClassLoader JavaDoc[] contextClassLoaders =
175             new ClassLoader JavaDoc[contextCLSet.size()];
176         int i = 0;
177         it = contextCLList.iterator();
178         while (it.hasNext()) {
179             Object JavaDoc contextClassLoader = it.next();
180             if (contextCLSet.contains(contextClassLoader)) {
181                 contextCLSet.remove(contextClassLoader);
182                 contextClassLoaders[i++] = (ClassLoader JavaDoc)contextClassLoader;
183             }
184         }
185
186         // Create merged context class.
187

188         ClassLoader JavaDoc baseClassLoader = this.getClass().getClassLoader();
189         if (contextClassLoaders.length > 0) {
190             baseClassLoader = new DelegateClassLoader
191                 (baseClassLoader, contextClassLoaders);
192         }
193
194         ClassInjector contextInjector = new ClassInjector
195             (baseClassLoader, (java.io.File JavaDoc[])null, null);
196
197         Class JavaDoc[] contexts = new Class JavaDoc[1 + mAppsWithContexts.length];
198         contexts[0] = HttpContext.class;
199         String JavaDoc[] prefixes = new String JavaDoc[contexts.length];
200
201         for (i=0; i<mAppsWithContexts.length; i++) {
202             Application app = mAppsWithContexts[i];
203             contexts[i + 1] = app.getContextType();
204             prefixes[i + 1] = cleanName((String JavaDoc)mAppNameMap.get(app)) + '$';
205         }
206
207         mContextConstructor =
208             MergedClass.getConstructor2(contextInjector, contexts, prefixes);
209     }
210     
211     public void destroy() {
212         for (int i=0; i<mApps.length; i++) {
213             mApps[i].destroy();
214         }
215     }
216
217     /**
218      * Always returns an instance of HttpContext.
219      */

220     public Object JavaDoc createContext(ApplicationRequest request,
221                                 ApplicationResponse response) {
222         ApplicationResponseImpl responseImpl =
223             (ApplicationResponseImpl)response;
224         responseImpl.setAppAndRequest(this, request);
225
226         HttpContext httpContext =
227             new HttpContextImpl(mServletContext, mLog, request, response,
228                                 response.getResponseBuffer());
229         responseImpl.setHttpContext(httpContext);
230         
231         ContextFactory factory =
232             new ContextFactory(httpContext, request, response);
233
234         try {
235             httpContext = (HttpContext)mContextConstructor.newInstance
236                 (new Object JavaDoc[]{factory});
237             responseImpl.setHttpContext(httpContext);
238             return httpContext;
239         }
240         catch (InvocationTargetException e) {
241             mLog.error("Error constructing context");
242             mLog.error(e.getTargetException());
243         }
244         catch (InstantiationException JavaDoc e) {
245             mLog.error("Error constructing context");
246             mLog.error(e);
247         }
248         catch (IllegalAccessException JavaDoc e) {
249             mLog.error("Error constructing context");
250             mLog.error(e);
251         }
252
253         // There was an error, return just the default context and hope for the
254
// best.
255
return httpContext;
256     }
257
258     public Class JavaDoc getContextType() {
259         return mContextConstructor.getDeclaringClass();
260     }
261
262     public Application[] getApplications() {
263         return (Application[])mApps.clone();
264     }
265
266     public String JavaDoc[] getApplicationNames() {
267         int length = mApps.length;
268         String JavaDoc[] names = new String JavaDoc[length];
269         for (int i=0; i<length; i++) {
270             names[i] = (String JavaDoc)mAppNameMap.get(mApps[i]);
271         }
272         return names;
273     }
274     
275     public String JavaDoc[] getContextPrefixNames() {
276         int length = mApps.length;
277         String JavaDoc[] names = new String JavaDoc[length];
278         for (int i=0; i<length; i++) {
279             names[i] = cleanName((String JavaDoc)mAppNameMap.get(mApps[i]));
280         }
281         return names;
282     }
283
284     private Application loadApplication(String JavaDoc name, Map plugins)
285         throws ServletException JavaDoc
286     {
287         mLog.info("Loading \"" + name + '"');
288
289         PropertyMap properties = mProperties.subMap(name);
290         String JavaDoc className = properties.getString("class");
291         if (className == null) {
292             mLog.error("No class specified for " + name);
293             return null;
294         }
295
296         // Load the user-specified Applications
297
Class JavaDoc appClass;
298         try {
299             appClass = Class.forName(className);
300         }
301         catch (ClassNotFoundException JavaDoc e) {
302             mLog.error(e);
303             return null;
304         }
305         catch (LinkageError JavaDoc e) {
306             mLog.error(e);
307             return null;
308         }
309         
310         Application app;
311         try {
312             app = (Application)appClass.newInstance();
313         }
314         catch (ClassCastException JavaDoc e) {
315             mLog.error("Class is not an Application: " + appClass);
316             return null;
317         }
318         catch (Exception JavaDoc e) {
319             mLog.error(e);
320             return null;
321         }
322         
323         // Initialize the Application
324
mLog.info("Initializing \"" + name + '"');
325
326         ApplicationConfig appConfig =
327             new InternalApplicationConfig(mBaseConfig, properties, plugins, name);
328
329         try {
330             app.init(appConfig);
331             return app;
332         }
333         catch (ServletException JavaDoc e) {
334             Throwable JavaDoc rootCause = e.getRootCause();
335             if (rootCause != null) {
336                 String JavaDoc message = e.getMessage();
337                 if (message != null && message.length() > 0) {
338                     mLog.error(message);
339                 }
340                 mLog.error(rootCause);
341             }
342             else {
343                 mLog.error(e);
344             }
345         }
346         catch (LinkageError JavaDoc e) {
347             mLog.error(e);
348         }
349         catch (Exception JavaDoc e) {
350             mLog.error(e);
351         }
352
353         return null;
354     }
355
356     private class ContextFactory implements MergedClass.InstanceFactory {
357         private final HttpContext mHttpContext;
358         private final ApplicationRequest mRequest;
359         private final ApplicationResponse mResponse;
360
361         ContextFactory(HttpContext httpContext,
362                        ApplicationRequest request,
363                        ApplicationResponse response) {
364             mHttpContext = httpContext;
365             mRequest = request;
366             mResponse = response;
367         }
368
369         public Object JavaDoc getInstance(int i) {
370             Object JavaDoc context;
371             if (i == 0) {
372                 context = mHttpContext;
373             }
374             else {
375                 context = mAppsWithContexts[i - 1].createContext
376                     (mRequest, mResponse);
377                 if (context == null) {
378                     mLog.warn("Null context created by " +
379                               mAppsWithContexts[i - 1]);
380                 }
381             }
382             return context;
383         }
384     }
385 }
386
Popular Tags