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-2002 Sun
 * Microsystems, Inc. All Rights Reserved.
 */

package org.netbeans.core.xml;

import org.openide.util.WeakListeners;
import java.io.IOException;
import java.beans.PropertyChangeListener;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.w3c.dom.DocumentType;


import org.openide.filesystems.FileObject;
import org.openide.filesystems.Repository;
import org.openide.loaders.*;
import org.openide.cookies.InstanceCookie;
import org.openide.util.Lookup;
import org.openide.util.lookup.*;
import org.openide.xml.EntityCatalog;
import org.openide.filesystems.FileChangeListener;
import org.openide.filesystems.FileRenameEvent;
import org.openide.filesystems.FileEvent;
import org.openide.filesystems.FileAttributeEvent;
import java.net.URL;
import org.openide.ErrorManager;


/** 
 * Entity resolver which loads entities (typically DTDs) from fixed
 * locations in the system file system, according to public ID.
 * 

* It expects that PUBLIC has at maximum three "//" parts * (standard // vendor // entity name // language). It is basically * converted to "/xml/entities/{vendor}/{entity_name}" resource name. *

* It also attaches Environment according to registrations * at /xml/lookups/ area. There can be registered: * Environment.Provider or deprecated XMLDataObject.Processor * and XMLDataObject.Info instances. *

* All above are core implementation features. * * @author Jaroslav Tulach */ public final class FileEntityResolver extends EntityCatalog implements Environment.Provider { private static final String ENTITY_PREFIX = "/xml/entities"; // NOI18N private static final String LOOKUP_PREFIX = "/xml/lookups"; // NOI18N /** Constructor */ public FileEntityResolver() { } /** Tries to find the entity on system file system. */ public InputSource resolveEntity(String publicID, String systemID) throws IOException, SAXException { if (publicID == null) { return null; } String id = convertPublicId (publicID); StringBuffer sb = new StringBuffer (200); sb.append (ENTITY_PREFIX); sb.append (id); FileObject fo = Repository.getDefault ().getDefaultFileSystem ().findResource (sb.toString ()); if (fo != null) { // fill in InputSource instance InputSource in = new InputSource (fo.getInputStream ()); try { Object myPublicID = fo.getAttribute("hint.originalPublicID"); //NOI18N if (myPublicID instanceof String) { in.setPublicId((String)myPublicID); } URL url = fo.getURL(); in.setSystemId(url.toString()); // we get nasty nbfs: instead nbres: but it is enough } catch (IOException ex) { // do no care just no system id } return in; } else { return null; } } /** A method that tries to find the correct lookup for given XMLDataObject. * @return the lookup */ public Lookup getEnvironment(DataObject obj) { if (obj instanceof XMLDataObject) { XMLDataObject xml = (XMLDataObject)obj; String id = null; try { DocumentType domDTD = xml.getDocument ().getDoctype (); if (domDTD != null) id = domDTD.getPublicId (); } catch (IOException ex) { ErrorManager.getDefault().notify (ex); return null; } catch (org.xml.sax.SAXException ex) { ErrorManager.getDefault().notify (ex); return null; } if (id == null) { return null; } id = convertPublicId (id); return new Lkp (id, xml); } else if (obj instanceof InstanceDataObject) { return getEnvForIDO((InstanceDataObject) obj); } return null; } private Lookup getEnvForIDO(InstanceDataObject ido) { FileEntityResolver.DTDParser parser = new DTDParser(ido.getPrimaryFile()); parser.parse(); String id = parser.getPublicId(); if (id == null) return null; id = convertPublicId (id); return new Lkp (id, ido); } /** A method that extracts a listener from data object. * * @param obj the data object that we are looking for environment of * @param source the obj that provides the environment * @return lookup provided by the obj or null if none has been found */ private static Lookup findLookup (DataObject obj, DataObject source) { if (source == null) { return null; } try { InstanceCookie cookie = (InstanceCookie)source.getCookie (InstanceCookie.class); if (cookie != null) { Object inst = cookie.instanceCreate (); if (inst instanceof Environment.Provider) { return ((Environment.Provider)inst).getEnvironment (obj); } if (!(obj instanceof XMLDataObject)) return null; if (inst instanceof XMLDataObject.Processor) { // convert provider XMLDataObject.Info info = new XMLDataObject.Info (); info.addProcessorClass (inst.getClass ()); inst = info; } if (inst instanceof XMLDataObject.Info) { return createInfoLookup ((XMLDataObject)obj, ((XMLDataObject.Info)inst)); } } } catch (IOException ex) { ErrorManager.getDefault ().notify (ex); } catch (ClassNotFoundException ex) { ErrorManager.getDefault ().notify (ex); } return null; } /** Ugly hack to get to openide hidden functionality. */ private static java.lang.reflect.Method method; private static Lookup createInfoLookup (XMLDataObject obj, XMLDataObject.Info info) { // well, it is a wormhole, but just for default compatibility if (method == null) { try { method = XMLDataObject.class.getDeclaredMethod ("createInfoLookup", new Class[] { // NOI18N XMLDataObject.class, XMLDataObject.Info.class }); method.setAccessible (true); } catch (Exception ex) { ErrorManager.getDefault ().notify (ex); return null; } } try { return (Lookup)method.invoke (null, new Object[] { obj, info }); } catch (Exception ex) { ErrorManager.getDefault ().notify (ex); return null; } } /** Converts the publicID into filesystem friendly name. *

* It expects that PUBLIC has at maximum three "//" parts * (standard // vendor // entity name // language). It is basically * converted to "vendor/entity_name" resource name. * * @see EntityCatalog */ private static String convertPublicId (String publicID) { char[] arr = publicID.toCharArray (); int numberofslashes = 0; int state = 0; int write = 0; OUT: for (int i = 0; i < arr.length; i++) { char ch = arr[i]; switch (state) { case 0: // initial state if (ch == '+' || ch == '-' || ch == 'I' || ch == 'S' || ch == 'O') { // do not write that char continue; } // switch to regular state state = 1; // fallthru case 1: // regular state expecting any character if (ch == '/') { state = 2; if (++numberofslashes == 3) { // last part of the ID, exit break OUT; } arr[write++] = '/'; continue; } break; case 2: // previous character was / if (ch == '/') { // ignore second / and write nothing continue; } state = 1; break; } // write the char into the array if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') { arr[write++] = ch; } else { arr[write++] = '_'; } } return new String (arr, 0, write); } /** Finds a fileobject for given ID. * @param id string id * @param last[0] will be filled with last file object we should listen on * @return file object that should represent it */ private static FileObject findObject (String id, FileObject[] last) { StringBuffer sb = new StringBuffer (200); sb.append (LOOKUP_PREFIX); sb.append (id); int len = sb.length (); // at least for now sb.append (".instance"); // NOI18N FileObject root = Repository.getDefault ().getDefaultFileSystem ().getRoot (); String toSearch1 = sb.toString (); int indx = searchFolder (root, toSearch1, last); if (indx == -1) { // not possible to find folders return null; } FileObject fo = last[0].getFileObject (toSearch1.substring (indx)); if (fo == null) { // try to find a file with xml extension sb.setLength (len); sb.append (".xml"); // NOI18N fo = last[0].getFileObject (sb.toString ().substring (indx)); } return fo; } /** Find last folder for resourceName. * @param fo file object to search from * @param resourceName name of file to find * @param last last[0] will be filled with the last found name * @return position of last / if everything has been searched, or -1 if some files are missing */ private static int searchFolder (FileObject fo, String resourceName, FileObject[] last) { int pos = 0; for (;;) { int next = resourceName.indexOf('/', pos); if (next == -1) { // end of the search last[0] = fo; return pos; } if (next == pos) { pos++; continue; } FileObject nf = fo.getFileObject(resourceName.substring (pos, next)); if (nf == null) { // not found a continuation last[0] = fo; return -1; } // proceed to next one pos = next + 1; fo = nf; } } // internally stops documet parsing when looking for public id private static class StopSaxException extends SAXException { public StopSaxException() { super("STOP"); } //NOI18N } private static final StopSaxException STOP = new StopSaxException(); //////////////////////////////////////////////////////////////////////// // DTDParser //////////////////////////////////////////////////////////////////////// /** resolve the PUBLIC item from the xml header of .settings file */ private static class DTDParser extends org.xml.sax.helpers.DefaultHandler implements org.xml.sax.ext.LexicalHandler { private String publicId = null; private FileObject src; public DTDParser(FileObject src) { this.src = src; } public String getPublicId() { return publicId; } public void parse() { try { org.xml.sax.XMLReader reader = org.openide.xml.XMLUtil.createXMLReader(false, false); reader.setContentHandler(this); reader.setEntityResolver(this); InputSource is = new InputSource(src.getURL().toExternalForm()); is.setByteStream(src.getInputStream()); try { reader.setFeature("http://xml.org/sax/features/validation", false); //NOI18N } catch (SAXException sex) { ErrorManager.getDefault().log(ErrorManager.INFORMATIONAL, "Warning: XML parser does not support validation feature."); //NOI18N } try { reader.setProperty("http://xml.org/sax/properties/lexical-handler", this); //NOI18N } catch (SAXException sex) { ErrorManager.getDefault().log(ErrorManager.EXCEPTION, "Warning: XML parser does not support lexical-handler feature."); //NOI18N } reader.parse(is); } catch (StopSaxException ex) { } catch (Exception ex) { // SAXException, FileNotFoundException, IOException try { // #25082: do not notify an exception if the file comes // from other filesystem than the system filesystem if (src.getFileSystem() == Repository.getDefault().getDefaultFileSystem()) { ErrorManager.getDefault().notify(ErrorManager.INFORMATIONAL, ex); } } catch (org.openide.filesystems.FileStateInvalidException fie) { // ignore } } } public InputSource resolveEntity(String publicId, String systemID) { InputSource ret = new InputSource(new java.io.StringReader("")); // NOI18N ret.setSystemId("StringReader"); //NOI18N return ret; } public void endDTD() throws org.xml.sax.SAXException { throw STOP; } public void startDTD(String name, String publicId, String systemId) throws org.xml.sax.SAXException { this.publicId = publicId; } public void startEntity(String str) throws org.xml.sax.SAXException {} public void endEntity(String str) throws org.xml.sax.SAXException {} public void comment(char[] values, int param, int param2) throws org.xml.sax.SAXException {} public void startCDATA() throws org.xml.sax.SAXException {} public void endCDATA() throws org.xml.sax.SAXException {} } /** A special lookup associated with id. */ private static final class Lkp extends ProxyLookup implements PropertyChangeListener, FileChangeListener { /** converted ID we are associated with */ private String id; /** for this data object we initialized this lookup */ private DataObject xml; /** last file folder we are listening on. Initialized lazily */ private FileObject folder; /** a data object that produces values Initialized lazily */ private DataObject obj; /** @param id the id to work on */ public Lkp (String id, DataObject xml) { super (new Lookup[0]); this.id = id; this.xml = xml; } /** Check whether all necessary values are updated. */ protected void beforeLookup (Template t) { if (folder == null && obj == null) { update (); } } /** Updates current state of the lookup. */ private void update () { FileObject[] last = new FileObject[1]; FileObject fo = findObject (id, last); DataObject o = null; if (fo != null) { try { o = DataObject.find (fo); } catch (org.openide.loaders.DataObjectNotFoundException ex) { ErrorManager.getDefault ().notify (ex); } } if (o == obj) { // the data object is still the same as used to be // Lookup l = findLookup (xml, o); if (o != null && l != null) { // just update the lookups setLookups (new Lookup[] { l }); // and exit return; } } else { // data object changed obj = o; Lookup l = findLookup(xml, o); if (o != null && l != null) { // add listener to changes of the data object o.addPropertyChangeListener ( org.openide.util.WeakListeners.propertyChange (this, o) ); // update the lookups setLookups (new Lookup[] { l }); // and exit return; } } // object is null => there are no lookups setLookups (new Lookup[0]); // and start listening on latest existing folder // if we did not do it yet if (folder != last[0]) { folder = last[0]; last[0].addFileChangeListener ( org.openide.filesystems.FileUtil.weakFileChangeListener (this, last[0]) ); } } /** Fired when a file is deleted. * @param fe the event describing context where action has taken place */ public void fileDeleted(FileEvent fe) { update (); } /** Fired when a new folder is created. This action can only be * listened to in folders containing the created folder up to the root of * file system. * * @param fe the event describing context where action has taken place */ public void fileFolderCreated(FileEvent fe) { update (); } /** Fired when a new file is created. This action can only be * listened in folders containing the created file up to the root of * file system. * * @param fe the event describing context where action has taken place */ public void fileDataCreated(FileEvent fe) { update (); } /** Fired when a file attribute is changed. * @param fe the event describing context where action has taken place, * the name of attribute and the old and new values. */ public void fileAttributeChanged(FileAttributeEvent fe) { } public void propertyChange(java.beans.PropertyChangeEvent ev) { String name = ev.getPropertyName(); if ( DataObject.PROP_COOKIE == name || DataObject.PROP_NAME == name || DataObject.PROP_VALID == name || DataObject.PROP_PRIMARY_FILE == name ) { update (); } } /** Fired when a file is renamed. * @param fe the event describing context where action has taken place * and the original name and extension. */ public void fileRenamed(FileRenameEvent fe) { update (); } /** Fired when a file is changed. * @param fe the event describing context where action has taken place */ public void fileChanged(FileEvent fe) { } } }

... 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.