KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > modules > websvc > api > jaxws > project > GeneratedFilesHelper


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.modules.websvc.api.jaxws.project;
21
22 import java.io.BufferedInputStream JavaDoc;
23 import java.io.BufferedOutputStream JavaDoc;
24 import java.io.ByteArrayInputStream JavaDoc;
25 import java.io.ByteArrayOutputStream JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.OutputStream JavaDoc;
30 import java.net.URI JavaDoc;
31 import java.net.URISyntaxException JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.util.HashMap JavaDoc;
34 import java.util.Map JavaDoc;
35 import java.util.Properties JavaDoc;
36 import java.util.zip.CRC32 JavaDoc;
37 import java.util.zip.Checksum JavaDoc;
38 import javax.xml.transform.Transformer JavaDoc;
39 import javax.xml.transform.TransformerException JavaDoc;
40 import javax.xml.transform.TransformerFactory JavaDoc;
41 import javax.xml.transform.stream.StreamResult JavaDoc;
42 import javax.xml.transform.stream.StreamSource JavaDoc;
43 import org.netbeans.api.project.ProjectManager;
44 import org.netbeans.modules.websvc.jaxwsmodel.project.UserQuestionHandler;
45 import org.netbeans.spi.project.support.ant.AntProjectHelper;
46 import org.netbeans.spi.project.support.ant.EditableProperties;
47 import org.openide.ErrorManager;
48 import org.openide.filesystems.FileLock;
49 import org.openide.filesystems.FileObject;
50 import org.openide.filesystems.FileSystem;
51 import org.openide.filesystems.FileUtil;
52 import org.openide.util.Mutex;
53 import org.openide.util.MutexException;
54 import org.openide.util.NbBundle;
55 import org.openide.util.UserQuestionException;
56 import org.openide.util.Utilities;
57
58 /**
59  * Helps a project type (re-)generate, and manage the state and versioning of,
60  * <code>build.xml</code> and <code>build-impl.xml</code>.
61  * @author Jesse Glick
62  */

63 public final class GeneratedFilesHelper {
64
65     /**
66      * Relative path from project directory to the user build script,
67      * <code>build.xml</code>.
68      */

69     public static final String JavaDoc BUILD_XML_PATH = "build.xml"; // NOI18N
70

71     /**
72      * Relative path from project directory to the implementation build script,
73      * <code>build-impl.xml</code>.
74      */

75     public static final String JavaDoc BUILD_IMPL_XML_PATH = "nbproject/build-impl.xml"; // NOI18N
76

77     /**
78      * Relative path from project directory to the jax-ws configuration file
79      * <code>jax-ws.xml</code>.
80      */

81     public static final String JavaDoc JAX_WS_XML_PATH = "nbproject/jax-ws.xml"; // NOI18N
82

83     /**
84      * Path to file storing information about generated files.
85      * It should be kept in version control, since it applies equally after a fresh
86      * project checkout; it does not apply to running Ant, so should not be in
87      * <code>project.properties</code>; and it includes a CRC of <code>project.xml</code>
88      * so it cannot be in that file either. It could be stored in some special
89      * comment at the end of the build script (e.g.) but many users would just
90      * compulsively delete it in this case since it looks weird.
91      */

92     static final String JavaDoc GENFILES_PROPERTIES_PATH = "nbproject/genfiles.properties"; // NOI18N
93

94     /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for <code>project.xml</code> CRC. */
95     private static final String JavaDoc KEY_SUFFIX_DATA_CRC = ".data.CRC32"; // NOI18N
96

97     /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for stylesheet CRC. */
98     private static final String JavaDoc KEY_SUFFIX_STYLESHEET_CRC = ".stylesheet.CRC32"; // NOI18N
99

100     /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for CRC of the script itself. */
101     private static final String JavaDoc KEY_SUFFIX_SCRIPT_CRC = ".script.CRC32"; // NOI18N
102

103     /** Suffix (after script path) of {@link #GENFILES_PROPERTIES_PATH} key for <code>jax-ws.xml</code> CRC. */
104     private static final String JavaDoc KEY_SUFFIX_JAX_WS_CRC = ".jax-ws.CRC32"; // NOI18N
105

106     /**
107      * A build script is missing from disk.
108      * This is mutually exclusive with the other flags.
109      * @see #getBuildScriptState
110      */

111     public static final int FLAG_MISSING = 2 << 0;
112     
113     /**
114      * A build script has been modified since last generated by
115      * {@link #generateBuildScriptFromStylesheet}.
116      * <p class="nonnormative">
117      * Probably this means it was edited by the user.
118      * </p>
119      * @see #getBuildScriptState
120      */

121     public static final int FLAG_MODIFIED = 2 << 1;
122     
123     /**
124      * A build script was generated from an older version of <code>project.xml</code>.
125      * It was last generated using a different version of <code>project.xml</code>,
126      * so using the current <code>project.xml</code> might produce a different
127      * result.
128      * <p class="nonnormative">
129      * This is quite likely in the case of
130      * <code>build.xml</code>; in the case of <code>build-impl.xml</code>, it
131      * probably means that the user edited <code>project.xml</code> manually,
132      * since if that were modified from {@link AntProjectHelper} methods and
133      * the project were saved, the script would have been regenerated
134      * already.
135      * </p>
136      * @see #getBuildScriptState
137      */

138     public static final int FLAG_OLD_PROJECT_XML = 2 << 2;
139     
140     /**
141      * A build script was generated from an older version of a stylesheet.
142      * It was last generated using a different (probably older) version of the
143      * XSLT stylesheet, so using the current stylesheet might produce a different
144      * result.
145      * <p class="nonnormative">
146      * Probably this means the project type
147      * provider module has been upgraded since the project was last saved (in
148      * the case of <code>build-impl.xml</code>) or created (in the case of
149      * <code>build.xml</code>).
150      * </p>
151      * @see #getBuildScriptState
152      */

153     public static final int FLAG_OLD_STYLESHEET = 2 << 3;
154     public static final int FLAG_OLD_JAX_WS = 2 << 5;
155     
156     /**
157      * The build script exists, but nothing else is known about it.
158      * This flag is mutually exclusive with {@link #FLAG_MISSING} but
159      * when set also sets {@link #FLAG_MODIFIED}, {@link #FLAG_OLD_STYLESHEET},
160      * and {@link #FLAG_OLD_PROJECT_XML} - since it is not known whether these
161      * conditions might obtain, it is safest to assume they do.
162      * <p class="nonnormative">
163      * Probably this means that <code>nbproject/genfiles.properties</code> was
164      * deleted by the user.
165      * </p>
166      * @see #getBuildScriptState
167      */

168     public static final int FLAG_UNKNOWN = 2 << 4;
169     
170     /** Associated project helper, or null if using only a directory. */
171     private final AntProjectHelper h;
172     
173     /** Project directory. */
174     private final FileObject dir;
175     
176     /**
177      * Create a helper based on the supplied project helper handle.
178      * @param h an Ant-based project helper supplied to the project type provider
179      */

180     public GeneratedFilesHelper(AntProjectHelper h) {
181         this.h = h;
182         dir = h.getProjectDirectory();
183     }
184     
185     /**
186      * Create a helper based only on a project directory.
187      * This can be used to perform the basic refresh functionality
188      * without being the owner of the project.
189      * It is only intended for use from the offline Ant task to
190      * refresh a project, and similar special situations.
191      * For normal circumstances please use only
192      * {@link GeneratedFilesHelper#GeneratedFilesHelper(AntProjectHelper)}.
193      * @param d the project directory
194      * @throws IllegalArgumentException if the supplied directory has no <code>project.xml</code>
195      */

196     public GeneratedFilesHelper(FileObject d) {
197         if (d == null || !d.isFolder() || d.getFileObject(AntProjectHelper.PROJECT_XML_PATH) == null) {
198             throw new IllegalArgumentException JavaDoc("Does not look like an Ant-based project: " + d); // NOI18N
199
}
200         h = null;
201         dir = d;
202     }
203     
204     /**
205      * Create <code>build.xml</code> or <code>nbproject/build-impl.xml</code>
206      * from <code>project.xml</code> plus a supplied XSLT stylesheet.
207      * This is the recommended way to create the build scripts from
208      * project metadata.
209      * <p class="nonnormative">
210      * You may wish to first check {@link #getBuildScriptState} to decide whether
211      * you really want to overwrite an existing build script. Typically if you
212      * find {@link #FLAG_MODIFIED} you should not overwrite it; or ask for confirmation
213      * first; or make a backup. Of course if you find neither of {@link #FLAG_OLD_STYLESHEET}
214      * nor {@link #FLAG_OLD_PROJECT_XML} then there is no reason to overwrite the
215      * script to begin with.
216      * </p>
217      * <p>
218      * Acquires write access.
219      * </p>
220      * @param path a project-relative file path such as {@link #BUILD_XML_PATH} or {@link #BUILD_IMPL_XML_PATH}
221      * @param stylesheet a URL to an XSLT stylesheet accepting <code>project.xml</code>
222      * as input and producing the build script as output
223      * @throws IOException if transforming or writing the output failed
224      * @throws IllegalStateException if the project was modified (and not being saved)
225      */

226     public void generateBuildScriptFromStylesheet(final String JavaDoc path, final URL JavaDoc stylesheet, final FileObject jaxWsFo) throws IOException JavaDoc, IllegalStateException JavaDoc {
227         if (path == null) {
228             throw new IllegalArgumentException JavaDoc("Null path"); // NOI18N
229
}
230         if (stylesheet == null) {
231             throw new IllegalArgumentException JavaDoc("Null stylesheet"); // NOI18N
232
}
233         try {
234             ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Object JavaDoc>() {
235                 public Object JavaDoc run() throws IOException JavaDoc {
236 // if (h != null && h.isProjectXmlModified()) {
237
// throw new IllegalStateException("Cannot generate build scripts from a modified project"); // NOI18N
238
// }
239
// Need to use an atomic action since otherwise creating new build scripts might
240
// cause them to not be recognized as Ant scripts.
241
dir.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() {
242                         public void run() throws IOException JavaDoc {
243
244                             FileObject projectXml = dir.getFileObject(AntProjectHelper.PROJECT_XML_PATH);
245                             final FileObject buildScriptXml = FileUtil.createData(dir, path);
246                             byte[] projectXmlData;
247                             InputStream JavaDoc is = projectXml.getInputStream();
248                             try {
249                                 projectXmlData = load(is);
250                             } finally {
251                                 is.close();
252                             }
253                             byte[] stylesheetData;
254                             is = stylesheet.openStream();
255                             try {
256                                 stylesheetData = load(is);
257                             } finally {
258                                 is.close();
259                             }
260                             final byte[] resultData;
261                             FileObject jaxWsFileObject=jaxWsFo;
262                             if (jaxWsFo==null || !jaxWsFo.isValid()) {
263                                 jaxWsFileObject = findJaxWsFileObject(dir);
264                             }
265
266                             TransformerFactory JavaDoc tf = TransformerFactory.newInstance();
267                             try {
268                                 StreamSource JavaDoc stylesheetSource = new StreamSource JavaDoc(
269                                     new ByteArrayInputStream JavaDoc(stylesheetData), stylesheet.toExternalForm());
270                                 Transformer JavaDoc t = tf.newTransformer(stylesheetSource);
271                                 if (jaxWsFileObject!=null) t.setParameter("jax_ws_uri",jaxWsFileObject.getURL().toURI().toASCIIString()); //NOI18N
272
File JavaDoc projectXmlF = FileUtil.toFile(projectXml);
273                                 assert projectXmlF != null;
274                                 StreamSource JavaDoc projectXmlSource = new StreamSource JavaDoc(
275                                     new ByteArrayInputStream JavaDoc(projectXmlData), projectXmlF.toURI().toString());
276                                 ByteArrayOutputStream JavaDoc result = new ByteArrayOutputStream JavaDoc();
277                                 t.transform(projectXmlSource, new StreamResult JavaDoc(result));
278                                 resultData = result.toByteArray();
279                             } catch (TransformerException JavaDoc e) {
280                                 throw (IOException JavaDoc)new IOException JavaDoc(e.toString()).initCause(e);
281                             } catch (URISyntaxException JavaDoc e) {
282                                 throw (IOException JavaDoc)new IOException JavaDoc(e.toString()).initCause(e);
283                             }
284                             // Update genfiles.properties too.
285
final EditableProperties p = new EditableProperties(true);
286                             FileObject genfiles = dir.getFileObject(GENFILES_PROPERTIES_PATH);
287                             if (genfiles != null && genfiles.isVirtual()) {
288                                 // #55164: deleted from CVS?
289
genfiles = null;
290                             }
291                             if (genfiles != null) {
292                                 is = genfiles.getInputStream();
293                                 try {
294                                     p.load(is);
295                                 } finally {
296                                     is.close();
297                                 }
298                             }
299                             p.setProperty(path + KEY_SUFFIX_DATA_CRC,
300                                 getCrc32(new ByteArrayInputStream JavaDoc(projectXmlData), projectXml));
301                             if (genfiles == null) {
302                                 // New file, set a comment on it. XXX this puts comment in middle if write build-impl.xml before build.xml
303
p.setComment(path + KEY_SUFFIX_DATA_CRC, new String JavaDoc[] {
304                                     "# " + NbBundle.getMessage(GeneratedFilesHelper.class, "COMMENT_genfiles.properties_1"), // NOI18N
305
"# " + NbBundle.getMessage(GeneratedFilesHelper.class, "COMMENT_genfiles.properties_2"), // NOI18N
306
}, false);
307                             }
308                             p.setProperty(path + KEY_SUFFIX_STYLESHEET_CRC,
309                                 getCrc32(new ByteArrayInputStream JavaDoc(stylesheetData), stylesheet));
310                             p.setProperty(path + KEY_SUFFIX_SCRIPT_CRC,
311                                 computeCrc32(new ByteArrayInputStream JavaDoc(resultData)));
312                             if (jaxWsFileObject!=null) {
313                                 byte[] jaxWsData;
314                                 InputStream JavaDoc jaxWsIs = jaxWsFileObject.getInputStream();
315                                 try {
316                                     jaxWsData = load(jaxWsIs);
317                                 } finally {
318                                     jaxWsIs.close();
319                                 }
320                                 p.setProperty(path + KEY_SUFFIX_JAX_WS_CRC,
321                                         getCrc32(new ByteArrayInputStream JavaDoc(jaxWsData),jaxWsFileObject));
322                             }
323                             if (genfiles == null) {
324                                 genfiles = FileUtil.createData(dir, GENFILES_PROPERTIES_PATH);
325                             }
326                             final FileObject _genfiles = genfiles;
327                             // You get the Spaghetti Code Award if you can follow the control flow in this method!
328
// Now is the time when you wish Java implemented call/cc.
329
// If you didn't understand that last comment, you don't get the Spaghetti Code Award.
330
final FileSystem.AtomicAction body = new FileSystem.AtomicAction() {
331                                 public void run() throws IOException JavaDoc {
332                                     // Try to acquire both locks together, since we need them both written.
333
FileLock lock1 = buildScriptXml.lock();
334                                     try {
335                                         FileLock lock2 = _genfiles.lock();
336                                         try {
337                                             OutputStream JavaDoc os1 = new EolFilterOutputStream(buildScriptXml.getOutputStream(lock1));
338                                             try {
339                                                 OutputStream JavaDoc os2 = _genfiles.getOutputStream(lock2);
340                                                 try {
341                                                     os1.write(resultData);
342                                                     p.store(os2);
343                                                 } finally {
344                                                     os2.close();
345                                                 }
346                                             } finally {
347                                                 os1.close();
348                                             }
349                                         } finally {
350                                             lock2.releaseLock();
351                                         }
352                                     } finally {
353                                         lock1.releaseLock();
354                                     }
355                                 }
356                             };
357                             try {
358                                 body.run();
359                             } catch (UserQuestionException uqe) {
360                                 // #57480: need to regenerate build-impl.xml, really.
361
UserQuestionHandler.handle(uqe, new UserQuestionHandler.Callback() {
362                                     public void accepted() {
363                                         // Try again.
364
try {
365                                             body.run();
366                                         } catch (UserQuestionException uqe2) {
367                                             // Need to try one more time - may have locked bSX but not yet gf.
368
UserQuestionHandler.handle(uqe2, new UserQuestionHandler.Callback() {
369                                                 public void accepted() {
370                                                     try {
371                                                         body.run();
372                                                     } catch (IOException JavaDoc e) {
373                                                         ErrorManager.getDefault().notify(e);
374                                                     }
375                                                 }
376                                                 public void denied() {}
377                                                 public void error(IOException JavaDoc e) {
378                                                     ErrorManager.getDefault().notify(e);
379                                                 }
380                                             });
381                                         } catch (IOException JavaDoc e) {
382                                             // Oh well.
383
ErrorManager.getDefault().notify(e);
384                                         }
385                                     }
386                                     public void denied() {
387                                         // OK, skip it.
388
}
389                                     public void error(IOException JavaDoc e) {
390                                         ErrorManager.getDefault().notify(e);
391                                         // Never mind.
392
}
393                                 });
394                             }
395                         }
396                     });
397                     return null;
398                 }
399             });
400         } catch (MutexException e) {
401             throw (IOException JavaDoc)e.getException();
402         }
403     }
404     
405     /**
406      * Load data from a stream into a buffer.
407      */

408     private static byte[] load(InputStream JavaDoc is) throws IOException JavaDoc {
409         int size = Math.max(1024, is.available()); // #46235
410
ByteArrayOutputStream JavaDoc baos = new ByteArrayOutputStream JavaDoc(size);
411         byte[] buf = new byte[size];
412         int read;
413         while ((read = is.read(buf)) != -1) {
414             baos.write(buf, 0, read);
415         }
416         return baos.toByteArray();
417     }
418     
419     /**
420      * Find what state a build script is in.
421      * This may be used by a project type provider to decide whether to create
422      * or overwrite it, and whether to produce a backup in the latter case.
423      * Various abnormal conditions are detected:
424      * {@link #FLAG_MISSING}, {@link #FLAG_MODIFIED}, {@link #FLAG_OLD_PROJECT_XML},
425      * {@link #FLAG_OLD_STYLESHEET}, and {@link #FLAG_UNKNOWN}.
426      * <p class="nonnormative">
427      * Currently {@link #FLAG_MODIFIED}, {@link #FLAG_OLD_STYLESHEET}, and
428      * {@link #FLAG_OLD_PROJECT_XML} are detected by computing a CRC-32
429      * of the script when it is created, as well as the CRC-32s of the
430      * stylesheet and <code>project.xml</code>. These CRCs are stored
431      * in a special file <code>nbproject/genfiles.properties</code>.
432      * The CRCs are based on the textual
433      * contents of the files (so even changed to whitespace etc. are considered
434      * changes), but are independent of platform newline conventions (since e.g.
435      * CVS will by default replace \n with \r\n when checking out on Windows).
436      * Changes to external files included into <code>project.xml</code> or the
437      * stylesheet (e.g. using XSLT's import facility) are <em>not</em> detected.
438      * </p>
439      * <p>
440      * If there is some kind of I/O error reading any files, {@link #FLAG_UNKNOWN}
441      * is returned (in conjunction with {@link #FLAG_MODIFIED},
442      * {@link #FLAG_OLD_STYLESHEET}, and {@link #FLAG_OLD_PROJECT_XML} to be safe).
443      * </p>
444      * <p>
445      * Acquires read access.
446      * </p>
447      * @param path a project-relative path such as {@link #BUILD_XML_PATH} or {@link #BUILD_IMPL_XML_PATH}
448      * @param stylesheet a URL to an XSLT stylesheet accepting <code>project.xml</code>
449      * as input and producing the build script as output
450      * (should match that given to {@link #generateBuildScriptFromStylesheet})
451      * @return a bitwise OR of various flags, or <code>0</code> if the script
452      * is present on disk and fully up-to-date
453      * @throws IllegalStateException if the project was modified
454      */

455     
456     public int getBuildScriptState(final String JavaDoc path, final URL JavaDoc stylesheet, final FileObject jaxWsFo) throws IllegalStateException JavaDoc {
457         try {
458             return ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<Integer JavaDoc>() {
459                 public Integer JavaDoc run() throws IOException JavaDoc {
460 // if (h != null && h.isProjectXmlModified()) {
461
// throw new IllegalStateException("Cannot generate build scripts from a modified project"); // NOI18N
462
// }
463
FileObject script = dir.getFileObject(path);
464                     if (script == null || /* #55164 */script.isVirtual()) {
465                         return new Integer JavaDoc(FLAG_MISSING);
466                     }
467                     int flags = 0;
468                     Properties JavaDoc p = new Properties JavaDoc();
469                     FileObject genfiles = dir.getFileObject(GENFILES_PROPERTIES_PATH);
470                     if (genfiles == null || /* #55164 */genfiles.isVirtual()) {
471                         // Who knows? User deleted it; anything might be wrong. Safest to assume
472
// that everything is.
473
return new Integer JavaDoc(FLAG_UNKNOWN | FLAG_MODIFIED |
474                                            FLAG_OLD_PROJECT_XML | FLAG_OLD_STYLESHEET | FLAG_OLD_JAX_WS);
475                     }
476                     InputStream JavaDoc is = new BufferedInputStream JavaDoc(genfiles.getInputStream());
477                     try {
478                         p.load(is);
479                     } finally {
480                         is.close();
481                     }
482                     FileObject projectXml = dir.getFileObject(AntProjectHelper.PROJECT_XML_PATH);
483                     if (projectXml != null && /* #55164 */!projectXml.isVirtual()) {
484                         String JavaDoc crc = getCrc32(projectXml);
485                         if (!crc.equals(p.getProperty(path + KEY_SUFFIX_DATA_CRC))) {
486                             flags |= FLAG_OLD_PROJECT_XML;
487                         }
488                     } else {
489                         // Broken project?!
490
flags |= FLAG_OLD_PROJECT_XML;
491                     }
492                     FileObject jaxWsFileObject=findJaxWsFileObject(dir);
493                     if (jaxWsFileObject!=null) {
494                         String JavaDoc crc = getCrc32(jaxWsFileObject);
495                         if (!crc.equals(p.getProperty(path + KEY_SUFFIX_JAX_WS_CRC))) {
496                             flags |= FLAG_OLD_JAX_WS;
497                         }
498                     }
499                     String JavaDoc crc = getCrc32(stylesheet);
500                     if (!crc.equals(p.getProperty(path + KEY_SUFFIX_STYLESHEET_CRC))) {
501                         flags |= FLAG_OLD_STYLESHEET;
502                     }
503                     crc = getCrc32(script);
504                     if (!crc.equals(p.getProperty(path + KEY_SUFFIX_SCRIPT_CRC))) {
505                         flags |= FLAG_MODIFIED;
506                     }
507                     return new Integer JavaDoc(flags);
508                 }
509             }).intValue();
510         } catch (MutexException e) {
511             ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, (IOException JavaDoc)e.getException());
512             return FLAG_UNKNOWN | FLAG_MODIFIED | FLAG_OLD_PROJECT_XML | FLAG_OLD_STYLESHEET | FLAG_OLD_JAX_WS;
513         }
514     }
515     
516     /**
517      * Compute the CRC-32 of the contents of a stream.
518      * \r\n and \r are both normalized to \n for purposes of the calculation.
519      */

520     static String JavaDoc computeCrc32(InputStream JavaDoc is) throws IOException JavaDoc {
521         Checksum JavaDoc crc = new CRC32 JavaDoc();
522         int last = -1;
523         int curr;
524         while ((curr = is.read()) != -1) {
525             if (curr != '\n' && last == '\r') {
526                 crc.update('\n');
527             }
528             if (curr != '\r') {
529                 crc.update(curr);
530             }
531             last = curr;
532         }
533         if (last == '\r') {
534             crc.update('\n');
535         }
536         int val = (int)crc.getValue();
537         String JavaDoc hex = Integer.toHexString(val);
538         while (hex.length() < 8) {
539             hex = "0" + hex; // NOI18N
540
}
541         return hex;
542     }
543     
544     // #50440 - cache CRC32's for various files to save time esp. during startup.
545

546     private static final Map JavaDoc<URL JavaDoc, String JavaDoc> crcCache = new HashMap JavaDoc<URL JavaDoc, String JavaDoc>();
547     private static final Map JavaDoc<URL JavaDoc, Long JavaDoc> crcCacheTimestampsXorSizes = new HashMap JavaDoc<URL JavaDoc, Long JavaDoc>();
548
549     /** Try to find a CRC in the cache according to location of file and last mod time xor size. */
550     private static synchronized String JavaDoc findCachedCrc32(URL JavaDoc u, long footprint) {
551         String JavaDoc crc = crcCache.get(u);
552         if (crc != null) {
553             Long JavaDoc l = crcCacheTimestampsXorSizes.get(u);
554             assert l != null;
555             if (l.longValue() == footprint) {
556                 // Cache hit.
557
return crc;
558             }
559         }
560         // Cache miss - missing or old.
561
return null;
562     }
563     
564     /** Cache a known CRC for a file, using current last mod time xor size. */
565     private static synchronized void cacheCrc32(String JavaDoc crc, URL JavaDoc u, long footprint) {
566         crcCache.put(u, crc);
567         crcCacheTimestampsXorSizes.put(u, new Long JavaDoc(footprint));
568     }
569     
570     /** Find (maybe cached) CRC for a file, using a preexisting input stream (not closed by this method). */
571     private static String JavaDoc getCrc32(InputStream JavaDoc is, FileObject fo) throws IOException JavaDoc {
572         URL JavaDoc u = fo.getURL();
573         fo.refresh(); // in case was written on disk and we did not notice yet...
574
long footprint = fo.lastModified().getTime() ^ fo.getSize();
575         String JavaDoc crc = findCachedCrc32(u, footprint);
576         if (crc == null) {
577             crc = computeCrc32(is);
578             cacheCrc32(crc, u, footprint);
579         }
580         return crc;
581     }
582
583     /** Find the time the file this URL represents was last modified xor its size, if possible. */
584     private static long checkFootprint(URL JavaDoc u) {
585         URL JavaDoc nested = FileUtil.getArchiveFile(u);
586         if (nested != null) {
587             u = nested;
588         }
589         if (u.getProtocol().equals("file")) { // NOI18N
590
File JavaDoc f = new File JavaDoc(URI.create(u.toExternalForm()));
591             return f.lastModified() ^ f.length();
592         } else {
593             return 0L;
594         }
595     }
596     
597     /** Find (maybe cached) CRC for a URL, using a preexisting input stream (not closed by this method). */
598     private static String JavaDoc getCrc32(InputStream JavaDoc is, URL JavaDoc u) throws IOException JavaDoc {
599         long footprint = checkFootprint(u);
600         String JavaDoc crc = null;
601         if (footprint != 0L) {
602             crc = findCachedCrc32(u, footprint);
603         }
604         if (crc == null) {
605             crc = computeCrc32(is);
606             if (footprint != 0L) {
607                 cacheCrc32(crc, u, footprint);
608             }
609         }
610         return crc;
611     }
612     
613     /** Find (maybe cached) CRC for a file. Will open its own input stream. */
614     private static String JavaDoc getCrc32(FileObject fo) throws IOException JavaDoc {
615         URL JavaDoc u = fo.getURL();
616         fo.refresh();
617         long footprint = fo.lastModified().getTime() ^ fo.getSize();
618         String JavaDoc crc = findCachedCrc32(u, footprint);
619         if (crc == null) {
620             InputStream JavaDoc is = fo.getInputStream();
621             try {
622                 crc = computeCrc32(new BufferedInputStream JavaDoc(is));
623                 cacheCrc32(crc, u, footprint);
624             } finally {
625                 is.close();
626             }
627         }
628         return crc;
629     }
630     
631     /** Find (maybe cached) CRC for a URL. Will open its own input stream. */
632     private static String JavaDoc getCrc32(URL JavaDoc u) throws IOException JavaDoc {
633         long footprint = checkFootprint(u);
634         String JavaDoc crc = null;
635         if (footprint != 0L) {
636             crc = findCachedCrc32(u, footprint);
637         }
638         if (crc == null) {
639             InputStream JavaDoc is = u.openStream();
640             try {
641                 crc = computeCrc32(new BufferedInputStream JavaDoc(is));
642                 if (footprint != 0L) {
643                     cacheCrc32(crc, u, footprint);
644                 }
645             } finally {
646                 is.close();
647             }
648         }
649         return crc;
650     }
651
652     /**
653      * Convenience method to refresh a build script if it can and should be.
654      * <p>
655      * If the script is not modified, and it is either missing, or the flag
656      * <code>checkForProjectXmlModified</code> is false, or it is out of date with
657      * respect to either <code>project.xml</code> or the stylesheet (or both),
658      * it is (re-)generated.
659      * </p>
660      * <p>
661      * Acquires write access.
662      * </p>
663      * <p class="nonnormative">
664      * Typical usage from {@link ProjectXmlSavedHook#projectXmlSaved} is to call
665      * this method for both {@link #BUILD_XML_PATH} and {@link #BUILD_IMPL_XML_PATH}
666      * with the appropriate stylesheets and with <code>checkForProjectXmlModified</code>
667      * false (the script is certainly out of date relative to <code>project.xml</code>).
668      * Typical usage from {@link org.netbeans.spi.project.ui.ProjectOpenedHook#projectOpened} is to call
669      * this method for both scripts with the appropriate stylesheets and with
670      * <code>checkForProjectXmlModified</code> true.
671      * </p>
672      * @param path a project-relative path such as {@link #BUILD_XML_PATH} or {@link #BUILD_IMPL_XML_PATH}
673      * @param stylesheet a URL to an XSLT stylesheet accepting <code>project.xml</code>
674      * as input and producing the build script as output
675      * @param checkForProjectXmlModified true if it is necessary to check whether the
676      * script is out of date with respect to
677      * <code>project.xml</code> and/or the stylesheet
678      * @return true if the script was in fact regenerated
679      * @throws IOException if transforming or writing the output failed
680      * @throws IllegalStateException if the project was modified
681      */

682     public boolean refreshBuildScript(final String JavaDoc path, final URL JavaDoc stylesheet, final FileObject jaxWsFo, final boolean checkForProjectXmlModified) throws IOException JavaDoc, IllegalStateException JavaDoc {
683         try {
684             return ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Boolean JavaDoc>() {
685                 public Boolean JavaDoc run() throws IOException JavaDoc {
686                     int flags = getBuildScriptState(path, stylesheet, jaxWsFo);
687                     if (shouldGenerateBuildScript(flags, checkForProjectXmlModified)) {
688                         generateBuildScriptFromStylesheet(path, stylesheet, jaxWsFo);
689                         return Boolean.TRUE;
690                     } else {
691                         return Boolean.FALSE;
692                     }
693                 }
694             }).booleanValue();
695         } catch (MutexException e) {
696             throw (IOException JavaDoc)e.getException();
697         }
698     }
699     
700     private static boolean shouldGenerateBuildScript(int flags, boolean checkForProjectXmlModified) {
701         if ((flags & GeneratedFilesHelper.FLAG_MISSING) != 0) {
702             // Yes, need it.
703
return true;
704         }
705         if ((flags & GeneratedFilesHelper.FLAG_MODIFIED) != 0) {
706             // No, don't overwrite a user build script.
707
// XXX modified build-impl.xml probably counts as a serious condition
708
// to warn the user about...
709
// Modified build.xml is no big deal.
710
return false;
711         }
712         if (!checkForProjectXmlModified) {
713             // OK, assume it is out of date.
714
return true;
715         }
716         // Check whether it is in fact out of date.
717
return (flags & (GeneratedFilesHelper.FLAG_OLD_PROJECT_XML |
718                          GeneratedFilesHelper.FLAG_OLD_STYLESHEET | FLAG_OLD_JAX_WS)) != 0;
719     }
720
721     // #45373 - workaround: on Windows make sure that all lines end with CRLF.
722
// marcow: Use at least some buffered output!
723
private static class EolFilterOutputStream extends BufferedOutputStream JavaDoc {
724
725         private boolean isActive = Utilities.isWindows();
726         private int last = -1;
727         
728         public EolFilterOutputStream(OutputStream JavaDoc os) {
729             super(os, 4096);
730         }
731         
732         public void write(byte[] b, int off, int len) throws IOException JavaDoc {
733             if (isActive) {
734                 for (int i = off; i < off + len; i++) {
735                     write(b[i]);
736                 }
737             }
738             else {
739                 super.write(b, off, len);
740             }
741         }
742
743         public void write(int b) throws IOException JavaDoc {
744             if (isActive) {
745                 if (b == '\n' && last != '\r') {
746                     super.write('\r');
747                 }
748                 last = b;
749             }
750             super.write(b);
751         }
752
753     }
754     
755     private FileObject findJaxWsFileObject(FileObject projectDir) {
756         return projectDir.getFileObject(JAX_WS_XML_PATH);
757     }
758     
759 }
760
Popular Tags