blob: f71659c4442fe869a1e3bc78917f54332cd8a390 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2006, 2014 Soyatec (http://www.soyatec.com), CEA, and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Soyatec - initial API and implementation
* Christian W. Damus (CEA) - Fix failure to propagate stream handlers of URLs (CDO)
* Christian W. Damus (CEA) - bug 435432
*
*******************************************************************************/
package org.eclipse.xwt.internal.xml;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.eclipse.xwt.IConstants;
import org.eclipse.xwt.XWT;
import org.eclipse.xwt.callback.IBeforeParsingCallback;
import org.eclipse.xwt.internal.core.Core;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
/**
* @author yyang
* @since 1.0
*/
public class ElementManager {
private DocumentRoot documentRoot;
private SAXParserFactory parserFactory;
private ErrorHandler errorHandler;
private String encoding;
/**
* Cache all elements.
*/
private Map<String, Element> elements;
/**
* Only cache root elements.
*/
private Element rootElement;
private Element xDataElement;
private static Random RANDOM = new Random();
public static String generateID(String typeName) {
return typeName + RANDOM.nextInt(Integer.MAX_VALUE);
}
public ElementManager() {
this(null);
}
public ElementManager(URL url) {
this.documentRoot = new DocumentRoot();
this.elements = new HashMap<String, Element>();
this.encoding = System.getProperty("file.encoding");
this.parserFactory = SAXParserFactory.newInstance();
this.parserFactory.setNamespaceAware(true);
this.parserFactory.setValidating(true);
if (url != null) {
try {
documentRoot.init(null, url);
} catch (IOException e) {
}
}
this.errorHandler = new ErrorHandler() {
// IFrameworkAdaptor adaptor =
// FrameworkUtil.getFrameworkAdaptor(context);
/*
* (non-Javadoc)
*
* @see
* org.xml.sax.ErrorHandler#error(org.xml.sax.SAXParseException)
*/
public void error(SAXParseException exception) throws SAXException {
Exception cause = exception.getException();
try {
if (cause != null) {
XWT.getLogger().error(cause);
} else {
XWT.getLogger().error(exception);
}
} catch (Exception e) {
if (cause != null) {
throw new SAXException(exception.getLocalizedMessage(),
cause);
} else {
throw new SAXException(exception);
}
}
}
/*
* (non-Javadoc)
*
* @see
* org.xml.sax.ErrorHandler#fatalError(org.xml.sax.SAXParseException
* )
*/
public void fatalError(SAXParseException exception)
throws SAXException {
Exception cause = exception.getException();
try {
if (cause != null) {
XWT.getLogger().error(cause);
} else {
XWT.getLogger().error(exception);
}
} catch (Exception e) {
if (cause != null) {
throw new SAXException(exception.getLocalizedMessage(),
cause);
} else {
throw new SAXException(exception);
}
}
throw new RuntimeException();
}
/*
* (non-Javadoc)
*
* @see
* org.xml.sax.ErrorHandler#warning(org.xml.sax.SAXParseException)
*/
public void warning(SAXParseException exception)
throws SAXException {
Exception cause = exception.getException();
try {
if (cause != null) {
XWT.getLogger().error(cause);
} else {
XWT.getLogger().error(exception);
}
} catch (Exception e) {
if (cause != null) {
throw new SAXException(exception.getLocalizedMessage(),
cause);
} else {
throw new SAXException(exception);
}
}
}
};
}
/*
* (non-Javadoc)
*
* @see org.soyatec.xaml.IElementManager#getDocumentRoot()
*/
public DocumentRoot getDocumentRoot() {
return documentRoot;
}
/*
* (non-Javadoc)
*
* @see org.soyatec.xaml.IElementManager#getElement(java.lang.String)
*/
public Element getElement(String id) {
assert id != null;
return elements.get(id);
}
/*
* (non-Javadoc)
*
* @see org.soyatec.xaml.IElementManager#getElements()
*/
public String[] getElements() {
return elements.keySet().toArray(IConstants.EMPTY_STRING_ARRAY);
}
/*
* (non-Javadoc)
*
* @see org.soyatec.xaml.IElementManager#getEncoding()
*/
public String getEncoding() {
return encoding;
}
/*
* (non-Javadoc)
*
* @see org.soyatec.xaml.IElementManager#getRootElement()
*/
public Element getRootElement() {
return rootElement;
}
/**
* Sets my root element (either loaded by me or perhaps obtained from some cache or other source).
*
* @param rootElement
* my root element
*/
public void setRootElement(Element rootElement) {
this.rootElement = rootElement;
}
/*
* (non-Javadoc)
*
* @see org.soyatec.xaml.IElementManager#hasElement(java.lang.String)
*/
public boolean hasElement(String id) {
assert id != null;
return elements.containsKey(id);
}
protected void setEncoding(String encoding) {
assert encoding != null;
this.encoding = encoding;
}
/**
* @see Core
*/
public Element load(URL url, IBeforeParsingCallback callback) throws Exception {
reset();
if (callback == null) {
// Initialize document root
documentRoot.init(null, url);
InputStream input = url.openStream();
try {
doLoad(input);
} finally {
input.close();
}
input = documentRoot.openStream();
try {
loadXData(input);
} finally {
input.close();
}
}
else {
String content = callback.onParsing(url.toString());
documentRoot.init(null, new URL(url, content)); // preserve the stream handler
InputStream input = new ByteArrayInputStream(content.getBytes());
try {
doLoad(input);
} finally {
input.close();
}
input = documentRoot.openStream();
try {
loadXData(input);
} finally {
input.close();
}
}
return rootElement;
}
/**
* @see Core
*/
public Element load(InputStream stream, URL url) throws Exception {
reset();
// Initialize document root
PushbackInputStream pis = null;
if (stream != null) {
if (stream instanceof PushbackInputStream) {
pis = (PushbackInputStream) stream;
} else {
pis = new PushbackInputStream(stream, 4);
}
}
documentRoot.init(pis, url);
InputStream input = pis;
if (pis == null) {
input = documentRoot.openStream();
}
doLoad(input);
input = documentRoot.openStream();
loadXData(input);
input.close();
return rootElement;
}
/**
* @see ElementHandler
*/
public void load(InputStream stream, DocumentObject parent)
throws SAXException {
assert stream != null;
ElementHandler contentHandler = new ElementHandler(parent, this);
try {
SAXParser parser = parserFactory.newSAXParser();
parser.getXMLReader().setErrorHandler(errorHandler);
parser.parse(stream, contentHandler);
} catch (ParserConfigurationException pce) {
throw new SAXException(pce.getLocalizedMessage(), pce);
} catch (IOException ioe) {
throw new SAXException(ioe.getLocalizedMessage(), ioe);
}
}
private void loadXData(InputStream stream) {
if (xDataElement != null) {
try {
SAXParser parser = parserFactory.newSAXParser();
parser.getXMLReader().setErrorHandler(errorHandler);
StringBuilder out = new StringBuilder();
parser.parse(stream, new XDataHandler(out));
String content = out.toString();
xDataElement.setContent(content);
} catch (ParserConfigurationException e) {
} catch (SAXException e) {
} catch (IOException e) {
}
}
}
/**
* @see ElementHandler
*/
protected void preElement(Element element) {
assert element != null;
assert !elements.containsKey(element.getId()) : "Element already exists in registry: "
+ element.getId();
// Add to cache.
elements.put(element.getId(), element);
// If it is a runnable element, add to top-level cache.
if (element.getParent() == null && rootElement == null) {
rootElement = element;
}
}
/**
* @see ElementHandler
*/
protected void postElement(Element element) {
assert element != null;
assert elements.containsKey(element.getId()) : "Element not found in registry: "
+ element.getId();
if ("xdata".equalsIgnoreCase(element.getName())
&& IConstants.XWT_X_NAMESPACE.equals(element.getNamespace())) {
xDataElement = element;
}
}
/**
* @see #load(File)
* @see #load(URL)
*/
private void doLoad(InputStream stream) throws Exception {
assert stream != null;
ElementHandler contentHandler = new ElementHandler(this);
try {
SAXParser parser = parserFactory.newSAXParser();
parser.getXMLReader().setErrorHandler(errorHandler);
parser.parse(stream, contentHandler);
} catch (SAXException saxe) {
// Exception cause = saxe.getException();
// try {
// if (cause != null) {
// XWT.getLogger().error(cause);
// } else {
// XWT.getLogger().error(saxe);
// }
// } catch (Exception e) {
// // e.printStackTrace();
// }
throw saxe;
} catch (ParserConfigurationException pce) {
try {
XWT.getLogger().error(pce);
} catch (Exception e) {
e.printStackTrace();
}
throw pce;
} catch (IOException ioe) {
try {
XWT.getLogger().error(ioe);
} catch (Exception e) {
e.printStackTrace();
}
throw ioe;
}
}
/**
* @see #load(File)
* @see #load(URL)
*/
private void reset() {
// Reset code base.
documentRoot.reset();
}
}