View Javadoc

1   /*
2    * Copyright 2007-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.maven.exceptions.runtime;
17  
18  import java.io.BufferedInputStream;
19  import java.io.File;
20  import java.io.FileInputStream;
21  import java.io.IOException;
22  import java.io.InputStream;
23  import java.net.URL;
24  import java.util.jar.JarEntry;
25  import java.util.jar.JarFile;
26  
27  import org.apache.commons.io.IOUtils;
28  import org.apache.commons.logging.Log;
29  import org.apache.commons.logging.LogFactory;
30  
31  /**
32   * Base implementation of class loaders that serve classes from the given
33   * directories.
34   */
35  public abstract class AbstractProjectClassLoader extends ClassLoader
36  {
37    // ********************************* Fields *********************************
38  
39    // --- constants ------------------------------------------------------------
40  
41    // --- members --------------------------------------------------------------
42  
43    /**
44     * Reference to the logger for this class.
45     */
46    private final Log log = LogFactory.getLog(AbstractProjectClassLoader.class);
47  
48    // ****************************** Initializer *******************************
49  
50    // ****************************** Constructors ******************************
51  
52    /**
53     * Default constructor.
54     *
55     * @param parent the parent class loader.
56     */
57    protected AbstractProjectClassLoader(final ClassLoader parent)
58    {
59      super(parent);
60    }
61  
62    // ****************************** Inner Classes *****************************
63  
64    // ********************************* Methods ********************************
65  
66    // --- init -----------------------------------------------------------------
67  
68    // --- get&set --------------------------------------------------------------
69  
70    // --- business -------------------------------------------------------------
71  
72    /**
73     * Ensures that the package of a class specified by the given name is already
74     * defined. If it is not defined the loaded class instance will not have a
75     * package reference.
76     *
77     * @param className the name of the class whose package is to check to be
78     *          already defined.
79     */
80    protected void ensurePackageProvided(final String className)
81    {
82      final int lastDotIndex = className.lastIndexOf('.');
83      if (lastDotIndex != -1)
84      {
85        final String packageName = className.substring(0, lastDotIndex);
86        final Package paccage = getPackage(packageName);
87        if (paccage == null)
88        {
89          definePackage(packageName, null, null, null, null, null, null, null);
90        }
91      }
92    }
93  
94    /**
95     * Loads the class. Ensures that the package of the class is defined.
96     *
97     * @param className the name of the class.
98     * @param classFile the file with the binary data.
99     * @return the loaded class definition.
100    * @throws ClassNotFoundException if the class cannot be loaded.
101    */
102   protected Class<?> loadClassFile(final String className, final File classFile)
103     throws ClassNotFoundException
104   {
105     ensurePackageProvided(className);
106     InputStream in = null;
107     try
108     {
109       in = new BufferedInputStream(new FileInputStream(classFile));
110       final byte[] data = IOUtils.toByteArray(in);
111       final Class<?> clazz = defineClass(className, data, 0, data.length);
112       return clazz;
113     }
114     catch (final IOException e)
115     {
116       final String message =
117           "Cannot load class '" + className + "' from file '" + classFile
118               + "'.";
119       if (log.isDebugEnabled())
120       {
121         log.debug(message);
122       }
123 
124       throw new ClassNotFoundException(message, e);
125     }
126     finally
127     {
128       IOUtils.closeQuietly(in);
129     }
130   }
131 
132   /**
133    * Opens a reader to the class file within the archive.
134    *
135    * @param className the name of the class to load.
136    * @param fileName the name of the class file to load.
137    * @param dirName the name of the directory the archive file is located.
138    * @return the reader to the source file for the given class in the archive.
139    * @throws ClassNotFoundException if the class cannot be found.
140    */
141   protected Class<?> loadClassFromLibrary(final String className,
142       final String fileName, final File dirName) throws ClassNotFoundException
143   {
144     ensurePackageProvided(className);
145     try
146     {
147       final JarFile jarFile = new JarFile(dirName); // NOPMD
148       final JarEntry entry = jarFile.getJarEntry(fileName);
149       if (entry != null)
150       {
151         InputStream in = null;
152         try
153         {
154           in = new BufferedInputStream(jarFile.getInputStream(entry));
155           final byte[] data = IOUtils.toByteArray(in);
156           final Class<?> clazz = defineClass(className, data, 0, data.length);
157           return clazz;
158         }
159         finally
160         {
161           IOUtils.closeQuietly(in);
162         }
163       }
164     }
165     catch (final IOException e)
166     {
167       final String message =
168           "Cannot load class '" + className + "' from file '" + dirName + "'.";
169       if (log.isDebugEnabled())
170       {
171         log.debug(message);
172       }
173 
174       throw new ClassNotFoundException(message, e);
175     }
176 
177     final String message =
178         "Cannot load class '" + className + "' from file '" + dirName + "'.";
179     if (log.isDebugEnabled())
180     {
181       log.debug(message);
182     }
183 
184     throw new ClassNotFoundException(message);
185   }
186 
187   /**
188    * Opens a reader to the resource file within the archive.
189    *
190    * @param resourceName the name of the resource to load.
191    * @param fileName the name of the resource file to load.
192    * @param dirName the name of the directory the archive file is located.
193    * @return the reader to the source file for the given class in the archive.
194    * @throws ClassNotFoundException if the class cannot be found.
195    */
196   protected URL loadResourceFromLibrary(final String resourceName,
197       final String fileName, final File dirName) throws IOException
198   {
199     ensurePackageProvided(resourceName);
200     try
201     {
202       return new URL("jar:file:" + dirName.getName() + "!/" + fileName);
203     }
204     catch (final IOException e)
205     {
206       final String message =
207           "Cannot load class '" + resourceName + "' from file '" + dirName
208               + "'.";
209       if (log.isDebugEnabled())
210       {
211         log.debug(message);
212       }
213       final IOException ioe = new IOException(message);
214       ioe.initCause(e);
215       throw ioe;
216     }
217   }
218 
219   // --- object basics --------------------------------------------------------
220 
221 }