View Javadoc

1   // ========================================================================
2   // Copyright (c) 2009 Intalio, Inc.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  package org.eclipse.jetty.osgi.boot.internal.webapp;
14  
15  import java.io.File;
16  import java.net.MalformedURLException;
17  import java.net.URL;
18  import java.net.URLClassLoader;
19  import java.util.ArrayList;
20  import java.util.HashMap;
21  import java.util.HashSet;
22  import java.util.Map;
23  import java.util.Set;
24  
25  import org.eclipse.jetty.server.Server;
26  import org.eclipse.jetty.webapp.WebAppContext;
27  
28  /**
29   * Helper to create a URL class-loader with the jars inside
30   * ${jetty.home}/lib/ext and ${jetty.home}/resources. In an ideal world, every
31   * library is an OSGi bundle that does loads nicely. To support standard jars or
32   * bundles that cannot be loaded in the current OSGi environment, we support
33   * inserting the jars in the usual jetty/lib/ext folders in the proper classpath
34   * for the webapps.
35   * <p>
36   * Also the folder resources typically contains central configuration files for
37   * things like: log config and others. We enable fragments to register classes
38   * that are called back and passed those resources to do what they need to do.
39   * </p>
40   * <p>
41   * For example the test-jndi webapplication depends on derby, derbytools,
42   * atomikos none of them are osgi bundles. we can either re-package them or we
43   * can place them in the usual lib/ext. <br/>
44   * In fact jasper's jsp libraries should maybe place in lib/ext too.
45   * </p>
46   * <p>
47   * The drawback is that those libraries will not be available in the OSGi
48   * classloader. Note that we could have setup those jars as embedded jars of the
49   * current bundle. However, we would need to know in advance what are those jars
50   * which was not acceptable. Also having those jars in a URLClassLoader seem to
51   * be required for some cases. For example jaspers' TldLocationsCache (replaced
52   * by TldScanner for servlet-3.0). <br/>
53   * Also all the dependencies of those libraries must be resolvable directly from
54   * the JettyBooStrapper bundle as it is set as the parent classloader. For
55   * example: if atomikos is placed in lib/ext it will work if and only if
56   * JettyBootStrapper import the necessary packages from javax.naming*,
57   * javax.transaction*, javax.mail* etc Most of the common cases of javax are
58   * added as optional import packages into jetty bootstrapper plugin. When there
59   * are not covered: please make a request or create a fragment or register a
60   * bundle with a buddy-policy onto the jetty bootstrapper..
61   * </p>
62   * <p>
63   * Alternatives to placing jars in lib/ext
64   * <ol>
65   * <li>Bundle the jars in an osgi bundle. Have the webapp(s) that context
66   * depends on them depend on that bundle. Things will go well for jetty.</li>
67   * <li>Bundle those jars in an osgi bundle-fragment that targets the
68   * jetty-bootstrap bundle</li>
69   * <li>Use equinox Buddy-Policy: register a buddy of the jetty bootstrapper
70   * bundle. (least favorite: it will work only on equinox)</li>
71   * </ol>
72   * </p>
73   */
74  public class LibExtClassLoaderHelper
75  {
76  
77      /**
78       * Class called back
79       */
80      public interface IFilesInJettyHomeResourcesProcessor
81      {
82          void processFilesInResourcesFolder(File jettyHome, Map<String, File> filesInResourcesFolder);
83      }
84  
85      public static Set<IFilesInJettyHomeResourcesProcessor> registeredFilesInJettyHomeResourcesProcessors = new HashSet<IFilesInJettyHomeResourcesProcessor>();
86  
87      /**
88       * @param server
89       * @return a url classloader with the jars of resources, lib/ext and the
90       *         jars passed in the other argument. The parent classloader usually
91       *         is the JettyBootStrapper (an osgi classloader.
92       * @throws MalformedURLException
93       */
94      public static URLClassLoader createLibEtcClassLoaderHelper(File jettyHome, Server server, ClassLoader parentClassLoader) throws MalformedURLException
95      {
96      	
97          ArrayList<URL> urls = new ArrayList<URL>();
98          File jettyResources = new File(jettyHome,"resources");
99          if (jettyResources.exists())
100         {
101             // make sure it contains something else than README:
102             Map<String, File> jettyResFiles = new HashMap<String, File>();
103             for (File f : jettyResources.listFiles())
104             {
105                 jettyResFiles.put(f.getName(),f);
106                 if (f.getName().toLowerCase().startsWith("readme"))
107                 {
108                     continue;
109                 }
110                 else
111                 {
112                     if (urls.isEmpty())
113                     {
114                         urls.add(jettyResources.toURI().toURL());
115                     }
116                 }
117             }
118             processFilesInResourcesFolder(jettyHome,jettyResFiles);
119         }
120         File libExt = new File(jettyHome,"lib/ext");
121         if (libExt.exists())
122         {
123             for (File f : libExt.listFiles())
124             {
125                 if (f.getName().endsWith(".jar"))
126                 {
127                     // cheap to tolerate folders so let's do it.
128                     URL url = f.toURI().toURL();
129                     if (f.isFile())
130                     {// is this necessary anyways?
131                         url = new URL("jar:" + url.toString() + "!/");
132                     }
133                     urls.add(url);
134                 }
135             }
136         }
137 
138         return new URLClassLoader(urls.toArray(new URL[urls.size()]),parentClassLoader);
139     }
140 
141     /**
142      * When we find files typically used for central logging configuration we do
143      * what it takes in this method to do what the user expects. Without
144      * depending too much directly on a particular logging framework.
145      * <p>
146      * We can afford to do some implementation specific code for a logging
147      * framework only in a fragment. <br/>
148      * Trying to configure log4j and logback in here.
149      * </p>
150      * <p>
151      * We recommend that slf4j jars are all placed in the osgi framework. And a
152      * single implementation if possible packaged as an osgi bundle is there.
153      * </p>
154      */
155     protected static void processFilesInResourcesFolder(File jettyHome, Map<String, File> childrenFiles)
156     {
157         for (IFilesInJettyHomeResourcesProcessor processor : registeredFilesInJettyHomeResourcesProcessors)
158         {
159             processor.processFilesInResourcesFolder(jettyHome,childrenFiles);
160         }
161     }
162 
163 }