1 //
2 // ========================================================================
3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 // ------------------------------------------------------------------------
5 // All rights reserved. This program and the accompanying materials
6 // are made available under the terms of the Eclipse Public License v1.0
7 // and Apache License v2.0 which accompanies this distribution.
8 //
9 // The Eclipse Public License is available at
10 // http://www.eclipse.org/legal/epl-v10.html
11 //
12 // The Apache License v2.0 is available at
13 // http://www.opensource.org/licenses/apache2.0.php
14 //
15 // You may elect to redistribute this code under either of these licenses.
16 // ========================================================================
17 //
18
19 package org.eclipse.jetty.osgi.boot.internal.webapp;
20
21 import java.io.File;
22 import java.net.MalformedURLException;
23 import java.net.URL;
24 import java.net.URLClassLoader;
25 import java.util.ArrayList;
26 import java.util.HashMap;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Locale;
30 import java.util.Map;
31 import java.util.Set;
32
33 import org.eclipse.jetty.server.Server;
34
35 /**
36 * LibExtClassLoaderHelper
37 *
38 *
39 * Helper to create a URL class-loader with the jars inside
40 * ${jetty.home}/lib/ext and ${jetty.home}/resources. In an ideal world, every
41 * library is an OSGi bundle that does loads nicely. To support standard jars or
42 * bundles that cannot be loaded in the current OSGi environment, we support
43 * inserting the jars in the usual jetty/lib/ext folders in the proper classpath
44 * for the webapps.
45 * <p>
46 * The drawback is that those jars will not be available in the OSGi
47 * classloader.
48 * </p>
49 * <p>
50 * Alternatives to placing jars in lib/ext:
51 * <ol>
52 * <li>Bundle the jars in an osgi bundle. Have the webapp(s) that need these jars
53 * depend on that bundle.</li>
54 * <li>Bundle those jars in an osgi bundle-fragment that targets the
55 * jetty-bootstrap bundle</li>
56 * <li>Use equinox Buddy-Policy: register a buddy of the jetty bootstrapper
57 * bundle. (Note: it will work only on equinox)</li>
58 * </ol>
59 * </p>
60 */
61 public class LibExtClassLoaderHelper
62 {
63 /* ------------------------------------------------------------ */
64 /**
65 * IFilesInJettyHomeResourcesProcessor
66 *
67 * Interface for callback impls
68 */
69 public interface IFilesInJettyHomeResourcesProcessor
70 {
71 void processFilesInResourcesFolder(File jettyHome, Map<String, File> filesInResourcesFolder);
72 }
73
74
75
76 public static final Set<IFilesInJettyHomeResourcesProcessor> registeredFilesInJettyHomeResourcesProcessors = new HashSet<IFilesInJettyHomeResourcesProcessor>();
77
78
79 /* ------------------------------------------------------------ */
80 /**
81 * @param server
82 * @return a url classloader with the jars of resources, lib/ext and the
83 * jars passed in the other argument. The parent classloader usually
84 * is the JettyBootStrapper (an osgi classloader.
85 * @throws MalformedURLException
86 */
87 public static ClassLoader createLibEtcClassLoader(File jettyHome, ClassLoader parentClassLoader) throws MalformedURLException
88 {
89 if (jettyHome == null) { return parentClassLoader; }
90 ArrayList<URL> urls = new ArrayList<URL>();
91 File jettyResources = new File(jettyHome, "resources");
92 if (jettyResources.exists())
93 {
94 // make sure it contains something else than README:
95 Map<String, File> jettyResFiles = new HashMap<String, File>();
96 for (File f : jettyResources.listFiles())
97 {
98 jettyResFiles.put(f.getName(), f);
99 if (f.getName().toLowerCase(Locale.ENGLISH).startsWith("readme"))
100 {
101 continue;
102 }
103 else
104 {
105 if (urls.isEmpty())
106 {
107 urls.add(jettyResources.toURI().toURL());
108 }
109 }
110 }
111 processFilesInResourcesFolder(jettyHome, jettyResFiles);
112 }
113 File libExt = new File(jettyHome, "lib/ext");
114 if (libExt.exists())
115 {
116 for (File f : libExt.listFiles())
117 {
118 if (f.getName().endsWith(".jar"))
119 {
120 // cheap to tolerate folders so let's do it.
121 URL url = f.toURI().toURL();
122 if (f.isFile())
123 {// is this necessary anyways?
124 url = new URL("jar:" + url.toString() + "!/");
125 }
126 urls.add(url);
127 }
128 }
129 }
130
131 return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader);
132 }
133
134
135 /* ------------------------------------------------------------ */
136 /**
137 * @param server
138 * @return a url classloader with the jars of resources, lib/ext and the
139 * jars passed in the other argument. The parent classloader usually
140 * is the JettyBootStrapper (an osgi classloader). If there was no
141 * extra jars to insert, then just return the parentClassLoader.
142 * @throws MalformedURLException
143 */
144 public static ClassLoader createLibExtClassLoader(List<File> jarsContainerOrJars, List<URL> otherJarsOrFolder, ClassLoader parentClassLoader)
145 throws MalformedURLException
146 {
147 if (jarsContainerOrJars == null && otherJarsOrFolder == null) { return parentClassLoader; }
148 List<URL> urls = new ArrayList<URL>();
149 if (otherJarsOrFolder != null)
150 {
151 urls.addAll(otherJarsOrFolder);
152 }
153 if (jarsContainerOrJars != null)
154 {
155 for (File libExt : jarsContainerOrJars)
156 {
157 if (libExt.isDirectory())
158 {
159 for (File f : libExt.listFiles())
160 {
161 if (f.getName().endsWith(".jar"))
162 {
163 // cheap to tolerate folders so let's do it.
164 URL url = f.toURI().toURL();
165 if (f.isFile())
166 {
167 // is this necessary anyways?
168 url = new URL("jar:" + url.toString() + "!/");
169 }
170 urls.add(url);
171 }
172 }
173 }
174 }
175 }
176 return new URLClassLoader(urls.toArray(new URL[urls.size()]), parentClassLoader);
177 }
178
179 /* ------------------------------------------------------------ */
180 /**
181 * When we find files typically used for central logging configuration we do
182 * what it takes in this method to do what the user expects. Without
183 * depending too much directly on a particular logging framework.
184 * <p>
185 * We can afford to do some implementation specific code for a logging
186 * framework only in a fragment. <br/>
187 * Trying to configure log4j and logback in here.
188 * </p>
189 * <p>
190 * We recommend that slf4j jars are all placed in the osgi framework. And a
191 * single implementation if possible packaged as an osgi bundle is there.
192 * </p>
193 */
194 protected static void processFilesInResourcesFolder(File jettyHome, Map<String, File> childrenFiles)
195 {
196 for (IFilesInJettyHomeResourcesProcessor processor : registeredFilesInJettyHomeResourcesProcessors)
197 {
198 processor.processFilesInResourcesFolder(jettyHome, childrenFiles);
199 }
200 }
201
202 }