All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openide.filesystems.XMLFileSystem Maven / Gradle / Ivy

There is a newer version: RELEASE240
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.openide.filesystems;

import java.beans.PropertyVetoException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.openide.util.Enumerations;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.openide.util.BaseUtilities;
import org.openide.xml.XMLUtil;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;

/** XML-based filesystem.
 * 
 *  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,bundlevalue
 *
 * 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 the following few 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 newvalue CDATA #IMPLIED>
 * < !ATTLIST attr serialvalue CDATA #IMPLIED>
 * < !ATTLIST attr urlvalue CDATA #IMPLIED>
 * < !ATTLIST attr bundlevalue CDATA #IMPLIED> <!-- since version 7.10 -->
 * 
* *

* The methodvalue attribute can be in form of pgk1.pkg2.ClassName.methodName * which should point to existing class with static method usually having no, one * or two arguments. This method does not need to be public or in public class, if * the filesystem has permissions to call the method. The method can take one * of the following signatures: *

 * static Value methodName();
 * static Value methodName(FileObject fo);
 * static Value methodName(FileObject fo, String attrName);
 * static Value methodName(Map attrs); // since 7.0
 * static Value methodName(Map attrs, String attrName); // since 7.0
 * 
* where Value can be any java type. *

* The newvalue should identify (using fully qualified name) a class * with a no-arguments constructor. The constructor does not need to be public, * just the filesystem has to have a permission to invoke it. *

* Existing implementations of filesystems that read XML layers, do not cache * instances returned from newvalue attributes and always return new ones.
* *

* If you are interested just in the Class of an attribute, but * without creating its instance, use fileObject.getAttribute("class:attrName"). * This instructs the XMLFileSystem to scan its XML files for definition of attrName * attribute and guess its class. The guessing is usually easy, * just for methodvalue types, the system needs to use * some kind of heuristic: it locates the appropriate factory method and returns * its return type. This may not be the actual type of the returned object at the end, * but it seems as the best guess without instantiating it. * @author Radek Matous */ public final class XMLFileSystem extends AbstractFileSystem { private static final long serialVersionUID = 28974107313702326L; // // // ... 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 DTD_MAP.put("-//NetBeans//DTD Filesystem 1.2//EN", "org/openide/filesystems/filesystem1_2.dtd"); //NOI18N } /** Url location of XML document */ private URL[] urlsToXml = new URL[] { }; private transient FileObjRef rootRef; /** 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(); if (uri == null) { throw new NullPointerException("Null uri"); // NOI18N } 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(); if (url == null) { throw new NullPointerException("Null url"); // NOI18N } 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 * @deprecated Useless. @Deprecated 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() { 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 void setXmlUrl(URL url, boolean validate) throws IOException, PropertyVetoException { try { beginAtomicAction(); synchronized (this) { setXmlUrls(new URL[] { url }, validate); } } finally { finishAtomicAction(); } } /** Getter of url fields. * @return URLs associated with XMLFileSystem. * @since 1.14 */ public URL[] getXmlUrls() { 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 * @since 1.14 */ public void setXmlUrls(URL[] urls) throws IOException, PropertyVetoException { try { beginAtomicAction(); synchronized (this) { setXmlUrls(urls, false); } } finally { finishAtomicAction(); } } @SuppressWarnings("deprecation") // need to set it for compat private void _setSystemName(String s) throws PropertyVetoException { setSystemName(s); } private synchronized void setXmlUrls(URL[] urls, boolean validate) throws IOException, PropertyVetoException { if (urls == null) { throw new NullPointerException("Null URL list"); // NOI18N } Collection asList = Arrays.asList(urls); if (asList.contains(null)) { throw new NullPointerException("Null URL list member: " + asList); // NOI18N } ResourceElem rootElem; String oldDisplayName = getDisplayName(); if (urls.length == 0) { urlsToXml = urls; refreshChildrenInAtomicAction((AbstractFolder) getRoot(), rootElem = new ResourceElem(true, urls)); // NOI18N rootElem = null; return; } Handler handler = new Handler(DTD_MAP, rootElem = new ResourceElem(true, urls), validate); // NOI18N try { _setSystemName("XML_" + urls[0].toExternalForm().replace('/','-')); // NOI18N } catch (PropertyVetoException pvx) { rootElem = null; throw pvx; } URL act = null; try { XMLReader xp = XMLUtil.createXMLReader(validate, false); xp.setEntityResolver(handler); xp.setContentHandler(handler); xp.setErrorHandler(handler); for (int index = 0; index < urls.length; index++) { act = urls[index]; handler.urlContext = act; String systemId = act.toExternalForm(); xp.parse(systemId); } urlsToXml = urls.clone(); refreshChildrenInAtomicAction((AbstractFolder) getRoot(), rootElem); } catch (IOException iox) { Exceptions.attachMessage(iox, Arrays.toString(urls)); throw iox; } catch (Exception e) { throw (IOException) new IOException(act + ": " + e.toString()).initCause(e); // NOI18N } finally { rootElem = null; } firePropertyChange(PROP_DISPLAY_NAME, oldDisplayName, getDisplayName()); } /** * @return if value of lastModified should be cached */ @Override 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 if (urls[0] == null) { throw new IOException("missing uriId"); // NOI18N } } try { setXmlUrls(urls); } 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. */ @Override 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. */ @Override public void removeNotify() { } @Override protected Reference createReference(T fo) { return new FileObjRef(fo); } private void refreshChildrenInAtomicAction(AbstractFolder fo, ResourceElem resElem) { try { beginAtomicAction(); Collection oldChildren = new HashSet(Collections.list(fo.existingSubFiles(true))); refreshChildren(fo, resElem); Collection newChildren = Collections.list(fo.existingSubFiles(true)); oldChildren.removeAll(newChildren); for (Iterator it = oldChildren.iterator(); it.hasNext();) { AbstractFileObject invalid = (AbstractFileObject)it.next(); if (invalid.validFlag) { invalid.validFlag = false; invalid.fileDeleted0(new FileEvent(invalid)); } } } 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()); int diff = initializeReference(currentRef, children[i]); fo2.lastModified(); if (fo2.isFolder()) { refreshChildren(fo2, children[i]); } else { if ((diff & 0x01) != 0) { fo2.fileChanged0(new FileEvent(fo2)); } else { if ((diff & 0x02) != 0) { fo2.fileAttributeChanged0(new FileAttributeEvent(fo2, null, null, null)); } } } } } /** Initialize a reference with parsed element. * @param currentRef the reference * @param resElem the new element * @return ret&0x01 if content changed, ret&0x02 if attributes changed. */ private int initializeReference(FileObjRef currentRef, ResourceElem resElem) { if (!currentRef.isInitialized()) { currentRef.initialize(resElem); return 0x00; } else { boolean attrDiff = currentRef.attacheAttrs(resElem.getAttr(false)); currentRef.setUrlContext(resElem.getUrlContext()); boolean diff = false; if (resElem.getContent() != null) { diff = !(currentRef.content instanceof byte[]) || !java.util.Arrays.equals((byte[])currentRef.content, resElem.getContent()); currentRef.content = resElem.getContent(); } else if (resElem.getURI() != null) { diff = !resElem.getURI().equals(currentRef.content); currentRef.content = resElem.getURI(); } return (diff ? 0x01 : 0x00) + (attrDiff ? 0x02 : 0x00); } } /** 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 int weight = Integer.MIN_VALUE; // initially unset private java.util.List urlContext = new ArrayList(); private XMLMapAttr foAttrs; private boolean isFolder; private String uri; public ResourceElem(boolean isFolder, URL... urlContext) { this.isFolder = isFolder; this.urlContext.addAll(Arrays.asList(urlContext)); if (isFolder) { children = new ArrayList(); names = new ArrayList(); } } ResourceElem addChild(String name, ResourceElem child) { if (!isFolder) { children = new ArrayList(); names = new ArrayList(); content = null; isFolder = true; } assert name != null && name.indexOf("/") == -1:(child.isFolder ? " mergedContext = new HashSet(); mergedContext.addAll(Arrays.asList(retVal.getUrlContext())); mergedContext.addAll(Arrays.asList(child.getUrlContext())); retVal.setUrlContext(mergedContext); } return retVal; } java.util.List getChildren() { return names; } ResourceElem getChild(String name) { return 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; } void setUrlContext(Collection context) { if (context != null) { urlContext.clear(); urlContext.addAll(context); } } String getURI() { return uri; } void setContent(byte[] content, String uri, int weight) { if (weight > this.weight) { this.weight = weight; this.content = content != null ? content.clone() : null; this.uri = uri; } } 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 */ private 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; } public String[] children(String name) { FileObject fo2name; if ((fo2name = fs.findResource(name)) == null) { return new String[] { }; } synchronized (fo2name) { return ((AbstractFolder) fo2name).getChildrenArray(); } } // // Change // public void createFolder(String name) throws java.io.IOException { throw new IOException(); } public void createData(String name) throws IOException { throw new IOException(); } public void rename(String oldName, String newName) throws IOException { throw new IOException(); } public void delete(String name) throws IOException { throw new IOException(); } // Info public java.util.Date lastModified(String name) { return fs.lastModified(name); } public boolean folder(String name) { return fs.isFolder(name); } public boolean readOnly(String name) { return true; } public String mimeType(String name) { return null; } public long size(String name) { if (fs.isFolder(name)) { return 0; } return fs.getSize(name); } 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; } public OutputStream outputStream(String name) throws java.io.IOException { throw new IOException(); } public void lock(String name) throws IOException { throw new FSException(NbBundle.getMessage(XMLFileSystem.class, "EXC_CannotLock", null, null, name)); } public void unlock(String name) { } public void markUnimportant(String name) { } 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); } public void writeAttribute(String name, String attrName, Object value) throws IOException { throw new IOException(); } 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 Enumerations.empty(); } return ref.attributes(); } public void renameAttributes(String oldName, String newName) { } 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 T fo; private Object content; private XMLMapAttr foAttrs; byte isFolder = -1; Object urlContext = null; public FileObjRef(T 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(); } setUrlContext(res.getUrlContext()); } public boolean isFolder() { return (isFolder == 1); } /** @return true if at lest one attribute changed */ public boolean attacheAttrs(XMLMapAttr attrs) { if ((attrs == null) || attrs.isEmpty()) { return false; } if (foAttrs == null) { foAttrs = new XMLMapAttr(); } Iterator it = attrs.entrySet().iterator(); boolean ch = false; while (it.hasNext()) { Map.Entry attrEntry = (Map.Entry) it.next(); Object prev = foAttrs.put(attrEntry.getKey(), attrEntry.getValue()); ch |= (prev == null && attrEntry.getValue() != null) || !prev.equals(attrEntry.getValue()); } return ch; } public void setUrlContext(URL[] ctx) { if (ctx.length > 0) { if (ctx.length > 1) { urlContext = ctx; } else { urlContext = ctx[0]; } } } public Enumeration attributes() { if (foAttrs == null) { return Enumerations.empty(); } else { Set 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 = 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; IOException ex = null; if (content == null) { return new ByteArrayInputStream(new byte[] { }); } if (content instanceof String) { try { is = createAbsoluteConnection(name).getInputStream(); } catch (IOException x) { ex = x; } } if (content instanceof byte[]) { is = new ByteArrayInputStream((byte[]) content); } if (is == null) { FileNotFoundException fnfe = new FileNotFoundException(name); if (ex != null) { fnfe.initCause(ex); } throw fnfe; } return is; } private URLConnection createAbsoluteConnection(String name) throws FileNotFoundException { URLConnection conn = null; IOException ex = null; if (!(content instanceof String)) { return null; } String uri = (String) content; URL[] uc = getLayers(); if (uc != null) { for (URL u : uc) { try { conn = new URL(u, uri).openConnection(); conn.connect(); break; } catch (IOException iox) { conn = null; ex = iox; } } } if (conn == null) { try { conn = new URL(uri).openConnection(); conn.connect(); } catch (IOException iox) { FileNotFoundException x = new FileNotFoundException(name); ExternalUtil.copyAnnotation(x, iox); throw x; } } return conn; } 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 { URLConnection urlConnection = createAbsoluteConnection(name); try { return urlConnection.getContentLength(); } finally { urlConnection.getInputStream().close(); } } catch (IOException iex) { } } return 0; } private static final Set NETWORK_PROTOCOLS = new HashSet(Arrays.asList("http", "https", "ftp")); // NOI18N /** One item cache to eliminate File.lastModified queries (see #160390). */ private static File lastFile = null; private static Date lastFileDate = null; public Date lastModified(String name) { URL url = null; Date retval = null; if ((content == null) || !(content instanceof String)) { URL[] all = getLayers(); url = (all != null && all.length > 0) ? all[0] : null; } else { try { url = createAbsoluteUrl(name); } catch (IOException iex) { url = null; } } if (url != null) { String protocol = url.getProtocol(); if ("jar".equals(protocol)) {//NOI18N URL tmp = FileUtil.getArchiveFile(url); url = (tmp != null) ? tmp : url; protocol = url.getProtocol(); } if ("file".equals(protocol)) { //NOI18N try { File f = BaseUtilities.toFile(URI.create(url.toExternalForm())); if (!f.equals(lastFile)) { lastFile = f; lastFileDate = new Date(f.lastModified()); } retval = lastFileDate; } catch (IllegalArgumentException x) { Logger.getLogger(XMLFileSystem.class.getName()).log(Level.FINE, "#121777: " + url, x); } } else /* #96928 */ if (!NETWORK_PROTOCOLS.contains(protocol)) { retval = timeFromDateHeaderField(url); } } if (retval == null) { retval = new Date(0); } return retval; } private java.util.Date timeFromDateHeaderField(URL url) { URLConnection urlConn; try { urlConn = url.openConnection(); return new Date(urlConn.getLastModified()); } 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 DefaultHandler { 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(); private int weight; private String uri; Handler(Map dtdMap, ResourceElem rootElem, boolean validate) { this.dtdMap = dtdMap; this.rootElem = rootElem; this.validate = validate; } @Override public void error(SAXParseException exception) throws SAXException { throw exception; } @Override public void warning(SAXParseException exception) throws SAXException { throw exception; } @Override public void fatalError(SAXParseException exception) throws SAXException { throw exception; } @Override public void startElement(String xmluri, String lname, String name, Attributes 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); 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(); uri = null; if (amap.getLength() > 1) { uri = amap.getValue("url"); // NOI18N } ResourceElem newRes = new ResourceElem(false, urlContext); topRE = topRE.addChild(foName, newRes); resElemStack.push(topRE); pcdata.setLength(0); weight = 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.getQName(i); String value = amap.getValue(i); if (XMLMapAttr.Attr.isValid(key) != -1) { XMLMapAttr.Attr attr = XMLMapAttr.createAttributeAndDecode(key, value); XMLMapAttr attrMap = topRE.getAttr(true); Object retVal = attrMap.put(foName, attr); if (retVal != null) { attrMap.put(foName, retVal); } } } if (MultiFileObject.WEIGHT_ATTRIBUTE.equals(amap.getValue("name"))) { String weightS = amap.getValue("intvalue"); if (weightS != null) { try { weight = Integer.parseInt(weightS); } catch (NumberFormatException x) { // ignore here (other places should report it) } } } return; } } @Override public void endElement(String uri, String lname, String name) throws SAXException { if ((elementStack.peek().hashCode() == FILE_CODE) && !topRE.isFolder()) { String string = pcdata.toString().trim(); topRE.setContent(string.length() > 0 ? string.getBytes() : null, this.uri, weight); pcdata.setLength(0); } int controlCode = name.hashCode(); elementStack.pop(); if ((controlCode == FOLDER_CODE) || (controlCode == FILE_CODE)) { resElemStack.pop(); topRE = resElemStack.peek(); return; } } @Override 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)); } @Override public InputSource resolveEntity(String pid, 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); } @Override public void startDocument() throws SAXException { super.startDocument(); resElemStack = new Stack(); resElemStack.push(rootElem); topRE = rootElem; elementStack = new Stack(); elementStack.push(""); // NOI18N } @Override public void endDocument() throws SAXException { super.endDocument(); resElemStack.pop(); elementStack.pop(); } } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy