View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.jci;
19  
20  import java.io.File;
21  
22  import org.apache.commons.io.FileUtils;
23  import org.apache.commons.jci.classes.ExtendedDump;
24  import org.apache.commons.jci.classes.SimpleDump;
25  import org.apache.commons.jci.compilers.CompilationResult;
26  import org.apache.commons.jci.compilers.JavaCompiler;
27  import org.apache.commons.jci.compilers.JavaCompilerSettings;
28  import org.apache.commons.jci.listeners.CompilingListener;
29  import org.apache.commons.jci.monitor.FilesystemAlterationMonitor;
30  import org.apache.commons.jci.problems.CompilationProblem;
31  import org.apache.commons.jci.problems.CompilationProblemHandler;
32  import org.apache.commons.jci.readers.ResourceReader;
33  import org.apache.commons.jci.stores.ResourceStore;
34  import org.apache.commons.jci.utils.ConversionUtils;
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  
38  /**
39   * 
40   * @author tcurdt
41   */
42  public final class CompilingClassLoaderTestCase extends AbstractTestCase {
43  
44      private final Log log = LogFactory.getLog(CompilingClassLoaderTestCase.class);
45  
46      private ReloadingClassLoader classloader;
47      private CompilingListener listener;
48      private FilesystemAlterationMonitor fam;
49          
50      private final static class MockJavaCompiler implements JavaCompiler {
51  
52          private final Log log = LogFactory.getLog(MockJavaCompiler.class);
53  
54          public CompilationResult compile(String[] pResourcePaths, ResourceReader pReader, ResourceStore pStore, ClassLoader pClassLoader, JavaCompilerSettings pSettings ) {
55  
56              for (int i = 0; i < pResourcePaths.length; i++) {
57                  final String resourcePath = pResourcePaths[i];
58                  final byte[] resourceContent = pReader.getBytes(resourcePath);
59  
60                  log.debug("resource " + resourcePath + " = " + ((resourceContent!=null)?new String(resourceContent):null) );
61  
62                  final byte[] data;
63  
64                  if ("jci/Simple.java".equals(resourcePath)) {
65  
66                      try {
67                          data = SimpleDump.dump(new String(resourceContent));
68                      } catch (Exception e) {
69                          throw new RuntimeException("cannot handle resource " + resourcePath, e);
70                      }
71  
72                  } else if ("jci/Extended.java".equals(resourcePath)) {
73  
74                      try {
75                          data = ExtendedDump.dump();
76                      } catch (Exception e) {
77                          throw new RuntimeException("cannot handle resource " + resourcePath, e);
78                      }
79  
80                  } else {
81                      throw new RuntimeException("cannot handle resource " + resourcePath);
82                  }
83  
84                  log.debug("compiling " + resourcePath + " (" + data.length + ")");
85  
86                  pStore.write(ConversionUtils.stripExtension(resourcePath) + ".class", data);
87  
88              }
89  
90              return new CompilationResult(new CompilationProblem[0]);
91          }
92  
93          public CompilationResult compile(String[] pResourcePaths, ResourceReader pReader, ResourceStore pStore, ClassLoader pClassLoader) {
94              return compile(pResourcePaths, pReader, pStore, pClassLoader, null);
95          }
96  
97          public CompilationResult compile(String[] pResourcePaths, ResourceReader pReader, ResourceStore pStore) {
98              return compile(pResourcePaths, pReader, pStore, null);
99          }
100 
101         public void setCompilationProblemHandler(CompilationProblemHandler pHandler) {
102         }
103 
104         public JavaCompilerSettings createDefaultSettings() {
105             return null;
106         }
107 
108     }
109     
110     @Override
111     protected void setUp() throws Exception {
112         super.setUp();
113         
114         classloader = new ReloadingClassLoader(this.getClass().getClassLoader());
115         listener = new CompilingListener(new MockJavaCompiler());   
116 
117         listener.addReloadNotificationListener(classloader);
118         
119         fam = new FilesystemAlterationMonitor();
120         fam.addListener(directory, listener);
121         fam.start();
122     }
123 
124     private void initialCompile() throws Exception {
125         log.debug("initial compile");        
126 
127         listener.waitForFirstCheck();
128                 
129         writeFile("jci/Simple.java", "Simple1");        
130         writeFile("jci/Extended.java", "Extended");        
131         
132         log.debug("waiting for compile changes to get applied");        
133         listener.waitForCheck();
134         
135         log.debug("*** ready to test");        
136     }
137     
138     public void testCreate() throws Exception {
139         initialCompile();
140         
141         log.debug("loading Simple");        
142         final Object simple = classloader.loadClass("jci.Simple").newInstance();        
143         assertEquals("Simple1", simple.toString());
144         
145         log.debug("loading Extended");        
146         final Object extended = classloader.loadClass("jci.Extended").newInstance();        
147         assertEquals("Extended:Simple1", extended.toString());
148     }
149 
150     public void testChange() throws Exception {        
151         initialCompile();
152 
153         final Object simple = classloader.loadClass("jci.Simple").newInstance();        
154         assertEquals("Simple1", simple.toString());
155         
156         final Object extended = classloader.loadClass("jci.Extended").newInstance();        
157         assertEquals("Extended:Simple1", extended.toString());
158 
159         delay();
160         writeFile("jci/Simple.java", "Simple2");
161         listener.waitForCheck();
162     
163         final Object simple2 = classloader.loadClass("jci.Simple").newInstance();        
164         assertEquals("Simple2", simple2.toString());
165         
166         final Object newExtended = classloader.loadClass("jci.Extended").newInstance();        
167         assertEquals("Extended:Simple2", newExtended.toString());
168     }
169 
170     public void testDelete() throws Exception {
171         initialCompile();
172 
173         final Object simple = classloader.loadClass("jci.Simple").newInstance();        
174         assertEquals("Simple1", simple.toString());
175         
176         final Object extended = classloader.loadClass("jci.Extended").newInstance();        
177         assertEquals("Extended:Simple1", extended.toString());
178                 
179         listener.waitForCheck();
180         
181         log.debug("deleting source file");
182         assertTrue(new File(directory, "jci/Extended.java").delete());
183         
184         listener.waitForCheck();
185        
186         log.debug("loading Simple");
187         final Object oldSimple = classloader.loadClass("jci.Simple").newInstance();        
188         assertEquals("Simple1", oldSimple.toString());
189 
190         log.debug("trying to loading Extended");
191         try {
192             classloader.loadClass("jci.Extended").newInstance();
193             fail();
194         } catch(final ClassNotFoundException e) {
195             assertEquals("jci.Extended", e.getMessage());
196         }        
197         
198         log.debug("deleting whole directory");
199         FileUtils.deleteDirectory(new File(directory, "jci"));
200 
201         listener.waitForCheck();
202 
203         log.debug("trying to loading Simple");
204         try {
205             classloader.loadClass("jci.Simple").newInstance();
206             fail();
207         } catch(final ClassNotFoundException e) {
208             assertEquals("jci.Simple", e.getMessage());
209         }
210 
211     }
212 
213     public void testDeleteDependency() throws Exception {        
214         initialCompile();
215 
216         final Object simple = classloader.loadClass("jci.Simple").newInstance();        
217         assertEquals("Simple1", simple.toString());
218         
219         final Object extended = classloader.loadClass("jci.Extended").newInstance();        
220         assertEquals("Extended:Simple1", extended.toString());
221         
222         log.debug("deleting source file");
223         assertTrue(new File(directory, "jci/Simple.java").delete());
224         listener.waitForCheck();
225 
226         log.debug("trying to load dependend class");
227         try {
228             classloader.loadClass("jci.Extended").newInstance();
229             fail();
230         } catch(final NoClassDefFoundError e) {
231             assertEquals("jci/Simple", e.getMessage());
232         }
233         
234     }
235 
236     @Override
237     protected void tearDown() throws Exception {
238         fam.removeListener(listener);
239         fam.stop();
240         super.tearDown();
241     }    
242 }