1 19 20 package org.netbeans.core.startup.layers; 21 22 import java.io.ByteArrayInputStream ; 23 import java.io.File ; 24 import java.io.IOException ; 25 import java.io.InputStream ; 26 import java.net.MalformedURLException ; 27 import java.net.URL ; 28 import java.net.URLConnection ; 29 import java.util.ArrayList ; 30 import java.util.Arrays ; 31 import java.util.Collections ; 32 import java.util.HashSet ; 33 import java.util.Iterator ; 34 import java.util.LinkedList ; 35 import java.util.List ; 36 import java.util.Set ; 37 import java.util.Stack ; 38 import java.util.logging.Level ; 39 import org.openide.filesystems.FileSystem; 40 import org.openide.util.NotImplementedException; 41 import org.openide.xml.XMLUtil; 42 import org.xml.sax.Attributes ; 43 import org.xml.sax.ContentHandler ; 44 import org.xml.sax.EntityResolver ; 45 import org.xml.sax.ErrorHandler ; 46 import org.xml.sax.InputSource ; 47 import org.xml.sax.Locator ; 48 import org.xml.sax.SAXException ; 49 import org.xml.sax.SAXParseException ; 50 import org.xml.sax.XMLReader ; 51 52 57 public abstract class ParsingLayerCacheManager extends LayerCacheManager implements ContentHandler , ErrorHandler , EntityResolver { 58 59 private final static String [] ATTR_TYPES = { 60 "boolvalue", 61 "bytevalue", 62 "charvalue", 63 "doublevalue", 64 "floatvalue", 65 "intvalue", 66 "longvalue", 67 "methodvalue", 68 "newvalue", 69 "serialvalue", 70 "shortvalue", 71 "stringvalue", 72 "urlvalue" 73 }; 74 75 private final static String DTD_1_0 = "-//NetBeans//DTD Filesystem 1.0//EN"; 76 private final static String DTD_1_1 = "-//NetBeans//DTD Filesystem 1.1//EN"; 77 78 private Locator locator; 79 private MemFolder root; 80 private Stack <Object > curr; private URL base; 82 private StringBuffer buf = new StringBuffer (); 83 private int fileCount, folderCount, attrCount; 84 private Set <String > oneLayerFiles; private boolean checkingForDuplicates; 89 private String currPath; 90 private boolean atLeastOneFileOrFolderInLayer; 91 92 94 protected ParsingLayerCacheManager(File cacheDir) throws IOException { 95 super(cacheDir); 96 } 97 98 101 public final void store(FileSystem fs, List <URL > urls) throws IOException { 102 store(fs, createRoot(urls)); 103 } 104 105 108 public final FileSystem store(List <URL > urls) throws IOException { 109 return store(createRoot(urls)); 110 } 111 112 115 private MemFolder createRoot(List <URL > urls) throws IOException { 116 root = new MemFolder(null); 117 curr = new Stack <Object >(); 118 curr.push(root); 119 try { 120 XMLReader r = XMLUtil.createXMLReader(); 122 r.setFeature("http://xml.org/sax/features/validation", false); 125 r.setFeature("http://xml.org/sax/features/namespaces", false); 126 r.setFeature("http://xml.org/sax/features/string-interning", true); 128 r.setContentHandler(this); 129 r.setErrorHandler(this); 130 r.setEntityResolver(this); 131 Exception carrier = null; 132 urls = new ArrayList <URL >(urls); 134 Collections.reverse(urls); 135 checkingForDuplicates = LayerCacheManager.err.isLoggable(Level.FINE); 136 Iterator <URL > it = urls.iterator(); 137 while (it.hasNext()) { 138 base = it.next(); if (checkingForDuplicates) { 140 oneLayerFiles = new HashSet <String >(100); 141 currPath = null; 142 } 143 LayerCacheManager.err.log(Level.FINE, "Parsing: {0}", base); 144 atLeastOneFileOrFolderInLayer = false; 145 try { 146 r.parse(base.toExternalForm()); 147 if (!atLeastOneFileOrFolderInLayer) { 148 LayerCacheManager.err.log(Level.WARNING, "Inefficient to include an empty layer in a module: {0}", base); 149 } 150 } catch (Exception e) { 151 curr.clear(); 152 curr.push(root); 153 LayerCacheManager.err.fine("Caught " + e + " while parsing: " + base); 154 if (carrier == null) { 155 carrier = e; 156 } else { 157 Throwable t = carrier; 158 while (t.getCause() != null) { 159 t = t.getCause(); 160 } 161 t.initCause(e); 162 } 163 } 164 } 165 if (carrier != null) throw carrier; 166 LayerCacheManager.err.fine("Finished layer parsing; " + fileCount + " files, " + folderCount + " folders, " + attrCount + " attributes"); 167 return root; 168 } catch (IOException ioe) { 169 throw ioe; 170 } catch (Exception e) { 171 throw (IOException ) new IOException (e.toString()).initCause(e); 172 } finally { 173 fileCount = folderCount = attrCount = 0; 174 base = null; 175 locator = null; 176 curr = null; 177 root = null; 178 oneLayerFiles = null; 179 currPath = null; 180 } 181 } 182 183 187 protected void store(FileSystem fs, MemFolder root) throws IOException { 188 throw new NotImplementedException(); 189 } 190 191 195 protected FileSystem store(MemFolder root) throws IOException { 196 throw new NotImplementedException(); 197 } 198 199 203 protected abstract boolean openURLs(); 204 205 public void startElement(String ns, String lname, String qname, Attributes attrs) throws SAXException { 206 if (qname == "filesystem") { 207 return; 208 } else if (qname == "folder") { 209 fileOrFolder(qname, attrs); 210 } else if (qname == "file") { 211 MemFile file = (MemFile)fileOrFolder(qname, attrs); 212 file.contents = null; 213 String u = attrs.getValue("url"); 214 if (u != null) { 215 try { 216 file.ref = new URL (base, u); 217 } catch (MalformedURLException mfue) { 218 throw (SAXException ) new SAXException (mfue.toString()).initCause(mfue); 219 } 220 } else { 221 file.ref = null; 222 } 223 } else if (qname == "attr") { 224 attrCount++; 225 MemAttr attr = new MemAttr(); 226 int len = attrs.getLength(); 227 for (int i = 0; i < len; i++) { 228 String attrName = attrs.getQName(i); 229 if ("name".equals(attrName)) { 230 attr.name = attrs.getValue(i); 231 } 232 else { 233 int idx = Arrays.binarySearch(ATTR_TYPES, attrName); 234 if (idx >= 0) { 235 attr.type = ATTR_TYPES[idx]; 236 attr.data = attrs.getValue(i); 237 } 238 } 239 if (attr.name != null && attr.data != null) { 240 break; 241 } 242 } 243 255 if (attr.type == null) throw new SAXParseException ("unknown <attr> value type for " + attr.name, locator); 256 MemFileOrFolder parent = (MemFileOrFolder)curr.peek(); 257 if (parent.attrs == null) parent.attrs = new LinkedList <MemAttr>(); 258 Iterator it = parent.attrs.iterator(); 259 while (it.hasNext()) { 260 if (((MemAttr)it.next()).name.equals(attr.name)) { 261 attrCount--; 262 it.remove(); 263 } 264 } 265 parent.attrs.add(attr); 266 if (checkingForDuplicates && !oneLayerFiles.add(currPath + "//" + attr.name)) { LayerCacheManager.err.warning("layer " + base + " contains duplicate attributes " + attr.name + " for " + currPath); 268 } 269 } else { 270 throw new SAXException (qname); 271 } 272 } 273 274 private MemFileOrFolder fileOrFolder(String qname, Attributes attrs) { 275 atLeastOneFileOrFolderInLayer = true; 276 String name = attrs.getValue("name"); 277 if (name == null) throw new NullPointerException ("No name"); if (!(curr.peek() instanceof MemFolder)) throw new ClassCastException ("Stack: " + curr); MemFolder parent = (MemFolder)curr.peek(); 280 MemFileOrFolder f = null; 281 if (parent.children == null) { 282 parent.children = new LinkedList <MemFileOrFolder>(); 283 } 284 else { 285 Iterator it = parent.children.iterator(); 286 while (it.hasNext()) { 287 MemFileOrFolder f2 = (MemFileOrFolder)it.next(); 288 if (f2.name.equals(name)) { 289 f = f2; 290 break; 291 } 292 } 293 } 294 if (f == null) { 295 if (qname == "folder") { f = new MemFolder(base); 297 folderCount++; 298 } else { 299 f = new MemFile(base); 300 fileCount++; 301 } 302 f.name = name; 303 parent.children.add(f); 304 } 305 curr.push(f); 306 if (checkingForDuplicates) { 307 if (currPath == null) { 308 currPath = name; 309 } else { 310 currPath += "/" + name; 311 } 312 if (!oneLayerFiles.add(currPath)) { 313 LayerCacheManager.err.warning("layer " + base + " contains duplicate " + qname + "s named " + currPath); 314 } 315 } 316 return f; 317 } 318 319 public void endElement(String ns, String lname, String qname) throws SAXException { 320 if (qname == "file" && buf.length() > 0) { 321 String text = buf.toString().trim(); 322 if (text.length() > 0) { 323 MemFile file = (MemFile)curr.peek(); 324 if (file.ref != null) throw new SAXParseException ("CDATA plus url= in <file>", locator); 325 LayerCacheManager.err.warning("use of inline CDATA text contents in <file name=\"" + file.name + "\"> deprecated for performance and charset safety at " + locator.getSystemId() + ":" + locator.getLineNumber() + ". Please use the 'url' attribute instead, or the file attribute 'originalFile' on *.shadow files (with IDE/1 > 2.23)."); 326 file.contents = text.getBytes(); 329 } 330 buf.setLength(0); 331 } 332 if (qname == "file" && openURLs()) { 333 MemFile file = (MemFile)curr.peek(); 334 if (file.ref != null && file.ref.toExternalForm().startsWith("jar:file:")) { try { 337 URLConnection conn = file.ref.openConnection(); 338 conn.connect(); 339 byte[] buf = new byte[conn.getContentLength()]; 340 InputStream is = conn.getInputStream(); 341 try { 342 int pos = 0; 343 while (pos < buf.length) { 344 int read = is.read(buf, pos, buf.length - pos); 345 if (read < 1) throw new IOException ("Premature EOF on " + file.ref.toExternalForm()); pos += read; 347 } 348 if (is.read() != -1) throw new IOException ("Delayed EOF on " + file.ref.toExternalForm()); } finally { 350 is.close(); 351 } 352 file.contents = buf; 353 file.ref = null; 354 } catch (IOException ioe) { 355 throw new SAXException (ioe); 356 } 357 } 358 } 359 if (qname == "file" || qname == "folder") { curr.pop(); 361 if (checkingForDuplicates) { 362 int i = currPath.lastIndexOf('/'); if (i == -1) { 364 currPath = null; 365 } else { 366 currPath = currPath.substring(0, i); 367 } 368 } 369 } 370 } 371 372 public void characters(char[] ch, int start, int len) throws SAXException { 373 Object currF = curr.peek(); 374 if (!(currF instanceof MemFile)) { 375 return; 376 } 377 buf.append(ch, start, len); 382 } 383 384 public void warning(SAXParseException e) throws SAXException { 385 LayerCacheManager.err.log(Level.WARNING, null, e); 386 } 387 388 public void fatalError(SAXParseException e) throws SAXException { 389 throw e; 390 } 391 392 public void error(SAXParseException e) throws SAXException { 393 throw e; 394 } 395 396 public InputSource resolveEntity(String pubid, String sysid) throws SAXException , IOException { 397 if (pubid != null && (pubid.equals(DTD_1_0) || pubid.equals(DTD_1_1))) { 398 return new InputSource (new ByteArrayInputStream (new byte[0])); 399 } else { 400 return null; 401 } 402 } 403 404 public void setDocumentLocator(Locator locator) { 405 this.locator = locator; 406 } 407 408 public void endDocument() throws SAXException { 409 if (curr.size() != 1) throw new SAXException ("Wrong stack: " + curr); } 411 412 public void startDocument() throws SAXException {} 413 414 public void startPrefixMapping(String str, String str1) throws SAXException {} 415 416 public void skippedEntity(String str) throws SAXException {} 417 418 public void processingInstruction(String str, String str1) throws SAXException {} 419 420 public void ignorableWhitespace(char[] values, int param, int param2) throws SAXException {} 421 422 public void endPrefixMapping(String str) throws SAXException {} 423 424 426 protected static abstract class MemFileOrFolder { 427 public String name; 428 public List <MemAttr> attrs = null; public final URL base; 430 431 public MemFileOrFolder (URL base) { 432 this.base = base; 433 } 434 } 435 436 438 protected static final class MemFolder extends MemFileOrFolder { 439 public List <MemFileOrFolder> children = null; 440 441 public MemFolder (URL base) { 442 super (base); 443 } 444 445 public String toString() { 446 return "MemFolder[" + name + "]"; } 448 } 449 450 452 protected static final class MemFile extends MemFileOrFolder { 453 public byte[] contents = null; public URL ref = null; 456 public MemFile (URL base) { 457 super (base); 458 } 459 460 public String toString() { 461 return "MemFile[" + name + "]"; } 463 } 464 465 467 protected static final class MemAttr { 468 public String name; 469 public String type; 470 public String data; 471 public String toString() { 472 return "MemAttr[" + name + "," + type + "," + data + "]"; } 474 } 475 476 } 477 | Popular Tags |