/******************************************************************************* | |
* 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(); | |
} | |
} |