alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 *                 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.io.*;
import java.lang.ref.*;
import java.util.*;

import org.openide.util.NbBundle;
import org.openide.util.io.NbMarshalledObject;
import org.openide.util.Utilities;

import org.xml.sax.*;

import javax.xml.parsers.*;
import org.openide.xml.XMLUtil;
import org.xml.sax.helpers.XMLReaderAdapter;

/** Implementation of AbstractFileSystem.Attr using a special file
 * in each folder for holding attributes.
 * It needs to hide
 * the file from the rest of system, so it also implements
 * AbstractFileSystem.List to exclude the file from the children list
 * (it can then serve to filter a plain list implementation).
 *
 *Description of format of special file ilustrates best DTD file that is showed in next lines:
 *
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 *
 * @author Jaroslav Tulach
 */
public class DefaultAttributes extends Object
    implements AbstractFileSystem.Attr, AbstractFileSystem.List {
    static final long serialVersionUID=-5801291358293736478L;

    /** File name of special file in each folder where attributes are saved.
     * @deprecated does not handle XML attributes
     */
    public final static String ATTR_NAME = "filesystem"; // NOI18N

    /** Extension of special file in each folder where attributes are saved.
     * @deprecated does not handle XML attributes
     */
    public final static String ATTR_EXT = "attributes"; // NOI18N

    /** Name with extension of special file in each folder where attributes are saved.
     * @deprecated does not handle XML attributes
     */
    public final static String ATTR_NAME_EXT = ATTR_NAME + '.' + ATTR_EXT;
    private final static String ATTR_NAME_EXT_XML = System.getProperty
    ("org.openide.filesystems.DefaultAttributes.ATTR_NAME_EXT_XML", ".nbattrs"); // NOI18N

    /** description of the fs to work on - info about files */
    private AbstractFileSystem.Info info;
    /** description of the fs to work on - work with files */
    private AbstractFileSystem.Change change;

    /** description of the fs to work on - listing of files */
    private AbstractFileSystem.List list;

    /** file name of attributes (default value corresponds to ATTR_NAME_EXT_XML) */
    private String fileName;
    
    /**  readOnlyAttrs is name of virtual attribute. This name of virtual attribute 
     * is shared between classes (and cannot be changed without breaking compatibility): 
     * - org.openide.filesystems.DefaultAttributes
     * - org.openide.loaders.ExecutionSupport
     * - org.openide.loaders.CompilerSupport
     * - org.netbeans.core.ExJarFileSystem
     */
    private final static String READONLY_ATTRIBUTES = "readOnlyAttrs"; //NOI18N

    /** Cache of attributes.
    * For name of folder gives map of maps of attibutes
    * (String, Reference (Table))
    */
    private transient Map cache;

    
    // 
    // 
    // ...
    private static final String PUBLIC_ID = "-//NetBeans//DTD DefaultAttributes 1.0//EN";// NOI18N
    private static final String DTD_PATH = "org/openide/filesystems/attributes.dtd";// NOI18N    

    
    /** Constructor.
    * @param info file object information to use
    * @param change file change hooks to use
    * @param list list to filter (can be null, but then this object cannot work as a list)
    */
    public DefaultAttributes (
        AbstractFileSystem.Info info,
        AbstractFileSystem.Change change,
        AbstractFileSystem.List list
    ) {
        this.info = info;
        this.change = change;
        this.list = list;
        fileName = ATTR_NAME_EXT_XML;        
    }
    
    /** Constructor.
     *      
     * @param info file object information to use
     * @param change file change hooks to use
     * @param list list to filter (can be null, but then this object cannot work as a list)
     * @param fileName
     * @since 4.35  
     */ 
    protected DefaultAttributes (
        AbstractFileSystem.Info info,
        AbstractFileSystem.Change change,
        AbstractFileSystem.List list,
        String fileName
    ) {
        this (info, change, list);
        this.fileName = fileName;
    }
    
    /** Methods to ensure backward compatibility for storing and
    * loading classes.
    */
    private void readObject (ObjectInputStream ois)
    throws ClassNotFoundException, IOException {
        ObjectInputStream.GetField fields = ois.readFields ();
        
        Object o1 = AbstractFileSystem.readImpl ("change", fields); // NOI18N
        Object o2 = AbstractFileSystem.readImpl ("info", fields); // NOI18N
        Object o3 = AbstractFileSystem.readImpl ("list", fields); // NOI18N

        change = (AbstractFileSystem.Change)o1;
        info = (AbstractFileSystem.Info)o2;
        list = (AbstractFileSystem.List)o3;                
    }


    /** Get the children list, filtering out the special attributes file.
    * You must have provided a non-null {@link AbstractFileSystem.List}
    * in the constructor for this to work. If you did not, the rest of the class will work
    * fine, but this method should not be called and this object should not be used
    * as a List implementation.
    *
    * @param f the folder, by name; e.g. top/next/afterthat
    * @return a list of children of the folder, as file.ext (no path)
    */
    public String[] children (String f) {
        String[] arr = list.children (f);
        int lookUpIndex = 0; 

        if (arr == null) {
            return null;
        }

        int size = arr.length;

       
        if (size == 1) {
            // In NB 3.2.x for OpenVMS, we had to use  "_nbattrs." as a attribute file.
            // However, OpenVMS now supports a file name beginning with "."
            // So we now have to copy the existing "_nbattrs." file into ".nbattrs"
            //
            if (Utilities.getOperatingSystem () == Utilities.OS_VMS && arr[0] != null && f != null) {
            	if (arr[0].equalsIgnoreCase ("_nbattrs.")) {
                    try {
                        change.delete(f+"/"+arr[0]); // NOI18N
                    } catch (IOException ioe) {}
                    arr[0] = getFileName();
            	}
            }
            
            if ((getFileName().equals(arr[0]) || ATTR_NAME_EXT_XML.equals(arr[0]) || ATTR_NAME_EXT.equals(arr[0]))) {
                try {
                    change.delete(f+"/"+arr[0]); // NOI18N
                } catch (IOException iox) {}
                return new String[] {};
            }
        }
                
        for (int i = 0; i < size; i++) {
            // In NB 3.2.x for OpenVMS, we had to use  "_nbattrs." as a attribute file.
            // However, OpenVMS now supports a file name beginning with "."
            // So we now have to copy the existing "_nbattrs." file into ".nbattrs"
            //
            if (Utilities.getOperatingSystem () == Utilities.OS_VMS && arr[i] != null && f != null) {
            	if (arr[i].equalsIgnoreCase ("_nbattrs.")) {
                    try {
                        File fp = new File (f+"/"+".nbattrs");
                        if ( ! fp.exists() ) {
                            cache = null;
                            copyVMSAttrFile (f);
                        }
                    } catch (IOException ioe) {}
                    arr[i] = getFileName();
            	}
            }

            String safeNbAttrsCopy  = getFileName()+"~";//NOI18N
            if (getFileName().equals(arr[i]) || ATTR_NAME_EXT.equals (arr[i]) || ATTR_NAME_EXT_XML.equals (arr[i]) || safeNbAttrsCopy.equals (arr[i])) {
                // exclude this index
                arr[i] = null;
                // there can be two files with attributes
                if (++lookUpIndex >= 2)  break;
            }                        
        }
        return arr;
    }

    /** Renames the attribute file for OpenVMS platform.
     *  The method renames "_nbattrs." into ".nbattrs".
     *  We cannot simply use the change.rename method
     *  because of the special property of OpenVMS having to do with
     *  a file name starting with "."
     *
     *  @param f the folder containg the attribute file
     */
    private void copyVMSAttrFile (String f) throws IOException {
        InputStream is = null;
        OutputStream os = null;
        
        try {
            
            change.createData (f+"/"+getFileName());
            is = info.inputStream (f+"/"+"_nbattrs.");
            os = info.outputStream (f+"/"+getFileName());
            
            byte [] buf = new byte[256];
            int readi;
            while ( (readi=is.read(buf,0,256)) >= 0x0 ) {
                os.write (buf,0,readi);
            }
           
            is.close ();
            //change.delete (f+"/"+"_nbattrs.");
            is = null;
        } catch (IOException ie) {
        } finally {
            if (is != null)
                is.close ();
            if (os != null)
                os.close ();
        }
    }

    // JST: Description
    //
    //
    // The class should be written in such a way that the access to disk is
    // synchronized (this). But during the access nobody is allowed to
    // perform serialization and deserialization
    // of unknown objects, so all objects should be wrapped into NbMarshalledObject
    // serialized or in reverse target NbMarshalledObject should be deserialized
    // and then not holding the lock the object obtained from it by a call to
    // marshall.get ().
    //
    // JST: Got it?


    /* Get the file attribute with the specified name.
    * @param name the file
    * @param attrName name of the attribute
    * @return appropriate (serializable) value or null if the attribute is unset (or could not be properly restored for some reason)
    */
    public Object readAttribute(String name, String attrName) {
        Table t;                        
        String[] arr = new String[2];
        split (name, arr);
        
        /** At the momement substitutes lack of API */
        if (attrName.equals (READONLY_ATTRIBUTES)) 
            return info.readOnly(arr[0]) ? Boolean.TRUE : Boolean.FALSE;
                
        synchronized (this) {
            // synchronized so only one table for each folder
            // can exist
            t = loadTable (arr[0]);
        }
        // JST:
        // had to split the code to do getAttr out of synchronized block
        // because the attribute can be serialized FileObject and
        // so the code returns back to FileSystem (that is usually synchronized)
        //
        // this leads to deadlocks between FS & DefaultAttributes implementation
        //
        // I do not know if the table should not be somehow synchronized,
        // but it seems ok.
        return t.getAttr (arr[1], attrName);
    }

    /* Set the file attribute with the specified name.
    * @param name the file
    * @param attrName name of the attribute
    * @param value new value or null 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 {
        // create object that should be serialized
        //NbMarshalledObject marshall = new NbMarshalledObject (value);
        int objType;

        String[] arr = new String[2];
        split (name, arr);

        for (;;) {
            int version;
            Table t;
            synchronized (this) {
                t = loadTable (arr[0]);
                version = t.version;
            }

            // Tests if the attribute is changing
            Object prev = t.getAttr(arr[1], attrName);
                
            if (prev == value /*|| (value != null && value.equals (prev))*/) {
                return;
            }

            synchronized (this) {
                Table t2 = loadTable (arr[0]);
                if (t == t2 && version == t2.version) {
                    // no modification between reading of the value =>
                    // save!
                    //Class cls = value.getClass();                    
                    if (value == null) {
                        t.setAttr (arr[1], attrName, null); // clear the attribute
                    }else {
                        if ((objType = XMLMapAttr.Attr.distinguishObject (value)) == XMLMapAttr.Attr.isValid("SERIALVALUE") ) { // NOI18N
                            t.setAttr (arr[1], attrName, value);//change value instead of marshall
                        }
                        else {
                            t.setAttr (arr[1], attrName, XMLMapAttr.createAttribute (objType,value.toString()) );
                        }
                    }
                    saveTable (arr[0], t);
                    // ok, saved
                    return;
                }
            }
            // otherwise try it again
        }
    }

    /* Get all file attribute names for the file.
    * @param name the file
    * @return enumeration of keys (as strings)
    */
    public synchronized Enumeration attributes(String name) {
        String[] arr = new String[2];
        split (name, arr);

        Table t = loadTable (arr[0]);
        return t.attrs (arr[1]);
    }

    /* Called when a file is renamed, to appropriatelly update its attributes.
    * 

* @param oldName old name of the file * @param newName new name of the file */ public synchronized void renameAttributes (String oldName, String newName) { try { String[] arr = new String[2]; split (oldName, arr); Table t = loadTable (arr[0]); Map v = (Map) t.remove (arr[1]); // System.out.println ("ARg[0] = " + arr[0] + " arr[1] = " + arr[1] + " value: " + v); // NOI18N if (v == null) { // no attrs no change return; } split (newName, arr); // Remove transient attributes: Iterator it = v.entrySet ().iterator (); while (it.hasNext ()) { Map.Entry pair = (Map.Entry) it.next (); if (FileUtil.transientAttributes.contains (pair.getKey ())) it.remove (); } t.put (arr[1], v); // System.out.println ("xyz[0] = " + arr[0] + " xyz[1] = " + arr[1] + " value: " + v); // NOI18N saveTable (arr[0], t); } catch (IOException e) { ExternalUtil.exception (e); } } /* Called when a file is deleted to also delete its attributes. * * @param name name of the file */ public synchronized void deleteAttributes (String name) { try { String[] arr = new String[2]; split (name, arr); Table t = loadTable (arr[0]); if (t.remove (arr[1]) != null) { // if there is a change saveTable (arr[0], t); } } catch (IOException e) { ExternalUtil.exception (e); } } /** Getter for the cache. */ private Map getCache () { if (cache == null) { cache = new HashMap (31); } return cache; } /** Splits name of a file to name of folder and to name of the file. * @param name of file * @param arr arr[0] will hold name of folder and arr[1] name of the file */ private static void split (String name, String[] arr) { int i = name.lastIndexOf ('/'); if (i == -1) { arr[0] = ""; // NOI18N arr[1] = name; return; } // folder name arr[0] = name.substring (0, i); // increase the i to be beyond the length if (++i == name.length ()) { arr[1] = ""; // NOI18N } else { // split it arr[1] = name.substring (i); } } /** Save attributes. * @param name name of folder to save attributes for * @param map map to save */ private void saveTable(String name, Table map) throws IOException { String fullName = (name.length()==0 ? "": (name + '/')) + getFileName(); // NOI18N /** OpenVMS now supports various special characters including "~"*/ String safeName = fullName+"~"; // NOI18N if (info.folder (fullName)) { if (map.size () == 0) { // ok no need to delete return; } // find parent change.createData (fullName); } else { if (map.size() == 0) { change.delete (fullName); return; } } PrintWriter pw = null; IOException ioexc = null; try { pw = new PrintWriter(new OutputStreamWriter (new BufferedOutputStream(info.outputStream (safeName)),"UTF8")); // NOI18N map.writeToXML(pw); pw.flush(); } catch (IOException iex) { ioexc = iex; } finally { if (pw != null) pw.close(); if (ioexc != null) { this.change.delete (safeName); throw ioexc; } else { try { this.change.delete (fullName); } catch (IOException iex2) { /** if delete fails, then also rename fails and exception will * be fired */ } this.change.rename(safeName,fullName); } } } /** Load attributes from cache or * from disk. * @param name of folder to load data from */ private Table loadTable(String name) { //throws IOException { Reference r = (Reference)getCache ().get (name); if (r != null) { Table m = (Table)r.get (); if (m != null) { return m; } } // have to load new table Table t = load (name); t.attach (name, this); getCache ().put (name, new SoftReference (t)); return t; } /** Loads the table. Does no initialization. */ private Table load (String name) { String acceptNames[] = {(name.length()==0 ? "": (name + '/')) + getFileName(),// NOI18N (name.length()==0 ? "": (name + '/')) + ATTR_NAME_EXT}; // NOI18N for (int i = 0; i < acceptNames.length;i++) { if (info.size (acceptNames[i]) > 0L) { try { InputStream fis = info.inputStream (acceptNames[i]); try { return loadTable (fis,acceptNames[i]); } finally { try { fis.close (); } catch (IOException e) { // ignore--who cares? } } } catch (FileNotFoundException ex) { ExternalUtil.exception(ex); } } } return new Table (); } /** Loads the Table of extended attributes for a input stream from binary serialized file or from XML. * @param is input stream * @param folderName name of file for better error message * @return the attributes table for this input stream */ static Table loadTable (InputStream is,String folderName) { Table retTable = new Table (); PushbackInputStream pbStream = null; boolean isSerialized = false; try { if (folderName.endsWith (ATTR_NAME_EXT)) { pbStream = new PushbackInputStream (is, 4 );//is.available() isSerialized = isSerialized (pbStream); } if (isSerialized && pbStream != null) { BufferedInputStream fis = new BufferedInputStream(pbStream); ObjectInputStream ois = new org.openide.util.io.NbObjectInputStream (fis); Object o = ois.readObject(); if (o instanceof Table) { return (Table)o; } } else { BufferedInputStream bis = (pbStream != null) ? new BufferedInputStream(pbStream) : new BufferedInputStream(is); retTable.readFromXML(bis, false); return retTable; } } catch (Exception e) { // [PENDING] use multi-arg getMessage (MessageFormat-style) properly here: IOException summaryEx = new IOException (NbBundle.getMessage(DefaultAttributes.class,"EXC_DefAttrReadErr")+": "+folderName); ExternalUtil.copyAnnotation (summaryEx, e); ExternalUtil.exception (summaryEx); } // create empty table, what else return new Table (); } /** Tests whether InputStream contains serialized data * @param pbStream is pushback input stream; tests 4 bytes and then returns them back * @return true if the file has serialized form */ static private final boolean isSerialized (PushbackInputStream pbStream) throws IOException{ int serialPattern [] = {'\u00AC','\u00ED','\u0000','\u0005'};//NOI18N patern for serialized objects byte checkedArray[] = new byte[serialPattern.length]; int unsignedConv = 0; pbStream.read(checkedArray,0,checkedArray.length); pbStream.unread(checkedArray); for (int i = 0; i < checkedArray.length;i++) { unsignedConv = (checkedArray[i] < 0) ? checkedArray[i]+256 : checkedArray[i]; if (serialPattern[i] != unsignedConv) return false; } return true; } /** Remove from cache */ synchronized void removeTable (String name) { getCache ().remove (name); } // // FileUtil.extractJar methods // /** Does the name seems like file with extended attributes? * @param name the name * @return true if so */ static boolean acceptName (String name) { return (name.endsWith (ATTR_NAME_EXT) || name.endsWith (ATTR_NAME_EXT_XML)); } private String getFileName() { if (fileName == null) { fileName = ATTR_NAME_EXT_XML; } return fileName; } /** Table that hold mapping between files and attributes. * Hold mapping of type (String, Map (String, Object)) */ final static class Table extends HashMap implements Externalizable { static final long serialVersionUID = 2353458763249746934L; /** name of folder we belong to */ private transient String name; /** attributes to belong to */ private transient DefaultAttributes attrs; /** version counting */ private transient int version = 0; /** Constructor */ public Table () { super (11); } /** Attaches to file in attributes */ public void attach (String name, DefaultAttributes attrs) { this.name = name; this.attrs = attrs; } /** Remove itself from the cache if finalized. */ protected void finalize () { // System.out.println ("Finalizing table for: " + name); // NOI18N attrs.removeTable (name); } /** For given file finds requested attribute. * @param fileName name of the file * @param attrName name of the attribute * @return attribute or null (if not found) */ public Object getAttr (String fileName, String attrName) { XMLMapAttr m = (XMLMapAttr)get (fileName); if (m != null) { Object o = null; try { o = m.getAttribute (attrName); } catch (Exception e) { ExternalUtil.annotate (e, "fileName = "+fileName); //NOI18N ExternalUtil.exception (e); } if (o == null) return null; if (!(o instanceof NbMarshalledObject)) return o; NbMarshalledObject mo = (NbMarshalledObject) o; try { return mo == null ? null : mo.get (); } catch (IOException e) { ExternalUtil.log("Cannot load attribute " + attrName + " from " + fileName); // NOI18N ExternalUtil.exception (e); } catch (ClassNotFoundException e) { ExternalUtil.log("Cannot load attribute " + attrName + " from " + fileName); // NOI18N ExternalUtil.exception (e); } } return null; } /** Sets an marshaled attribute to the table. */ final void setMarshalledAttr ( String fileName, String attrName, NbMarshalledObject obj ) { setAttr (fileName, attrName, obj); } /** * Sets an attribute to the table. * New added - for Sandwich project (XML format instead of serialization) . * @param fileName - name of file * @param attrName - name of attribute * @param obj - attribute */ final void setAttr (String fileName, String attrName, Object obj) { XMLMapAttr m = (XMLMapAttr)get (fileName); if (m == null) { m = new XMLMapAttr();//HashMap (7);//XMLMapAttr(); put (fileName, m); } m.put (attrName, obj, false); if (obj == null && m.size() == 1) { remove(fileName); } // increments the version version++; } /** Enum of attributes for one file. */ public Enumeration attrs (String fileName) { Map m = (Map)get (fileName); if (m == null) { return org.openide.util.Enumerations.empty(); } else { HashSet s = new HashSet (m.keySet ()); return Collections.enumeration (s); } } /** * Parses element: * @return new instance of subclass (anonymous class)of ElementHandler */ private ElementHandler parseFirstLevel() { ElementHandler elemService = new ElementHandler() { private final String[] ELM_KEYS = {"ATTRIBUTES"};// NOI18N private final String[] MANDAT_ATTR_KEYS = {"VERSION"};// NOI18N public void internalStartElement(String elemName, HashMap mapMandatory,HashMap mapAllowed) throws SAXException { // later can check version } protected String[] getKeys() {return ELM_KEYS;} protected String[] getMandatoryAttrs() {return MANDAT_ATTR_KEYS;} }; return elemService; } /** * Parses element: * @param fileName is parsed from XML * @return new instance of subclass (anonymous class)of ElementHandler */ private ElementHandler parseSecondLevel(final StringBuffer fileName) { ElementHandler elemService = new ElementHandler() { private final String[] ELM_KEYS = {"FILEOBJECT"};// NOI18N private final String[] MANDAT_ATTR_KEYS = {"NAME"};// NOI18N public void internalStartElement(String elemName, HashMap mapMandatory,HashMap mapAllowed) throws SAXException { String temp; fileName.delete(0,fileName.length()); temp = (String)mapMandatory.get("NAME");// NOI18N if (temp == null) temp = (String)mapMandatory.get("name");// NOI18N if (temp != null) fileName.append(temp); } public void endElement(String elementName) throws SAXException {} protected String[] getKeys() {return ELM_KEYS;} protected String[] getMandatoryAttrs() {return MANDAT_ATTR_KEYS;} }; return elemService; } /** * Parses element: * @param fileName is name of fileobject, which is assigned to attribute * @return new instance of subclass (anonymous class)of ElementHandler */ private ElementHandler parseThirdLevel(final StringBuffer fileName) { ElementHandler elemService = new ElementHandler() { private final String[] ELM_KEYS = {"ATTR"};// NOI18N private final String[] MANDAT_ATTR_KEYS = {"NAME"};// NOI18N public void internalStartElement(String elemName, HashMap mapMandatory,HashMap mapAllowed) throws SAXException { String attrName; if (mapAllowed.isEmpty()) return; attrName = (String)mapMandatory.get("NAME");// NOI18N if (attrName == null) attrName = (String)mapMandatory.get("name");// NOI18N if (attrName == null) return; Iterator it = mapAllowed.entrySet ().iterator (); while (it.hasNext ()) { Map.Entry pair = (Map.Entry) it.next (); if (XMLMapAttr.Attr.isValid((String)pair.getKey()) != -1) { XMLMapAttr.Attr attr = XMLMapAttr.createAttributeAndDecode((String)pair.getKey(),(String)pair.getValue()); setAttr (fileName.toString(), attrName,attr); } } } protected String[] getKeys() {return ELM_KEYS;} protected String[] getMandatoryAttrs() {return MANDAT_ATTR_KEYS;} protected String[] getAllowedAttrs() {return XMLMapAttr.Attr.getAttrTypes ();} //ALLOWED_ATTR_KEYS }; return elemService; } /** Writes itself to XML * @param pw is PrintWriter */ public void writeToXML (PrintWriter pw) /*throws IOException */{ // list of names Iterator it = new TreeSet(keySet()).iterator(); XMLMapAttr.writeHeading(pw); while (it.hasNext ()) { String file = (String)it.next (); XMLMapAttr attr = (XMLMapAttr)get (file); if (attr != null && !attr.isEmpty ()) { attr.write(pw, file, " ");// NOI18N } } XMLMapAttr.writeEnding(pw); } /** * Reads itself from XML format * New added - for Sandwich project (XML format instead of serialization) . * @param is input stream (which is parsed) * @return Table */ public void readFromXML (InputStream is, boolean validate) throws SAXException { StringBuffer fileName = new StringBuffer(); ElementHandler[] elmKeyService = {parseFirstLevel(),parseSecondLevel(fileName),parseThirdLevel(fileName)};// String dtd = getClass().getClassLoader().getResource( DTD_PATH ).toExternalForm(); InnerParser parser = new InnerParser(PUBLIC_ID, dtd, elmKeyService); try { parser.parseXML(is, validate); } catch(Exception ioe) { throw (SAXException)ExternalUtil.copyAnnotation (new SAXException (NbBundle.getMessage(DefaultAttributes.class,"EXC_DefAttrReadErr")),ioe); } catch (FactoryConfigurationError fce) { // ??? see http://openide.netbeans.org/servlets/ReadMsg?msgId=340881&listName=dev throw (SAXException)ExternalUtil.copyAnnotation(new SAXException(NbBundle.getMessage(DefaultAttributes.class, "EXC_DefAttrReadErr")), fce); } } /** Writes external. * @param oo * @throws IOException */ public void writeExternal (ObjectOutput oo) throws IOException { // list of names Iterator it = keySet ().iterator (); while (it.hasNext ()) { String file = (String)it.next (); Map attr = (Map)get (file); if (attr != null && !attr.isEmpty ()) { oo.writeObject (file); Iterator entries = attr.entrySet ().iterator (); while (entries.hasNext ()) { Map.Entry entry = (Map.Entry)entries.next (); String key = (String)entry.getKey (); Object value = entry.getValue (); if (key != null && value != null) { oo.writeObject (key); oo.writeObject (value); } } oo.writeObject (null); } } oo.writeObject (null); } /** Reads external. */ public void readExternal (ObjectInput oi) throws IOException, ClassNotFoundException { for (;;) { String file = (String)oi.readObject (); if (file == null) break; for (;;) { String attr = (String)oi.readObject (); if (attr == null) break; Object o = oi.readObject (); // backward compatibility if (o instanceof java.rmi.MarshalledObject) { o = ((java.rmi.MarshalledObject)o).get (); o = new NbMarshalledObject (o); } // end of backward compatibility if (o instanceof NbMarshalledObject) { setAttr (file, attr, o); } } } } } /** Element handler should be used as superclass for future classes. These future classes should be passed * to constructor of InnerParser as Array. (ElementHandler[]). Each subclass of ElementHandler is responsible for * processing one or more elements in XML file. * Each subclass of ElementHandler should overwrite one or more of these methods: * - protected String[] getKeys() * - protected String[] getMandatoryAttrs() * - protected String[] getAllowedAttrs() * - protected void endElement(String name) throws SAXException {} * - protected void characters(char[] ch, int start, int length) throws SAXException {} * - protected void internalStartElement(String elemName, HashMap mapMandatory,HashMap mapAllowed) throws SAXException {} */ static abstract class ElementHandler { private int mandatAttrCount; public void startElement(String elemName, AttributeList attrList) throws SAXException { HashMap mapAllowed =new HashMap(); HashMap mapMandatory =new HashMap(); if ( checkAttributes(attrList,mapMandatory,mapAllowed) == false ) { throw new SAXException (NbBundle.getMessage(DefaultAttributes.class,"XML_InaccurateParam")+": "+elemName);// NOI18N } internalStartElement(elemName, mapMandatory,mapAllowed); } /** Inner parser calls this method to notify this class that start element was parsed () * @param elemName name of element * @param mapMandatory map(String attributeName,String attributeValue) which holds pairs attributeName and attributeValue, which are mandatory for this element * @param mapAllowed map(String attributeName,String attributeValue) which holds pairs attributeName and attributeValue, which are optional for this element * @throws SAXException */ protected void internalStartElement(String elemName, HashMap mapMandatory,HashMap mapAllowed) throws SAXException {} /** Inner parser calls this method to notify this class that there is content between start element and end element * @param ch[] array of characters found between start and end element * @param start is start position in ch[] * @param length is length of content * @throws SAXException */ protected void characters(char[] ch, int start, int length) throws SAXException {} /** Inner parser calls this method to notify this class that end element was parsed * @param elemName name of element * @throws SAXException */ protected void endElement(String elemName) throws SAXException {} private static final String[] EMPTY = {}; /** @return names of elements which this class can process */ protected String[] getKeys() { return EMPTY; } /** @return names of attributes which are checked and are mandatory */ protected String[] getMandatoryAttrs() { return getKeys(); } /** @return names of attributes which are allowed, are expected, but are not mandatory */ protected String[] getAllowedAttrs() { return EMPTY; } private int isMyTag(String name) {return isInArray(name,getKeys());} private int isAllowedAttr(String name) {return isInArray(name,getAllowedAttrs());} private boolean isMandatOK() {return (mandatAttrCount == getMandatoryAttrs().length);} private int isMandatoryAttr(String name) { int retValue = isInArray(name,getMandatoryAttrs()); if ( retValue != -1 ) mandatAttrCount++; return retValue; } private int isInArray(String name,String[] arr) { if (arr == null || name == null) return -1; String correctStr = name.trim(); for( int i = 0; i < arr.length; i++) { if (correctStr.equalsIgnoreCase(arr[i]) == true) return i; } return -1; } private boolean checkAttributes(AttributeList attrList,HashMap mapMandatory,HashMap mapAllowed) { String temp; mandatAttrCount = 0; if (attrList == null) return false; for (int i = 0; i < attrList.getLength(); i++) { if (isMandatoryAttr(attrList.getName(i)) != -1) { temp = attrList.getName(i).toUpperCase(); mapMandatory.put(temp,attrList.getValue(i)); continue; } if ( isAllowedAttr(attrList.getName(i)) != -1) { temp = attrList.getName(i).toUpperCase(); mapAllowed.put(temp,attrList.getValue(i)); continue; } } return isMandatOK(); } } /** Class that can be used to parse XML document (Expects array of ElementHandler clasess). Calls handler methods of ElementHandler clasess. */ static class InnerParser extends HandlerBase { private ElementHandler[] elmKeyService;// = {fileSystemElement(attrStack),folderElement(attrStack),fileElement(attrStack),attrElement(attrStack)}; private String tagInProcess = ""; // NOI18N private String publicId; private String publicURL; InnerParser(String publicId, String publicURL, ElementHandler[] elmKeyService) { this.elmKeyService = elmKeyService; this.publicId = publicId; this.publicURL = publicURL; } /** Starts parsing document, that can be localized by means of uri parameter * @param validate * @param uri adress of document, that will be parsed * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public void parseXML(String uri, boolean validate) throws IOException, SAXException, ParserConfigurationException, FactoryConfigurationError { Parser parser = getParser(validate); parser.parse(uri); } /** Starts parsing document - if you have document`s InputStream * @param validate * @param is document`s InputStream * @throws ParserConfigurationException * @throws IOException * @throws SAXException */ public void parseXML(InputStream is, boolean validate) throws IOException, SAXException, ParserConfigurationException, FactoryConfigurationError { InputSource iSource = new InputSource(is); Parser parser = getParser(validate); parser.parse(iSource); } private Parser getParser(boolean validate) throws SAXException, ParserConfigurationException, FactoryConfigurationError { Parser parser; parser = new XMLReaderAdapter (XMLUtil.createXMLReader(validate)); // create document handler and register it //parser.setEntityResolver(entityRes); parser.setEntityResolver(this); parser.setDocumentHandler(this);//before new InnerParser() - now this parser.setErrorHandler(this); return parser; } 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 startDocument() throws SAXException {} public void endDocument() throws SAXException {} public void startElement(String name, AttributeList amap) throws SAXException { tagInProcess = name = name.trim(); for (int i = 0; i < elmKeyService.length;i++) { if ( elmKeyService[i].isMyTag(name) != -1) { elmKeyService[i].startElement(name,amap); return; } } throw new SAXException (NbBundle.getMessage(DefaultAttributes.class,"XML_UnknownElement")+" "+name);// NOI18N } public void endElement(String name) throws SAXException { for (int i = 0; i < elmKeyService.length;i++) { if ( elmKeyService[i].isMyTag(name.trim()) != -1) { elmKeyService[i].endElement(name.trim()); return; } } throw new SAXException (NbBundle.getMessage(DefaultAttributes.class,"XML_UnknownElement")+" "+name);// NOI18N } public void characters(char[] ch, int start, int length) throws SAXException { for (int i = 0; i < elmKeyService.length;i++) { if ( elmKeyService[i].isMyTag(tagInProcess) != -1) { elmKeyService[i].characters(ch,start,length); return; } } throw new SAXException (NbBundle.getMessage(DefaultAttributes.class,"XML_UnknownElement")+" "+tagInProcess);// NOI18N } public InputSource resolveEntity(java.lang.String pid,java.lang.String sid) throws SAXException { if (pid != null && pid.equals(publicId)) return new InputSource (publicURL); return new InputSource (sid); } } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.