View Javadoc

1   /*
2    * Jour - java profiler and monitoring library
3    *
4    * Copyright (C) 2004 Jour team
5    *
6    * This library is free software; you can redistribute it and/or
7    * modify it under the terms of the GNU Library General Public
8    * License as published by the Free Software Foundation; either
9    * version 2 of the License, or (at your option) any later version.
10   *
11   * This library is distributed in the hope that it will be useful,
12   * but WITHOUT ANY WARRANTY; without even the implied warranty of
13   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14   * Library General Public License for more details.
15   *
16   * You should have received a copy of the GNU Library General Public
17   * License along with this library; if not, write to the
18   * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19   * Boston, MA  02111-1307, USA.
20   */
21  package net.sf.jour;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.util.Enumeration;
26  import java.util.Iterator;
27  import java.util.List;
28  import java.util.Properties;
29  import java.util.Vector;
30  
31  import javassist.ClassPool;
32  import javassist.CtClass;
33  import javassist.NotFoundException;
34  import net.sf.jour.instrumentor.Instrumentor;
35  import net.sf.jour.instrumentor.InstrumentorResults;
36  import net.sf.jour.instrumentor.InstrumentorResultsImpl;
37  import net.sf.jour.log.Logger;
38  import net.sf.jour.processor.DirectoryInputSource;
39  import net.sf.jour.processor.DirectoryOutputWriter;
40  import net.sf.jour.processor.Entry;
41  import net.sf.jour.processor.EntryHelper;
42  import net.sf.jour.processor.InputSource;
43  import net.sf.jour.processor.InstrumentedCreatedEntry;
44  import net.sf.jour.processor.InstrumentedEntry;
45  import net.sf.jour.processor.JarFileInputSource;
46  import net.sf.jour.processor.OutputWriter;
47  import net.sf.jour.util.BuildVersion;
48  import net.sf.jour.util.CmdArgs;
49  
50  /**
51   * 
52   * Created on 02.10.2004
53   * 
54   * Contributing Author(s):
55   * 
56   * Misha Lifschitz <mishalifschitz at users.sourceforge.net> (Inital
57   * implementation) Vlad Skarzhevskyy <vlads at users.sourceforge.net> (Inital
58   * implementation)
59   * 
60   * @author michaellif
61   * @version $Revision: 67 $ ($Author: vlads $) $Date: 2007-10-10 18:49:54 -0400
62   *          (Wed, 10 Oct 2007) $
63   */
64  public class PreProcessor {
65  
66  	protected static final Logger log = Logger.getLogger();
67  
68  	public long savedClasses;
69  
70  	public long countClasses;
71  
72  	private long countMethods;
73  
74  	private long countCounstructors;
75  
76  	private File input;
77  
78  	private File output;
79  
80  	private boolean copyClasses = false;
81  
82  	private boolean copyResources = false;
83  
84  	private boolean useSystemClassPath = false;
85  
86  	Config config;
87  
88  	ClassPool classPool;
89  
90  	public static void main(String[] args) {
91  		Properties argsp = CmdArgs.load(args);
92  		if ((args.length < 1) || argsp.getProperty("help") != null) {
93  			StringBuffer usage = new StringBuffer();
94  			usage.append("Usage:\n java ").append(PreProcessor.class.getName());
95  			usage.append(" --config jour.xml --src classesDir|classes.jar --dst outDir\n");
96  			usage.append("    (--classpath classpath) (--copy resource|classes|all) (--systempath)\n");
97  			System.out.println(usage);
98  			return;
99  		}
100 
101 		try {
102 			PreProcessor pp = new PreProcessor(argsp);
103 			pp.process();
104 
105 			System.out.println("Processed Classes     " + pp.countClasses);
106 			System.out.println("Altered Counstructors " + pp.countCounstructors);
107 			System.out.println("Altered Methods       " + pp.countMethods);
108 			System.out.println("Saved Classes         " + pp.savedClasses);
109 
110 		} catch (Throwable e) {
111 			e.printStackTrace();
112 			throw new Error(e);
113 		}
114 	}
115 
116 	public PreProcessor(String[] args) throws NotFoundException {
117 		this(CmdArgs.load(args));
118 	}
119 
120 	public PreProcessor(Properties properties) throws NotFoundException {
121 		String configFileName = properties.getProperty("config");
122 		String out = properties.getProperty("dst");
123 		String in = properties.getProperty("src");
124 		if (out == null) {
125 			out = in;
126 		}
127 		String copy = properties.getProperty("config");
128 		if ("all".equalsIgnoreCase(copy)) {
129 			setCopyClasses(true);
130 			setCopyResources(true);
131 		} else if ("classes".equalsIgnoreCase(copy)) {
132 			setCopyClasses(true);
133 		} else if ("resources".equalsIgnoreCase(copy)) {
134 			setCopyResources(true);
135 		}
136 
137 		this.useSystemClassPath = "true".equals(properties.getProperty("systempath"));
138 
139 		List classpath = new Vector();
140 
141 		Object cp = properties.get("cp");
142 		if (cp != null) {
143 			if (cp instanceof List) {
144 				classpath.addAll((List) cp);
145 			} else {
146 				classpath.add(cp);
147 			}
148 		}
149 		cp = properties.get("classpath");
150 		if (cp != null) {
151 			if (cp instanceof List) {
152 				classpath.addAll((List) cp);
153 			} else {
154 				classpath.add(cp);
155 			}
156 		}
157 
158 		try {
159 			init(configFileName, new File(in).getCanonicalFile(), new File(out).getCanonicalFile(), classpath);
160 		} catch (IOException e) {
161 			throw new Error("Can't configure input/output path", e);
162 		}
163 	}
164 
165 	public PreProcessor(String configFileName, File in, File out, List classpath) {
166 		init(configFileName, in, out, classpath);
167 	}
168 
169 	private void init(String configFileName, File in, File out, List classpath) {
170 		if ((in == null) || (!in.exists())) {
171 			throw new Error("Input jar or folder expected");
172 		}
173 		if (in.isFile() && (!in.getName().endsWith(".jar"))) {
174 			throw new Error("Input file should be .jar");
175 		}
176 		log.debug("input " + in.getAbsolutePath());
177 		log.debug("output " + out.getAbsolutePath());
178 		this.input = in;
179 		this.output = out;
180 		this.config = new Config(configFileName);
181 		this.classPool = new ClassPool();
182 		try {
183 			this.classPool.appendClassPath(this.input.getAbsolutePath());
184 
185 			if (classpath != null) {
186 				for (Iterator i = classpath.iterator(); i.hasNext();) {
187 					String path = (String) i.next();
188 					log.debug("classPath " + path);
189 					this.classPool.appendPathList(path);
190 				}
191 			}
192 		} catch (NotFoundException e) {
193 			log.error("Can't setup class path", e);
194 			throw new ConfigException("Can't setup class path", e);
195 		}
196 	}
197 
198 	public void process() throws Exception {
199 
200 		log.info("Jour, version " + BuildVersion.getVersion());
201 
202 		if (this.useSystemClassPath) {
203 			log.debug("useSystemClassPath");
204 			this.classPool.appendSystemPath();
205 		}
206 
207 		OutputWriter outputWriter;
208 		if (!output.isFile()) {
209 			outputWriter = new DirectoryOutputWriter(output);
210 		} else {
211 			throw new ConfigException("jar output not supported yet");
212 		}
213 
214 		InputSource inputSource;
215 		if (input.isDirectory()) {
216 			inputSource = new DirectoryInputSource(input);
217 		} else {
218 			inputSource = new JarFileInputSource(input);
219 		}
220 
221 		int countEntry = 0;
222 		int countResources = 0;
223 		int countNIClasses = 0;
224 		try {
225 
226 			for (Enumeration en = inputSource.getEntries(); en.hasMoreElements();) {
227 				Entry e = (Entry) en.nextElement();
228 				log.debug(e.getName());
229 				if (outputWriter.needUpdate(e)) {
230 					if (!e.isClass()) {
231 						if (isCopyResources()) {
232 							outputWriter.write(e);
233 							countResources++;
234 						}
235 					} else {
236 						if (instrument(e, outputWriter) == InstrumentorResultsImpl.NOT_MODIFIED) {
237 							if (isCopyClasses()) {
238 								outputWriter.write(e);
239 								countNIClasses++;
240 							}
241 						}
242 					}
243 				}
244 				countEntry++;
245 			}
246 		} finally {
247 			inputSource.close();
248 			outputWriter.close();
249 		}
250 		log.debug("countEntry   " + countEntry);
251 
252 		log.info("Processed Classes     " + this.countClasses);
253 		log.info("Altered Counstructors " + this.countCounstructors);
254 		log.info("Altered Methods       " + this.countMethods);
255 		log.info("Saved Classes         " + this.savedClasses);
256 		if (isCopyClasses()) {
257 			log.info("NotInstr Classes      " + countNIClasses);
258 		}
259 		if (isCopyResources()) {
260 			log.info("Resources             " + countResources);
261 		}
262 	}
263 
264 	public InstrumentorResults instrument(Entry entry, OutputWriter outputWriter) throws IOException {
265 		this.countClasses++;
266 		String className = EntryHelper.getClassName(entry);
267 		Instrumentor[] instrumentors = config.getInstrumentors(className);
268 		if (instrumentors.length > 0) {
269 			log.debug("intercepting class " + className);
270 			Interceptor interceptor = new Interceptor(config, classPool, className, instrumentors);
271 			CtClass ctClass = interceptor.instrument();
272 			InstrumentorResults rc = interceptor.getInstrumentorResults();
273 			log.debug("intercepted methods " + rc.getCountMethods());
274 			if (rc.isModified()) {
275 				this.savedClasses++;
276 				this.countCounstructors += rc.getCountCounstructors();
277 				this.countMethods += rc.getCountMethods();
278 				outputWriter.write(new InstrumentedEntry(entry, ctClass));
279 				if (rc.getCreatedClasses() != null) {
280 					for (Iterator i = rc.getCreatedClasses().iterator(); i.hasNext();) {
281 						outputWriter.write(new InstrumentedCreatedEntry(entry, ctClass, (CtClass) i.next()));
282 						this.savedClasses++;
283 					}
284 				}
285 				return rc;
286 			}
287 		}
288 		return InstrumentorResultsImpl.NOT_MODIFIED;
289 	}
290 
291 	public long getCountCounstructors() {
292 		return countCounstructors;
293 	}
294 
295 	public long getCountMethods() {
296 		return countMethods;
297 	}
298 
299 	public long getSavedClasses() {
300 		return savedClasses;
301 	}
302 
303 	public long getCountClasses() {
304 		return countClasses;
305 	}
306 
307 	/**
308 	 * @return the copyClasses
309 	 */
310 	public boolean isCopyClasses() {
311 		return copyClasses;
312 	}
313 
314 	/**
315 	 * @param copyClasses
316 	 *            the copyClasses to set
317 	 */
318 	public void setCopyClasses(boolean copyClasses) {
319 		this.copyClasses = copyClasses;
320 	}
321 
322 	/**
323 	 * @return the copyResources
324 	 */
325 	public boolean isCopyResources() {
326 		return copyResources;
327 	}
328 
329 	/**
330 	 * @param copyResources
331 	 *            the copyResources to set
332 	 */
333 	public void setCopyResources(boolean copyResources) {
334 		this.copyResources = copyResources;
335 	}
336 
337 	/**
338 	 * @return the useSystemClassPath
339 	 */
340 	public boolean isUseSystemClassPath() {
341 		return useSystemClassPath;
342 	}
343 
344 	/**
345 	 * @param useSystemClassPath
346 	 *            the useSystemClassPath to set
347 	 */
348 	public void setUseSystemClassPath(boolean useSystemClassPath) {
349 		this.useSystemClassPath = useSystemClassPath;
350 	}
351 
352 }