Source Code Cross Referenced for JEnable.java in  » XML » jibx-1.1.5 » jenable » 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 » XML » jibx 1.1.5 » jenable 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * Copyright (c) 2000-2001 Sosnoski Software Solutions, Inc.
0003:         *
0004:         * Permission is hereby granted, free of charge, to any person obtaining a copy
0005:         * of this software and associated documentation files (the "Software"), to deal
0006:         * in the Software without restriction, including without limitation the rights
0007:         * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0008:         * copies of the Software, and to permit persons to whom the Software is
0009:         * furnished to do so, subject to the following conditions:
0010:         *
0011:         * The above copyright notice and this permission notice shall be included in
0012:         * all copies or substantial portions of the Software.
0013:         *
0014:         * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015:         * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016:         * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0017:         * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0018:         * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0019:         * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0020:         * IN THE SOFTWARE.
0021:         */
0022:
0023:        import java.io.*;
0024:        import java.util.*;
0025:
0026:        /**
0027:         * Source configuration processor program. This program processes a set of Java
0028:         * source files (or standard input to standard output, if no source files are
0029:         * specified), scanning for configuration control lines. A control line is a
0030:         * line that starts with "//#token*" (valid only as the first line of a
0031:         * file), "//#token{" (beginning an option block), "//#}token{" (inverting an
0032:         * option block), or "//#token} (closing an option block). The first two formats
0033:         * also allow a '!' immediately before the token in order to invert the token
0034:         * state.<p>
0035:         *
0036:         * The token strings to be processed are specified on the command line as
0037:         * either enabled or disabled. See the program documentation for more details
0038:         * of the command line options and usage.<p>
0039:         *
0040:         * Nested option blocks are allowed, but overlapping option blocks are an
0041:         * error. In order to ensure proper processing of nested option blocks, the
0042:         * user should generally specify <b>every</b> token used for the nested blocks
0043:         * as either enabled or disabled if <b>any</b> of them are either enabled or
0044:         * disabled. It is an error if an indeterminant beginning of block token (one
0045:         * with a token which is not on either list) is immediately contained within
0046:         * a block with an enabled token. In other words, the case:
0047:         * <pre>
0048:         *   //#a{
0049:         *   //#b{
0050:         *   //#c{
0051:         *	 //#c}
0052:         *	 //#b}
0053:         *	 //#a}
0054:         * </pre>
0055:         * gives an error if "a" is on the enabled list and "b" is not on either list,
0056:         * or if "a" is not on the disabled list, "b" is on the enabled list,  and "c"
0057:         * is not on either list.
0058:         *
0059:         * @author Dennis M. Sosnoski
0060:         * @version 0.8
0061:         */
0062:
0063:        public class JEnable {
0064:            /** Lead text for option token. */
0065:            protected static final String OPTION_LEAD = "//#";
0066:            /** Length of lead text for option token. */
0067:            protected static final int LEAD_LENGTH = OPTION_LEAD.length();
0068:
0069:            /** Size of buffer used to copy file. */
0070:            protected static final int COPY_BUFFER_SIZE = 4096;
0071:
0072:            /** Return code for not an option line. */
0073:            protected static final int NOT_OPTION = 0;
0074:            /** Return code for file option line. */
0075:            protected static final int FILE_OPTION = 1;
0076:            /** Return code for block start option line. */
0077:            protected static final int BLOCK_START_OPTION = 2;
0078:            /** Return code for block else option line. */
0079:            protected static final int BLOCK_ELSE_OPTION = 3;
0080:            /** Return code for block end option line. */
0081:            protected static final int BLOCK_END_OPTION = 4;
0082:            /** Return code for block comment option line. */
0083:            protected static final int BLOCK_COMMENT_OPTION = 5;
0084:
0085:            /** Error text for file option not on first line. */
0086:            protected static final String FILE_OPTION_ERR = "file option token must be first line of file";
0087:            /** Error text for token nested within block for same token. */
0088:            protected static final String NESTED_SAME_ERR = "block option start cannot be nested within block with same token";
0089:            /** Error text for indeterminant token nested in enabled block. */
0090:            protected static final String INDETERM_ERR = "block option token within enabled block must be enabled or disabled";
0091:            /** Error text for block end token not matching block start token. */
0092:            protected static final String UNBALANCED_ERR = "block option end without matching start";
0093:            /** Error text for block else token not matching block start token. */
0094:            protected static final String BADELSE_ERR = "block option else without matching start";
0095:            /** Error text for end of file with open block. */
0096:            protected static final String UNCLOSED_ERR = "end of file with open block";
0097:            /** Error text for unknown option token type. */
0098:            protected static final String UNKNOWN_OPTION_ERR = "unknown option line type";
0099:            /** Error text for file option line with unknown file extension. */
0100:            protected static final String EXTENSION_ERR = "unknown file option line extension";
0101:            /** Error text for unable to rename file to backup directory. */
0102:            protected static final String BACKUP_DIR_ERR = "unable to create backup directory";
0103:            /** Error text for unable to delete old backup file. */
0104:            protected static final String OLD_BACKUP_ERR = "unable to delete old backup file";
0105:            /** Error text for unable to rename file within directory. */
0106:            protected static final String BACKUP_FILE_ERR = "unable to rename file for backup";
0107:            /** Error text for unable to delete original file. */
0108:            protected static final String DELETE_ERR = "unable to delete input file";
0109:            /** Error text for unable to rename original file. */
0110:            protected static final String RENAME_ERR = "unable to rename source file";
0111:            /** Error text for unable to rename temp file. */
0112:            protected static final String TEMP_RENAME_ERR = "unable to rename temp file";
0113:            /** Error text for unable to delete temporary file. */
0114:            protected static final String TEMP_DELETE_ERR = "unable to delete temporary output file";
0115:            /** Error text for unable to change file modify timestamp. */
0116:            protected static final String STAMP_ERR = "unable to change file modify timestamp";
0117:            /** Error text for token in both sets. */
0118:            protected static final String DUAL_USE_ERR = "Same token cannot be both enabled and disabled";
0119:
0120:            /** Preserve timestamp on modified files flag. */
0121:            protected boolean m_keepStamp;
0122:
0123:            /** Mark backup file with tilde flag. */
0124:            protected boolean m_markBackup;
0125:
0126:            /** List modified files flag. */
0127:            protected boolean m_listModified;
0128:
0129:            /** List all files processed flag. */
0130:            protected boolean m_listProcessed;
0131:
0132:            /** List file summary by path flag. */
0133:            protected boolean m_listSummary;
0134:
0135:            /** Backup root path (null if not backing up). */
0136:            protected File m_backupDir;
0137:
0138:            /** Map for enabled tokens (values same as keys). */
0139:            protected Hashtable m_enabledTokens;
0140:
0141:            /** Map for disabled tokens (values same as keys). */
0142:            protected Hashtable m_disabledTokens;
0143:
0144:            /** Number of files matched. */
0145:            protected int m_matchedCount;
0146:
0147:            /** Number of files modified. */
0148:            protected int m_modifiedCount;
0149:
0150:            /** Current option token, set by check method. */
0151:            private String m_token;
0152:
0153:            /** Inverted token flag, set by check method. */
0154:            private boolean m_invert;
0155:
0156:            /** Offset past end of token in line, set by check method. */
0157:            private int m_endOffset;
0158:
0159:            /**
0160:             * Constructor.
0161:             *
0162:             * @param keep preserve timestamp on modified files flag
0163:             * @param mark mark backup files with tilde flag
0164:             * @param mods list modified files flag
0165:             * @param quiet do not list file summaries by path flag
0166:             * @param verbose list all files processed flag
0167:             * @param backup root back for backup directory tree (<code>null</code> if
0168:             * no backups)
0169:             * @param enabled map of enabled tokens
0170:             * @param disabled map of disabled tokens
0171:             */
0172:
0173:            protected JEnable(boolean keep, boolean mark, boolean mods,
0174:                    boolean quiet, boolean verbose, File backup,
0175:                    Hashtable enabled, Hashtable disabled) {
0176:                m_keepStamp = keep;
0177:                m_markBackup = mark;
0178:                m_listModified = mods;
0179:                m_listProcessed = verbose;
0180:                m_listSummary = !quiet;
0181:                m_backupDir = backup;
0182:                m_enabledTokens = enabled;
0183:                m_disabledTokens = disabled;
0184:            }
0185:
0186:            /**
0187:             * Checks for valid first character of token. The first character must be
0188:             * an alpha or underscore.
0189:             *
0190:             * @param chr character to be validated
0191:             * @return <code>true</code> if valid first character, <code>false</code>
0192:             * if not
0193:             */
0194:
0195:            protected static boolean isTokenLeadChar(char chr) {
0196:                return (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z')
0197:                        || chr == '_';
0198:            }
0199:
0200:            /**
0201:             * Checks for valid body character of token. All body characters must be
0202:             * an alpha, digits, or underscore.
0203:             *
0204:             * @param chr character to be validated
0205:             * @return <code>true</code> if valid body character, <code>false</code>
0206:             * if not
0207:             */
0208:
0209:            protected static boolean isTokenBodyChar(char chr) {
0210:                return (chr >= 'a' && chr <= 'z') || (chr >= 'A' && chr <= 'Z')
0211:                        || chr == '_' || (chr >= '0' && chr <= '9');
0212:            }
0213:
0214:            /**
0215:             * Convenience method for generating an error report exception.
0216:             *
0217:             * @param lnum line number within file
0218:             * @param line source line to check for option
0219:             * @param msg error message text
0220:             * @throws IOException wrapping the error information
0221:             */
0222:
0223:            protected void throwError(int lnum, String line, String msg)
0224:                    throws IOException {
0225:                throw new IOException("Error on input line " + lnum + ", "
0226:                        + msg + ":\n" + line);
0227:            }
0228:
0229:            /**
0230:             * Check if line is an option. Returns a code for the option line type
0231:             * (or "not an option line"), with the actual token from the line stored
0232:             * in the instance variable. Ugly technique, but the only easy way to
0233:             * return multiple results without using another class.
0234:             *
0235:             * @param lnum line number within file (used for error reporting)
0236:             * @param line source line to check for option
0237:             * @return return code for option line type
0238:             * @throws IOException on option line error
0239:             */
0240:
0241:            protected int checkOptionLine(int lnum, String line)
0242:                    throws IOException {
0243:
0244:                // check if line is a candidate for option token
0245:                int type = NOT_OPTION;
0246:                m_token = null;
0247:                m_invert = false;
0248:                m_endOffset = 0;
0249:                if (line.length() > LEAD_LENGTH && line.startsWith(OPTION_LEAD)) {
0250:
0251:                    // check for special leading character before token
0252:                    int offset = LEAD_LENGTH;
0253:                    char lead = line.charAt(offset);
0254:                    if (lead == '!' || lead == '}') {
0255:                        offset++;
0256:                    } else {
0257:                        lead = 0;
0258:                    }
0259:
0260:                    // make sure a valid token start character follows
0261:                    int start = offset;
0262:                    if (isTokenLeadChar(line.charAt(start))) {
0263:
0264:                        // parse the token characters
0265:                        int scan = LEAD_LENGTH + 1;
0266:                        while (scan < line.length()) {
0267:                            char chr = line.charAt(scan++);
0268:                            if (!isTokenBodyChar(chr)) {
0269:
0270:                                // token found, classify and set type
0271:                                m_token = line.substring(start, scan - 1);
0272:                                m_endOffset = scan;
0273:                                switch (chr) {
0274:
0275:                                case '*':
0276:
0277:                                    // file option, inverted token is only variation
0278:                                    type = FILE_OPTION;
0279:                                    if (lead == '!') {
0280:                                        m_invert = true;
0281:                                    } else if (lead != 0) {
0282:                                        throwError(lnum, line,
0283:                                                UNKNOWN_OPTION_ERR);
0284:                                    }
0285:                                    break;
0286:
0287:                                case '{':
0288:
0289:                                    // block start option, check variations
0290:                                    if (lead == '}') {
0291:                                        type = BLOCK_ELSE_OPTION;
0292:                                    } else {
0293:                                        if (lead == '!') {
0294:                                            m_invert = true;
0295:                                        }
0296:                                        type = BLOCK_START_OPTION;
0297:                                    }
0298:                                    break;
0299:
0300:                                case '}':
0301:
0302:                                    // block end option, no variations allowed
0303:                                    type = BLOCK_END_OPTION;
0304:                                    if (lead != 0) {
0305:                                        throwError(lnum, line,
0306:                                                UNKNOWN_OPTION_ERR);
0307:                                    }
0308:                                    break;
0309:
0310:                                case ':':
0311:
0312:                                    // block comment option, no variations allowed
0313:                                    type = BLOCK_COMMENT_OPTION;
0314:                                    if (lead != 0) {
0315:                                        throwError(lnum, line,
0316:                                                UNKNOWN_OPTION_ERR);
0317:                                    }
0318:                                    break;
0319:
0320:                                default:
0321:
0322:                                    // no idea what this is supposed to be
0323:                                    throwError(lnum, line, UNKNOWN_OPTION_ERR);
0324:                                    break;
0325:
0326:                                }
0327:                                break;
0328:                            }
0329:                        }
0330:                    }
0331:                }
0332:                return type;
0333:            }
0334:
0335:            /**
0336:             * Processes source options for a text stream. If an error occurs in
0337:             * processing, this generates an <code>IOException</code> with the error
0338:             * information (including input line number).
0339:             *
0340:             * @param in input reader for source data
0341:             * @param lead first line of file (previously read for checking file enable
0342:             * or disable)
0343:             * @param out output writer for modified source data
0344:             * @return <code>true</code> if source modified, <code>false</code> if not
0345:             */
0346:
0347:            protected boolean processStream(BufferedReader in, String lead,
0348:                    BufferedWriter out) throws IOException {
0349:
0350:                // initialize state information
0351:                Stack enables = new Stack();
0352:                Stack nests = new Stack();
0353:                String disable = null;
0354:                boolean changed = false;
0355:
0356:                // basic file line copy loop
0357:                String line = lead;
0358:                int lnum = 1;
0359:                while (line != null) {
0360:
0361:                    // process based on option type
0362:                    boolean option = true;
0363:                    int type = checkOptionLine(lnum, line);
0364:                    switch (type) {
0365:
0366:                    case NOT_OPTION:
0367:                        option = false;
0368:                        break;
0369:
0370:                    case FILE_OPTION:
0371:
0372:                        // file option processed outside, but must be first line
0373:                        if (lnum > 1) {
0374:                            throwError(lnum, line, FILE_OPTION_ERR);
0375:                        }
0376:                        break;
0377:
0378:                    case BLOCK_START_OPTION:
0379:
0380:                        // option block start token, must not be duplicated
0381:                        if (nests.indexOf(m_token) >= 0) {
0382:                            throwError(lnum, line, NESTED_SAME_ERR);
0383:                        } else {
0384:
0385:                            // push to nesting stack and check if we're handling
0386:                            nests.push(m_token);
0387:                            if (disable == null) {
0388:
0389:                                // see if we know about this token
0390:                                boolean on = m_enabledTokens
0391:                                        .containsKey(m_token);
0392:                                boolean off = m_disabledTokens
0393:                                        .containsKey(m_token);
0394:
0395:                                // swap flags if inverted token
0396:                                if (m_invert) {
0397:                                    boolean hold = on;
0398:                                    on = off;
0399:                                    off = hold;
0400:                                }
0401:
0402:                                // handle start of block
0403:                                if (off) {
0404:
0405:                                    // set disabling option
0406:                                    disable = m_token;
0407:
0408:                                } else if (on) {
0409:
0410:                                    // stack enabled option
0411:                                    enables.push(m_token);
0412:
0413:                                } else if (!enables.empty()) {
0414:
0415:                                    // error if unknown inside enable
0416:                                    throwError(lnum, line, INDETERM_ERR);
0417:                                }
0418:                            }
0419:                        }
0420:                        break;
0421:
0422:                    case BLOCK_ELSE_OPTION:
0423:
0424:                        // option block else, must match top of nesting stack
0425:                        if (nests.empty() || !nests.peek().equals(m_token)) {
0426:                            throwError(lnum, line, BADELSE_ERR);
0427:                        } else {
0428:
0429:                            // reverse current state, if known
0430:                            if (disable == null) {
0431:
0432:                                // enabled state, check if top of stack
0433:                                if (!enables.empty()) {
0434:                                    if (enables.peek().equals(m_token)) {
0435:
0436:                                        // flip to disable state
0437:                                        enables.pop();
0438:                                        disable = m_token;
0439:
0440:                                    }
0441:                                }
0442:
0443:                            } else if (disable.equals(m_token)) {
0444:
0445:                                // flip to enable state
0446:                                disable = null;
0447:                                enables.push(m_token);
0448:
0449:                            }
0450:                        }
0451:                        break;
0452:
0453:                    case BLOCK_END_OPTION:
0454:
0455:                        // option block end, must match top of nesting stack
0456:                        if (nests.empty() || !nests.peek().equals(m_token)) {
0457:                            throwError(lnum, line, UNBALANCED_ERR);
0458:                        } else {
0459:
0460:                            // remove from nesting stack and check state
0461:                            nests.pop();
0462:                            if (disable == null) {
0463:
0464:                                // enabled state, check if top of stack
0465:                                if (!enables.empty()) {
0466:                                    if (enables.peek().equals(m_token)) {
0467:                                        enables.pop();
0468:                                    }
0469:                                }
0470:
0471:                            } else if (disable.equals(m_token)) {
0472:                                disable = null;
0473:                            }
0474:                        }
0475:                        break;
0476:
0477:                    case BLOCK_COMMENT_OPTION:
0478:
0479:                        // disabled line option, check if clearing
0480:                        if ((disable != null && !disable.equals(m_token))
0481:                                || (disable == null && enables
0482:                                        .contains(m_token))) {
0483:
0484:                            // clear disabled line option
0485:                            line = line.substring(m_endOffset);
0486:                            option = false;
0487:                            changed = true;
0488:                        }
0489:                        break;
0490:
0491:                    default:
0492:                        throwError(lnum, line, UNKNOWN_OPTION_ERR);
0493:                    }
0494:
0495:                    // check for disabling lines
0496:                    if (!option && disable != null) {
0497:
0498:                        // change line to disabled state
0499:                        line = OPTION_LEAD + disable + ':' + line;
0500:                        changed = true;
0501:                    }
0502:
0503:                    // write (possibly modified) line to output
0504:                    out.write(line);
0505:                    out.newLine();
0506:
0507:                    // read next line of input
0508:                    line = in.readLine();
0509:                    lnum++;
0510:
0511:                }
0512:
0513:                // check for valid end state
0514:                if (nests.size() > 0) {
0515:                    throwError(lnum, (String) nests.pop(), UNCLOSED_ERR);
0516:                }
0517:                out.flush();
0518:                return changed;
0519:            }
0520:
0521:            /**
0522:             * Processes source options for a file. Starts by checking the first line
0523:             * of the file for a file option and processing that. If, after processing
0524:             * the file option, the file has a ".java" extension, it is processed for
0525:             * other option lines.<p>
0526:             *
0527:             * This saves the output to a temporary file, then if processing is
0528:             * completed successfully first renames or moves the original file (if
0529:             * backup has been requested), or deletes it (if backup not requested),
0530:             * and then renames the temporary file to the original file name.<p>
0531:             *
0532:             * Processing errors are printed to <code>System.err</code>, and any
0533:             * results are discarded without being saved.
0534:             *
0535:             * @param file source file to be processed
0536:             * @return <code>true</code> if source modified, <code>false</code> if not
0537:             */
0538:
0539:            protected boolean processFile(File file) {
0540:                File temp = null;
0541:                try {
0542:
0543:                    // set up basic information
0544:                    String name = file.getName();
0545:                    String dir = file.getParent();
0546:                    int split = name.lastIndexOf('.');
0547:                    String ext = (split >= 0) ? name.substring(split + 1) : "";
0548:                    String toext = ext;
0549:                    long stamp = m_keepStamp ? file.lastModified() : 0;
0550:                    File target = file;
0551:
0552:                    // check first line for file option
0553:                    BufferedReader in = new BufferedReader(new FileReader(file));
0554:                    String line = in.readLine();
0555:                    int type = checkOptionLine(1, line);
0556:                    if (type == FILE_OPTION) {
0557:
0558:                        // make sure we have one of the extensions we know about
0559:                        if (ext.equals("java") || ext.equals("javx")) {
0560:
0561:                            // set "to" extension based on option setting
0562:                            if (m_enabledTokens.contains(m_token)) {
0563:                                toext = m_invert ? "javx" : "java";
0564:                            } else if (m_disabledTokens.contains(m_token)) {
0565:                                toext = m_invert ? "java" : "javx";
0566:                            }
0567:
0568:                            // generate new target file name if different extension
0569:                            if (!toext.equals(ext)) {
0570:                                split = name.indexOf('.');
0571:                                name = name.substring(0, split) + '.' + toext;
0572:                                target = new File(dir, name);
0573:                            }
0574:
0575:                        } else {
0576:                            throw new IOException(EXTENSION_ERR);
0577:                        }
0578:
0579:                    }
0580:
0581:                    // check if extension valid for processing
0582:                    boolean changed = false;
0583:                    if (!toext.equals("javx")) {
0584:
0585:                        // set up output to temporary file in same directory
0586:                        temp = File.createTempFile("sop", null, file
0587:                                .getParentFile());
0588:                        BufferedWriter out = new BufferedWriter(new FileWriter(
0589:                                temp));
0590:
0591:                        // process the file for changes
0592:                        changed = processStream(in, line, out);
0593:                        in.close();
0594:                        out.close();
0595:                        if (changed) {
0596:
0597:                            // handle backup of original file
0598:                            if (m_backupDir != null) {
0599:
0600:                                // construct path within backup directory
0601:                                String extra = file.getCanonicalPath();
0602:                                int mark = extra.indexOf(File.separatorChar);
0603:                                if (mark >= 0) {
0604:                                    extra = extra.substring(mark + 1);
0605:                                }
0606:                                File backup = new File(m_backupDir, extra);
0607:
0608:                                // copy file to backup directory
0609:                                File backdir = backup.getParentFile();
0610:                                if (!backdir.exists() && !backdir.mkdirs()) {
0611:                                    throw new IOException(BACKUP_DIR_ERR + '\n'
0612:                                            + backdir.getPath());
0613:                                }
0614:                                if (backup.exists()) {
0615:                                    if (!backup.delete()) {
0616:                                        throw new IOException(OLD_BACKUP_ERR);
0617:                                    }
0618:                                }
0619:                                byte[] buff = new byte[COPY_BUFFER_SIZE];
0620:                                InputStream is = new FileInputStream(file);
0621:                                OutputStream os = new FileOutputStream(backup);
0622:                                int bytes;
0623:                                while ((bytes = is.read(buff)) >= 0) {
0624:                                    os.write(buff, 0, bytes);
0625:                                }
0626:                                is.close();
0627:                                os.close();
0628:                                backup.setLastModified(file.lastModified());
0629:
0630:                            }
0631:                            if (m_markBackup) {
0632:
0633:                                // suffix file name with tilde
0634:                                File backup = new File(dir, name + '~');
0635:                                if (backup.exists()) {
0636:                                    if (!backup.delete()) {
0637:                                        throw new IOException(OLD_BACKUP_ERR);
0638:                                    }
0639:                                }
0640:                                if (!file.renameTo(backup)) {
0641:                                    throw new IOException(BACKUP_FILE_ERR);
0642:                                }
0643:
0644:                            } else {
0645:
0646:                                // just delete the original file
0647:                                if (!file.delete()) {
0648:                                    throw new IOException(DELETE_ERR);
0649:                                }
0650:                            }
0651:
0652:                            // rename temp to target name
0653:                            if (temp.renameTo(target)) {
0654:                                if (m_keepStamp
0655:                                        && !target.setLastModified(stamp)) {
0656:                                    throw new IOException(STAMP_ERR);
0657:                                }
0658:                            } else {
0659:                                throw new IOException(TEMP_RENAME_ERR);
0660:                            }
0661:
0662:                        } else {
0663:
0664:                            // just discard the temporary output file
0665:                            if (!temp.delete()) {
0666:                                throw new IOException(TEMP_DELETE_ERR);
0667:                            }
0668:
0669:                            // check if file needs to be renamed
0670:                            if (!toext.equals(ext)) {
0671:
0672:                                // just rename file for file option result
0673:                                if (file.renameTo(target)) {
0674:                                    changed = true;
0675:                                    if (m_keepStamp
0676:                                            && !target.setLastModified(stamp)) {
0677:                                        throw new IOException(STAMP_ERR);
0678:                                    }
0679:                                } else {
0680:                                    throw new IOException(RENAME_ERR);
0681:                                }
0682:                            }
0683:                        }
0684:
0685:                    } else if (!toext.equals(ext)) {
0686:
0687:                        // just rename file for file option result
0688:                        in.close();
0689:                        if (file.renameTo(target)) {
0690:                            changed = true;
0691:                            if (m_keepStamp && !target.setLastModified(stamp)) {
0692:                                throw new IOException(STAMP_ERR);
0693:                            }
0694:                        } else {
0695:                            throw new IOException(RENAME_ERR);
0696:                        }
0697:
0698:                    }
0699:
0700:                    // check file listing
0701:                    if (changed && (m_listProcessed || m_listModified)) {
0702:                        System.out.println("  modified file " + file.getPath());
0703:                    } else if (m_listProcessed) {
0704:                        System.out.println("  checked file " + file.getPath());
0705:                    }
0706:                    return changed;
0707:
0708:                } catch (Exception ex) {
0709:
0710:                    // report error
0711:                    System.err.println("Error processing " + file.getPath());
0712:                    System.err.println(ex.getMessage());
0713:
0714:                    // discard temporary output file
0715:                    if (temp != null) {
0716:                        try {
0717:                            temp.delete();
0718:                        } catch (Exception ex2) {
0719:                        }
0720:                    }
0721:                    return false;
0722:
0723:                }
0724:            }
0725:
0726:            /**
0727:             * Checks if file or directory name directly matches a pattern. This
0728:             * method accepts one or more '*' wildcard characters in the pattern,
0729:             * calling itself recursively in order to handle multiple wildcards.
0730:             *
0731:             * @param name file or directory name
0732:             * @param pattern match pattern
0733:             * @return <code>true</code> if any pattern matched, <code>false</code>
0734:             * if not
0735:             */
0736:
0737:            protected boolean isPathMatch(String name, String pattern) {
0738:
0739:                // check special match cases first
0740:                if (pattern.length() == 0) {
0741:                    return name.length() == 0;
0742:                } else if (pattern.charAt(0) == '*') {
0743:
0744:                    // check if the wildcard is all that's left of pattern
0745:                    if (pattern.length() == 1) {
0746:                        return true;
0747:                    } else {
0748:
0749:                        // check if another wildcard follows next segment of text
0750:                        pattern = pattern.substring(1);
0751:                        int split = pattern.indexOf('*');
0752:                        if (split > 0) {
0753:
0754:                            // recurse on each match to text segment
0755:                            String piece = pattern.substring(0, split);
0756:                            pattern = pattern.substring(split);
0757:                            int offset = -1;
0758:                            while ((offset = name.indexOf(piece, ++offset)) > 0) {
0759:                                int end = offset + piece.length();
0760:                                if (isPathMatch(name.substring(end), pattern)) {
0761:                                    return true;
0762:                                }
0763:                            }
0764:
0765:                        } else {
0766:
0767:                            // no more wildcards, need exact match to end of name
0768:                            return name.endsWith(pattern);
0769:
0770:                        }
0771:                    }
0772:                } else {
0773:
0774:                    // check for leading text before first wildcard
0775:                    int split = pattern.indexOf('*');
0776:                    if (split > 0) {
0777:
0778:                        // match leading text to start of name
0779:                        String piece = pattern.substring(0, split);
0780:                        if (name.startsWith(piece)) {
0781:                            return isPathMatch(name.substring(split), pattern
0782:                                    .substring(split));
0783:                        } else {
0784:                            return false;
0785:                        }
0786:
0787:                    } else {
0788:
0789:                        // no wildcards, need exact match
0790:                        return name.equals(pattern);
0791:
0792:                    }
0793:                }
0794:                return false;
0795:            }
0796:
0797:            /**
0798:             * Checks if file name matches a pattern. This works a little differently
0799:             * from the general path matching in that if the pattern does not include
0800:             * an extension both ".java" and ".javx" file extensions are matched. If
0801:             * the pattern includes an extension ending in '*' it is blocked from
0802:             * matching with a tilde final character in the file name as a special case.
0803:             *
0804:             * @param name file or directory name
0805:             * @param pattern match pattern
0806:             * @return <code>true</code> if any file modified, <code>false</code> if not
0807:             */
0808:
0809:            protected boolean isNameMatch(String name, String pattern) {
0810:
0811:                // check for extension included in pattern
0812:                if (pattern.indexOf('.') >= 0) {
0813:
0814:                    // pattern includes extension, use as is except for tilde endings
0815:                    if (name.charAt(name.length() - 1) != '~'
0816:                            || pattern.charAt(pattern.length() - 1) == '~') {
0817:                        return isPathMatch(name, pattern);
0818:                    }
0819:
0820:                } else {
0821:
0822:                    // split extension from file name
0823:                    int split = name.lastIndexOf('.');
0824:                    if (split >= 0) {
0825:
0826:                        // check for valid extension with match on name
0827:                        String ext = name.substring(split + 1);
0828:                        if (ext.equals("java") || ext.equals("javx")) {
0829:                            return isPathMatch(name.substring(0, split),
0830:                                    pattern);
0831:                        }
0832:                    }
0833:
0834:                }
0835:                return false;
0836:            }
0837:
0838:            /**
0839:             * Process files matching path segment. This method matches a single step
0840:             * (directory specification) in a path for each call, calling itself
0841:             * recursively to match the complete path.
0842:             *
0843:             * @param base base directory for path match
0844:             * @param path file path remaining to be processed
0845:             */
0846:
0847:            protected void matchPathSegment(File base, String path) {
0848:
0849:                // find break for leading directory if any in path
0850:                File[] files = base.listFiles();
0851:                int split = path.indexOf('/');
0852:                if (split >= 0) {
0853:
0854:                    // split off the directory and check it
0855:                    String dir = path.substring(0, split);
0856:                    String next = path.substring(split + 1);
0857:                    if (dir.equals("**")) {
0858:
0859:                        // match directly against files in this directory
0860:                        matchPathSegment(base, next);
0861:
0862:                        // walk all directories in tree under this one
0863:                        for (int i = 0; i < files.length; i++) {
0864:                            if (files[i].isDirectory()) {
0865:                                matchPathSegment(files[i], path);
0866:                            }
0867:                        }
0868:
0869:                    } else {
0870:
0871:                        // try for concrete match to directory
0872:                        for (int i = 0; i < files.length; i++) {
0873:                            if (files[i].isDirectory()) {
0874:                                if (isPathMatch(files[i].getName(), dir)) {
0875:                                    matchPathSegment(files[i], next);
0876:                                }
0877:                            }
0878:                        }
0879:
0880:                    }
0881:                } else {
0882:
0883:                    // match directly against files in this directory
0884:                    for (int i = 0; i < files.length; i++) {
0885:                        if (!files[i].isDirectory()) {
0886:                            if (isNameMatch(files[i].getName(), path)) {
0887:                                m_matchedCount++;
0888:                                if (processFile(files[i])) {
0889:                                    m_modifiedCount++;
0890:                                }
0891:                            }
0892:                        }
0893:                    }
0894:
0895:                }
0896:            }
0897:
0898:            /**
0899:             * Process all files matching path and print summary. The file path
0900:             * format is similar to Ant, supporting arbitrary directory recursion using
0901:             * '**' separators between '/' separators. Single '*'s may be used within
0902:             * names for wildcarding, but aside from the special case of the directory
0903:             * recursion matcher only one '*' may be used per name.<p>
0904:             *
0905:             * If an extension is
0906:             * not specified for the final name in the path both ".java" and ".javx"
0907:             * extensions are checked, but after checking for file option lines (which
0908:             * may change the file extension) only ".java" extensions are processed for
0909:             * other source options.
0910:             *
0911:             * @param path file path to be processed
0912:             */
0913:
0914:            protected void processPath(String path) {
0915:
0916:                // make sure we have something to process
0917:                if (path.length() > 0) {
0918:
0919:                    // begin matching from root or current directory
0920:                    if (path.charAt(0) == '/') {
0921:                        matchPathSegment(new File(File.separator), path
0922:                                .substring(1));
0923:                    } else {
0924:                        matchPathSegment(new File("."), path);
0925:                    }
0926:
0927:                    // print summary information for path
0928:                    if (m_listSummary) {
0929:                        System.out.println(" matched " + m_matchedCount
0930:                                + " files and modified " + m_modifiedCount
0931:                                + " for path: " + path);
0932:                        m_matchedCount = 0;
0933:                        m_modifiedCount = 0;
0934:                    }
0935:                }
0936:            }
0937:
0938:            /**
0939:             * Parse comma-separated token list. Parses and validates the tokens,
0940:             * adding them to the supplied list. errors are signalled by throwing
0941:             * <code>IllegalArgumentException</code>.
0942:             *
0943:             * @param list comma-separated token list to be parsed
0944:             * @param tokens list of tokens to add to
0945:             * @throws IllegalArgumentException on error in supplied list
0946:             */
0947:
0948:            protected static void parseTokenList(String list, Vector tokens) {
0949:
0950:                // accumulate comma-delimited tokens from list
0951:                while (list.length() > 0) {
0952:
0953:                    // find end for next token
0954:                    int mark = list.indexOf(',');
0955:                    String token;
0956:                    if (mark == 0) {
0957:                        throw new IllegalArgumentException("Empty token not "
0958:                                + "allowed: \"" + list + '"');
0959:                    } else if (mark > 0) {
0960:
0961:                        // split token off list
0962:                        token = list.substring(0, mark);
0963:                        list = list.substring(mark + 1);
0964:
0965:                    } else {
0966:
0967:                        // use rest of list as final token
0968:                        token = list;
0969:                        list = "";
0970:                    }
0971:
0972:                    // validate the token
0973:                    for (int i = 0; i < token.length(); i++) {
0974:                        char chr = token.charAt(i);
0975:                        if ((i == 0 && !isTokenLeadChar(chr))
0976:                                || (i > 0 && !isTokenBodyChar(chr))) {
0977:                            throw new IllegalArgumentException("Illegal "
0978:                                    + "character in token: \"" + token + '"');
0979:                        }
0980:                    }
0981:
0982:                    // add validated token to list
0983:                    tokens.add(token);
0984:                }
0985:            }
0986:
0987:            /**
0988:             * Test driver, just reads the input parameters and executes the source
0989:             * checks.
0990:             *
0991:             * @param argv command line arguments
0992:             */
0993:
0994:            public static void main(String[] argv) {
0995:                if (argv.length > 0) {
0996:
0997:                    // parse the leading command line parameters
0998:                    boolean valid = true;
0999:                    boolean keep = false;
1000:                    boolean listmod = false;
1001:                    boolean quiet = false;
1002:                    boolean tilde = false;
1003:                    boolean verbose = false;
1004:                    File backup = null;
1005:                    Vector enables = new Vector();
1006:                    Vector disables = new Vector();
1007:                    int anum = 0;
1008:                    while (anum < argv.length && argv[anum].charAt(0) == '-') {
1009:                        String arg = argv[anum++];
1010:                        int cnum = 1;
1011:                        while (cnum < arg.length()) {
1012:                            char option = Character.toLowerCase(arg
1013:                                    .charAt(cnum++));
1014:                            switch (option) {
1015:
1016:                            case 'b':
1017:                                if (anum < argv.length) {
1018:                                    try {
1019:                                        backup = new File(argv[anum++]);
1020:                                        if (!backup.isDirectory()) {
1021:                                            System.err
1022:                                                    .println("Backup directory "
1023:                                                            + "path must be a directory");
1024:                                        }
1025:                                    } catch (SecurityException ex) {
1026:                                        System.err.println("Unable to access "
1027:                                                + "backup directory");
1028:                                    }
1029:                                } else {
1030:                                    System.err
1031:                                            .println("Missing directory path "
1032:                                                    + "for -b option");
1033:                                }
1034:                                break;
1035:
1036:                            case 'd':
1037:                            case 'e':
1038:                                if (anum < argv.length) {
1039:
1040:                                    // accumulate comma-delimited tokens from list
1041:                                    Vector tokens = (option == 'd') ? disables
1042:                                            : enables;
1043:                                    try {
1044:                                        parseTokenList(argv[anum++], tokens);
1045:                                    } catch (IllegalArgumentException ex) {
1046:                                        System.err.println(ex.getMessage());
1047:                                        return;
1048:                                    }
1049:                                    if (option == 'd') {
1050:                                        disables = tokens;
1051:                                    } else {
1052:                                        enables = tokens;
1053:                                    }
1054:
1055:                                } else {
1056:                                    System.err
1057:                                            .println("Missing token list for -"
1058:                                                    + option + " option");
1059:                                    return;
1060:                                }
1061:                                break;
1062:
1063:                            case 'p':
1064:                                keep = true;
1065:                                break;
1066:
1067:                            case 'q':
1068:                                quiet = true;
1069:                                break;
1070:
1071:                            case 'm':
1072:                                listmod = true;
1073:                                break;
1074:
1075:                            case 't':
1076:                                tilde = true;
1077:                                break;
1078:
1079:                            case 'v':
1080:                                verbose = true;
1081:                                break;
1082:
1083:                            default:
1084:                                System.err.println("Unknown option -" + option);
1085:                                return;
1086:                            }
1087:                        }
1088:                    }
1089:
1090:                    // build hashsets of the tokens, checking for overlap
1091:                    Hashtable enabled = new Hashtable();
1092:                    for (int i = 0; i < enables.size(); i++) {
1093:                        Object token = enables.elementAt(i);
1094:                        enabled.put(token, token);
1095:                    }
1096:                    Hashtable disabled = new Hashtable();
1097:                    for (int i = 0; i < disables.size(); i++) {
1098:                        Object token = disables.elementAt(i);
1099:                        disabled.put(token, token);
1100:                        if (enabled.containsKey(token)) {
1101:                            System.err.println(DUAL_USE_ERR + ": " + token);
1102:                            return;
1103:                        }
1104:                    }
1105:
1106:                    // construct an instance of class
1107:                    JEnable opt = new JEnable(keep, tilde, listmod, quiet,
1108:                            verbose, backup, enabled, disabled);
1109:
1110:                    // check if we have file paths
1111:                    if (anum < argv.length) {
1112:
1113:                        // process each file path supplied
1114:                        while (anum < argv.length) {
1115:                            String arg = argv[anum++];
1116:                            int split;
1117:                            while ((split = arg.indexOf(',')) > 0) {
1118:                                String path = arg.substring(0, split);
1119:                                opt.processPath(path);
1120:                                arg = arg.substring(split + 1);
1121:                            }
1122:                            opt.processPath(arg);
1123:                        }
1124:
1125:                    } else {
1126:
1127:                        // just process standard input to standard output
1128:                        BufferedReader in = new BufferedReader(
1129:                                new InputStreamReader(System.in));
1130:                        BufferedWriter out = new BufferedWriter(
1131:                                new OutputStreamWriter(System.out));
1132:
1133:                        // check first line for disabled token
1134:                        try {
1135:                            String line = in.readLine();
1136:                            int type = opt.checkOptionLine(1, line);
1137:                            if (type == FILE_OPTION) {
1138:                                boolean discard = opt.m_invert ? enabled
1139:                                        .contains(opt.m_token) : disabled
1140:                                        .contains(opt.m_token);
1141:                                if (discard) {
1142:                                    return;
1143:                                }
1144:                            }
1145:                            opt.processStream(in, line, out);
1146:                        } catch (IOException ex) {
1147:                            System.err.println(ex.getMessage());
1148:                        }
1149:                    }
1150:                } else {
1151:                    System.err
1152:                            .println("\nJEnable Java source configuration processor version "
1153:                                    + "0.8\nUsage: JEnable [-options] path-list\n"
1154:                                    + "Options are:\n"
1155:                                    + " -b   backup directory tree (base directory is next "
1156:                                    + "argument)\n"
1157:                                    + " -d   disabled token list (comma-separated token name list"
1158:                                    + " is next argument)\n"
1159:                                    + " -e   enabled token list (comma-separated token name list"
1160:                                    + " is next argument)\n"
1161:                                    + " -m   list modified files as they're processed\n"
1162:                                    + " -p   preserve timestamp on modified files\n"
1163:                                    + " -q   quiet mode, do not print file summary by path\n"
1164:                                    + " -t   backup modified files in same directory with '~' "
1165:                                    + "suffix\n"
1166:                                    + " -v   verbose listing of all files processed (modified or "
1167:                                    + "not)\n"
1168:                                    + "These options may be concatenated together with a single"
1169:                                    + " leading dash.\n\n"
1170:                                    + "Path lists may include '*' wildcards, and may consist of "
1171:                                    + "multiple paths\n"
1172:                                    + "separated by ',' characters. The special directory "
1173:                                    + "pattern '**' matches\n"
1174:                                    + "any number of intervening directories. Any number of path "
1175:                                    + "list parameters may\n"
1176:                                    + "be supplied.\n");
1177:                }
1178:            }
1179:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.