Source Code Cross Referenced for ConfigurationParser.java in  » Development » proguard » proguard » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Development » proguard » proguard 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * ProGuard -- shrinking, optimization, obfuscation, and preverification
0003:         *             of Java bytecode.
0004:         *
0005:         * Copyright (c) 2002-2007 Eric Lafortune (eric@graphics.cornell.edu)
0006:         *
0007:         * This program is free software; you can redistribute it and/or modify it
0008:         * under the terms of the GNU General Public License as published by the Free
0009:         * Software Foundation; either version 2 of the License, or (at your option)
0010:         * any later version.
0011:         *
0012:         * This program is distributed in the hope that it will be useful, but WITHOUT
0013:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0014:         * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
0015:         * more details.
0016:         *
0017:         * You should have received a copy of the GNU General Public License along
0018:         * with this program; if not, write to the Free Software Foundation, Inc.,
0019:         * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0020:         */
0021:        package proguard;
0022:
0023:        import proguard.classfile.ClassConstants;
0024:        import proguard.classfile.util.ClassUtil;
0025:        import proguard.util.ListUtil;
0026:
0027:        import java.io.*;
0028:        import java.net.URL;
0029:        import java.util.*;
0030:
0031:        /**
0032:         * This class parses ProGuard configurations. Configurations can be read from an
0033:         * array of arguments or from a configuration file or URL.
0034:         *
0035:         * @author Eric Lafortune
0036:         */
0037:        public class ConfigurationParser {
0038:            private WordReader reader;
0039:            private String nextWord;
0040:            private String lastComments;
0041:
0042:            /**
0043:             * Creates a new ConfigurationParser for the given String arguments.
0044:             */
0045:            public ConfigurationParser(String[] args) throws IOException {
0046:                this (args, null);
0047:            }
0048:
0049:            /**
0050:             * Creates a new ConfigurationParser for the given String arguments,
0051:             * with the given base directory.
0052:             */
0053:            public ConfigurationParser(String[] args, File baseDir)
0054:                    throws IOException {
0055:                reader = new ArgumentWordReader(args, baseDir);
0056:
0057:                readNextWord();
0058:            }
0059:
0060:            /**
0061:             * Creates a new ConfigurationParser for the given file.
0062:             */
0063:            public ConfigurationParser(File file) throws IOException {
0064:                reader = new FileWordReader(file);
0065:
0066:                readNextWord();
0067:            }
0068:
0069:            /**
0070:             * Creates a new ConfigurationParser for the given URL.
0071:             */
0072:            public ConfigurationParser(URL url) throws IOException {
0073:                reader = new FileWordReader(url);
0074:
0075:                readNextWord();
0076:            }
0077:
0078:            /**
0079:             * Parses and returns the configuration.
0080:             * @param configuration the configuration that is updated as a side-effect.
0081:             * @throws ParseException if the any of the configuration settings contains
0082:             *                        a syntax error.
0083:             * @throws IOException if an IO error occurs while reading a configuration.
0084:             */
0085:            public void parse(Configuration configuration)
0086:                    throws ParseException, IOException {
0087:                while (nextWord != null) {
0088:                    lastComments = reader.lastComments();
0089:
0090:                    // First include directives.
0091:                    if (ConfigurationConstants.AT_DIRECTIVE
0092:                            .startsWith(nextWord)
0093:                            || ConfigurationConstants.INCLUDE_DIRECTIVE
0094:                                    .startsWith(nextWord))
0095:                        configuration.lastModified = parseIncludeArgument(configuration.lastModified);
0096:                    else if (ConfigurationConstants.BASE_DIRECTORY_DIRECTIVE
0097:                            .startsWith(nextWord))
0098:                        parseBaseDirectoryArgument();
0099:
0100:                    // Then configuration options with or without arguments.
0101:                    else if (ConfigurationConstants.INJARS_OPTION
0102:                            .startsWith(nextWord))
0103:                        configuration.programJars = parseClassPathArgument(
0104:                                configuration.programJars, false);
0105:                    else if (ConfigurationConstants.OUTJARS_OPTION
0106:                            .startsWith(nextWord))
0107:                        configuration.programJars = parseClassPathArgument(
0108:                                configuration.programJars, true);
0109:                    else if (ConfigurationConstants.LIBRARYJARS_OPTION
0110:                            .startsWith(nextWord))
0111:                        configuration.libraryJars = parseClassPathArgument(
0112:                                configuration.libraryJars, false);
0113:                    else if (ConfigurationConstants.RESOURCEJARS_OPTION
0114:                            .startsWith(nextWord))
0115:                        throw new ParseException(
0116:                                "The '-resourcejars' option is no longer supported. Please use the '-injars' option for all input");
0117:                    else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES_OPTION
0118:                            .startsWith(nextWord))
0119:                        configuration.skipNonPublicLibraryClasses = parseNoArgument(false);
0120:                    else if (ConfigurationConstants.DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS_OPTION
0121:                            .startsWith(nextWord))
0122:                        configuration.skipNonPublicLibraryClassMembers = parseNoArgument(false);
0123:                    else if (ConfigurationConstants.TARGET_OPTION
0124:                            .startsWith(nextWord))
0125:                        configuration.targetClassVersion = parseClassVersion();
0126:                    else if (ConfigurationConstants.FORCE_PROCESSING_OPTION
0127:                            .startsWith(nextWord))
0128:                        configuration.lastModified = parseNoArgument(Long.MAX_VALUE);
0129:
0130:                    else if (ConfigurationConstants.KEEP_OPTION
0131:                            .startsWith(nextWord))
0132:                        configuration.keep = parseKeepSpecificationArguments(
0133:                                configuration.keep, true, false, false);
0134:                    else if (ConfigurationConstants.KEEP_CLASS_MEMBERS_OPTION
0135:                            .startsWith(nextWord))
0136:                        configuration.keep = parseKeepSpecificationArguments(
0137:                                configuration.keep, false, false, false);
0138:                    else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBERS_OPTION
0139:                            .startsWith(nextWord))
0140:                        configuration.keep = parseKeepSpecificationArguments(
0141:                                configuration.keep, false, true, false);
0142:                    else if (ConfigurationConstants.KEEP_NAMES_OPTION
0143:                            .startsWith(nextWord))
0144:                        configuration.keep = parseKeepSpecificationArguments(
0145:                                configuration.keep, true, false, true);
0146:                    else if (ConfigurationConstants.KEEP_CLASS_MEMBER_NAMES_OPTION
0147:                            .startsWith(nextWord))
0148:                        configuration.keep = parseKeepSpecificationArguments(
0149:                                configuration.keep, false, false, true);
0150:                    else if (ConfigurationConstants.KEEP_CLASSES_WITH_MEMBER_NAMES_OPTION
0151:                            .startsWith(nextWord))
0152:                        configuration.keep = parseKeepSpecificationArguments(
0153:                                configuration.keep, false, true, true);
0154:                    else if (ConfigurationConstants.PRINT_SEEDS_OPTION
0155:                            .startsWith(nextWord))
0156:                        configuration.printSeeds = parseOptionalFile();
0157:
0158:                    else if (ConfigurationConstants.DONT_SHRINK_OPTION
0159:                            .startsWith(nextWord))
0160:                        configuration.shrink = parseNoArgument(false);
0161:                    else if (ConfigurationConstants.PRINT_USAGE_OPTION
0162:                            .startsWith(nextWord))
0163:                        configuration.printUsage = parseOptionalFile();
0164:                    else if (ConfigurationConstants.WHY_ARE_YOU_KEEPING_OPTION
0165:                            .startsWith(nextWord))
0166:                        configuration.whyAreYouKeeping = parseClassSpecificationArguments(configuration.whyAreYouKeeping);
0167:
0168:                    else if (ConfigurationConstants.DONT_OPTIMIZE_OPTION
0169:                            .startsWith(nextWord))
0170:                        configuration.optimize = parseNoArgument(false);
0171:                    else if (ConfigurationConstants.OPTIMIZATION_PASSES
0172:                            .startsWith(nextWord))
0173:                        configuration.optimizationPasses = parseIntegerArgument();
0174:                    else if (ConfigurationConstants.ASSUME_NO_SIDE_EFFECTS_OPTION
0175:                            .startsWith(nextWord))
0176:                        configuration.assumeNoSideEffects = parseClassSpecificationArguments(configuration.assumeNoSideEffects);
0177:                    else if (ConfigurationConstants.ALLOW_ACCESS_MODIFICATION_OPTION
0178:                            .startsWith(nextWord))
0179:                        configuration.allowAccessModification = parseNoArgument(true);
0180:
0181:                    else if (ConfigurationConstants.DONT_OBFUSCATE_OPTION
0182:                            .startsWith(nextWord))
0183:                        configuration.obfuscate = parseNoArgument(false);
0184:                    else if (ConfigurationConstants.PRINT_MAPPING_OPTION
0185:                            .startsWith(nextWord))
0186:                        configuration.printMapping = parseOptionalFile();
0187:                    else if (ConfigurationConstants.APPLY_MAPPING_OPTION
0188:                            .startsWith(nextWord))
0189:                        configuration.applyMapping = parseFile();
0190:                    else if (ConfigurationConstants.OBFUSCATION_DICTIONARY_OPTION
0191:                            .startsWith(nextWord))
0192:                        configuration.obfuscationDictionary = parseFile();
0193:                    else if (ConfigurationConstants.OVERLOAD_AGGRESSIVELY_OPTION
0194:                            .startsWith(nextWord))
0195:                        configuration.overloadAggressively = parseNoArgument(true);
0196:                    else if (ConfigurationConstants.USE_UNIQUE_CLASS_MEMBER_NAMES_OPTION
0197:                            .startsWith(nextWord))
0198:                        configuration.useUniqueClassMemberNames = parseNoArgument(true);
0199:                    else if (ConfigurationConstants.DONT_USE_MIXED_CASE_CLASS_NAMES_OPTION
0200:                            .startsWith(nextWord))
0201:                        configuration.useMixedCaseClassNames = parseNoArgument(false);
0202:                    else if (ConfigurationConstants.FLATTEN_PACKAGE_HIERARCHY_OPTION
0203:                            .startsWith(nextWord))
0204:                        configuration.flattenPackageHierarchy = ClassUtil
0205:                                .internalClassName(parseOptionalArgument());
0206:                    else if (ConfigurationConstants.REPACKAGE_CLASSES_OPTION
0207:                            .startsWith(nextWord))
0208:                        configuration.repackageClasses = ClassUtil
0209:                                .internalClassName(parseOptionalArgument());
0210:                    else if (ConfigurationConstants.DEFAULT_PACKAGE_OPTION
0211:                            .startsWith(nextWord))
0212:                        configuration.repackageClasses = ClassUtil
0213:                                .internalClassName(parseOptionalArgument());
0214:                    else if (ConfigurationConstants.KEEP_ATTRIBUTES_OPTION
0215:                            .startsWith(nextWord))
0216:                        configuration.keepAttributes = parseCommaSeparatedList(
0217:                                "attribute name", true, true, false, true,
0218:                                false, configuration.keepAttributes);
0219:                    else if (ConfigurationConstants.RENAME_SOURCE_FILE_ATTRIBUTE_OPTION
0220:                            .startsWith(nextWord))
0221:                        configuration.newSourceFileAttribute = parseOptionalArgument();
0222:                    else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_NAMES_OPTION
0223:                            .startsWith(nextWord))
0224:                        configuration.adaptResourceFileNames = parseCommaSeparatedList(
0225:                                "resource file name", true, true, false, false,
0226:                                false, configuration.adaptResourceFileNames);
0227:                    else if (ConfigurationConstants.ADAPT_RESOURCE_FILE_CONTENTS_OPTION
0228:                            .startsWith(nextWord))
0229:                        configuration.adaptResourceFileContents = parseCommaSeparatedList(
0230:                                "resource file name", true, true, false, false,
0231:                                false, configuration.adaptResourceFileContents);
0232:
0233:                    else if (ConfigurationConstants.DONT_PREVERIFY_OPTION
0234:                            .startsWith(nextWord))
0235:                        configuration.preverify = parseNoArgument(false);
0236:                    else if (ConfigurationConstants.MICRO_EDITION_OPTION
0237:                            .startsWith(nextWord))
0238:                        configuration.microEdition = parseNoArgument(true);
0239:
0240:                    else if (ConfigurationConstants.VERBOSE_OPTION
0241:                            .startsWith(nextWord))
0242:                        configuration.verbose = parseNoArgument(true);
0243:                    else if (ConfigurationConstants.DONT_NOTE_OPTION
0244:                            .startsWith(nextWord))
0245:                        configuration.note = parseNoArgument(false);
0246:                    else if (ConfigurationConstants.DONT_WARN_OPTION
0247:                            .startsWith(nextWord))
0248:                        configuration.warn = parseNoArgument(false);
0249:                    else if (ConfigurationConstants.IGNORE_WARNINGS_OPTION
0250:                            .startsWith(nextWord))
0251:                        configuration.ignoreWarnings = parseNoArgument(true);
0252:                    else if (ConfigurationConstants.PRINT_CONFIGURATION_OPTION
0253:                            .startsWith(nextWord))
0254:                        configuration.printConfiguration = parseOptionalFile();
0255:                    else if (ConfigurationConstants.DUMP_OPTION
0256:                            .startsWith(nextWord))
0257:                        configuration.dump = parseOptionalFile();
0258:                    else {
0259:                        throw new ParseException("Unknown option "
0260:                                + reader.locationDescription());
0261:                    }
0262:                }
0263:            }
0264:
0265:            /**
0266:             * Closes the configuration.
0267:             * @throws IOException if an IO error occurs while closing the configuration.
0268:             */
0269:            public void close() throws IOException {
0270:                if (reader != null) {
0271:                    reader.close();
0272:                }
0273:            }
0274:
0275:            private long parseIncludeArgument(long lastModified)
0276:                    throws ParseException, IOException {
0277:                // Read the configuation file name.
0278:                readNextWord("configuration file name");
0279:
0280:                File file = file(nextWord);
0281:                reader.includeWordReader(new FileWordReader(file));
0282:
0283:                readNextWord();
0284:
0285:                return Math.max(lastModified, file.lastModified());
0286:            }
0287:
0288:            private void parseBaseDirectoryArgument() throws ParseException,
0289:                    IOException {
0290:                // Read the base directory name.
0291:                readNextWord("base directory name");
0292:
0293:                reader.setBaseDir(file(nextWord));
0294:
0295:                readNextWord();
0296:            }
0297:
0298:            private ClassPath parseClassPathArgument(ClassPath classPath,
0299:                    boolean isOutput) throws ParseException, IOException {
0300:                // Create a new List if necessary.
0301:                if (classPath == null) {
0302:                    classPath = new ClassPath();
0303:                }
0304:
0305:                while (true) {
0306:                    // Read the next jar name.
0307:                    readNextWord("jar or directory name");
0308:
0309:                    // Create a new class path entry.
0310:                    ClassPathEntry entry = new ClassPathEntry(file(nextWord),
0311:                            isOutput);
0312:
0313:                    // Read the opening parenthesis or the separator, if any.
0314:                    readNextWord();
0315:
0316:                    // Read the optional filters.
0317:                    if (!configurationEnd()
0318:                            && ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD
0319:                                    .equals(nextWord)) {
0320:                        // Read all filters in an array.
0321:                        String[] filters = new String[5];
0322:
0323:                        int counter = 0;
0324:                        do {
0325:                            // Read the filter.
0326:                            filters[counter++] = ListUtil
0327:                                    .commaSeparatedString(parseCommaSeparatedList(
0328:                                            "filter", true, false, true, false,
0329:                                            true, null));
0330:                        } while (counter < filters.length
0331:                                && ConfigurationConstants.SEPARATOR_KEYWORD
0332:                                        .equals(nextWord));
0333:
0334:                        // Make sure there is a closing parenthesis.
0335:                        if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD
0336:                                .equals(nextWord)) {
0337:                            throw new ParseException(
0338:                                    "Expecting separating '"
0339:                                            + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD
0340:                                            + "' or '"
0341:                                            + ConfigurationConstants.SEPARATOR_KEYWORD
0342:                                            + "', or closing '"
0343:                                            + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD
0344:                                            + "' before "
0345:                                            + reader.locationDescription());
0346:                        }
0347:
0348:                        // Set all filters from the array on the entry.
0349:                        entry.setFilter(filters[--counter]);
0350:                        if (counter > 0) {
0351:                            entry.setJarFilter(filters[--counter]);
0352:                            if (counter > 0) {
0353:                                entry.setWarFilter(filters[--counter]);
0354:                                if (counter > 0) {
0355:                                    entry.setEarFilter(filters[--counter]);
0356:                                    if (counter > 0) {
0357:                                        entry.setZipFilter(filters[--counter]);
0358:                                    }
0359:                                }
0360:                            }
0361:                        }
0362:
0363:                        // Read the separator, if any.
0364:                        readNextWord();
0365:                    }
0366:
0367:                    // Add the entry to the list.
0368:                    classPath.add(entry);
0369:
0370:                    if (configurationEnd()) {
0371:                        return classPath;
0372:                    }
0373:
0374:                    if (!nextWord
0375:                            .equals(ConfigurationConstants.JAR_SEPARATOR_KEYWORD)) {
0376:                        throw new ParseException(
0377:                                "Expecting class path separator '"
0378:                                        + ConfigurationConstants.JAR_SEPARATOR_KEYWORD
0379:                                        + "' before "
0380:                                        + reader.locationDescription());
0381:                    }
0382:                }
0383:            }
0384:
0385:            private int parseClassVersion() throws ParseException, IOException {
0386:                // Read the obligatory target.
0387:                readNextWord("java version");
0388:
0389:                int classVersion = ClassUtil.internalClassVersion(nextWord);
0390:                if (classVersion == 0) {
0391:                    throw new ParseException("Unsupported java version "
0392:                            + reader.locationDescription());
0393:                }
0394:
0395:                readNextWord();
0396:
0397:                return classVersion;
0398:            }
0399:
0400:            private int parseIntegerArgument() throws ParseException,
0401:                    IOException {
0402:                try {
0403:                    // Read the obligatory integer.
0404:                    readNextWord("integer");
0405:
0406:                    int integer = Integer.parseInt(nextWord);
0407:
0408:                    readNextWord();
0409:
0410:                    return integer;
0411:                } catch (NumberFormatException e) {
0412:                    throw new ParseException(
0413:                            "Expecting integer argument instead of '"
0414:                                    + nextWord + "' before "
0415:                                    + reader.locationDescription());
0416:                }
0417:            }
0418:
0419:            private File parseFile() throws ParseException, IOException {
0420:                // Read the obligatory file name.
0421:                readNextWord("file name");
0422:
0423:                // Make sure the file is properly resolved.
0424:                File file = file(nextWord);
0425:
0426:                readNextWord();
0427:
0428:                return file;
0429:            }
0430:
0431:            private File parseOptionalFile() throws ParseException, IOException {
0432:                // Read the optional file name.
0433:                readNextWord();
0434:
0435:                // Didn't the user specify a file name?
0436:                if (configurationEnd()) {
0437:                    return new File("");
0438:                }
0439:
0440:                // Make sure the file is properly resolved.
0441:                File file = file(nextWord);
0442:
0443:                readNextWord();
0444:
0445:                return file;
0446:            }
0447:
0448:            private String parseOptionalArgument() throws IOException {
0449:                // Read the optional argument.
0450:                readNextWord();
0451:
0452:                // Didn't the user specify an argument?
0453:                if (configurationEnd()) {
0454:                    return "";
0455:                }
0456:
0457:                String fileName = nextWord;
0458:
0459:                readNextWord();
0460:
0461:                return fileName;
0462:            }
0463:
0464:            private boolean parseNoArgument(boolean value) throws IOException {
0465:                readNextWord();
0466:
0467:                return value;
0468:            }
0469:
0470:            private long parseNoArgument(long value) throws IOException {
0471:                readNextWord();
0472:
0473:                return value;
0474:            }
0475:
0476:            private List parseKeepSpecificationArguments(
0477:                    List keepSpecifications, boolean markClasses,
0478:                    boolean markConditionally, boolean allowShrinking)
0479:                    throws ParseException, IOException {
0480:                // Create a new List if necessary.
0481:                if (keepSpecifications == null) {
0482:                    keepSpecifications = new ArrayList();
0483:                }
0484:
0485:                //boolean allowShrinking    = false;
0486:                boolean allowOptimization = false;
0487:                boolean allowObfuscation = false;
0488:
0489:                // Read the keep modifiers.
0490:                while (true) {
0491:                    readNextWord("keyword '"
0492:                            + ConfigurationConstants.CLASS_KEYWORD + "' or '"
0493:                            + ClassConstants.EXTERNAL_ACC_INTERFACE + "'", true);
0494:
0495:                    if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD
0496:                            .equals(nextWord)) {
0497:                        // Not a comma. Stop parsing the keep modifiers.
0498:                        break;
0499:                    }
0500:
0501:                    readNextWord("keyword '"
0502:                            + ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION
0503:                            + "', '"
0504:                            + ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION
0505:                            + "', or '"
0506:                            + ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION
0507:                            + "'");
0508:
0509:                    if (ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION
0510:                            .startsWith(nextWord)) {
0511:                        allowShrinking = true;
0512:                    } else if (ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION
0513:                            .startsWith(nextWord)) {
0514:                        allowOptimization = true;
0515:                    } else if (ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION
0516:                            .startsWith(nextWord)) {
0517:                        allowObfuscation = true;
0518:                    } else {
0519:                        throw new ParseException(
0520:                                "Expecting keyword '"
0521:                                        + ConfigurationConstants.ALLOW_SHRINKING_SUBOPTION
0522:                                        + "', '"
0523:                                        + ConfigurationConstants.ALLOW_OPTIMIZATION_SUBOPTION
0524:                                        + "', or '"
0525:                                        + ConfigurationConstants.ALLOW_OBFUSCATION_SUBOPTION
0526:                                        + "' before "
0527:                                        + reader.locationDescription());
0528:                    }
0529:                }
0530:
0531:                // Read the class configuration.
0532:                ClassSpecification classSpecification = parseClassSpecificationArguments();
0533:
0534:                // Create and add the keep configuration.
0535:                keepSpecifications.add(new KeepSpecification(markClasses,
0536:                        markConditionally, allowShrinking, allowOptimization,
0537:                        allowObfuscation, classSpecification));
0538:
0539:                return keepSpecifications;
0540:            }
0541:
0542:            private List parseClassSpecificationArguments(
0543:                    List classSpecifications) throws ParseException,
0544:                    IOException {
0545:                // Create a new List if necessary.
0546:                if (classSpecifications == null) {
0547:                    classSpecifications = new ArrayList();
0548:                }
0549:
0550:                // Read and add the class configuration.
0551:                readNextWord("keyword '" + ConfigurationConstants.CLASS_KEYWORD
0552:                        + "' or '" + ClassConstants.EXTERNAL_ACC_INTERFACE
0553:                        + "'", true);
0554:
0555:                classSpecifications.add(parseClassSpecificationArguments());
0556:
0557:                return classSpecifications;
0558:            }
0559:
0560:            private ClassSpecification parseClassSpecificationArguments()
0561:                    throws ParseException, IOException {
0562:                // Clear the annotation type.
0563:                String annotationType = null;
0564:
0565:                // Clear the class access modifiers.
0566:                int requiredSetClassAccessFlags = 0;
0567:                int requiredUnsetClassAccessFlags = 0;
0568:
0569:                // Parse the class annotations and access modifiers until the class keyword.
0570:                while (!ConfigurationConstants.CLASS_KEYWORD.equals(nextWord)) {
0571:                    // Parse the annotation type, if any.
0572:                    if (ConfigurationConstants.ANNOTATION_KEYWORD
0573:                            .equals(nextWord)) {
0574:                        annotationType = ClassUtil.internalType(ListUtil
0575:                                .commaSeparatedString(parseCommaSeparatedList(
0576:                                        "annotation type", true, false, false,
0577:                                        true, false, null)));
0578:
0579:                        continue;
0580:                    }
0581:
0582:                    // Strip the negating sign, if any.
0583:                    String strippedWord = nextWord
0584:                            .startsWith(ConfigurationConstants.NEGATOR_KEYWORD) ? nextWord
0585:                            .substring(1)
0586:                            : nextWord;
0587:
0588:                    // Parse the class access modifiers.
0589:                    int accessFlag = strippedWord
0590:                            .equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC
0591:                            : strippedWord
0592:                                    .equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL
0593:                                    : strippedWord
0594:                                            .equals(ClassConstants.EXTERNAL_ACC_INTERFACE) ? ClassConstants.INTERNAL_ACC_INTERFACE
0595:                                            : strippedWord
0596:                                                    .equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT
0597:                                                    : unknownAccessFlag();
0598:                    if (strippedWord.equals(nextWord)) {
0599:                        requiredSetClassAccessFlags |= accessFlag;
0600:                    } else {
0601:                        requiredUnsetClassAccessFlags |= accessFlag;
0602:                    }
0603:
0604:                    if ((requiredSetClassAccessFlags & requiredUnsetClassAccessFlags) != 0) {
0605:                        throw new ParseException(
0606:                                "Conflicting class access modifiers for '"
0607:                                        + strippedWord + "' before "
0608:                                        + reader.locationDescription());
0609:                    }
0610:
0611:                    if (ClassConstants.EXTERNAL_ACC_INTERFACE
0612:                            .equals(strippedWord)) {
0613:                        // The interface keyword. Stop parsing the class flags.
0614:                        break;
0615:                    }
0616:
0617:                    readNextWord("keyword '"
0618:                            + ConfigurationConstants.CLASS_KEYWORD + "' or '"
0619:                            + ClassConstants.EXTERNAL_ACC_INTERFACE + "'");
0620:                }
0621:
0622:                // Parse the class name part.
0623:                String externalClassName = ListUtil
0624:                        .commaSeparatedString(parseCommaSeparatedList(
0625:                                "class name or interface name", true, false,
0626:                                false, true, false, null));
0627:
0628:                // For backward compatibility, allow a single "*" wildcard to match any
0629:                // class.
0630:                String className = ConfigurationConstants.ANY_CLASS_KEYWORD
0631:                        .equals(externalClassName) ? null : ClassUtil
0632:                        .internalClassName(externalClassName);
0633:
0634:                // Clear the annotation type and the class name of the extends part.
0635:                String extendsAnnotationType = null;
0636:                String extendsClassName = null;
0637:
0638:                if (!configurationEnd()) {
0639:                    // Parse 'implements ...' or 'extends ...' part, if any.
0640:                    if (ConfigurationConstants.IMPLEMENTS_KEYWORD
0641:                            .equals(nextWord)
0642:                            || ConfigurationConstants.EXTENDS_KEYWORD
0643:                                    .equals(nextWord)) {
0644:                        readNextWord("class name or interface name", true);
0645:
0646:                        // Parse the annotation type, if any.
0647:                        if (ConfigurationConstants.ANNOTATION_KEYWORD
0648:                                .equals(nextWord)) {
0649:                            extendsAnnotationType = ClassUtil
0650:                                    .internalType(ListUtil
0651:                                            .commaSeparatedString(parseCommaSeparatedList(
0652:                                                    "annotation type", true,
0653:                                                    false, false, true, false,
0654:                                                    null)));
0655:                        }
0656:
0657:                        String externalExtendsClassName = ListUtil
0658:                                .commaSeparatedString(parseCommaSeparatedList(
0659:                                        "class name or interface name", false,
0660:                                        false, false, true, false, null));
0661:
0662:                        extendsClassName = ConfigurationConstants.ANY_CLASS_KEYWORD
0663:                                .equals(externalExtendsClassName) ? null
0664:                                : ClassUtil
0665:                                        .internalClassName(externalExtendsClassName);
0666:                    }
0667:                }
0668:
0669:                // Create the basic class specification.
0670:                ClassSpecification classSpecification = new ClassSpecification(
0671:                        lastComments, requiredSetClassAccessFlags,
0672:                        requiredUnsetClassAccessFlags, annotationType,
0673:                        className, extendsAnnotationType, extendsClassName);
0674:
0675:                // Now add any class members to this class specification.
0676:                if (!configurationEnd()) {
0677:                    // Check the class member opening part.
0678:                    if (!ConfigurationConstants.OPEN_KEYWORD.equals(nextWord)) {
0679:                        throw new ParseException("Expecting opening '"
0680:                                + ConfigurationConstants.OPEN_KEYWORD + "' at "
0681:                                + reader.locationDescription());
0682:                    }
0683:
0684:                    // Parse all class members.
0685:                    while (true) {
0686:                        readNextWord("class member description"
0687:                                + " or closing '"
0688:                                + ConfigurationConstants.CLOSE_KEYWORD + "'",
0689:                                true);
0690:
0691:                        if (nextWord
0692:                                .equals(ConfigurationConstants.CLOSE_KEYWORD)) {
0693:                            // The closing brace. Stop parsing the class members.
0694:                            readNextWord();
0695:
0696:                            break;
0697:                        }
0698:
0699:                        parseMemberSpecificationArguments(externalClassName,
0700:                                classSpecification);
0701:                    }
0702:                }
0703:
0704:                return classSpecification;
0705:            }
0706:
0707:            private void parseMemberSpecificationArguments(
0708:                    String externalClassName,
0709:                    ClassSpecification classSpecification)
0710:                    throws ParseException, IOException {
0711:                // Clear the annotation name.
0712:                String annotationType = null;
0713:
0714:                // Parse the class member access modifiers, if any.
0715:                int requiredSetMemberAccessFlags = 0;
0716:                int requiredUnsetMemberAccessFlags = 0;
0717:
0718:                while (!configurationEnd(true)) {
0719:                    // Parse the annotation type, if any.
0720:                    if (ConfigurationConstants.ANNOTATION_KEYWORD
0721:                            .equals(nextWord)) {
0722:                        annotationType = ClassUtil.internalType(ListUtil
0723:                                .commaSeparatedString(parseCommaSeparatedList(
0724:                                        "annotation type", true, false, false,
0725:                                        true, false, null)));
0726:
0727:                        continue;
0728:                    }
0729:
0730:                    String strippedWord = nextWord.startsWith("!") ? nextWord
0731:                            .substring(1) : nextWord;
0732:
0733:                    // Parse the class member access modifiers.
0734:                    int accessFlag = strippedWord
0735:                            .equals(ClassConstants.EXTERNAL_ACC_PUBLIC) ? ClassConstants.INTERNAL_ACC_PUBLIC
0736:                            : strippedWord
0737:                                    .equals(ClassConstants.EXTERNAL_ACC_PRIVATE) ? ClassConstants.INTERNAL_ACC_PRIVATE
0738:                                    : strippedWord
0739:                                            .equals(ClassConstants.EXTERNAL_ACC_PROTECTED) ? ClassConstants.INTERNAL_ACC_PROTECTED
0740:                                            : strippedWord
0741:                                                    .equals(ClassConstants.EXTERNAL_ACC_STATIC) ? ClassConstants.INTERNAL_ACC_STATIC
0742:                                                    : strippedWord
0743:                                                            .equals(ClassConstants.EXTERNAL_ACC_FINAL) ? ClassConstants.INTERNAL_ACC_FINAL
0744:                                                            : strippedWord
0745:                                                                    .equals(ClassConstants.EXTERNAL_ACC_SYNCHRONIZED) ? ClassConstants.INTERNAL_ACC_SYNCHRONIZED
0746:                                                                    : strippedWord
0747:                                                                            .equals(ClassConstants.EXTERNAL_ACC_VOLATILE) ? ClassConstants.INTERNAL_ACC_VOLATILE
0748:                                                                            : strippedWord
0749:                                                                                    .equals(ClassConstants.EXTERNAL_ACC_TRANSIENT) ? ClassConstants.INTERNAL_ACC_TRANSIENT
0750:                                                                                    : strippedWord
0751:                                                                                            .equals(ClassConstants.EXTERNAL_ACC_NATIVE) ? ClassConstants.INTERNAL_ACC_NATIVE
0752:                                                                                            : strippedWord
0753:                                                                                                    .equals(ClassConstants.EXTERNAL_ACC_ABSTRACT) ? ClassConstants.INTERNAL_ACC_ABSTRACT
0754:                                                                                                    : strippedWord
0755:                                                                                                            .equals(ClassConstants.EXTERNAL_ACC_STRICT) ? ClassConstants.INTERNAL_ACC_STRICT
0756:                                                                                                            : 0;
0757:                    if (accessFlag == 0) {
0758:                        // Not a class member access modifier. Stop parsing them.
0759:                        break;
0760:                    }
0761:
0762:                    if (strippedWord.equals(nextWord)) {
0763:                        requiredSetMemberAccessFlags |= accessFlag;
0764:                    } else {
0765:                        requiredUnsetMemberAccessFlags |= accessFlag;
0766:                    }
0767:
0768:                    // Make sure the user doesn't try to set and unset the same
0769:                    // access flags simultaneously.
0770:                    if ((requiredSetMemberAccessFlags & requiredUnsetMemberAccessFlags) != 0) {
0771:                        throw new ParseException(
0772:                                "Conflicting class member access modifiers for "
0773:                                        + reader.locationDescription());
0774:                    }
0775:
0776:                    readNextWord("class member description");
0777:                }
0778:
0779:                // Parse the class member type and name part.
0780:
0781:                // Did we get a special wildcard?
0782:                if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD
0783:                        .equals(nextWord)
0784:                        || ConfigurationConstants.ANY_FIELD_KEYWORD
0785:                                .equals(nextWord)
0786:                        || ConfigurationConstants.ANY_METHOD_KEYWORD
0787:                                .equals(nextWord)) {
0788:                    // Act according to the type of wildcard..
0789:                    if (ConfigurationConstants.ANY_CLASS_MEMBER_KEYWORD
0790:                            .equals(nextWord)) {
0791:                        checkFieldAccessFlags(requiredSetMemberAccessFlags,
0792:                                requiredUnsetMemberAccessFlags);
0793:                        checkMethodAccessFlags(requiredSetMemberAccessFlags,
0794:                                requiredUnsetMemberAccessFlags);
0795:
0796:                        classSpecification.addField(new MemberSpecification(
0797:                                requiredSetMemberAccessFlags,
0798:                                requiredUnsetMemberAccessFlags, annotationType,
0799:                                null, null));
0800:                        classSpecification.addMethod(new MemberSpecification(
0801:                                requiredSetMemberAccessFlags,
0802:                                requiredUnsetMemberAccessFlags, annotationType,
0803:                                null, null));
0804:                    } else if (ConfigurationConstants.ANY_FIELD_KEYWORD
0805:                            .equals(nextWord)) {
0806:                        checkFieldAccessFlags(requiredSetMemberAccessFlags,
0807:                                requiredUnsetMemberAccessFlags);
0808:
0809:                        classSpecification.addField(new MemberSpecification(
0810:                                requiredSetMemberAccessFlags,
0811:                                requiredUnsetMemberAccessFlags, annotationType,
0812:                                null, null));
0813:                    } else if (ConfigurationConstants.ANY_METHOD_KEYWORD
0814:                            .equals(nextWord)) {
0815:                        checkMethodAccessFlags(requiredSetMemberAccessFlags,
0816:                                requiredUnsetMemberAccessFlags);
0817:
0818:                        classSpecification.addMethod(new MemberSpecification(
0819:                                requiredSetMemberAccessFlags,
0820:                                requiredUnsetMemberAccessFlags, annotationType,
0821:                                null, null));
0822:                    }
0823:
0824:                    // We still have to read the closing separator.
0825:                    readNextWord("separator '"
0826:                            + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
0827:
0828:                    if (!ConfigurationConstants.SEPARATOR_KEYWORD
0829:                            .equals(nextWord)) {
0830:                        throw new ParseException("Expecting separator '"
0831:                                + ConfigurationConstants.SEPARATOR_KEYWORD
0832:                                + "' before " + reader.locationDescription());
0833:                    }
0834:                } else {
0835:                    // Make sure we have a proper type.
0836:                    checkJavaIdentifier("java type");
0837:                    String type = nextWord;
0838:
0839:                    readNextWord("class member name");
0840:                    String name = nextWord;
0841:
0842:                    // Did we get just one word before the opening parenthesis?
0843:                    if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD
0844:                            .equals(name)) {
0845:                        // This must be a constructor then.
0846:                        // Make sure the type is a proper constructor name.
0847:                        if (!(type
0848:                                .equals(ClassConstants.INTERNAL_METHOD_NAME_INIT)
0849:                                || type.equals(externalClassName) || type
0850:                                .equals(ClassUtil
0851:                                        .externalShortClassName(externalClassName)))) {
0852:                            throw new ParseException("Expecting type and name "
0853:                                    + "instead of just '" + type + "' before "
0854:                                    + reader.locationDescription());
0855:                        }
0856:
0857:                        // Assign the fixed constructor type and name.
0858:                        type = ClassConstants.EXTERNAL_TYPE_VOID;
0859:                        name = ClassConstants.INTERNAL_METHOD_NAME_INIT;
0860:                    } else {
0861:                        // It's not a constructor.
0862:                        // Make sure we have a proper name.
0863:                        checkJavaIdentifier("class member name");
0864:
0865:                        // Read the opening parenthesis or the separating
0866:                        // semi-colon.
0867:                        readNextWord("opening '"
0868:                                + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD
0869:                                + "' or separator '"
0870:                                + ConfigurationConstants.SEPARATOR_KEYWORD
0871:                                + "'");
0872:                    }
0873:
0874:                    // Are we looking at a field, a method, or something else?
0875:                    if (ConfigurationConstants.SEPARATOR_KEYWORD
0876:                            .equals(nextWord)) {
0877:                        // It's a field.
0878:                        checkFieldAccessFlags(requiredSetMemberAccessFlags,
0879:                                requiredUnsetMemberAccessFlags);
0880:
0881:                        // We already have a field descriptor.
0882:                        String descriptor = ClassUtil.internalType(type);
0883:
0884:                        // Add the field.
0885:                        classSpecification.addField(new MemberSpecification(
0886:                                requiredSetMemberAccessFlags,
0887:                                requiredUnsetMemberAccessFlags, annotationType,
0888:                                name, descriptor));
0889:                    } else if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD
0890:                            .equals(nextWord)) {
0891:                        // It's a method.
0892:                        checkMethodAccessFlags(requiredSetMemberAccessFlags,
0893:                                requiredUnsetMemberAccessFlags);
0894:
0895:                        // Parse the method arguments.
0896:                        String descriptor = ClassUtil.internalMethodDescriptor(
0897:                                type, parseCommaSeparatedList("argument", true,
0898:                                        true, true, true, false, null));
0899:
0900:                        if (!ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD
0901:                                .equals(nextWord)) {
0902:                            throw new ParseException(
0903:                                    "Expecting separating '"
0904:                                            + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD
0905:                                            + "' or closing '"
0906:                                            + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD
0907:                                            + "' before "
0908:                                            + reader.locationDescription());
0909:                        }
0910:
0911:                        // Read the separator after the closing parenthesis.
0912:                        readNextWord("separator '"
0913:                                + ConfigurationConstants.SEPARATOR_KEYWORD
0914:                                + "'");
0915:
0916:                        if (!ConfigurationConstants.SEPARATOR_KEYWORD
0917:                                .equals(nextWord)) {
0918:                            throw new ParseException("Expecting separator '"
0919:                                    + ConfigurationConstants.SEPARATOR_KEYWORD
0920:                                    + "' before "
0921:                                    + reader.locationDescription());
0922:                        }
0923:
0924:                        // Add the method.
0925:                        classSpecification.addMethod(new MemberSpecification(
0926:                                requiredSetMemberAccessFlags,
0927:                                requiredUnsetMemberAccessFlags, annotationType,
0928:                                name, descriptor));
0929:                    } else {
0930:                        // It doesn't look like a field or a method.
0931:                        throw new ParseException("Expecting opening '"
0932:                                + ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD
0933:                                + "' or separator '"
0934:                                + ConfigurationConstants.SEPARATOR_KEYWORD
0935:                                + "' before " + reader.locationDescription());
0936:                    }
0937:                }
0938:            }
0939:
0940:            /**
0941:             * Reads a comma-separated list of java identifiers or of file names. If an
0942:             * empty list is allowed, the reading will end after a closing parenthesis
0943:             * or semi-colon.
0944:             */
0945:            private List parseCommaSeparatedList(String expectedDescription,
0946:                    boolean readFirstWord, boolean allowEmptyList,
0947:                    boolean expectClosingParenthesis,
0948:                    boolean checkJavaIdentifiers,
0949:                    boolean replaceSystemProperties, List list)
0950:                    throws ParseException, IOException {
0951:                if (list == null) {
0952:                    list = new ArrayList();
0953:                }
0954:
0955:                if (readFirstWord) {
0956:                    if (expectClosingParenthesis || !allowEmptyList) {
0957:                        // Read the first list entry.
0958:                        readNextWord(expectedDescription);
0959:                    } else {
0960:                        // Read the first list entry, if there is any.
0961:                        readNextWord();
0962:
0963:                        // Check if the list is empty.
0964:                        if (configurationEnd()
0965:                                || nextWord
0966:                                        .equals(ConfigurationConstants.ANY_ATTRIBUTE_KEYWORD)) {
0967:                            return list;
0968:                        }
0969:                    }
0970:                }
0971:
0972:                while (true) {
0973:                    if (expectClosingParenthesis
0974:                            && list.size() == 0
0975:                            && (ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD
0976:                                    .equals(nextWord) || ConfigurationConstants.SEPARATOR_KEYWORD
0977:                                    .equals(nextWord))) {
0978:                        break;
0979:                    }
0980:
0981:                    if (checkJavaIdentifiers) {
0982:                        checkJavaIdentifier("java type");
0983:                    }
0984:
0985:                    if (replaceSystemProperties) {
0986:                        nextWord = replaceSystemProperties(nextWord);
0987:                    }
0988:
0989:                    list.add(nextWord);
0990:
0991:                    if (expectClosingParenthesis) {
0992:                        // Read a comma (or a closing parenthesis, or a different word).
0993:                        readNextWord("separating '"
0994:                                + ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD
0995:                                + "' or closing '"
0996:                                + ConfigurationConstants.CLOSE_ARGUMENTS_KEYWORD
0997:                                + "'");
0998:                    } else {
0999:                        // Read a comma (or a different word).
1000:                        readNextWord();
1001:                    }
1002:
1003:                    if (!ConfigurationConstants.ARGUMENT_SEPARATOR_KEYWORD
1004:                            .equals(nextWord)) {
1005:                        break;
1006:                    }
1007:
1008:                    // Read the next list entry.
1009:                    readNextWord(expectedDescription);
1010:                }
1011:
1012:                return list;
1013:            }
1014:
1015:            /**
1016:             * Throws a ParseException for an unexpected keyword.
1017:             */
1018:            private int unknownAccessFlag() throws ParseException {
1019:                throw new ParseException("Unexpected keyword "
1020:                        + reader.locationDescription());
1021:            }
1022:
1023:            /**
1024:             * Creates a properly resolved File, based on the given word.
1025:             */
1026:            private File file(String word) throws ParseException {
1027:                String fileName = replaceSystemProperties(word);
1028:                File file = new File(fileName);
1029:
1030:                // Try to get an absolute file.
1031:                if (!file.isAbsolute()) {
1032:                    file = new File(reader.getBaseDir(), fileName);
1033:                }
1034:
1035:                // Try to get a canonical representation.
1036:                try {
1037:                    file = file.getCanonicalFile();
1038:                } catch (IOException ex) {
1039:                    // Just keep the original representation.
1040:                }
1041:
1042:                return file;
1043:            }
1044:
1045:            /**
1046:             * Replaces any system properties in the given word by their values
1047:             * (e.g. the substring "<java.home>" is replaced by its value).
1048:             */
1049:            private String replaceSystemProperties(String word)
1050:                    throws ParseException {
1051:                int fromIndex = 0;
1052:                while (true) {
1053:                    fromIndex = word.indexOf(
1054:                            ConfigurationConstants.OPEN_SYSTEM_PROPERTY,
1055:                            fromIndex);
1056:                    if (fromIndex < 0) {
1057:                        break;
1058:                    }
1059:
1060:                    int toIndex = word.indexOf(
1061:                            ConfigurationConstants.CLOSE_SYSTEM_PROPERTY,
1062:                            fromIndex + 1);
1063:                    if (toIndex < 0) {
1064:                        throw new ParseException("Expecting closing '"
1065:                                + ConfigurationConstants.CLOSE_SYSTEM_PROPERTY
1066:                                + "' after opening '"
1067:                                + ConfigurationConstants.OPEN_SYSTEM_PROPERTY
1068:                                + "' in " + reader.locationDescription());
1069:                    }
1070:
1071:                    String propertyName = word
1072:                            .substring(fromIndex + 1, toIndex);
1073:                    String propertyValue = System.getProperty(propertyName);
1074:                    if (propertyValue == null) {
1075:                        throw new ParseException("Value of system property '"
1076:                                + propertyName + "' is undefined in "
1077:                                + reader.locationDescription());
1078:                    }
1079:
1080:                    word = word.substring(0, fromIndex) + propertyValue
1081:                            + word.substring(toIndex + 1);
1082:                }
1083:
1084:                return word;
1085:            }
1086:
1087:            /**
1088:             * Reads the next word of the configuration in the 'nextWord' field,
1089:             * throwing an exception if there is no next word.
1090:             */
1091:            private void readNextWord(String expectedDescription)
1092:                    throws ParseException, IOException {
1093:                readNextWord(expectedDescription, false);
1094:            }
1095:
1096:            /**
1097:             * Reads the next word of the configuration in the 'nextWord' field,
1098:             * throwing an exception if there is no next word.
1099:             */
1100:            private void readNextWord(String expectedDescription,
1101:                    boolean expectingAtCharacter) throws ParseException,
1102:                    IOException {
1103:                readNextWord();
1104:                if (configurationEnd(expectingAtCharacter)) {
1105:                    throw new ParseException("Expecting " + expectedDescription
1106:                            + " before " + reader.locationDescription());
1107:                }
1108:            }
1109:
1110:            /**
1111:             * Reads the next word of the configuration in the 'nextWord' field.
1112:             */
1113:            private void readNextWord() throws IOException {
1114:                nextWord = reader.nextWord();
1115:            }
1116:
1117:            /**
1118:             * Returns whether the end of the configuration has been reached.
1119:             */
1120:            private boolean configurationEnd() {
1121:                return configurationEnd(false);
1122:            }
1123:
1124:            /**
1125:             * Returns whether the end of the configuration has been reached.
1126:             */
1127:            private boolean configurationEnd(boolean expectingAtCharacter) {
1128:                return nextWord == null
1129:                        || nextWord
1130:                                .startsWith(ConfigurationConstants.OPTION_PREFIX)
1131:                        || (!expectingAtCharacter && nextWord
1132:                                .equals(ConfigurationConstants.AT_DIRECTIVE));
1133:            }
1134:
1135:            /**
1136:             * Checks whether the given word is a valid Java identifier and throws
1137:             * a ParseException if it isn't. Wildcard characters are accepted.
1138:             */
1139:            private void checkJavaIdentifier(String expectedDescription)
1140:                    throws ParseException {
1141:                if (!isJavaIdentifier(nextWord)) {
1142:                    throw new ParseException("Expecting " + expectedDescription
1143:                            + " before " + reader.locationDescription());
1144:                }
1145:            }
1146:
1147:            /**
1148:             * Returns whether the given word is a valid Java identifier.
1149:             * Wildcard characters are accepted.
1150:             */
1151:            private boolean isJavaIdentifier(String aWord) {
1152:                for (int index = 0; index < aWord.length(); index++) {
1153:                    char c = aWord.charAt(index);
1154:                    if (!(Character.isJavaIdentifierPart(c) || c == '.'
1155:                            || c == '[' || c == ']' || c == '<' || c == '>'
1156:                            || c == '-' || c == '!' || c == '*' || c == '?' || c == '%')) {
1157:                        return false;
1158:                    }
1159:                }
1160:
1161:                return true;
1162:            }
1163:
1164:            /**
1165:             * Checks whether the given access flags are valid field access flags,
1166:             * throwing a ParseException if they aren't.
1167:             */
1168:            private void checkFieldAccessFlags(
1169:                    int requiredSetMemberAccessFlags,
1170:                    int requiredUnsetMemberAccessFlags) throws ParseException {
1171:                if (((requiredSetMemberAccessFlags | requiredUnsetMemberAccessFlags) & ~ClassConstants.VALID_INTERNAL_ACC_FIELD) != 0) {
1172:                    throw new ParseException(
1173:                            "Invalid method access modifier for field before "
1174:                                    + reader.locationDescription());
1175:                }
1176:            }
1177:
1178:            /**
1179:             * Checks whether the given access flags are valid method access flags,
1180:             * throwing a ParseException if they aren't.
1181:             */
1182:            private void checkMethodAccessFlags(
1183:                    int requiredSetMemberAccessFlags,
1184:                    int requiredUnsetMemberAccessFlags) throws ParseException {
1185:                if (((requiredSetMemberAccessFlags | requiredUnsetMemberAccessFlags) & ~ClassConstants.VALID_INTERNAL_ACC_METHOD) != 0) {
1186:                    throw new ParseException(
1187:                            "Invalid field access modifier for method before "
1188:                                    + reader.locationDescription());
1189:                }
1190:            }
1191:
1192:            /**
1193:             * A main method for testing configuration parsing.
1194:             */
1195:            public static void main(String[] args) {
1196:                try {
1197:                    ConfigurationParser parser = new ConfigurationParser(args);
1198:
1199:                    try {
1200:                        parser.parse(new Configuration());
1201:                    } catch (ParseException ex) {
1202:                        ex.printStackTrace();
1203:                    } finally {
1204:                        parser.close();
1205:                    }
1206:                } catch (IOException ex) {
1207:                    ex.printStackTrace();
1208:                }
1209:            }
1210:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.