/* * Sun Public License Notice * * The contents of this file are subject to the Sun Public License * Version 1.0 (the "License"). You may not use this file except in * compliance with the License. A copy of the License is available at * http://www.sun.com/ * * The Original Code is NetBeans. The Initial Developer of the Original * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun * Microsystems, Inc. All Rights Reserved. */ package org.openide.filesystems; import java.lang.ref.*; import java.io.*; import java.lang.reflect.*; import java.beans.*; import java.util.*; import java.net.*; import org.openide.util.enums.EmptyEnumeration; import org.openide.util.NbBundle; import org.xml.sax.*; import javax.xml.parsers.SAXParserFactory; /** XML-based filesystem. * <PRE> * Description of format of XML file (which can be parsed by XMLFileSystem) * ================================================================== * Allowed Elements: filesystem,file,folder,attr * * Mandatory attributes: * -for filesystem version=... (e.g. "1.0") * -for file,folder,attr name=.... (e.g.: <folder name="Config">) * -for attr is mandatory one of bytevalue,shortvalue,intvalue,longvalue,floatvalue,doublevalue,boolvalue,charvalue,stringvalue,methodvalue,serialvalue,urlvalue * * Allowed atributes: * -for file: url=.... (e.g.: <file name="sample.xml" url="file:/c:\sample.xml">) * -for folder,filesystem nothing allowed * * * * Note: file can contain content e.g.: * < file name="sample.java"> * < ![CDATA[ * package org.sample; * import java.io; * ]]> * < /file> * But using url="..." is preferred. * * * This class implements virtual FileSystem. It is special case of FileSystem in XML format. * * Description of this format best ilustrate DTD file that is showed in next lines: * < !ELEMENT filesystem (file | folder)*> * < !ATTLIST filesystem version CDATA #REQUIRED> //version not checkked yet * < !ELEMENT folder (file |folder | attr)*> * < !ATTLIST folder name CDATA #REQUIRED> //name of folder * < !ELEMENT file (#PCDATA | attr)*> * < !ATTLIST file name CDATA #REQUIRED> //name of file * < !ATTLIST file url CDATA #IMPLIED> //content of the file can be find at url * < !ELEMENT attr EMPTY> * < !ATTLIST attr name CDATA #REQUIRED> //name of attribute * < !ATTLIST attr bytevalue CDATA #IMPLIED>//the rest - types of attributes * < !ATTLIST attr shortvalue CDATA #IMPLIED> * < !ATTLIST attr intvalue CDATA #IMPLIED> * < !ATTLIST attribute longvalue CDATA #IMPLIED> * < !ATTLIST attr floatvalue CDATA #IMPLIED> * < !ATTLIST attr doublevalue CDATA #IMPLIED> * < !ATTLIST attr boolvalue CDATA #IMPLIED> * < !ATTLIST attr charvalue CDATA #IMPLIED> * < !ATTLIST attr stringvalue CDATA #IMPLIED> * < !ATTLIST attr methodvalue CDATA #IMPLIED> * < !ATTLIST attr serialvalue CDATA #IMPLIED> * < !ATTLIST attr urlvalue CDATA #IMPLIED> * </PRE> * @author Radek Matous */ public final class XMLFileSystem extends AbstractFileSystem { static final long serialVersionUID = 28974107313702326L; /** Url location of XML document */ private URL[] urlsToXml = new URL[] {}; private transient FileObjRef rootRef; // <?xml version="1.0"?> // <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.0//EN" "http://www.netbeans.org/dtds/filesystem-1_0.dtd"> // <filesystem>...</filesystem> private static final Map DTD_MAP = new HashMap (); static { DTD_MAP.put ("-//NetBeans//DTD Filesystem 1.0//EN", "org/openide/filesystems/filesystem.dtd"); //NOI18N DTD_MAP.put ("-//NetBeans//DTD Filesystem 1.1//EN", "org/openide/filesystems/filesystem1_1.dtd");//NOI18N } /** Constructor. Creates new XMLFileSystem */ public XMLFileSystem() { Impl impl = new Impl (this); this.list = impl; this.info = impl; this.change = impl; this.attr = impl; } /** Constructor. Creates new XMLFileSystem. * @param uri to file with definition of XMLFileSystem * @throws SAXException if parsing is not succesful */ public XMLFileSystem(String uri) throws SAXException { this(); try { setXmlUrl(new URL(uri)); } catch(Exception e) { throw (SAXException)ExternalUtil.copyAnnotation (new SAXException (e.getMessage()),e); } } /** Constructor. Creates new XMLFileSystem. * @param url to definition of XMLFileSystem * @throws SAXException if parsing not succesful */ public XMLFileSystem(URL url) throws SAXException{ this(); try { setXmlUrl(url); } catch(Exception e) { throw (SAXException)ExternalUtil.copyAnnotation (new SAXException (e.getMessage()),e); } } /** Constructor. Allows user to provide own capabilities * for this filesystem. * @param cap capabilities for this filesystem */ public XMLFileSystem(FileSystemCapability cap) { this (); setCapability (cap); } /** Getter of url field. * @return URL associated with XMLFileSystem or null if no URL was set. * In case that definition of XMLFileSystem * is merged from more URLs than the first is returned. */ public URL getXmlUrl () { // JST return urlsToXml.length > 0?urlsToXml[0]:null; } /** * Setter of url field. Set name of the XML file. * @param url with definition of XMLFileSystem * @throws PropertyVetoException if the change is not allowed by a listener * @throws IOException if the file is not valid */ public synchronized void setXmlUrl (URL url) throws IOException, PropertyVetoException { setXmlUrl (url, false); } /** * Setter of url field. Set name of the XML file. * @param url with definition of XMLFileSystem * @param validate sets validating of SAXParser * @throws PropertyVetoException if the change is not allowed by a listener * @throws IOException if the file is not valid */ public synchronized void setXmlUrl (URL url, boolean validate) throws IOException, PropertyVetoException { setXmlUrls(new URL[] {url}, validate); } /** Getter of url fields. * @return URLs associated with XMLFileSystem. * @deprecated experimental method. Nobody should rely on this method yet. * @since 1.14 */ public URL[] getXmlUrls () { // JST return urlsToXml; } /** Setter of url fields. First URL in array sets name of XMLFileSystem. * If more then one url in array of URLs defines the same FileObject, then * url with lower index in array overrides (means content and attributes) the other. * @param urls array of definitions (in xml form) of XMLFileSystem * @throws IOException if the file is not valid * @throws PropertyVetoException if the change is not allowed by a listener * @deprecated experimental method. Nobody should rely on this method yet. * @since 1.14 */ public synchronized void setXmlUrls (URL[] urls) throws IOException, PropertyVetoException { setXmlUrls(urls, false); } private synchronized void setXmlUrls (URL[] urls, boolean validate) throws IOException, PropertyVetoException { //long time = System.currentTimeMillis(); ResourceElem rootElem; String oldDisplayName = getDisplayName (); if (urls.length == 0) { urlsToXml = new URL[] {}; refreshChildrenInAtomicAction ((AbstractFolder)getRoot(),rootElem = new ResourceElem(true,urls,null) ); // NOI18N rootElem = null; return; } Handler handler = new Handler(DTD_MAP,rootElem = new ResourceElem (true,urls,null), validate); // NOI18N URL[] origUrls = urlsToXml; urlsToXml = new URL[urls.length]; try { setSystemName("XML_"+urls[0].toExternalForm());// NOI18N } catch (PropertyVetoException pvx) { urlsToXml = origUrls; rootElem = null; throw pvx; } URL act = null; try { SAXParserFactory factory = SAXParserFactory.newInstance (); factory.setValidating (validate); factory.setNamespaceAware(false); Parser xp = factory.newSAXParser ().getParser (); xp.setEntityResolver(handler); xp.setDocumentHandler(handler); xp.setErrorHandler(handler); for (int index = 0; index < urls.length; index++) { act = urls[index]; urlsToXml[index] = act; handler.urlContext = act; xp.parse(act.toExternalForm()); } //time = System.currentTimeMillis() - time; //System.err.println("Parsing took " + time + "ms"); //time = System.currentTimeMillis(); refreshChildrenInAtomicAction ((AbstractFolder)getRoot (),rootElem ); //time = System.currentTimeMillis() - time; //System.err.println("Notifying took " + time + "ms"); } catch (IOException iox) { urlsToXml = origUrls; throw iox; } catch (Exception e) { IOException x = new IOException (e.getMessage()+" : "+act); // NOI18N ExternalUtil.copyAnnotation (x,e); throw x; } finally { rootElem = null; } firePropertyChange (PROP_DISPLAY_NAME, oldDisplayName, getDisplayName ()); } /** * @return if value of lastModified should be cached */ boolean isLastModifiedCacheEnabled () { return false; } /** * Test if the file is folder or contains data. * @param name name of the file * @return true if the file is folder, false otherwise */ private boolean isFolder(String name) { Reference ref = findReference(name); if (ref != null && (ref instanceof FileObjRef) ) { return ((FileObjRef) ref).isFolder(); } return false; } /** * Get input stream. * * @param name the file to test * @return an input stream to read the contents of this file * @exception FileNotFoundException if the file does not exists or is invalid */ private InputStream getInputStream(String name) throws java.io.FileNotFoundException { Reference ref = findReference(name); if (ref != null && (ref instanceof FileObjRef ) ) { return ((FileObjRef) ref).getInputStream(name); } throw new FileNotFoundException (NbBundle.getMessage(XMLFileSystem.class, "EXC_CanntRead", name));// NOI18N } /** * Get URL. * * @param name of the file to test * @return URL of resource or null * @exception FileNotFoundException if the file does not exists or is invalid */ URL getURL (String name) throws java.io.FileNotFoundException { Reference ref = findReference(name); if (ref != null && (ref instanceof FileObjRef ) ) { return ((FileObjRef) ref).createAbsoluteUrl(name); } throw new FileNotFoundException (NbBundle.getMessage(XMLFileSystem.class, "EXC_CanntRead", name));// NOI18N } /** Get size of stream*/ private long getSize (String name) { Reference ref = findReference(name); if (ref != null && (ref instanceof FileObjRef ) ) { return ((FileObjRef) ref).getSize(name); } return 0; } /**returns value of last modification*/ private java.util.Date lastModified(String name) { Reference ref = findReference(name); if (ref != null && (ref instanceof FileObjRef ) ) { return ((FileObjRef) ref).lastModified (name); } /**return value for resource that does not exists*/ return new Date (0); } /** Provides a name for the system that can be presented to the user. * @return user presentable name of the filesystem */ public String getDisplayName() { if (urlsToXml.length == 0 || urlsToXml[0] == null || urlsToXml[0].toExternalForm().length() == 0) return NbBundle.getMessage(XMLFileSystem.class,"XML_NotValidXMLFileSystem");// NOI18N return "XML:"+urlsToXml[0].toExternalForm().trim();// NOI18N } /** Test if the filesystem is read-only or not. * @return true if the system is read-only */ public boolean isReadOnly() { return true; } /** Initializes the root of FS. */ private void readObject (ObjectInputStream ois) throws IOException, ClassNotFoundException { //ois.defaultReadObject (); ObjectInputStream.GetField fields = ois.readFields(); URL[] urls = (URL[]) fields.get ("urlsToXml",null); // NOI18N if (urls == null) { urls = new URL[1]; urls[0] = (URL) fields.get ("uriId",null); // NOI18N } try { if (urlsToXml.length != 1) setXmlUrls(urlsToXml); else setXmlUrl(urlsToXml[0]); } catch (PropertyVetoException ex) { IOException x = new IOException (ex.getMessage()); ExternalUtil.copyAnnotation (x,ex); throw x; } } /** Notifies this filesystem that it has been added to the repository. * Various initialization tasks should go here. Default implementation is noop. */ public void addNotify() {} /** Notifies this filesystem that it has been removed from the repository. * Concrete filesystem implementations should perform clean-up here. * Default implementation is noop. */ public void removeNotify() {} protected Reference createReference(FileObject fo) { return new FileObjRef (fo); } private void refreshChildrenInAtomicAction (AbstractFolder fo, ResourceElem resElem) { try { beginAtomicAction (); refreshChildren (fo, resElem); } finally { finishAtomicAction (); } } /** refreshes children recursively.*/ private void refreshChildren (AbstractFolder fo, ResourceElem resElem) { if (fo.isRoot()) initializeReference (rootRef = new FileObjRef (fo), resElem); java.util.List nameList = resElem.getChildren (); String[] names = new String[nameList.size ()]; ResourceElem[] children = new ResourceElem[names.length]; nameList.toArray(names); for (int i = 0; i < names.length; i++) children[i] = resElem.getChild (names[i]); fo.refresh(null, null, true, true, names); for (int i = 0; i < children.length; i++) { AbstractFolder fo2 = (AbstractFolder)fo.getFileObject (names[i]); FileObjRef currentRef = (FileObjRef )findReference (fo2.getPath ()); initializeReference (currentRef, children[i]); if (fo2.isFolder()) refreshChildren (fo2,children[i]); } } private void initializeReference (FileObjRef currentRef, ResourceElem resElem) { if (!currentRef.isInitialized ()) currentRef.initialize (resElem); else { currentRef.attacheAttrs (resElem.getAttr (false)); currentRef.setUrlContext (resElem.getUrlContext ()); if (resElem.getContent() != null) { currentRef.content = resElem.getContent(); } else if (resElem.getURI() != null) { currentRef.content = resElem.getURI(); } } } /** Temporary hierarchical structure of resources. Used while parsing.*/ private static class ResourceElem { private java.util.List children; private java.util.List names; private byte[] content; private java.util.List urlContext = new ArrayList (); private XMLMapAttr foAttrs; private boolean isFolder; private String uri; public ResourceElem (boolean isFolder, URL[] urlContext, String uri) { this.isFolder = isFolder; this.uri = uri; this.urlContext.addAll(Arrays.asList(urlContext)); if (isFolder) { children = new ArrayList (); names = new ArrayList (); } } public ResourceElem (boolean isFolder, URL urlContext, String uri) { this.isFolder = isFolder; this.uri = uri; this.urlContext.add(urlContext); if (isFolder) { children = new ArrayList (); names = new ArrayList (); } } ResourceElem addChild (String name, ResourceElem child) { if (!isFolder) throw new IllegalArgumentException("not a folder"); // NOI18N ResourceElem retVal = child; int idx = names.indexOf(name); if (idx == -1) { names.add(name); children.add(child); } else { retVal = (ResourceElem)children.get(idx); } return retVal; } java.util.List getChildren () { return names; } ResourceElem getChild (String name) { return (ResourceElem )children.get(names.indexOf(name)); } XMLMapAttr getAttr ( boolean create ) { if (create && foAttrs == null) foAttrs = new XMLMapAttr (); return foAttrs; } byte[] getContent () { return content; } URL[] getUrlContext () { URL[] retVal = new URL[urlContext.size()]; urlContext.toArray(retVal); return retVal; } String getURI () { return uri; } void setContent (byte[] content) { if (this.content == null) { byte[] alloc = new byte[content.length]; System.arraycopy(content, 0, alloc, 0, content.length); this.content = alloc; } } boolean isFolder () { return isFolder; } } //private void debugInfo(String dbgStr) { System.out.println(dbgStr);} /** Implementation of all interfaces List, Change, Info and Attr * that delegates to XMLFileSystem */ public static class Impl extends Object implements AbstractFileSystem.List, AbstractFileSystem.Info, AbstractFileSystem.Change, AbstractFileSystem.Attr { /** generated Serialized Version UID */ static final long serialVersionUID = -67233358102597232L; /** the pointer to filesystem */ private XMLFileSystem fs; /** Constructor. * @param fs the filesystem to delegate to */ public Impl (XMLFileSystem fs) { this.fs = fs; } /** * * Scans children for given name * @return array of children`s names * @param name the folder, by name; e.g. <code>top/next/afterthat</code> */ public String[] children (String name) { FileObject fo2name; if (( fo2name = fs.findResource(name) ) == null) return new String[] {}; synchronized (fo2name) { return ((AbstractFolder)fo2name).getChildrenArray(); } } // // Change // /** * Creates new folder named name. * @param name name of folder * @throws IOException if operation fails */ public void createFolder (String name) throws java.io.IOException { throw new IOException (); } /** * Create new data file. * * @param name name of the file * @exception IOException if the file cannot be created (e.g. already exists) */ public void createData (String name) throws IOException { throw new IOException (); } /** Rename a file. * @param oldName old name of the file; fully qualified * @param newName new name of the file; fully qualified * @exception IOException if it could not be renamed */ public void rename(String oldName, String newName) throws IOException { throw new IOException (); } /** * Delete the file. * * @param name name of file * @exception IOException if the file could not be deleted */ public void delete (String name) throws IOException { throw new IOException (); } // Info /** * * Get last modification time. * @param name the file to test * @return the date */ public java.util.Date lastModified(String name) { return fs.lastModified (name); } /** * Test if the file is folder or contains data. * @param name name of the file * @return true if the file is folder, false otherwise */ public boolean folder (String name) { return fs.isFolder(name); } /** * Test whether this file can be written to or not. * @param name the file to test * @return <CODE>true</CODE> if file is read-only */ public boolean readOnly (String name) { return true; } /** Get the MIME type of the file. If filesystem has no special support * for MIME types then can simply return null. FileSystem can register * MIME types for a well-known extensions: FileUtil.setMIMEType(String ext, String mimeType) * or together with filesystem supply some resolvers subclassed from MIMEResolver. * * @param name the file to test * @return the MIME type textual representation (e.g. <code>"text/plain"</code>) * or null if no special support for recognizing MIME is implemented. */ public String mimeType (String name) { return null; } /** * Get the size of the file. * * @param name the file to test * @return the size of the file in bytes or zero if the file does not contain data (does not * exist or is a folder). */ public long size (String name) { if (fs.isFolder(name)) return 0; return fs.getSize (name); } /** * Get input stream. * * @param name the file to test * @return an input stream to read the contents of this file * @exception FileNotFoundException if the file does not exists or is invalid */ public InputStream inputStream (String name) throws java.io.FileNotFoundException { InputStream is = fs.getInputStream(name); if (is == null) throw new java.io.FileNotFoundException (name); return is; } /** * Get output stream. * * @param name the file to test * @return output stream to overwrite the contents of this file * @exception IOException if an error occures (the file is invalid, etc.) */ public OutputStream outputStream (String name) throws java.io.IOException { throw new IOException (); } /** * Does nothing to lock the file. * * @param name name of the file * @throws IOException if cannot be locked */ public void lock (String name) throws IOException { FSException.io ("EXC_CannotLock", name, fs.getDisplayName (), name); // NOI18N } /** * Does nothing to unlock the file. * * @param name name of the file */ public void unlock (String name) { } /** * Does nothing. * * @param name the file to mark */ public void markUnimportant (String name) { } /** Get the file attribute with the specified name. * @param name the file * @param attrName name of the attribute * @return appropriate (serializable) value or <CODE>null</CODE> if the attribute is unset (or could not be properly restored for some reason) */ public Object readAttribute(String name,String attrName) { FileObjRef ref = (FileObjRef)fs.findReference(name); if (ref == null && name.length() == 0 && fs.rootRef != null) ref = fs.rootRef; if (ref == null ) return null; return ref.readAttribute(attrName); } /** Set the file attribute with the specified name. * @param name the file * @param attrName name of the attribute * @param value new value or <code>null</code> to clear the attribute. Must be serializable, although particular filesystems may or may not use serialization to store attribute values. * @exception IOException if the attribute cannot be set. If serialization is used to store it, this may in fact be a subclass such as {@link NotSerializableException}. */ public void writeAttribute(String name,String attrName,Object value) throws IOException { throw new IOException (); } /** Get all file attribute names for the file. * @param name the file * @return enumeration of keys (as strings) */ public Enumeration attributes(String name) { FileObjRef ref = (FileObjRef)fs.findReference(name); if (ref == null && name.length() == 0 && fs.rootRef != null) ref = fs.rootRef; if (ref == null ) return EmptyEnumeration.EMPTY; return ref.attributes(); } /** Called when a file is renamed, to appropriately update its attributes. * @param oldName old name of the file * @param newName new name of the file */ public void renameAttributes(String oldName,String newName) { } /** Called when a file is deleted, to also delete its attributes. * * @param name name of the file */ public void deleteAttributes(String name) { } } /** Strong reference to FileObject. To FileObject may be attached attributes (XMLMapAttr) * and info about if it is folder or not. */ private static class FileObjRef extends WeakReference { private FileObject fo; private Object content; private XMLMapAttr foAttrs; byte isFolder = -1; // URL[] urlContext = null; Object urlContext = null; public FileObjRef (FileObject fo) { super (fo); this.fo = fo; } public boolean isInitialized () { return (isFolder != -1); } public void initialize (ResourceElem res) { content = res.getContent (); XMLMapAttr tmp = res.getAttr (false); if (tmp != null && !tmp.isEmpty()) { foAttrs = tmp; } isFolder = (byte)(res.isFolder ()?1:0); if (content == null) content = res.getURI (); //urlContext = res.getUrlContext (); setUrlContext (res.getUrlContext ()); } public boolean isFolder() { return (isFolder == 1); } public void attacheAttrs (XMLMapAttr attrs) { if ( attrs == null || attrs.isEmpty()) { return; } if (foAttrs == null) foAttrs = new XMLMapAttr (); Iterator it = attrs.entrySet ().iterator (); while (it.hasNext()) { Map.Entry attrEntry = (Map.Entry )it.next(); foAttrs.put (attrEntry.getKey(), attrEntry.getValue()); } } public void setUrlContext (URL[] ctx) { if (ctx.length > 0) { if (ctx.length > 1) { urlContext = ctx; } else { urlContext = ctx[0]; } } //urlContext = ctx; } public Enumeration attributes() { if (foAttrs == null) { return EmptyEnumeration.EMPTY; } else { HashSet s = new HashSet (foAttrs.keySet ()); return Collections.enumeration (s); } } private URL[] getLayers() { if (urlContext == null) return null; if (urlContext instanceof URL[]) return (URL[])urlContext; return new URL[] { (URL)urlContext }; } public Object readAttribute(String attrName) { if (attrName.equals("layers")) { //NOI18N return getLayers(); } if (foAttrs == null) return null; FileObject topFO = (FileObject) MultiFileObject.attrAskedFileObject.get(); FileObject f = topFO == null ? fo : topFO; MultiFileObject.attrAskedFileObject.set(null); try { Object[] objs = new Object[] {f,attrName}; return foAttrs.get(attrName,objs); } finally { MultiFileObject.attrAskedFileObject.set(topFO); } } /** * Get input stream. * * @return an input stream to read the contents of this file * @param context * @param name the file to test * @exception FileNotFoundException if the file does not exists or is invalid */ public InputStream getInputStream(String name) throws java.io.FileNotFoundException { InputStream is = null; if (content == null) return new ByteArrayInputStream (new byte[] {}); if (content instanceof String) { URL absURL = createAbsoluteUrl (name); try { is = absURL.openStream(); } catch (IOException iox) { FileNotFoundException x = new FileNotFoundException (name); ExternalUtil.copyAnnotation (x,iox); throw x; } } if (content instanceof byte[]){ is = new ByteArrayInputStream((byte[])content); } if (is == null) throw new FileNotFoundException (name); return is; } private URL createAbsoluteUrl (String name) throws java.io.FileNotFoundException { if (!(content instanceof String)) return null; String uri = (String)content; try { URL[] uc = getLayers(); URL retVal = (uc == null || uc.length == 0)?new URL (uri): new URL (uc[0],uri); return retVal; } catch(IOException ex) {// neni koser osetreni - RM FileNotFoundException x = new FileNotFoundException (name); ExternalUtil.copyAnnotation (x,ex); throw x; } } public long getSize (String name) { if (content == null) return 0; if (content instanceof byte[]) return ((byte[])content).length; if (content instanceof String) { try { URL absURL = createAbsoluteUrl (name); return absURL.openConnection().getContentLength(); } catch (IOException iex) {} } return 0; } public Date lastModified(String name) { if (content == null || !(content instanceof String)) return new Date (0); URL url; try { url = createAbsoluteUrl (name); } catch (IOException iex) { return new Date (0); } File localFile = getLocalFile (url); if (localFile != null) return new Date (localFile.lastModified()); return timeFromDateHeaderField (url); } /** can return null*/ private File getLocalFile (URL url0) { return getFileFromResourceString (getLocalResource(url0)); } /** can return null*/ private static String getLocalResource(URL url) { if (url == null) return null; if (url.getProtocol().equals("jar")) {// NOI18N URL testURL = null; try { testURL = new URL(url.getFile()); if (testURL.getProtocol().equals("file"))// NOI18N return testURL.getFile(); } catch (MalformedURLException mfx) { return null; } } if (url.getProtocol().equals("file")) {// NOI18N return url.getFile(); } return null; } /** can return null*/ private static File getFileFromResourceString (String localResource) { if (localResource == null) return null; int idx = localResource.indexOf('!'); String fileName = (idx != -1) ? localResource.substring(0,idx) : localResource; File f = new File(fileName); if (f.exists()) return f; return null; } private java.util.Date timeFromDateHeaderField (URL url) { URLConnection urlConn; try { urlConn = url.openConnection (); return new java.util.Date (urlConn.getDate()); } catch (IOException ie) { return new java.util.Date (0); } } } /** Class that can be used to parse XML document (Expects array of ElementHandler clasess). Calls handler methods of ElementHandler clasess. */ static class Handler extends HandlerBase { private static final int FOLDER_CODE = "folder".hashCode();// NOI18N private static final int FILE_CODE = "file".hashCode();// NOI18N private static final int ATTR_CODE = "attr".hashCode();// NOI18N private ResourceElem rootElem; private boolean validate = false; Stack resElemStack = new Stack (); Stack elementStack = new Stack (); URL urlContext; private Map dtdMap; private ResourceElem topRE; private StringBuffer pcdata = new StringBuffer(); Handler(Map dtdMap, ResourceElem rootElem, boolean validate) { this.dtdMap = dtdMap; this.rootElem = rootElem; this.validate = validate; } public void error(SAXParseException exception) throws SAXException { throw exception; } public void warning(SAXParseException exception) throws SAXException { throw exception; } public void fatalError(SAXParseException exception) throws SAXException { throw exception; } public void startElement(String name, AttributeList amap) throws SAXException { int controlCode = name.hashCode(); elementStack.push(name); String foName = amap.getValue("name");// NOI18N if (controlCode == FOLDER_CODE) { if (foName == null) throw new SAXException (NbBundle.getMessage(XMLFileSystem.class,"XML_MisssingAttr"));// NOI18N ResourceElem newRes = new ResourceElem (true, urlContext, null); topRE = topRE.addChild (foName, newRes); resElemStack.push(topRE); return ; } if (controlCode == FILE_CODE) { if (foName == null) throw new SAXException (NbBundle.getMessage(XMLFileSystem.class,"XML_MisssingAttr"));// NOI18N foName = foName.intern(); String uri = null; if (amap.getLength () > 1) uri = amap.getValue("url");// NOI18N ResourceElem newRes = new ResourceElem (false, urlContext, uri); topRE = topRE.addChild (foName, newRes); resElemStack.push(topRE); pcdata.setLength(0); return ; } if (controlCode == ATTR_CODE) { if (foName == null) throw new SAXException (NbBundle.getMessage(XMLFileSystem.class,"XML_MisssingAttr"));// NOI18N int len = amap.getLength (); for (int i = 0; i < len; i++ ) { String key = amap.getName(i); String value = amap.getValue(i); if (XMLMapAttr.Attr.isValid(key) != -1) { XMLMapAttr.Attr attr = new XMLMapAttr.Attr(key,value); XMLMapAttr attrMap = topRE.getAttr (true); Object retVal = attrMap.put(foName,attr); if (retVal != null) attrMap.put(foName,retVal); } } return ; } } public void endElement(String name) throws SAXException { if (elementStack.peek().hashCode() == FILE_CODE && !topRE.isFolder ()) { String string = pcdata.toString().trim(); if (string.length() > 0) { topRE.setContent (string.getBytes()); } pcdata.setLength(0); } int controlCode = name.hashCode(); elementStack.pop(); if (controlCode == FOLDER_CODE || controlCode == FILE_CODE) { resElemStack.pop(); topRE = (ResourceElem)resElemStack.peek(); return ; } } public void characters(char[] ch, int start, int length) throws SAXException { if (elementStack.peek().hashCode() != FILE_CODE) return; if (topRE.isFolder ()) return; pcdata.append(new String(ch,start,length)); } public InputSource resolveEntity(java.lang.String pid,java.lang.String sid) throws SAXException { String publicURL = (String) dtdMap.get (pid); if (publicURL != null) { if (validate) { publicURL = getClass().getClassLoader().getResource( publicURL ).toExternalForm(); return new InputSource(publicURL); } else { return new InputSource(new ByteArrayInputStream(new byte[0])); } } return new InputSource (sid); } public void startDocument() throws org.xml.sax.SAXException { super.startDocument(); resElemStack = new Stack (); resElemStack.push(rootElem); topRE = rootElem; elementStack = new Stack (); elementStack.push("<root>"); // NOI18N } public void endDocument() throws org.xml.sax.SAXException { super.endDocument(); resElemStack.pop (); elementStack.pop (); } } }