/* (C) 2001-2002, DIUF, http://www.unifr.ch/diuf
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package iiuf.xmillum;
import iiuf.dom.DOMUtils;
import iiuf.dom.DOMUtilsNS;
import iiuf.dom.ElementList;
import iiuf.util.Queue;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.MalformedURLException;
import java.util.LinkedList;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Templates;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.dom.DOMResult;
import org.w3c.dom.Document;
import org.w3c.dom.DocumentFragment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.InputSource;
/**
* IllumDocument
*
* Manages all data related to a document presented in xmillum.
*
* @author $Author: ohitz $
* @version $Revision: 1.1 $
*/
public class IllumDocument {
public final static String XMI_DOCUMENT = "document";
public final static String XMI_LAYER = "layer";
public final static String XMI_TOOL = "tool";
public final static String XMI_HANDLER = "handler";
public final static String XMI_DISPLAYABLE = "object";
public final static String XMI_FLAG = "flag";
public final static String XMI_STYLE = "style";
public final static String XMI_CLASSPATH = "classpath";
public final static String XMI_NSURI = "http://www-iiuf.unifr.ch/~hitz/xmillum";
protected BrowserContext context;
protected URL baseURL;
protected Element sourceDocument;
protected Element stylesheetDocument;
protected Document internalDocument;
protected Templates stylesheetCompiled;
DocumentBuilder documentBuilder;
/***
* Creates a new IllumDocument.
*
* @param context BrowserContext this document is attached to.
*/
public IllumDocument(BrowserContext context) {
this.context = context;
try {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
documentBuilder = dbf.newDocumentBuilder();
} catch (ParserConfigurationException e) {
e.printStackTrace();
}
}
/**
* Checks if a source document is loaded.
*
* @return True if a source document is loaded, false otherwise.
*/
public boolean hasSource() {
return sourceDocument != null;
}
/**
* Checks if a stylesheet is loaded.
*
* @return True if a stylesheet is loaded, false otherwise.
*/
public boolean hasStylesheet() {
return stylesheetCompiled != null;
}
/**
* Sets the source document.
*
* @param e Root element of the source document.
*/
public void setSourceDocument(Element e) throws IllumException {
context.elementTagger = (e != null) ? new ElementTagger(e, "tmp:refvalue") : null;
sourceDocument = e;
}
/**
* Strips off the "tmp" attributes from the source document and
* returns it.
*
* @return The source document, without any "tmp" attributes.
*/
public Element getStrippedOriginalDocument() {
Element s = getSourceDocument();
DOMUtils.removeAttributesFromDescendants(s, "tmp");
try {
setSourceDocument(null);
} catch (IllumException e) {
}
return s;
}
/**
* Returns a copy of the source document and strips off all "tmp"
* attributes.
*
* @return Copy of the source document.
*/
public Element getStrippedOriginalDocumentCopy() {
Element root = (Element) sourceDocument.cloneNode(true);
DOMUtils.removeAttributesFromDescendants(root, "tmp");
return root;
}
/**
* Returns the source document
*
* @return Source document.
*/
public Element getSourceDocument() {
return sourceDocument;
}
/**
* Sets the stylesheet.
*
* @param e Root element of the stylesheet.
*/
public void setStylesheetDocument(Element e) throws IllumException {
try {
stylesheetDocument = e;
stylesheetCompiled = null;
if (e != null) {
TransformerFactory tFactory = TransformerFactory.newInstance();
stylesheetCompiled = tFactory.newTemplates(new DOMSource(e.getOwnerDocument()));
}
} catch (TransformerConfigurationException ex) {
throw new IllumException(ex);
} catch (TransformerFactoryConfigurationError ex) {
throw new IllumException(ex);
}
}
/**
* Returns the stylesheet document.
*
* @return Root element of the stylesheet.
*/
public Element getStylesheetDocument() {
return stylesheetDocument;
}
/**
* Returns the internal document.
*
* @return Internal document
*/
public Document getInternalDocument() {
return internalDocument;
}
/**
* Sets the base URL used for relative accesses.
*
* @param base Base URL for relative used for relative accesses.
*/
private void setBaseURL(URL base) {
baseURL = base;
}
/**
* Returns the base URL.
*
* @return Base URL.
*/
public URL getBaseURL() {
return baseURL;
}
/**
* Loads the source document.
*
* @param source Source document to load.
*/
public void loadSourceDocument(IllumSource source) throws IllumException {
setBaseURL(source.getBaseURL());
setSourceDocument(source.getData());
}
/**
* Loads the stylesheet document.
*
* @param url URL of the stylesheet to load.
*/
public void loadStylesheet(URL url) throws IllumException {
try {
InputSource isource = new InputSource(url.openStream());
Element ss = documentBuilder.parse(isource).getDocumentElement();
setStylesheetDocument(ss);
ssURL = url;
} catch (IOException e) {
throw new IllumException(e);
} catch (SAXException e) {
throw new IllumException(e);
}
}
URL ssURL;
/**
* Transforms the source document using the stylesheet.
*/
public void transform() throws IllumException {
try {
internalDocument = documentBuilder.newDocument();
Transformer transformer = stylesheetCompiled.newTransformer();
if (baseURL != null) {
transformer.setParameter("xmillum.baseurl", baseURL.toString());
}
transformer.transform(new DOMSource(sourceDocument), new DOMResult(internalDocument));
} catch (TransformerConfigurationException e) {
internalDocument = null;
throw new IllumException(e);
} catch (TransformerException e) {
internalDocument = null;
throw new IllumException(e);
}
}
public ClassLoader getClassLoader() {
try {
if (internalDocument.getDocumentElement().hasAttribute(XMI_CLASSPATH)) {
URL u = new URL(ssURL, internalDocument.getDocumentElement().getAttribute(XMI_CLASSPATH));
return new URLClassLoader(new URL[] { u });
}
} catch (MalformedURLException e) {
e.printStackTrace();
}
return ClassLoader.getSystemClassLoader();
}
public NodeList getHandlers() {
return DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_HANDLER);
}
public NodeList getDisplayables() {
return DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_DISPLAYABLE);
}
public NodeList getFlags() {
return DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_FLAG);
}
public NodeList getStyles() {
return DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_STYLE);
}
/**
* Returns the names of the layers defined by the stylesheet.
*
* @return List of layer names
*/
public String[] getLayerNames() {
if (internalDocument == null) {
return new String[0];
}
NodeList layers = DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_LAYER);
String[] l = new String[layers.getLength()];
for (int i = 0; i < layers.getLength(); i++) {
l[i] = ((Element) layers.item(i)).getAttribute("name");
}
return l;
}
/**
* Returns a layer defined by its name.
*
* @param layer Name of the desired layer
* @return <xmi:layer> element of the desired layer
*/
public Element getLayer(String layer) {
NodeList layers = DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_LAYER);
for (int i = 0; i < layers.getLength(); i++) {
Element l = (Element) layers.item(i);
if (l.getAttribute("name").equals(layer)) {
return l;
}
}
return null;
}
/**
* Returns the tools defined in the internal document.
*
* @return List of <xmi:tool> elements
*/
public NodeList getTools() {
return DOMUtilsNS.getChildsByTagName(internalDocument.getDocumentElement(), XMI_NSURI, XMI_TOOL);
}
/**
* Returns the element in the source document which is referenced by
* the given reference.
*
* @param reference Reference to find
* @return Element referenced by the given reference
*/
public Element getSourceElementWithReference(String reference) {
return context.elementTagger.getElementWithTag(reference);
}
/**
* Returns a NodeList with the elements in the internal document
* which reference the element having the given reference in the
* source.
*
* @param reference Reference to find
* @return Elements that are referencing the given reference
*/
public NodeList getInternalElementsWhichReference(String reference) {
String[] layers = getLayerNames();
ElementList el = new ElementList();
for (int j = 0; j < layers.length; j++) {
LinkedList l = DOMUtils.getElementsWithAttribute(getLayer(layers[j]), "ref", reference);
for (int i = 0; i < l.size(); i++) {
el.add(l.get(i));
}
}
return el;
}
}