Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: com/puppycrawl/tools/checkstyle/bcel/ClassFileSetCheck.java


1   //Tested with BCEL-5.1
2   //http://jakarta.apache.org/builds/jakarta-bcel/release/v5.1/
3   
4   package com.puppycrawl.tools.checkstyle.bcel;
5   
6   import java.io.File;
7   import java.io.IOException;
8   import java.io.InputStream;
9   import java.util.Enumeration;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.Set;
13  import java.util.zip.ZipEntry;
14  import java.util.zip.ZipFile;
15  
16  import org.apache.bcel.Repository;
17  import org.apache.bcel.classfile.ClassParser;
18  import org.apache.bcel.classfile.JavaClass;
19  import org.apache.bcel.classfile.Visitor;
20  import org.apache.bcel.util.ClassLoaderRepository;
21  
22  import com.puppycrawl.tools.checkstyle.DefaultContext;
23  import com.puppycrawl.tools.checkstyle.ModuleFactory;
24  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
25  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
26  import com.puppycrawl.tools.checkstyle.api.Configuration;
27  import com.puppycrawl.tools.checkstyle.api.Context;
28  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
29  
30  /**
31   * Checks a set of class files using BCEL
32   * @author Rick Giles
33   */
34  //TODO: Refactor with AbstractFileSetCheck and TreeWalker
35  public class ClassFileSetCheck
36      extends AbstractFileSetCheck
37      implements IObjectSetVisitor
38  {
39      /** visitors for BCEL parse tree walk */
40      private final Set mTreeVisitors = new HashSet();
41  
42      /** all the registered checks */
43      private final Set mAllChecks = new HashSet();
44  
45      /** all visitors for IObjectSetVisitor visits */
46      private final Set mObjectSetVisitors = new HashSet();
47  
48      /** class loader to resolve classes with. **/
49      private ClassLoader mClassLoader;
50  
51      /** context of child components */
52      private Context mChildContext;
53  
54      /** a factory for creating submodules (i.e. the Checks) */
55      private ModuleFactory mModuleFactory;
56  
57      /**
58       * Creates a new <code>ClassFileSetCheck</code> instance.
59       * Initializes the acceptable file extensions.
60       */
61      public ClassFileSetCheck()
62      {
63          setFileExtensions(new String[]{"class", "jar", "zip"});
64      }
65  
66      /**
67       * Stores the class loader and makes it the Repository's class loader.
68       * @param aClassLoader class loader to resolve classes with.
69       */
70      public void setClassLoader(ClassLoader aClassLoader)
71      {
72          Repository.setRepository(new ClassLoaderRepository(aClassLoader));
73          mClassLoader = aClassLoader;
74      }
75  
76      /**
77       * Sets the module factory for creating child modules (Checks).
78       * @param aModuleFactory the factory
79       */
80      public void setModuleFactory(ModuleFactory aModuleFactory)
81      {
82          mModuleFactory = aModuleFactory;
83      }
84  
85      /**
86       * Instantiates, configures and registers a Check that is specified
87       * in the provided configuration.
88       * @see com.puppycrawl.tools.checkstyle.api.AutomaticBean
89       */
90      public void setupChild(Configuration aChildConf)
91          throws CheckstyleException
92      {
93          // TODO: improve the error handing
94          final String name = aChildConf.getName();
95          final Object module = mModuleFactory.createModule(name);
96          if (!(module instanceof AbstractCheckVisitor)) {
97              throw new CheckstyleException(
98                  "ClassFileSet is not allowed as a parent of " + name);
99          }
100         final AbstractCheckVisitor c = (AbstractCheckVisitor) module;
101         c.contextualize(mChildContext);
102         c.configure(aChildConf);
103         c.init();
104 
105         registerCheck(c);
106     }
107 
108     /** @see com.puppycrawl.tools.checkstyle.api.Configurable */
109     public void finishLocalSetup()
110     {
111         DefaultContext checkContext = new DefaultContext();
112         checkContext.add("classLoader", mClassLoader);
113         checkContext.add("messages", getMessageCollector());
114         checkContext.add("severity", getSeverity());
115 
116         mChildContext = checkContext;
117     }
118 
119     /**
120      * Register a check.
121      * @param aCheck the check to register
122      */
123     private void registerCheck(AbstractCheckVisitor aCheck)
124     {
125         mAllChecks.add(aCheck);
126     }
127 
128     /**
129      * @see com.puppycrawl.tools.checkstyle.api.FileSetCheck
130      */
131     public void process(File[] aFiles)
132     {
133         registerVisitors();
134 
135         // get all the JavaClasses in the files
136         final Set javaClasses = extractJavaClasses(aFiles);
137 
138         visitSet(javaClasses);
139 
140         // walk each Java class parse tree
141         final JavaClassWalker walker = new JavaClassWalker();
142         walker.setVisitor(getTreeVisitor());
143         final Iterator it = javaClasses.iterator();
144         while (it.hasNext()) {
145             final JavaClass clazz = (JavaClass) it.next();
146             visitObject(clazz);
147             walker.walk(clazz);
148             leaveObject(clazz);
149         }
150 
151         leaveSet(javaClasses);
152         fireErrors();
153     }
154 
155     /**
156      * Gets the visitor for a parse tree walk.
157      * @return the visitor for a parse tree walk.
158      */
159     private Visitor getTreeVisitor()
160     {
161         return new VisitorSet(mTreeVisitors);
162     }
163 
164     /**
165      * Registers all the visitors for IObjectSetVisitor visits, and for
166      * tree walk visits.
167      */
168     private void registerVisitors()
169     {
170         mObjectSetVisitors.addAll(mAllChecks);
171         final Iterator it = mAllChecks.iterator();
172         while (it.hasNext()) {
173             final AbstractCheckVisitor check = (AbstractCheckVisitor) it.next();
174             final IDeepVisitor visitor = check.getVisitor();
175             mObjectSetVisitors.add(visitor);
176             mTreeVisitors.add(visitor);
177         }
178     }
179 
180     /**
181      * Gets the set of all visitors for all the checks.
182      * @return the set of all visitors for all the checks.
183      */
184     private Set getObjectSetVisitors()
185     {
186         return mObjectSetVisitors;
187     }
188 
189     /**
190      * Gets the set of all JavaClasses within a set of Files.
191      * @param aFiles the set of files to extract from.
192      * @return the set of all JavaClasses within aFiles.
193      */
194     private Set extractJavaClasses(File[] aFiles)
195     {
196         final Set result = new HashSet();
197         final File[] classFiles = filter(aFiles);
198         // get Java classes from each filtered file
199         for (int i = 0; i < classFiles.length; i++) {
200             try {
201                 final Set extracted = extractJavaClasses(classFiles[i]);
202                 result.addAll(extracted);
203             }
204             catch (IOException e) {
205                 // TODO Auto-generated catch block
206                 e.printStackTrace();
207             }
208         }
209         return result;
210     }
211 
212     /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */
213     public void visitSet(Set aSet)
214     {
215         // register the JavaClasses in the Repository
216         Repository.clearCache();
217         Iterator it = aSet.iterator();
218         while (it.hasNext()) {
219             final JavaClass javaClass = (JavaClass) it.next();
220             Repository.addClass(javaClass);
221         }
222 
223         // visit the visitors
224         it = getObjectSetVisitors().iterator();
225         while (it.hasNext()) {
226             final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next();
227             visitor.visitSet(aSet);
228         }
229     }
230 
231     /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */
232     public void visitObject(Object aObject)
233     {
234         final Iterator it = getObjectSetVisitors().iterator();
235         while (it.hasNext()) {
236             final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next();
237             visitor.visitObject(aObject);
238         }
239     }
240 
241     /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */
242     public void leaveObject(Object aObject)
243     {
244         final Iterator it = getObjectSetVisitors().iterator();
245         while (it.hasNext()) {
246             final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next();
247             visitor.leaveObject(aObject);
248         }
249     }
250 
251     /** @see com.puppycrawl.tools.checkstyle.bcel.IObjectSetVisitor */
252     public void leaveSet(Set aSet)
253     {
254         final Iterator it = getObjectSetVisitors().iterator();
255         while (it.hasNext()) {
256             final IObjectSetVisitor visitor = (IObjectSetVisitor) it.next();
257             visitor.leaveSet(aSet);
258         }
259     }
260 
261     /**
262      * Extracts the JavaClasses from .class, .zip, and .jar files.
263      * @param aFile the file to extract from.
264      * @return the set of JavaClasses from aFile.
265      * @throws IOException if there is an error.
266      */
267     private Set extractJavaClasses(File aFile)
268         throws IOException
269     {
270         final Set result = new HashSet();
271         final String fileName = aFile.getPath();
272         if (fileName.endsWith(".jar") || fileName.endsWith(".zip")) {
273             final ZipFile zipFile = new ZipFile(fileName);
274             final Enumeration entries = zipFile.entries();
275             while (entries.hasMoreElements()) {
276                 final ZipEntry entry = (ZipEntry) entries.nextElement();
277                 final String entryName = entry.getName();
278                 if (entryName.endsWith(".class")) {
279                     final InputStream in = zipFile.getInputStream(entry);
280                     final JavaClass javaClass =
281                         new ClassParser(in, entryName).parse();
282                     result.add(javaClass);
283                 }
284             }
285         }
286         else {
287             final JavaClass javaClass = new ClassParser(fileName).parse();
288             result.add(javaClass);
289         }
290         return result;
291     }
292 
293     /**
294      * Notify all listeners about the errors in a file.
295      * Calls <code>MessageDispatcher.fireErrors()</code> with
296      * all logged errors and than clears errors' list.
297      */
298     private void fireErrors()
299     {
300         final LocalizedMessage[] errors = getMessageCollector().getMessages();
301         getMessageCollector().reset();
302         getMessageDispatcher().fireErrors("", errors);
303     }
304 }