Source Code Cross Referenced for GeneratedFilesHelper.java in  » IDE-Netbeans » ruby » org » netbeans » modules » ruby » spi » project » support » rake » 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 » IDE Netbeans » ruby » org.netbeans.modules.ruby.spi.project.support.rake 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003:         *
004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * The contents of this file are subject to the terms of either the GNU
007:         * General Public License Version 2 only ("GPL") or the Common
008:         * Development and Distribution License("CDDL") (collectively, the
009:         * "License"). You may not use this file except in compliance with the
010:         * License. You can obtain a copy of the License at
011:         * http://www.netbeans.org/cddl-gplv2.html
012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013:         * specific language governing permissions and limitations under the
014:         * License.  When distributing the software, include this License Header
015:         * Notice in each file and include the License file at
016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
017:         * particular file as subject to the "Classpath" exception as provided
018:         * by Sun in the GPL Version 2 section of the License file that
019:         * accompanied this code. If applicable, add the following below the
020:         * License Header, with the fields enclosed by brackets [] replaced by
021:         * your own identifying information:
022:         * "Portions Copyrighted [year] [name of copyright owner]"
023:         *
024:         * Contributor(s):
025:         *
026:         * The Original Software is NetBeans. The Initial Developer of the Original
027:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
028:         * Microsystems, Inc. All Rights Reserved.
029:         *
030:         * If you wish your version of this file to be governed by only the CDDL
031:         * or only the GPL Version 2, indicate your decision by adding
032:         * "[Contributor] elects to include this software in this distribution
033:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
034:         * single choice of license, a recipient has the option to distribute
035:         * your version of this file under either the CDDL, the GPL Version 2 or
036:         * to extend the choice of license to its licensees as provided above.
037:         * However, if you add GPL Version 2 code and therefore, elected the GPL
038:         * Version 2 license, then the option applies only if the new code is
039:         * made subject to such option by the copyright holder.
040:         */
041:
042:        package org.netbeans.modules.ruby.spi.project.support.rake;
043:
044:        import java.io.BufferedInputStream;
045:        import java.io.BufferedOutputStream;
046:        import java.io.ByteArrayInputStream;
047:        import java.io.ByteArrayOutputStream;
048:        import java.io.File;
049:        import java.io.IOException;
050:        import java.io.InputStream;
051:        import java.io.OutputStream;
052:        import java.net.URI;
053:        import java.net.URL;
054:        import java.util.HashMap;
055:        import java.util.Map;
056:        import java.util.Properties;
057:        import java.util.zip.CRC32;
058:        import java.util.zip.Checksum;
059:        import javax.xml.transform.Transformer;
060:        import javax.xml.transform.TransformerException;
061:        import javax.xml.transform.TransformerFactory;
062:        import javax.xml.transform.stream.StreamResult;
063:        import javax.xml.transform.stream.StreamSource;
064:        import org.netbeans.api.project.ProjectManager;
065:        import org.netbeans.modules.ruby.modules.project.rake.UserQuestionHandler;
066:        import org.openide.ErrorManager;
067:        import org.openide.filesystems.FileLock;
068:        import org.openide.filesystems.FileObject;
069:        import org.openide.filesystems.FileSystem;
070:        import org.openide.filesystems.FileUtil;
071:        import org.openide.util.Mutex;
072:        import org.openide.util.MutexException;
073:        import org.openide.util.NbBundle;
074:        import org.openide.util.UserQuestionException;
075:        import org.openide.util.Utilities;
076:
077:        /**
078:         * Helps a project type (re-)generate, and manage the state and versioning of,
079:         * <code>build.xml</code> and <code>build-impl.xml</code>.
080:         * @author Jesse Glick
081:         */
082:        public final class GeneratedFilesHelper {
083:
084:            /**
085:             * Relative path from project directory to the user build script,
086:             * <code>build.xml</code>.
087:             */
088:            public static final String BUILD_XML_PATH = "build.xml"; // NOI18N
089:
090:            /**
091:             * Relative path from project directory to the implementation build script,
092:             * <code>build-impl.xml</code>.
093:             */
094:            public static final String BUILD_IMPL_XML_PATH = "nbproject/build-impl.xml"; // NOI18N
095:
096:            /**
097:             * Path to file storing information about generated files.
098:             * It should be kept in version control, since it applies equally after a fresh
099:             * project checkout; it does not apply to running Ant, so should not be in
100:             * <code>project.properties</code>; and it includes a CRC of <code>project.xml</code>
101:             * so it cannot be in that file either. It could be stored in some special
102:             * comment at the end of the build script (e.g.) but many users would just
103:             * compulsively delete it in this case since it looks weird.
104:             */
105:            static final String GENFILES_PROPERTIES_PATH = "nbproject/genfiles.properties"; // NOI18N
106:
107:            /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for <code>project.xml</code> CRC. */
108:            private static final String KEY_SUFFIX_DATA_CRC = ".data.CRC32"; // NOI18N
109:
110:            /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for stylesheet CRC. */
111:            private static final String KEY_SUFFIX_STYLESHEET_CRC = ".stylesheet.CRC32"; // NOI18N
112:
113:            /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for CRC of the script itself. */
114:            private static final String KEY_SUFFIX_SCRIPT_CRC = ".script.CRC32"; // NOI18N
115:
116:            /**
117:             * A build script is missing from disk.
118:             * This is mutually exclusive with the other flags.
119:             * @see #getBuildScriptState
120:             */
121:            public static final int FLAG_MISSING = 2 << 0;
122:
123:            /**
124:             * A build script has been modified since last generated by
125:             * {@link #generateBuildScriptFromStylesheet}.
126:             * <p class="nonnormative">
127:             * Probably this means it was edited by the user.
128:             * </p>
129:             * @see #getBuildScriptState
130:             */
131:            public static final int FLAG_MODIFIED = 2 << 1;
132:
133:            /**
134:             * A build script was generated from an older version of <code>project.xml</code>.
135:             * It was last generated using a different version of <code>project.xml</code>,
136:             * so using the current <code>project.xml</code> might produce a different
137:             * result.
138:             * <p class="nonnormative">
139:             * This is quite likely in the case of
140:             * <code>build.xml</code>; in the case of <code>build-impl.xml</code>, it
141:             * probably means that the user edited <code>project.xml</code> manually,
142:             * since if that were modified from {@link RakeProjectHelper} methods and
143:             * the project were saved, the script would have been regenerated
144:             * already.
145:             * </p>
146:             * @see #getBuildScriptState
147:             */
148:            public static final int FLAG_OLD_PROJECT_XML = 2 << 2;
149:
150:            /**
151:             * A build script was generated from an older version of a stylesheet.
152:             * It was last generated using a different (probably older) version of the
153:             * XSLT stylesheet, so using the current stylesheet might produce a different
154:             * result.
155:             * <p class="nonnormative">
156:             * Probably this means the project type
157:             * provider module has been upgraded since the project was last saved (in
158:             * the case of <code>build-impl.xml</code>) or created (in the case of
159:             * <code>build.xml</code>).
160:             * </p>
161:             * @see #getBuildScriptState
162:             */
163:            public static final int FLAG_OLD_STYLESHEET = 2 << 3;
164:
165:            /**
166:             * The build script exists, but nothing else is known about it.
167:             * This flag is mutually exclusive with {@link #FLAG_MISSING} but
168:             * when set also sets {@link #FLAG_MODIFIED}, {@link #FLAG_OLD_STYLESHEET},
169:             * and {@link #FLAG_OLD_PROJECT_XML} - since it is not known whether these
170:             * conditions might obtain, it is safest to assume they do.
171:             * <p class="nonnormative">
172:             * Probably this means that <code>nbproject/genfiles.properties</code> was
173:             * deleted by the user.
174:             * </p>
175:             * @see #getBuildScriptState
176:             */
177:            public static final int FLAG_UNKNOWN = 2 << 4;
178:
179:            /** Associated project helper, or null if using only a directory. */
180:            private final RakeProjectHelper h;
181:
182:            /** Project directory. */
183:            private final FileObject dir;
184:
185:            /**
186:             * Create a helper based on the supplied project helper handle.
187:             * @param h an Ant-based project helper supplied to the project type provider
188:             */
189:            public GeneratedFilesHelper(RakeProjectHelper h) {
190:                this .h = h;
191:                dir = h.getProjectDirectory();
192:            }
193:
194:            /**
195:             * Create a helper based only on a project directory.
196:             * This can be used to perform the basic refresh functionality
197:             * without being the owner of the project.
198:             * It is only intended for use from the offline Ant task to
199:             * refresh a project, and similar special situations.
200:             * For normal circumstances please use only
201:             * {@link GeneratedFilesHelper#GeneratedFilesHelper(RakeProjectHelper)}.
202:             * @param d the project directory
203:             * @throws IllegalArgumentException if the supplied directory has no <code>project.xml</code>
204:             */
205:            public GeneratedFilesHelper(FileObject d) {
206:                if (d == null
207:                        || !d.isFolder()
208:                        || d.getFileObject(RakeProjectHelper.PROJECT_XML_PATH) == null) {
209:                    throw new IllegalArgumentException(
210:                            "Does not look like an Ant-based project: " + d); // NOI18N
211:                }
212:                h = null;
213:                dir = d;
214:            }
215:
216:            /**
217:             * Create <code>build.xml</code> or <code>nbproject/build-impl.xml</code>
218:             * from <code>project.xml</code> plus a supplied XSLT stylesheet.
219:             * This is the recommended way to create the build scripts from
220:             * project metadata.
221:             * <p class="nonnormative">
222:             * You may wish to first check {@link #getBuildScriptState} to decide whether
223:             * you really want to overwrite an existing build script. Typically if you
224:             * find {@link #FLAG_MODIFIED} you should not overwrite it; or ask for confirmation
225:             * first; or make a backup. Of course if you find neither of {@link #FLAG_OLD_STYLESHEET}
226:             * nor {@link #FLAG_OLD_PROJECT_XML} then there is no reason to overwrite the
227:             * script to begin with.
228:             * </p>
229:             * <p>
230:             * Acquires write access.
231:             * </p>
232:             * @param path a project-relative file path such as {@link #BUILD_XML_PATH} or {@link #BUILD_IMPL_XML_PATH}
233:             * @param stylesheet a URL to an XSLT stylesheet accepting <code>project.xml</code>
234:             *                   as input and producing the build script as output
235:             * @throws IOException if transforming or writing the output failed
236:             * @throws IllegalStateException if the project was modified (and not being saved)
237:             */
238:            public void generateBuildScriptFromStylesheet(final String path,
239:                    final URL stylesheet) throws IOException,
240:                    IllegalStateException {
241:                if (path == null) {
242:                    throw new IllegalArgumentException("Null path"); // NOI18N
243:                }
244:                if (stylesheet == null) {
245:                    throw new IllegalArgumentException("Null stylesheet"); // NOI18N
246:                }
247:                try {
248:                    ProjectManager.mutex().writeAccess(
249:                            new Mutex.ExceptionAction<Void>() {
250:                                public Void run() throws IOException {
251:                                    if (h != null && h.isProjectXmlModified()) {
252:                                        throw new IllegalStateException(
253:                                                "Cannot generate build scripts from a modified project"); // NOI18N
254:                                    }
255:                                    // Need to use an atomic action since otherwise creating new build scripts might
256:                                    // cause them to not be recognized as Ant scripts.
257:                                    dir.getFileSystem().runAtomicAction(
258:                                            new FileSystem.AtomicAction() {
259:                                                public void run()
260:                                                        throws IOException {
261:                                                    FileObject projectXml = dir
262:                                                            .getFileObject(RakeProjectHelper.PROJECT_XML_PATH);
263:                                                    final FileObject buildScriptXml = FileUtil
264:                                                            .createData(dir,
265:                                                                    path);
266:                                                    byte[] projectXmlData;
267:                                                    InputStream is = projectXml
268:                                                            .getInputStream();
269:                                                    try {
270:                                                        projectXmlData = load(is);
271:                                                    } finally {
272:                                                        is.close();
273:                                                    }
274:                                                    byte[] stylesheetData;
275:                                                    is = stylesheet
276:                                                            .openStream();
277:                                                    try {
278:                                                        stylesheetData = load(is);
279:                                                    } finally {
280:                                                        is.close();
281:                                                    }
282:                                                    final byte[] resultData;
283:                                                    TransformerFactory tf = TransformerFactory
284:                                                            .newInstance();
285:                                                    try {
286:                                                        StreamSource stylesheetSource = new StreamSource(
287:                                                                new ByteArrayInputStream(
288:                                                                        stylesheetData),
289:                                                                stylesheet
290:                                                                        .toExternalForm());
291:                                                        Transformer t = tf
292:                                                                .newTransformer(stylesheetSource);
293:                                                        File projectXmlF = FileUtil
294:                                                                .toFile(projectXml);
295:                                                        assert projectXmlF != null;
296:                                                        StreamSource projectXmlSource = new StreamSource(
297:                                                                new ByteArrayInputStream(
298:                                                                        projectXmlData),
299:                                                                projectXmlF
300:                                                                        .toURI()
301:                                                                        .toString());
302:                                                        ByteArrayOutputStream result = new ByteArrayOutputStream();
303:                                                        t
304:                                                                .transform(
305:                                                                        projectXmlSource,
306:                                                                        new StreamResult(
307:                                                                                result));
308:                                                        resultData = result
309:                                                                .toByteArray();
310:                                                    } catch (TransformerException e) {
311:                                                        throw (IOException) new IOException(
312:                                                                e.toString())
313:                                                                .initCause(e);
314:                                                    }
315:                                                    // Update genfiles.properties too.
316:                                                    final EditableProperties p = new EditableProperties(
317:                                                            true);
318:                                                    FileObject genfiles = dir
319:                                                            .getFileObject(GENFILES_PROPERTIES_PATH);
320:                                                    if (genfiles != null
321:                                                            && genfiles
322:                                                                    .isVirtual()) {
323:                                                        // #55164: deleted from CVS?
324:                                                        genfiles = null;
325:                                                    }
326:                                                    if (genfiles != null) {
327:                                                        is = genfiles
328:                                                                .getInputStream();
329:                                                        try {
330:                                                            p.load(is);
331:                                                        } finally {
332:                                                            is.close();
333:                                                        }
334:                                                    }
335:                                                    p
336:                                                            .setProperty(
337:                                                                    path
338:                                                                            + KEY_SUFFIX_DATA_CRC,
339:                                                                    getCrc32(
340:                                                                            new ByteArrayInputStream(
341:                                                                                    projectXmlData),
342:                                                                            projectXml));
343:                                                    if (genfiles == null) {
344:                                                        // New file, set a comment on it. XXX this puts comment in middle if write build-impl.xml before build.xml
345:                                                        p
346:                                                                .setComment(
347:                                                                        path
348:                                                                                + KEY_SUFFIX_DATA_CRC,
349:                                                                        new String[] {
350:                                                                                "# "
351:                                                                                        + NbBundle
352:                                                                                                .getMessage(
353:                                                                                                        GeneratedFilesHelper.class,
354:                                                                                                        "COMMENT_genfiles.properties_1"), // NOI18N
355:                                                                                "# "
356:                                                                                        + NbBundle
357:                                                                                                .getMessage(
358:                                                                                                        GeneratedFilesHelper.class,
359:                                                                                                        "COMMENT_genfiles.properties_2"), // NOI18N
360:                                                                        },
361:                                                                        false);
362:                                                    }
363:                                                    p
364:                                                            .setProperty(
365:                                                                    path
366:                                                                            + KEY_SUFFIX_STYLESHEET_CRC,
367:                                                                    getCrc32(
368:                                                                            new ByteArrayInputStream(
369:                                                                                    stylesheetData),
370:                                                                            stylesheet));
371:                                                    p
372:                                                            .setProperty(
373:                                                                    path
374:                                                                            + KEY_SUFFIX_SCRIPT_CRC,
375:                                                                    computeCrc32(new ByteArrayInputStream(
376:                                                                            resultData)));
377:                                                    if (genfiles == null) {
378:                                                        genfiles = FileUtil
379:                                                                .createData(
380:                                                                        dir,
381:                                                                        GENFILES_PROPERTIES_PATH);
382:                                                    }
383:                                                    final FileObject _genfiles = genfiles;
384:                                                    // You get the Spaghetti Code Award if you can follow the control flow in this method!
385:                                                    // Now is the time when you wish Java implemented call/cc.
386:                                                    // If you didn't understand that last comment, you don't get the Spaghetti Code Award.
387:                                                    final FileSystem.AtomicAction body = new FileSystem.AtomicAction() {
388:                                                        public void run()
389:                                                                throws IOException {
390:                                                            // Try to acquire both locks together, since we need them both written.
391:                                                            FileLock lock1 = buildScriptXml
392:                                                                    .lock();
393:                                                            try {
394:                                                                FileLock lock2 = _genfiles
395:                                                                        .lock();
396:                                                                try {
397:                                                                    OutputStream os1 = new EolFilterOutputStream(
398:                                                                            buildScriptXml
399:                                                                                    .getOutputStream(lock1));
400:                                                                    try {
401:                                                                        OutputStream os2 = _genfiles
402:                                                                                .getOutputStream(lock2);
403:                                                                        try {
404:                                                                            os1
405:                                                                                    .write(resultData);
406:                                                                            p
407:                                                                                    .store(os2);
408:                                                                        } finally {
409:                                                                            os2
410:                                                                                    .close();
411:                                                                        }
412:                                                                    } finally {
413:                                                                        os1
414:                                                                                .close();
415:                                                                    }
416:                                                                } finally {
417:                                                                    lock2
418:                                                                            .releaseLock();
419:                                                                }
420:                                                            } finally {
421:                                                                lock1
422:                                                                        .releaseLock();
423:                                                            }
424:                                                        }
425:                                                    };
426:                                                    try {
427:                                                        body.run();
428:                                                    } catch (UserQuestionException uqe) {
429:                                                        // #57480: need to regenerate build-impl.xml, really.
430:                                                        UserQuestionHandler
431:                                                                .handle(
432:                                                                        uqe,
433:                                                                        new UserQuestionHandler.Callback() {
434:                                                                            public void accepted() {
435:                                                                                // Try again.
436:                                                                                try {
437:                                                                                    body
438:                                                                                            .run();
439:                                                                                } catch (UserQuestionException uqe2) {
440:                                                                                    // Need to try one more time - may have locked bSX but not yet gf.
441:                                                                                    UserQuestionHandler
442:                                                                                            .handle(
443:                                                                                                    uqe2,
444:                                                                                                    new UserQuestionHandler.Callback() {
445:                                                                                                        public void accepted() {
446:                                                                                                            try {
447:                                                                                                                body
448:                                                                                                                        .run();
449:                                                                                                            } catch (IOException e) {
450:                                                                                                                ErrorManager
451:                                                                                                                        .getDefault()
452:                                                                                                                        .notify(
453:                                                                                                                                e);
454:                                                                                                            }
455:                                                                                                        }
456:
457:                                                                                                        public void denied() {
458:                                                                                                        }
459:
460:                                                                                                        public void error(
461:                                                                                                                IOException e) {
462:                                                                                                            ErrorManager
463:                                                                                                                    .getDefault()
464:                                                                                                                    .notify(
465:                                                                                                                            e);
466:                                                                                                        }
467:                                                                                                    });
468:                                                                                } catch (IOException e) {
469:                                                                                    // Oh well.
470:                                                                                    ErrorManager
471:                                                                                            .getDefault()
472:                                                                                            .notify(
473:                                                                                                    e);
474:                                                                                }
475:                                                                            }
476:
477:                                                                            public void denied() {
478:                                                                                // OK, skip it.
479:                                                                            }
480:
481:                                                                            public void error(
482:                                                                                    IOException e) {
483:                                                                                ErrorManager
484:                                                                                        .getDefault()
485:                                                                                        .notify(
486:                                                                                                e);
487:                                                                                // Never mind.
488:                                                                            }
489:                                                                        });
490:                                                    }
491:                                                }
492:                                            });
493:                                    return null;
494:                                }
495:                            });
496:                } catch (MutexException e) {
497:                    throw (IOException) e.getException();
498:                }
499:            }
500:
501:            /**
502:             * Load data from a stream into a buffer.
503:             */
504:            private static byte[] load(InputStream is) throws IOException {
505:                int size = Math.max(1024, is.available()); // #46235
506:                ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
507:                byte[] buf = new byte[size];
508:                int read;
509:                while ((read = is.read(buf)) != -1) {
510:                    baos.write(buf, 0, read);
511:                }
512:                return baos.toByteArray();
513:            }
514:
515:            /**
516:             * Find what state a build script is in.
517:             * This may be used by a project type provider to decide whether to create
518:             * or overwrite it, and whether to produce a backup in the latter case.
519:             * Various abnormal conditions are detected:
520:             * {@link #FLAG_MISSING}, {@link #FLAG_MODIFIED}, {@link #FLAG_OLD_PROJECT_XML},
521:             * {@link #FLAG_OLD_STYLESHEET}, and {@link #FLAG_UNKNOWN}.
522:             * <p class="nonnormative">
523:             * Currently {@link #FLAG_MODIFIED}, {@link #FLAG_OLD_STYLESHEET}, and
524:             * {@link #FLAG_OLD_PROJECT_XML} are detected by computing a CRC-32
525:             * of the script when it is created, as well as the CRC-32s of the
526:             * stylesheet and <code>project.xml</code>. These CRCs are stored
527:             * in a special file <code>nbproject/genfiles.properties</code>.
528:             * The CRCs are based on the textual
529:             * contents of the files (so even changed to whitespace etc. are considered
530:             * changes), but are independent of platform newline conventions (since e.g.
531:             * CVS will by default replace \n with \r\n when checking out on Windows).
532:             * Changes to external files included into <code>project.xml</code> or the
533:             * stylesheet (e.g. using XSLT's import facility) are <em>not</em> detected.
534:             * </p>
535:             * <p>
536:             * If there is some kind of I/O error reading any files, {@link #FLAG_UNKNOWN}
537:             * is returned (in conjunction with {@link #FLAG_MODIFIED},
538:             * {@link #FLAG_OLD_STYLESHEET}, and {@link #FLAG_OLD_PROJECT_XML} to be safe).
539:             * </p>
540:             * <p>
541:             * Acquires read access.
542:             * </p>
543:             * @param path a project-relative path such as {@link #BUILD_XML_PATH} or {@link #BUILD_IMPL_XML_PATH}
544:             * @param stylesheet a URL to an XSLT stylesheet accepting <code>project.xml</code>
545:             *                   as input and producing the build script as output
546:             *                   (should match that given to {@link #generateBuildScriptFromStylesheet})
547:             * @return a bitwise OR of various flags, or <code>0</code> if the script
548:             *         is present on disk and fully up-to-date
549:             * @throws IllegalStateException if the project was modified
550:             */
551:            public int getBuildScriptState(final String path,
552:                    final URL stylesheet) throws IllegalStateException {
553:                try {
554:                    return ProjectManager.mutex().readAccess(
555:                            new Mutex.ExceptionAction<Integer>() {
556:                                public Integer run() throws IOException {
557:                                    if (h != null && h.isProjectXmlModified()) {
558:                                        throw new IllegalStateException(
559:                                                "Cannot generate build scripts from a modified project"); // NOI18N
560:                                    }
561:                                    FileObject script = dir.getFileObject(path);
562:                                    if (script == null
563:                                            || /* #55164 */script.isVirtual()) {
564:                                        return FLAG_MISSING;
565:                                    }
566:                                    int flags = 0;
567:                                    Properties p = new Properties();
568:                                    FileObject genfiles = dir
569:                                            .getFileObject(GENFILES_PROPERTIES_PATH);
570:                                    if (genfiles == null
571:                                            || /* #55164 */genfiles
572:                                                    .isVirtual()) {
573:                                        // Who knows? User deleted it; anything might be wrong. Safest to assume
574:                                        // that everything is.
575:                                        return FLAG_UNKNOWN | FLAG_MODIFIED
576:                                                | FLAG_OLD_PROJECT_XML
577:                                                | FLAG_OLD_STYLESHEET;
578:                                    }
579:                                    InputStream is = new BufferedInputStream(
580:                                            genfiles.getInputStream());
581:                                    try {
582:                                        p.load(is);
583:                                    } finally {
584:                                        is.close();
585:                                    }
586:                                    FileObject projectXml = dir
587:                                            .getFileObject(RakeProjectHelper.PROJECT_XML_PATH);
588:                                    if (projectXml != null
589:                                            && /* #55164 */!projectXml
590:                                                    .isVirtual()) {
591:                                        String crc = getCrc32(projectXml);
592:                                        if (!crc.equals(p.getProperty(path
593:                                                + KEY_SUFFIX_DATA_CRC))) {
594:                                            flags |= FLAG_OLD_PROJECT_XML;
595:                                        }
596:                                    } else {
597:                                        // Broken project?!
598:                                        flags |= FLAG_OLD_PROJECT_XML;
599:                                    }
600:                                    String crc = getCrc32(stylesheet);
601:                                    if (!crc.equals(p.getProperty(path
602:                                            + KEY_SUFFIX_STYLESHEET_CRC))) {
603:                                        flags |= FLAG_OLD_STYLESHEET;
604:                                    }
605:                                    crc = getCrc32(script);
606:                                    if (!crc.equals(p.getProperty(path
607:                                            + KEY_SUFFIX_SCRIPT_CRC))) {
608:                                        flags |= FLAG_MODIFIED;
609:                                    }
610:                                    return flags;
611:                                }
612:                            });
613:                } catch (MutexException e) {
614:                    ErrorManager.getDefault().notify(
615:                            ErrorManager.INFORMATIONAL,
616:                            (IOException) e.getException());
617:                    return FLAG_UNKNOWN | FLAG_MODIFIED | FLAG_OLD_PROJECT_XML
618:                            | FLAG_OLD_STYLESHEET;
619:                }
620:            }
621:
622:            /**
623:             * Compute the CRC-32 of the contents of a stream.
624:             * \r\n and \r are both normalized to \n for purposes of the calculation.
625:             */
626:            static String computeCrc32(InputStream is) throws IOException {
627:                Checksum crc = new CRC32();
628:                int last = -1;
629:                int curr;
630:                while ((curr = is.read()) != -1) {
631:                    if (curr != '\n' && last == '\r') {
632:                        crc.update('\n');
633:                    }
634:                    if (curr != '\r') {
635:                        crc.update(curr);
636:                    }
637:                    last = curr;
638:                }
639:                if (last == '\r') {
640:                    crc.update('\n');
641:                }
642:                int val = (int) crc.getValue();
643:                String hex = Integer.toHexString(val);
644:                while (hex.length() < 8) {
645:                    hex = "0" + hex; // NOI18N
646:                }
647:                return hex;
648:            }
649:
650:            // #50440 - cache CRC32's for various files to save time esp. during startup.
651:
652:            private static final Map<URL, String> crcCache = new HashMap<URL, String>();
653:            private static final Map<URL, Long> crcCacheTimestampsXorSizes = new HashMap<URL, Long>();
654:
655:            /** Try to find a CRC in the cache according to location of file and last mod time xor size. */
656:            private static synchronized String findCachedCrc32(URL u,
657:                    long footprint) {
658:                String crc = crcCache.get(u);
659:                if (crc != null) {
660:                    Long l = crcCacheTimestampsXorSizes.get(u);
661:                    assert l != null;
662:                    if (l == footprint) {
663:                        // Cache hit.
664:                        return crc;
665:                    }
666:                }
667:                // Cache miss - missing or old.
668:                return null;
669:            }
670:
671:            /** Cache a known CRC for a file, using current last mod time xor size. */
672:            private static synchronized void cacheCrc32(String crc, URL u,
673:                    long footprint) {
674:                crcCache.put(u, crc);
675:                crcCacheTimestampsXorSizes.put(u, footprint);
676:            }
677:
678:            /** Find (maybe cached) CRC for a file, using a preexisting input stream (not closed by this method). */
679:            private static String getCrc32(InputStream is, FileObject fo)
680:                    throws IOException {
681:                URL u = fo.getURL();
682:                fo.refresh(); // in case was written on disk and we did not notice yet...
683:                long footprint = fo.lastModified().getTime() ^ fo.getSize();
684:                String crc = findCachedCrc32(u, footprint);
685:                if (crc == null) {
686:                    crc = computeCrc32(is);
687:                    cacheCrc32(crc, u, footprint);
688:                }
689:                return crc;
690:            }
691:
692:            /** Find the time the file this URL represents was last modified xor its size, if possible. */
693:            private static long checkFootprint(URL u) {
694:                URL nested = FileUtil.getArchiveFile(u);
695:                if (nested != null) {
696:                    u = nested;
697:                }
698:                if (u.getProtocol().equals("file")) { // NOI18N
699:                    File f = new File(URI.create(u.toExternalForm()));
700:                    return f.lastModified() ^ f.length();
701:                } else {
702:                    return 0L;
703:                }
704:            }
705:
706:            /** Find (maybe cached) CRC for a URL, using a preexisting input stream (not closed by this method). */
707:            private static String getCrc32(InputStream is, URL u)
708:                    throws IOException {
709:                long footprint = checkFootprint(u);
710:                String crc = null;
711:                if (footprint != 0L) {
712:                    crc = findCachedCrc32(u, footprint);
713:                }
714:                if (crc == null) {
715:                    crc = computeCrc32(is);
716:                    if (footprint != 0L) {
717:                        cacheCrc32(crc, u, footprint);
718:                    }
719:                }
720:                return crc;
721:            }
722:
723:            /** Find (maybe cached) CRC for a file. Will open its own input stream. */
724:            private static String getCrc32(FileObject fo) throws IOException {
725:                URL u = fo.getURL();
726:                fo.refresh();
727:                long footprint = fo.lastModified().getTime() ^ fo.getSize();
728:                String crc = findCachedCrc32(u, footprint);
729:                if (crc == null) {
730:                    InputStream is = fo.getInputStream();
731:                    try {
732:                        crc = computeCrc32(new BufferedInputStream(is));
733:                        cacheCrc32(crc, u, footprint);
734:                    } finally {
735:                        is.close();
736:                    }
737:                }
738:                return crc;
739:            }
740:
741:            /** Find (maybe cached) CRC for a URL. Will open its own input stream. */
742:            private static String getCrc32(URL u) throws IOException {
743:                long footprint = checkFootprint(u);
744:                String crc = null;
745:                if (footprint != 0L) {
746:                    crc = findCachedCrc32(u, footprint);
747:                }
748:                if (crc == null) {
749:                    InputStream is = u.openStream();
750:                    try {
751:                        crc = computeCrc32(new BufferedInputStream(is));
752:                        if (footprint != 0L) {
753:                            cacheCrc32(crc, u, footprint);
754:                        }
755:                    } finally {
756:                        is.close();
757:                    }
758:                }
759:                return crc;
760:            }
761:
762:            /**
763:             * Convenience method to refresh a build script if it can and should be.
764:             * <p>
765:             * If the script is not modified, and it is either missing, or the flag
766:             * <code>checkForProjectXmlModified</code> is false, or it is out of date with
767:             * respect to either <code>project.xml</code> or the stylesheet (or both),
768:             * it is (re-)generated.
769:             * </p>
770:             * <p>
771:             * Acquires write access.
772:             * </p>
773:             * <p class="nonnormative">
774:             * Typical usage from {@link ProjectXmlSavedHook#projectXmlSaved} is to call
775:             * this method for both {@link #BUILD_XML_PATH} and {@link #BUILD_IMPL_XML_PATH}
776:             * with the appropriate stylesheets and with <code>checkForProjectXmlModified</code>
777:             * false (the script is certainly out of date relative to <code>project.xml</code>).
778:             * Typical usage from {@link org.netbeans.spi.project.ui.ProjectOpenedHook#projectOpened} is to call
779:             * this method for both scripts with the appropriate stylesheets and with
780:             * <code>checkForProjectXmlModified</code> true.
781:             * </p>
782:             * @param path a project-relative path such as {@link #BUILD_XML_PATH} or {@link #BUILD_IMPL_XML_PATH}
783:             * @param stylesheet a URL to an XSLT stylesheet accepting <code>project.xml</code>
784:             *                   as input and producing the build script as output
785:             * @param checkForProjectXmlModified true if it is necessary to check whether the
786:             *                                script is out of date with respect to
787:             *                                <code>project.xml</code> and/or the stylesheet
788:             * @return true if the script was in fact regenerated
789:             * @throws IOException if transforming or writing the output failed
790:             * @throws IllegalStateException if the project was modified
791:             */
792:            public boolean refreshBuildScript(final String path,
793:                    final URL stylesheet,
794:                    final boolean checkForProjectXmlModified)
795:                    throws IOException, IllegalStateException {
796:                try {
797:                    return ProjectManager.mutex().writeAccess(
798:                            new Mutex.ExceptionAction<Boolean>() {
799:                                public Boolean run() throws IOException {
800:                                    int flags = getBuildScriptState(path,
801:                                            stylesheet);
802:                                    if (shouldGenerateBuildScript(flags,
803:                                            checkForProjectXmlModified)) {
804:                                        generateBuildScriptFromStylesheet(path,
805:                                                stylesheet);
806:                                        return true;
807:                                    } else {
808:                                        return false;
809:                                    }
810:                                }
811:                            });
812:                } catch (MutexException e) {
813:                    throw (IOException) e.getException();
814:                }
815:            }
816:
817:            private static boolean shouldGenerateBuildScript(int flags,
818:                    boolean checkForProjectXmlModified) {
819:                if ((flags & GeneratedFilesHelper.FLAG_MISSING) != 0) {
820:                    // Yes, need it.
821:                    return true;
822:                }
823:                if ((flags & GeneratedFilesHelper.FLAG_MODIFIED) != 0) {
824:                    // No, don't overwrite a user build script.
825:                    // XXX modified build-impl.xml probably counts as a serious condition
826:                    // to warn the user about...
827:                    // Modified build.xml is no big deal.
828:                    return false;
829:                }
830:                if (!checkForProjectXmlModified) {
831:                    // OK, assume it is out of date.
832:                    return true;
833:                }
834:                // Check whether it is in fact out of date.
835:                return (flags & (GeneratedFilesHelper.FLAG_OLD_PROJECT_XML | GeneratedFilesHelper.FLAG_OLD_STYLESHEET)) != 0;
836:            }
837:
838:            // #45373 - workaround: on Windows make sure that all lines end with CRLF.
839:            // marcow: Use at least some buffered output!
840:            private static class EolFilterOutputStream extends
841:                    BufferedOutputStream {
842:
843:                private boolean isActive = Utilities.isWindows();
844:                private int last = -1;
845:
846:                public EolFilterOutputStream(OutputStream os) {
847:                    super (os, 4096);
848:                }
849:
850:                public void write(byte[] b, int off, int len)
851:                        throws IOException {
852:                    if (isActive) {
853:                        for (int i = off; i < off + len; i++) {
854:                            write(b[i]);
855:                        }
856:                    } else {
857:                        super .write(b, off, len);
858:                    }
859:                }
860:
861:                public void write(int b) throws IOException {
862:                    if (isActive) {
863:                        if (b == '\n' && last != '\r') {
864:                            super .write('\r');
865:                        }
866:                        last = b;
867:                    }
868:                    super.write(b);
869:                }
870:
871:            }
872:        }
w_w_w___._j__a__va___2_s___.___co__m_ | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.