View Javadoc

1   /*
2    * $Id: MuleApplicationClassLoader.java 23030 2011-09-26 18:02:33Z mike.schilling $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.launcher;
12  
13  import org.mule.api.config.MuleProperties;
14  import org.mule.util.FileUtils;
15  import org.mule.util.SystemUtils;
16  
17  import java.io.File;
18  import java.io.IOException;
19  import java.net.MalformedURLException;
20  import java.net.URL;
21  import java.util.ArrayList;
22  import java.util.Collection;
23  import java.util.Collections;
24  import java.util.Enumeration;
25  import java.util.List;
26  import java.util.Set;
27  
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  public class MuleApplicationClassLoader extends FineGrainedControlClassLoader
32  {
33  
34      /**
35       * Library directory in Mule application.
36       */
37      public static final String PATH_LIBRARY = "lib";
38  
39      /**
40       * Classes and resources directory in Mule application.
41       */
42      public static final String PATH_CLASSES = "classes";
43  
44      /**
45       * Directory for standard mule modules and transports
46       */
47      public static final String PATH_MULE = "mule";
48  
49      /**
50       * Sub-directory for per-application mule modules and transports
51       */
52      public static final String PATH_PER_APP = "per-app";
53  
54      protected static final URL[] CLASSPATH_EMPTY = new URL[0];
55      protected final transient Log logger = LogFactory.getLog(getClass());
56  
57      protected List<ShutdownListener> shutdownListeners = new ArrayList<ShutdownListener>();
58  
59      private String appName;
60  
61      public MuleApplicationClassLoader(String appName, ClassLoader parentCl)
62      {
63          this(appName, parentCl, Collections.<String>emptySet());
64      }
65  
66      public MuleApplicationClassLoader(String appName, ClassLoader parentCl, Set<String> loaderOverrides)
67      {
68          super(CLASSPATH_EMPTY, parentCl, loaderOverrides);
69          this.appName = appName;
70          try
71          {
72              // get lib dir
73              final String muleHome = System.getProperty(MuleProperties.MULE_HOME_DIRECTORY_PROPERTY);
74              String configPath = String.format("%s/apps/%s", muleHome, appName);
75              File parentFile = new File(configPath); 
76              File classesDir = new File(parentFile, PATH_CLASSES);
77              addURL(classesDir.toURI().toURL());
78  
79              File libDir = new File(parentFile, PATH_LIBRARY);
80              addJars(appName, libDir, true);
81  
82              // Add per-app mule modules (if any)
83              File libs = new File(muleHome, PATH_LIBRARY);
84              File muleLibs = new File(libs, PATH_MULE);
85              File perAppLibs = new File(muleLibs, PATH_PER_APP);
86              addJars(appName, perAppLibs, false);
87          }
88          catch (IOException e)
89          {
90              if (logger.isDebugEnabled())
91              {
92                  logger.debug(String.format("[%s]", appName), e);
93              }
94          }
95      }
96  
97      /**
98       * Add jars from the supplied directory to the class path
99       */
100     private void addJars(String appName, File dir, boolean verbose) throws MalformedURLException
101     {
102         if (dir.exists() && dir.canRead())
103         {
104             @SuppressWarnings("unchecked")
105             Collection<File> jars = FileUtils.listFiles(dir, new String[]{"jar"}, false);
106 
107             if (!jars.isEmpty() && logger.isInfoEnabled())
108             {
109                 StringBuilder sb = new StringBuilder();
110                 sb.append(String.format("[%s] Loading the following jars:%n", appName));
111                 sb.append("=============================").append(SystemUtils.LINE_SEPARATOR);
112 
113                 for (File jar : jars)
114                 {
115                     sb.append(jar.toURI().toURL()).append(SystemUtils.LINE_SEPARATOR);
116                 }
117 
118                 sb.append("=============================").append(SystemUtils.LINE_SEPARATOR);
119 
120                 if (verbose)
121                 {
122                     logger.info(sb.toString());
123                 }
124                 else
125                 {
126                     logger.debug(sb.toString());
127                 }
128             }
129 
130             for (File jar : jars)
131             {
132                 addURL(jar.toURI().toURL());
133             }
134         }
135     }
136 
137     @Override
138     protected Class<?> findClass(String name) throws ClassNotFoundException
139     {
140         return super.findClass(name);
141     }
142 
143     @Override
144     protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException
145     {
146         return super.loadClass(name, resolve);
147     }
148 
149     @Override
150     public URL getResource(String name)
151     {
152         return super.getResource(name);
153     }
154 
155     @Override
156     public Enumeration<URL> getResources(String name) throws IOException
157     {
158         return super.getResources(name);
159     }
160 
161     @Override
162     public void close()
163     {
164         for (ShutdownListener listener : shutdownListeners)
165         {
166             try
167             {
168                 listener.execute();
169             }
170             catch (Exception e)
171             {
172                 logger.error(e);
173             }
174         }
175         super.close();
176     }
177 
178     public void addShutdownListener(ShutdownListener listener)
179     {
180         this.shutdownListeners.add(listener);
181     }
182 
183     public String getAppName()
184     {
185         return appName;
186     }
187 
188     @Override
189     public String toString()
190     {
191         return String.format("%s[%s]@%s", getClass().getName(),
192                              appName,
193                              Integer.toHexString(System.identityHashCode(this)));
194     }
195 
196     /**
197      * Optional hook, invoked synchronously right before the classloader is disposed of and closed.
198      */
199     public interface ShutdownListener
200     {
201         void execute();
202     }
203 }