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