KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > jdt > core > ToolFactory


1 /*******************************************************************************
2  * Copyright (c) 2000, 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.jdt.core;
12
13 import java.io.File JavaDoc;
14 import java.io.IOException JavaDoc;
15 import java.io.InputStream JavaDoc;
16 import java.util.HashMap JavaDoc;
17 import java.util.Map JavaDoc;
18 import java.util.zip.ZipEntry JavaDoc;
19 import java.util.zip.ZipFile JavaDoc;
20
21 import org.eclipse.core.resources.IFile;
22 import org.eclipse.core.runtime.*;
23 import org.eclipse.jdt.core.compiler.IScanner;
24 import org.eclipse.jdt.core.formatter.CodeFormatter;
25 import org.eclipse.jdt.core.formatter.DefaultCodeFormatterConstants;
26 import org.eclipse.jdt.core.util.ClassFileBytesDisassembler;
27 import org.eclipse.jdt.core.util.ClassFormatException;
28 import org.eclipse.jdt.core.util.IClassFileReader;
29 import org.eclipse.jdt.internal.compiler.classfmt.ClassFileConstants;
30 import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
31 import org.eclipse.jdt.internal.compiler.util.SuffixConstants;
32 import org.eclipse.jdt.internal.compiler.util.Util;
33 import org.eclipse.jdt.internal.core.JarPackageFragmentRoot;
34 import org.eclipse.jdt.internal.core.JavaModelManager;
35 import org.eclipse.jdt.internal.core.PackageFragment;
36 import org.eclipse.jdt.internal.core.util.ClassFileReader;
37 import org.eclipse.jdt.internal.core.util.Disassembler;
38 import org.eclipse.jdt.internal.core.util.PublicScanner;
39 import org.eclipse.jdt.internal.formatter.DefaultCodeFormatter;
40
41 /**
42  * Factory for creating various compiler tools, such as scanners, parsers and compilers.
43  * <p>
44  * This class provides static methods only; it is not intended to be instantiated or subclassed by clients.
45  * </p>
46  *
47  * @since 2.0
48  */

49 public class ToolFactory {
50     
51     /**
52      * This mode is used for formatting new code when some formatter options should not be used.
53      * In particular, options that preserve the indentation of comments are not used.
54      * In the future, newly added options may be ignored as well.
55      * <p>Clients that are formatting new code are recommended to use this mode.
56      * </p>
57      *
58      * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN
59      * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN
60      * @see #createCodeFormatter(Map, int)
61      * @since 3.3
62      */

63     public static final int M_FORMAT_NEW = new Integer JavaDoc(0).intValue();
64     
65     /**
66      * This mode is used for formatting existing code when all formatter options should be used.
67      * In particular, options that preserve the indentation of comments are used.
68      * <p>Clients that are formatting existing code are recommended to use this mode.
69      * </p>
70      *
71      * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN
72      * @see DefaultCodeFormatterConstants#FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN
73      * @see #createCodeFormatter(Map, int)
74      * @since 3.3
75      */

76     public static final int M_FORMAT_EXISTING = new Integer JavaDoc(1).intValue();
77
78     /**
79      * Create an instance of a code formatter. A code formatter implementation can be contributed via the
80      * extension point "org.eclipse.jdt.core.codeFormatter". If unable to find a registered extension, the factory
81      * will default to using the default code formatter.
82      *
83      * @return an instance of a code formatter
84      * @see ICodeFormatter
85      * @see ToolFactory#createDefaultCodeFormatter(Map)
86      * @deprecated Use {@link #createCodeFormatter(Map)} instead. Extension point is discontinued
87      */

88     public static ICodeFormatter createCodeFormatter(){
89         
90             Plugin jdtCorePlugin = JavaCore.getPlugin();
91             if (jdtCorePlugin == null) return null;
92         
93             IExtensionPoint extension = jdtCorePlugin.getDescriptor().getExtensionPoint(JavaModelManager.FORMATTER_EXTPOINT_ID);
94             if (extension != null) {
95                 IExtension[] extensions = extension.getExtensions();
96                 for(int i = 0; i < extensions.length; i++){
97                     IConfigurationElement [] configElements = extensions[i].getConfigurationElements();
98                     for(int j = 0; j < configElements.length; j++){
99                         try {
100                             Object JavaDoc execExt = configElements[j].createExecutableExtension("class"); //$NON-NLS-1$
101
if (execExt instanceof ICodeFormatter){
102                                 // use first contribution found
103
return (ICodeFormatter)execExt;
104                             }
105                         } catch(CoreException e){
106                             // unable to instantiate extension, will answer default formatter instead
107
}
108                     }
109                 }
110             }
111         // no proper contribution found, use default formatter
112
return createDefaultCodeFormatter(null);
113     }
114
115     /**
116      * Create an instance of the built-in code formatter.
117      * <p>The given options should at least provide the source level ({@link JavaCore#COMPILER_SOURCE}),
118      * the compiler compliance level ({@link JavaCore#COMPILER_COMPLIANCE}) and the target platform
119      * ({@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}).
120      * Without these options, it is not possible for the code formatter to know what kind of source it needs to format.
121      * </p><p>
122      * Note this is equivalent to <code>createCodeFormatter(options, M_FORMAT_NEW)</code>. Thus some code formatter options
123      * may be ignored. See @{link {@link #M_FORMAT_NEW} for more details.
124      * </p>
125      * @param options - the options map to use for formatting with the default code formatter. Recognized options
126      * are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use
127      * the current settings from <code>JavaCore#getOptions</code>.
128      * @return an instance of the built-in code formatter
129      * @see CodeFormatter
130      * @see JavaCore#getOptions()
131      * @since 3.0
132      */

133     public static CodeFormatter createCodeFormatter(Map JavaDoc options){
134         return createCodeFormatter(options, M_FORMAT_NEW);
135     }
136
137     /**
138      * Create an instance of the built-in code formatter.
139      * <p>The given options should at least provide the source level ({@link JavaCore#COMPILER_SOURCE}),
140      * the compiler compliance level ({@link JavaCore#COMPILER_COMPLIANCE}) and the target platform
141      * ({@link JavaCore#COMPILER_CODEGEN_TARGET_PLATFORM}).
142      * Without these options, it is not possible for the code formatter to know what kind of source it needs to format.
143      * </p>
144      * <p>The given mode determines what options should be enabled when formatting the code. It can have the following
145      * values: {@link #M_FORMAT_NEW}, {@link #M_FORMAT_EXISTING}, but other values may be added in the future.
146      * </p>
147      *
148      * @param options the options map to use for formatting with the default code formatter. Recognized options
149      * are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use
150      * the current settings from <code>JavaCore#getOptions</code>.
151      * @param mode the given mode to modify the given options.
152      *
153      * @return an instance of the built-in code formatter
154      * @see CodeFormatter
155      * @see JavaCore#getOptions()
156      * @since 3.3
157      */

158     public static CodeFormatter createCodeFormatter(Map JavaDoc options, int mode) {
159         if (options == null) options = JavaCore.getOptions();
160         Map JavaDoc currentOptions = new HashMap JavaDoc(options);
161         if (mode == M_FORMAT_NEW) {
162             // disable the option for not indenting comments starting on first column
163
currentOptions.put(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_BLOCK_COMMENTS_ON_FIRST_COLUMN, DefaultCodeFormatterConstants.FALSE);
164             currentOptions.put(DefaultCodeFormatterConstants.FORMATTER_NEVER_INDENT_LINE_COMMENTS_ON_FIRST_COLUMN, DefaultCodeFormatterConstants.FALSE);
165         }
166         return new DefaultCodeFormatter(currentOptions);
167     }
168
169     /**
170      * Create a classfile bytecode disassembler, able to produce a String representation of a given classfile.
171      *
172      * @return a classfile bytecode disassembler
173      * @see ClassFileBytesDisassembler
174      * @since 2.1
175      */

176     public static ClassFileBytesDisassembler createDefaultClassFileBytesDisassembler(){
177         return new Disassembler();
178     }
179     
180     /**
181      * Create a classfile bytecode disassembler, able to produce a String representation of a given classfile.
182      *
183      * @return a classfile bytecode disassembler
184      * @see org.eclipse.jdt.core.util.IClassFileDisassembler
185      * @deprecated Use {@link #createDefaultClassFileBytesDisassembler()} instead
186      */

187     public static org.eclipse.jdt.core.util.IClassFileDisassembler createDefaultClassFileDisassembler(){
188         class DeprecatedDisassembler extends Disassembler implements org.eclipse.jdt.core.util.IClassFileDisassembler {
189             // for backward compatibility, defines a disassembler which implements IClassFileDisassembler
190
}
191         return new DeprecatedDisassembler();
192     }
193     
194     /**
195      * Create a classfile reader onto a classfile Java element.
196      * Create a default classfile reader, able to expose the internal representation of a given classfile
197      * according to the decoding flag used to initialize the reader.
198      * Answer null if the file named fileName doesn't represent a valid .class file.
199      *
200      * The decoding flags are described in IClassFileReader.
201      *
202      * @param classfile the classfile element to introspect
203      * @param decodingFlag the flag used to decode the class file reader.
204      * @return a default classfile reader
205      *
206      * @see IClassFileReader
207      */

208     public static IClassFileReader createDefaultClassFileReader(IClassFile classfile, int decodingFlag){
209
210         IPackageFragmentRoot root = (IPackageFragmentRoot) classfile.getAncestor(IJavaElement.PACKAGE_FRAGMENT_ROOT);
211         if (root != null){
212             try {
213                 if (root instanceof JarPackageFragmentRoot) {
214                     String JavaDoc archiveName = null;
215                     ZipFile JavaDoc jar = null;
216                     try {
217                         jar = ((JarPackageFragmentRoot)root).getJar();
218                         archiveName = jar.getName();
219                     } finally {
220                         JavaModelManager.getJavaModelManager().closeZipFile(jar);
221                     }
222                     PackageFragment packageFragment = (PackageFragment) classfile.getParent();
223                     String JavaDoc classFileName = classfile.getElementName();
224                     String JavaDoc entryName = org.eclipse.jdt.internal.core.util.Util.concatWith(packageFragment.names, classFileName, '/');
225                     return createDefaultClassFileReader(archiveName, entryName, decodingFlag);
226                 } else {
227                     InputStream JavaDoc in = null;
228                     try {
229                         in = ((IFile) classfile.getResource()).getContents();
230                         return createDefaultClassFileReader(in, decodingFlag);
231                     } finally {
232                         if (in != null)
233                             try {
234                                 in.close();
235                             } catch (IOException JavaDoc e) {
236                                 // ignore
237
}
238                     }
239                 }
240             } catch(CoreException e){
241                 // unable to read
242
}
243         }
244         return null;
245     }
246
247     /**
248      * Create a default classfile reader, able to expose the internal representation of a given classfile
249      * according to the decoding flag used to initialize the reader.
250      * Answer null if the input stream contents cannot be retrieved
251      *
252      * The decoding flags are described in IClassFileReader.
253      *
254      * @param stream the given input stream to read
255      * @param decodingFlag the flag used to decode the class file reader.
256      * @return a default classfile reader
257      *
258      * @see IClassFileReader
259      * @since 3.2
260      */

261     public static IClassFileReader createDefaultClassFileReader(InputStream JavaDoc stream, int decodingFlag) {
262         try {
263             return new ClassFileReader(Util.getInputStreamAsByteArray(stream, -1), decodingFlag);
264         } catch(ClassFormatException e) {
265             return null;
266         } catch(IOException JavaDoc e) {
267             return null;
268         }
269     }
270     
271     /**
272      * Create a default classfile reader, able to expose the internal representation of a given classfile
273      * according to the decoding flag used to initialize the reader.
274      * Answer null if the file named fileName doesn't represent a valid .class file.
275      * The fileName has to be an absolute OS path to the given .class file.
276      *
277      * The decoding flags are described in IClassFileReader.
278      *
279      * @param fileName the name of the file to be read
280      * @param decodingFlag the flag used to decode the class file reader.
281      * @return a default classfile reader
282      *
283      * @see IClassFileReader
284      */

285     public static IClassFileReader createDefaultClassFileReader(String JavaDoc fileName, int decodingFlag){
286         try {
287             return new ClassFileReader(Util.getFileByteContent(new File JavaDoc(fileName)), decodingFlag);
288         } catch(ClassFormatException e) {
289             return null;
290         } catch(IOException JavaDoc e) {
291             return null;
292         }
293     }
294
295     /**
296      * Create a default classfile reader, able to expose the internal representation of a given classfile
297      * according to the decoding flag used to initialize the reader.
298      * Answer null if the file named zipFileName doesn't represent a valid zip file or if the zipEntryName
299      * is not a valid entry name for the specified zip file or if the bytes don't represent a valid
300      * .class file according to the JVM specifications.
301      *
302      * The decoding flags are described in IClassFileReader.
303      *
304      * @param zipFileName the name of the zip file
305      * @param zipEntryName the name of the entry in the zip file to be read
306      * @param decodingFlag the flag used to decode the class file reader.
307      * @return a default classfile reader
308      * @see IClassFileReader
309      */

310     public static IClassFileReader createDefaultClassFileReader(String JavaDoc zipFileName, String JavaDoc zipEntryName, int decodingFlag){
311         ZipFile JavaDoc zipFile = null;
312         try {
313             if (JavaModelManager.ZIP_ACCESS_VERBOSE) {
314                 System.out.println("(" + Thread.currentThread() + ") [ToolFactory.createDefaultClassFileReader()] Creating ZipFile on " + zipFileName); //$NON-NLS-1$ //$NON-NLS-2$
315
}
316             zipFile = new ZipFile JavaDoc(zipFileName);
317             ZipEntry JavaDoc zipEntry = zipFile.getEntry(zipEntryName);
318             if (zipEntry == null) {
319                 return null;
320             }
321             if (!zipEntryName.toLowerCase().endsWith(SuffixConstants.SUFFIX_STRING_class)) {
322                 return null;
323             }
324             byte classFileBytes[] = Util.getZipEntryByteContent(zipEntry, zipFile);
325             return new ClassFileReader(classFileBytes, decodingFlag);
326         } catch(ClassFormatException e) {
327             return null;
328         } catch(IOException JavaDoc e) {
329             return null;
330         } finally {
331             if (zipFile != null) {
332                 try {
333                     zipFile.close();
334                 } catch(IOException JavaDoc e) {
335                     // ignore
336
}
337             }
338         }
339     }
340     
341     /**
342      * Create an instance of the built-in code formatter. A code formatter implementation can be contributed via the
343      * extension point "org.eclipse.jdt.core.codeFormatter". If unable to find a registered extension, the factory will
344      * default to using the default code formatter.
345      *
346      * @param options - the options map to use for formatting with the default code formatter. Recognized options
347      * are documented on <code>JavaCore#getDefaultOptions()</code>. If set to <code>null</code>, then use
348      * the current settings from <code>JavaCore#getOptions</code>.
349      * @return an instance of the built-in code formatter
350      * @see ICodeFormatter
351      * @see ToolFactory#createCodeFormatter()
352      * @see JavaCore#getOptions()
353      * @deprecated Use {@link #createCodeFormatter(Map)} instead
354      */

355     public static ICodeFormatter createDefaultCodeFormatter(Map JavaDoc options){
356         if (options == null) options = JavaCore.getOptions();
357         return new org.eclipse.jdt.internal.formatter.old.CodeFormatter(options);
358     }
359     
360     /**
361      * Create a scanner, indicating the level of detail requested for tokenizing. The scanner can then be
362      * used to tokenize some source in a Java aware way.
363      * Here is a typical scanning loop:
364      *
365      * <code>
366      * <pre>
367      * IScanner scanner = ToolFactory.createScanner(false, false, false, false);
368      * scanner.setSource("int i = 0;".toCharArray());
369      * while (true) {
370      * int token = scanner.getNextToken();
371      * if (token == ITerminalSymbols.TokenNameEOF) break;
372      * System.out.println(token + " : " + new String(scanner.getCurrentTokenSource()));
373      * }
374      * </pre>
375      * </code>
376      *
377      * <p>
378      * The returned scanner will tolerate unterminated line comments (missing line separator). It can be made stricter
379      * by using API with extra boolean parameter (<code>strictCommentMode</code>).
380      * <p>
381      * @param tokenizeComments if set to <code>false</code>, comments will be silently consumed
382      * @param tokenizeWhiteSpace if set to <code>false</code>, white spaces will be silently consumed,
383      * @param assertMode if set to <code>false</code>, occurrences of 'assert' will be reported as identifiers
384      * (<code>ITerminalSymbols#TokenNameIdentifier</code>), whereas if set to <code>true</code>, it
385      * would report assert keywords (<code>ITerminalSymbols#TokenNameassert</code>). Java 1.4 has introduced
386      * a new 'assert' keyword.
387      * @param recordLineSeparator if set to <code>true</code>, the scanner will record positions of encountered line
388      * separator ends. In case of multi-character line separators, the last character position is considered. These positions
389      * can then be extracted using <code>IScanner#getLineEnds</code>. Only non-unicode escape sequences are
390      * considered as valid line separators.
391      * @return a scanner
392      * @see org.eclipse.jdt.core.compiler.IScanner
393      */

394     public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean assertMode, boolean recordLineSeparator){
395
396         PublicScanner scanner = new PublicScanner(tokenizeComments, tokenizeWhiteSpace, false/*nls*/, assertMode ? ClassFileConstants.JDK1_4 : ClassFileConstants.JDK1_3/*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
397         scanner.recordLineSeparator = recordLineSeparator;
398         return scanner;
399     }
400     
401     /**
402      * Create a scanner, indicating the level of detail requested for tokenizing. The scanner can then be
403      * used to tokenize some source in a Java aware way.
404      * Here is a typical scanning loop:
405      *
406      * <code>
407      * <pre>
408      * IScanner scanner = ToolFactory.createScanner(false, false, false, false);
409      * scanner.setSource("int i = 0;".toCharArray());
410      * while (true) {
411      * int token = scanner.getNextToken();
412      * if (token == ITerminalSymbols.TokenNameEOF) break;
413      * System.out.println(token + " : " + new String(scanner.getCurrentTokenSource()));
414      * }
415      * </pre>
416      * </code>
417      *
418      * <p>
419      * The returned scanner will tolerate unterminated line comments (missing line separator). It can be made stricter
420      * by using API with extra boolean parameter (<code>strictCommentMode</code>).
421      * <p>
422      * @param tokenizeComments if set to <code>false</code>, comments will be silently consumed
423      * @param tokenizeWhiteSpace if set to <code>false</code>, white spaces will be silently consumed,
424      * @param recordLineSeparator if set to <code>true</code>, the scanner will record positions of encountered line
425      * separator ends. In case of multi-character line separators, the last character position is considered. These positions
426      * can then be extracted using <code>IScanner#getLineEnds</code>. Only non-unicode escape sequences are
427      * considered as valid line separators.
428      * @param sourceLevel if set to <code>&quot;1.3&quot;</code> or <code>null</code>, occurrences of 'assert' will be reported as identifiers
429      * (<code>ITerminalSymbols#TokenNameIdentifier</code>), whereas if set to <code>&quot;1.4&quot;</code>, it
430      * would report assert keywords (<code>ITerminalSymbols#TokenNameassert</code>). Java 1.4 has introduced
431      * a new 'assert' keyword.
432      * @return a scanner
433      * @see org.eclipse.jdt.core.compiler.IScanner
434      * @since 3.0
435      */

436     public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean recordLineSeparator, String JavaDoc sourceLevel) {
437         PublicScanner scanner = null;
438         long level = CompilerOptions.versionToJdkLevel(sourceLevel);
439         if (level == 0) level = ClassFileConstants.JDK1_3; // fault-tolerance
440
scanner = new PublicScanner(tokenizeComments, tokenizeWhiteSpace, false/*nls*/,level /*sourceLevel*/, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
441         scanner.recordLineSeparator = recordLineSeparator;
442         return scanner;
443     }
444
445     /**
446      * Create a scanner, indicating the level of detail requested for tokenizing. The scanner can then be
447      * used to tokenize some source in a Java aware way.
448      * Here is a typical scanning loop:
449      *
450      * <code>
451      * <pre>
452      * IScanner scanner = ToolFactory.createScanner(false, false, false, false);
453      * scanner.setSource("int i = 0;".toCharArray());
454      * while (true) {
455      * int token = scanner.getNextToken();
456      * if (token == ITerminalSymbols.TokenNameEOF) break;
457      * System.out.println(token + " : " + new String(scanner.getCurrentTokenSource()));
458      * }
459      * </pre>
460      * </code>
461      *
462      * <p>
463      * The returned scanner will tolerate unterminated line comments (missing line separator). It can be made stricter
464      * by using API with extra boolean parameter (<code>strictCommentMode</code>).
465      * <p>
466      * @param tokenizeComments if set to <code>false</code>, comments will be silently consumed
467      * @param tokenizeWhiteSpace if set to <code>false</code>, white spaces will be silently consumed,
468      * @param recordLineSeparator if set to <code>true</code>, the scanner will record positions of encountered line
469      * separator ends. In case of multi-character line separators, the last character position is considered. These positions
470      * can then be extracted using <code>IScanner#getLineEnds</code>. Only non-unicode escape sequences are
471      * considered as valid line separators.
472      * @param sourceLevel if set to <code>&quot;1.3&quot;</code> or <code>null</code>, occurrences of 'assert' will be reported as identifiers
473      * (<code>ITerminalSymbols#TokenNameIdentifier</code>), whereas if set to <code>&quot;1.4&quot;</code>, it
474      * would report assert keywords (<code>ITerminalSymbols#TokenNameassert</code>). Java 1.4 has introduced
475      * a new 'assert' keyword.
476      * @param complianceLevel This is used to support the Unicode 4.0 character sets. if set to 1.5 or above,
477      * the Unicode 4.0 is supporte, otherwise Unicode 3.0 is supported.
478      * @return a scanner
479      * @see org.eclipse.jdt.core.compiler.IScanner
480      *
481      * @since 3.1
482      */

483     public static IScanner createScanner(boolean tokenizeComments, boolean tokenizeWhiteSpace, boolean recordLineSeparator, String JavaDoc sourceLevel, String JavaDoc complianceLevel) {
484         PublicScanner scanner = null;
485         long sourceLevelValue = CompilerOptions.versionToJdkLevel(sourceLevel);
486         if (sourceLevelValue == 0) sourceLevelValue = ClassFileConstants.JDK1_3; // fault-tolerance
487
long complianceLevelValue = CompilerOptions.versionToJdkLevel(complianceLevel);
488         if (complianceLevelValue == 0) complianceLevelValue = ClassFileConstants.JDK1_3; // fault-tolerance
489
scanner = new PublicScanner(tokenizeComments, tokenizeWhiteSpace, false/*nls*/,sourceLevelValue /*sourceLevel*/, complianceLevelValue, null/*taskTags*/, null/*taskPriorities*/, true/*taskCaseSensitive*/);
490         scanner.recordLineSeparator = recordLineSeparator;
491         return scanner;
492     }
493 }
494
Popular Tags