1 19 20 package org.netbeans.modules.websvc.api.jaxws.project; 21 22 import java.io.BufferedInputStream ; 23 import java.io.BufferedOutputStream ; 24 import java.io.ByteArrayInputStream ; 25 import java.io.ByteArrayOutputStream ; 26 import java.io.File ; 27 import java.io.IOException ; 28 import java.io.InputStream ; 29 import java.io.OutputStream ; 30 import java.net.URI ; 31 import java.net.URISyntaxException ; 32 import java.net.URL ; 33 import java.util.HashMap ; 34 import java.util.Map ; 35 import java.util.Properties ; 36 import java.util.zip.CRC32 ; 37 import java.util.zip.Checksum ; 38 import javax.xml.transform.Transformer ; 39 import javax.xml.transform.TransformerException ; 40 import javax.xml.transform.TransformerFactory ; 41 import javax.xml.transform.stream.StreamResult ; 42 import javax.xml.transform.stream.StreamSource ; 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 63 public final class GeneratedFilesHelper { 64 65 69 public static final String BUILD_XML_PATH = "build.xml"; 71 75 public static final String BUILD_IMPL_XML_PATH = "nbproject/build-impl.xml"; 77 81 public static final String JAX_WS_XML_PATH = "nbproject/jax-ws.xml"; 83 92 static final String GENFILES_PROPERTIES_PATH = "nbproject/genfiles.properties"; 94 95 private static final String KEY_SUFFIX_DATA_CRC = ".data.CRC32"; 97 98 private static final String KEY_SUFFIX_STYLESHEET_CRC = ".stylesheet.CRC32"; 100 101 private static final String KEY_SUFFIX_SCRIPT_CRC = ".script.CRC32"; 103 104 private static final String KEY_SUFFIX_JAX_WS_CRC = ".jax-ws.CRC32"; 106 111 public static final int FLAG_MISSING = 2 << 0; 112 113 121 public static final int FLAG_MODIFIED = 2 << 1; 122 123 138 public static final int FLAG_OLD_PROJECT_XML = 2 << 2; 139 140 153 public static final int FLAG_OLD_STYLESHEET = 2 << 3; 154 public static final int FLAG_OLD_JAX_WS = 2 << 5; 155 156 168 public static final int FLAG_UNKNOWN = 2 << 4; 169 170 171 private final AntProjectHelper h; 172 173 174 private final FileObject dir; 175 176 180 public GeneratedFilesHelper(AntProjectHelper h) { 181 this.h = h; 182 dir = h.getProjectDirectory(); 183 } 184 185 196 public GeneratedFilesHelper(FileObject d) { 197 if (d == null || !d.isFolder() || d.getFileObject(AntProjectHelper.PROJECT_XML_PATH) == null) { 198 throw new IllegalArgumentException ("Does not look like an Ant-based project: " + d); } 200 h = null; 201 dir = d; 202 } 203 204 226 public void generateBuildScriptFromStylesheet(final String path, final URL stylesheet, final FileObject jaxWsFo) throws IOException , IllegalStateException { 227 if (path == null) { 228 throw new IllegalArgumentException ("Null path"); } 230 if (stylesheet == null) { 231 throw new IllegalArgumentException ("Null stylesheet"); } 233 try { 234 ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Object >() { 235 public Object run() throws IOException { 236 dir.getFileSystem().runAtomicAction(new FileSystem.AtomicAction() { 242 public void run() throws IOException { 243 244 FileObject projectXml = dir.getFileObject(AntProjectHelper.PROJECT_XML_PATH); 245 final FileObject buildScriptXml = FileUtil.createData(dir, path); 246 byte[] projectXmlData; 247 InputStream 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 tf = TransformerFactory.newInstance(); 267 try { 268 StreamSource stylesheetSource = new StreamSource ( 269 new ByteArrayInputStream (stylesheetData), stylesheet.toExternalForm()); 270 Transformer t = tf.newTransformer(stylesheetSource); 271 if (jaxWsFileObject!=null) t.setParameter("jax_ws_uri",jaxWsFileObject.getURL().toURI().toASCIIString()); File projectXmlF = FileUtil.toFile(projectXml); 273 assert projectXmlF != null; 274 StreamSource projectXmlSource = new StreamSource ( 275 new ByteArrayInputStream (projectXmlData), projectXmlF.toURI().toString()); 276 ByteArrayOutputStream result = new ByteArrayOutputStream (); 277 t.transform(projectXmlSource, new StreamResult (result)); 278 resultData = result.toByteArray(); 279 } catch (TransformerException e) { 280 throw (IOException )new IOException (e.toString()).initCause(e); 281 } catch (URISyntaxException e) { 282 throw (IOException )new IOException (e.toString()).initCause(e); 283 } 284 final EditableProperties p = new EditableProperties(true); 286 FileObject genfiles = dir.getFileObject(GENFILES_PROPERTIES_PATH); 287 if (genfiles != null && genfiles.isVirtual()) { 288 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 (projectXmlData), projectXml)); 301 if (genfiles == null) { 302 p.setComment(path + KEY_SUFFIX_DATA_CRC, new String [] { 304 "# " + NbBundle.getMessage(GeneratedFilesHelper.class, "COMMENT_genfiles.properties_1"), "# " + NbBundle.getMessage(GeneratedFilesHelper.class, "COMMENT_genfiles.properties_2"), }, false); 307 } 308 p.setProperty(path + KEY_SUFFIX_STYLESHEET_CRC, 309 getCrc32(new ByteArrayInputStream (stylesheetData), stylesheet)); 310 p.setProperty(path + KEY_SUFFIX_SCRIPT_CRC, 311 computeCrc32(new ByteArrayInputStream (resultData))); 312 if (jaxWsFileObject!=null) { 313 byte[] jaxWsData; 314 InputStream 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 (jaxWsData),jaxWsFileObject)); 322 } 323 if (genfiles == null) { 324 genfiles = FileUtil.createData(dir, GENFILES_PROPERTIES_PATH); 325 } 326 final FileObject _genfiles = genfiles; 327 final FileSystem.AtomicAction body = new FileSystem.AtomicAction() { 331 public void run() throws IOException { 332 FileLock lock1 = buildScriptXml.lock(); 334 try { 335 FileLock lock2 = _genfiles.lock(); 336 try { 337 OutputStream os1 = new EolFilterOutputStream(buildScriptXml.getOutputStream(lock1)); 338 try { 339 OutputStream 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 UserQuestionHandler.handle(uqe, new UserQuestionHandler.Callback() { 362 public void accepted() { 363 try { 365 body.run(); 366 } catch (UserQuestionException uqe2) { 367 UserQuestionHandler.handle(uqe2, new UserQuestionHandler.Callback() { 369 public void accepted() { 370 try { 371 body.run(); 372 } catch (IOException e) { 373 ErrorManager.getDefault().notify(e); 374 } 375 } 376 public void denied() {} 377 public void error(IOException e) { 378 ErrorManager.getDefault().notify(e); 379 } 380 }); 381 } catch (IOException e) { 382 ErrorManager.getDefault().notify(e); 384 } 385 } 386 public void denied() { 387 } 389 public void error(IOException e) { 390 ErrorManager.getDefault().notify(e); 391 } 393 }); 394 } 395 } 396 }); 397 return null; 398 } 399 }); 400 } catch (MutexException e) { 401 throw (IOException )e.getException(); 402 } 403 } 404 405 408 private static byte[] load(InputStream is) throws IOException { 409 int size = Math.max(1024, is.available()); ByteArrayOutputStream baos = new ByteArrayOutputStream (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 455 456 public int getBuildScriptState(final String path, final URL stylesheet, final FileObject jaxWsFo) throws IllegalStateException { 457 try { 458 return ProjectManager.mutex().readAccess(new Mutex.ExceptionAction<Integer >() { 459 public Integer run() throws IOException { 460 FileObject script = dir.getFileObject(path); 464 if (script == null || script.isVirtual()) { 465 return new Integer (FLAG_MISSING); 466 } 467 int flags = 0; 468 Properties p = new Properties (); 469 FileObject genfiles = dir.getFileObject(GENFILES_PROPERTIES_PATH); 470 if (genfiles == null || genfiles.isVirtual()) { 471 return new Integer (FLAG_UNKNOWN | FLAG_MODIFIED | 474 FLAG_OLD_PROJECT_XML | FLAG_OLD_STYLESHEET | FLAG_OLD_JAX_WS); 475 } 476 InputStream is = new BufferedInputStream (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 && !projectXml.isVirtual()) { 484 String crc = getCrc32(projectXml); 485 if (!crc.equals(p.getProperty(path + KEY_SUFFIX_DATA_CRC))) { 486 flags |= FLAG_OLD_PROJECT_XML; 487 } 488 } else { 489 flags |= FLAG_OLD_PROJECT_XML; 491 } 492 FileObject jaxWsFileObject=findJaxWsFileObject(dir); 493 if (jaxWsFileObject!=null) { 494 String 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 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 (flags); 508 } 509 }).intValue(); 510 } catch (MutexException e) { 511 ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, (IOException )e.getException()); 512 return FLAG_UNKNOWN | FLAG_MODIFIED | FLAG_OLD_PROJECT_XML | FLAG_OLD_STYLESHEET | FLAG_OLD_JAX_WS; 513 } 514 } 515 516 520 static String computeCrc32(InputStream is) throws IOException { 521 Checksum crc = new CRC32 (); 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 hex = Integer.toHexString(val); 538 while (hex.length() < 8) { 539 hex = "0" + hex; } 541 return hex; 542 } 543 544 546 private static final Map <URL , String > crcCache = new HashMap <URL , String >(); 547 private static final Map <URL , Long > crcCacheTimestampsXorSizes = new HashMap <URL , Long >(); 548 549 550 private static synchronized String findCachedCrc32(URL u, long footprint) { 551 String crc = crcCache.get(u); 552 if (crc != null) { 553 Long l = crcCacheTimestampsXorSizes.get(u); 554 assert l != null; 555 if (l.longValue() == footprint) { 556 return crc; 558 } 559 } 560 return null; 562 } 563 564 565 private static synchronized void cacheCrc32(String crc, URL u, long footprint) { 566 crcCache.put(u, crc); 567 crcCacheTimestampsXorSizes.put(u, new Long (footprint)); 568 } 569 570 571 private static String getCrc32(InputStream is, FileObject fo) throws IOException { 572 URL u = fo.getURL(); 573 fo.refresh(); long footprint = fo.lastModified().getTime() ^ fo.getSize(); 575 String crc = findCachedCrc32(u, footprint); 576 if (crc == null) { 577 crc = computeCrc32(is); 578 cacheCrc32(crc, u, footprint); 579 } 580 return crc; 581 } 582 583 584 private static long checkFootprint(URL u) { 585 URL nested = FileUtil.getArchiveFile(u); 586 if (nested != null) { 587 u = nested; 588 } 589 if (u.getProtocol().equals("file")) { File f = new File (URI.create(u.toExternalForm())); 591 return f.lastModified() ^ f.length(); 592 } else { 593 return 0L; 594 } 595 } 596 597 598 private static String getCrc32(InputStream is, URL u) throws IOException { 599 long footprint = checkFootprint(u); 600 String 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 614 private static String getCrc32(FileObject fo) throws IOException { 615 URL u = fo.getURL(); 616 fo.refresh(); 617 long footprint = fo.lastModified().getTime() ^ fo.getSize(); 618 String crc = findCachedCrc32(u, footprint); 619 if (crc == null) { 620 InputStream is = fo.getInputStream(); 621 try { 622 crc = computeCrc32(new BufferedInputStream (is)); 623 cacheCrc32(crc, u, footprint); 624 } finally { 625 is.close(); 626 } 627 } 628 return crc; 629 } 630 631 632 private static String getCrc32(URL u) throws IOException { 633 long footprint = checkFootprint(u); 634 String crc = null; 635 if (footprint != 0L) { 636 crc = findCachedCrc32(u, footprint); 637 } 638 if (crc == null) { 639 InputStream is = u.openStream(); 640 try { 641 crc = computeCrc32(new BufferedInputStream (is)); 642 if (footprint != 0L) { 643 cacheCrc32(crc, u, footprint); 644 } 645 } finally { 646 is.close(); 647 } 648 } 649 return crc; 650 } 651 652 682 public boolean refreshBuildScript(final String path, final URL stylesheet, final FileObject jaxWsFo, final boolean checkForProjectXmlModified) throws IOException , IllegalStateException { 683 try { 684 return ProjectManager.mutex().writeAccess(new Mutex.ExceptionAction<Boolean >() { 685 public Boolean run() throws IOException { 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 )e.getException(); 697 } 698 } 699 700 private static boolean shouldGenerateBuildScript(int flags, boolean checkForProjectXmlModified) { 701 if ((flags & GeneratedFilesHelper.FLAG_MISSING) != 0) { 702 return true; 704 } 705 if ((flags & GeneratedFilesHelper.FLAG_MODIFIED) != 0) { 706 return false; 711 } 712 if (!checkForProjectXmlModified) { 713 return true; 715 } 716 return (flags & (GeneratedFilesHelper.FLAG_OLD_PROJECT_XML | 718 GeneratedFilesHelper.FLAG_OLD_STYLESHEET | FLAG_OLD_JAX_WS)) != 0; 719 } 720 721 private static class EolFilterOutputStream extends BufferedOutputStream { 724 725 private boolean isActive = Utilities.isWindows(); 726 private int last = -1; 727 728 public EolFilterOutputStream(OutputStream os) { 729 super(os, 4096); 730 } 731 732 public void write(byte[] b, int off, int len) throws IOException { 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 { 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 |