View Javadoc

1   /*
2    * Copyright 2005 The Apache Software Foundation.
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  
17  package org.apache.jdo.impl.enhancer.core;
18  
19  import java.io.IOException;
20  import java.io.InputStream;
21  import java.io.OutputStream;
22  import java.io.PrintWriter;
23  import java.io.DataInputStream;
24  import java.io.DataOutputStream;
25  
26  import java.util.Properties;
27  
28  import org.apache.jdo.impl.enhancer.ClassFileEnhancer;
29  import org.apache.jdo.impl.enhancer.EnhancerFatalError;
30  import org.apache.jdo.impl.enhancer.EnhancerUserException;
31  import org.apache.jdo.impl.enhancer.OutputStreamWrapper;
32  import org.apache.jdo.impl.enhancer.classfile.ClassFile;
33  import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
34  import org.apache.jdo.impl.enhancer.meta.EnhancerMetaDataUserException;
35  import org.apache.jdo.impl.enhancer.util.Support;
36  
37  
38  
39  
40  
41  
42  
43  /***
44   * Provides a JDO byte-code enhancer.
45   */
46  public class EnhancerFilter
47      extends Support
48      implements ClassFileEnhancer
49  {
50      static public final String DO_TIMING_STATISTICS
51          = "Enhancer.doTimingStatistics";
52      static public final String DUMP_CLASS
53          = "Enhancer.dumpClass";
54      static public final String NO_AUGMENT
55          = "Enhancer.noAugment";
56      static public final String NO_ANNOTATE
57          = "Enhancer.noAnnotate";
58      static public final String VERBOSE_LEVEL
59          = "Enhancer.verboseLevel";
60      static public final String VERBOSE_LEVEL_QUIET
61          = "quiet";
62      static public final String VERBOSE_LEVEL_WARN
63          = "warn";
64      static public final String VERBOSE_LEVEL_VERBOSE
65          = "verbose";
66      static public final String VERBOSE_LEVEL_DEBUG
67          = "debug";
68  
69      /* Central repository for the options selected by
70       * the user and the current state of the Filter execution */
71      private Environment env = new Environment();
72  
73      /***
74       * Initializes an instance of a JDO enhancer.
75       * @param metaData the JDO meta-data object
76       * @param settings enhancement properties
77       * @param out standard ouput stream for the enhancer
78       */
79      protected void init(EnhancerMetaData metaData,
80                          Properties  settings,
81                          PrintWriter out,
82                          PrintWriter err)
83          throws EnhancerUserException, EnhancerFatalError
84      {
85          if (metaData == null) {
86              throw new EnhancerFatalError(
87                  getI18N("enhancer.internal_error",
88                          "Illegal argument: metaData == null"));
89          }
90  
91          env.setEnhancerMetaData(metaData);
92  
93          final String doTiming
94              = (settings == null
95                 ? null
96                 : settings.getProperty(DO_TIMING_STATISTICS));
97          env.setDoTimingStatistics(Boolean.valueOf(doTiming).booleanValue());
98  
99          final String dumpClass
100             = (settings == null
101                ? null
102                : settings.getProperty(DUMP_CLASS));
103         env.setDumpClass(Boolean.valueOf(dumpClass).booleanValue());
104 
105         final String noAugment
106             = (settings == null
107                ? null
108                : settings.getProperty(NO_AUGMENT));
109         env.setNoAugment(Boolean.valueOf(noAugment).booleanValue());
110 
111         final String noAnnotate
112             = (settings == null
113                ? null
114                : settings.getProperty(NO_ANNOTATE));
115         env.setNoAnnotate(Boolean.valueOf(noAnnotate).booleanValue());
116 
117         // set verbose level
118         if  (err != null) {
119             env.setErrorWriter(err);
120         }
121         if  (out != null) {
122             env.setOutputWriter(out);
123         }
124         final String verboseLevel
125             = (settings == null ? null : settings.getProperty(VERBOSE_LEVEL));
126         if (VERBOSE_LEVEL_QUIET.equals(verboseLevel)) {
127             env.setVerbose(false);
128             env.setQuiet(true);
129         } else if (VERBOSE_LEVEL_WARN.equals(verboseLevel)) {
130             env.setVerbose(false);
131             env.setQuiet(false);
132         } else if (VERBOSE_LEVEL_VERBOSE.equals(verboseLevel)) {
133             env.setVerbose(true);
134             env.setQuiet(false);
135         } else if (VERBOSE_LEVEL_DEBUG.equals(verboseLevel)) {
136             env.setVerbose(true);
137             env.setQuiet(false);
138         } else {
139             env.setVerbose(false);
140             env.setQuiet(false);
141         }
142     }
143 
144     /***
145      * Creates an instance of a JDO enhancer.
146      * @param metaData the JDO meta-data object
147      * @param settings enhancement properties
148      * @param out standard ouput stream for the enhancer
149      */
150     public EnhancerFilter(EnhancerMetaData metaData,
151                     Properties  settings,
152                     PrintWriter out,
153                     PrintWriter err)
154         throws EnhancerUserException, EnhancerFatalError
155     {
156         init(metaData, settings, out, err);
157     }
158 
159     /***
160      * Enhances a given class according to the JDO meta-data.
161      */
162     private boolean enhanceClassFile1(InputStream inClassFile,
163                                       OutputStreamWrapper outClassFile)
164         throws EnhancerUserException
165     {
166         // check arguments
167         affirm(inClassFile, "Illegal argument: inClassFile == null.");
168         affirm(outClassFile, "Illegal argument: outClassFile == null.");
169 
170         // parse class
171         final ClassFile cf;
172         final Controller cc;
173         try {
174             // create class file
175             final DataInputStream dis = new DataInputStream(inClassFile);
176             final boolean allowJDK12ClassFiles = true;
177             cf = new ClassFile(dis, allowJDK12ClassFiles);
178             //@lars: do not close the input stream
179             //dis.close();
180 
181             // create class control
182             cc = new Controller(cf, env);
183 
184             // get real class name
185             final String className = cf.classNameString();
186         } catch (ClassFormatError ex) {
187             throw new EnhancerUserException(
188                 getI18N("enhancer.class_format_error"),
189                 ex);
190         }
191 
192         // enhance class
193         cc.enhanceClass();
194         if (env.errorCount() > 0) {
195             // retrieve error messages
196             env.getErrorWriter().flush();
197 
198             throw new EnhancerUserException(env.getLastErrorMessage());
199         }
200         affirm(env.errorCount() == 0);
201 
202         // write class
203         boolean changed = cc.updated();
204         try {
205             if (changed) {
206                 env.message("writing enhanced class " + cf.userClassName()
207                             + " to output stream");
208             } else {
209                 env.message("no changes to class " + cf.userClassName());
210             }
211             outClassFile.setClassName(cf.userClassName());
212             final DataOutputStream dos
213                 = new DataOutputStream(outClassFile.getStream());
214             cf.write(dos);
215             dos.flush();
216         } catch (IOException ex) {
217             throw new EnhancerUserException(
218                 getI18N("enhancer.io_error_while_writing_stream"),
219                 ex);
220         }
221         return changed;
222     }
223 
224     /***
225      * Enhances a given class according to the JDO meta-data.
226      */
227     public boolean enhanceClassFile(InputStream         inClassFile,
228                                     OutputStreamWrapper outClassFile)
229         throws EnhancerUserException, EnhancerFatalError
230     {
231         env.verbose("---------------------------------------------------------------------------");
232         env.messageNL("Enhancer: enhancing classfile ...");
233 
234         // reset environment to clear class map etc.
235         env.reset();
236 
237         // enhance class file; check Exceptions
238         final boolean changed;
239         try {
240             changed = enhanceClassFile1(inClassFile, outClassFile);
241         } catch (EnhancerUserException ex) {
242             // reset environment to clear class map etc.
243             env.reset();
244             throw ex;
245         } catch (EnhancerMetaDataUserException ex) {
246             // note: catch EnhancerMetaDataUserException before RuntimeException
247 
248             // reset environment to clear class map etc.
249             env.reset();
250             throw new EnhancerUserException(
251                 getI18N("enhancer.error", ex.getMessage()),
252                 ex);
253         } catch (RuntimeException ex) {
254             // reset environment to clear class map etc.
255             env.reset();
256             ex.printStackTrace ();
257             throw new EnhancerFatalError(
258                 getI18N("enhancer.internal_error", ex.getMessage()),
259                 ex);
260         }
261 
262         env.messageNL(changed
263                       ? "Enhancer: classfile enhanced successfully."
264                       : "Enhancer: classfile not changed.");
265         return changed;
266     }
267 
268     public boolean enhanceClassFile(InputStream in,
269                                     OutputStream out)
270         throws EnhancerUserException,
271         EnhancerFatalError
272     {
273         return enhanceClassFile(in, new OutputStreamWrapper(out));
274     }
275 }