blob: 53fbdc703b28a90f9935b66de8eb17ecf4b04c05 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2005 IBM Corporation 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:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.wst.common.internal.emf.resource;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.jem.util.logger.proxy.Logger;
import org.eclipse.wst.common.internal.emf.utilities.DOMLoadOptions;
import org.eclipse.wst.common.internal.emf.utilities.DOMUtilities;
import org.eclipse.wst.common.internal.emf.utilities.Revisit;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class EMF2DOMRenderer extends AbstractRendererImpl implements Renderer {
protected Map domAdapterRegistry;
protected boolean needsToCreateDOM = true;
protected Document document;
/**
* Constructor for DOMRendererImpl.
*/
public EMF2DOMRenderer() {
super();
if (managesDOMAdapters())
initDOMAdapterRegistry();
}
/**
* @see com.ibm.etools.emf2xml.Renderer#doLoad(InputStream, Map)
*/
public void doLoad(InputStream in, Map options) throws IOException {
if ((in != null) || !useStreamsForIO()) {
loadDocument(in, options);
EMF2DOMAdapter adapter = createRootDOMAdapter();
adapter.updateMOF();
}
}
protected void loadDocument(InputStream in, Map options) throws IOException {
try {
DOMLoadOptions domOpts = new DOMLoadOptions();
domOpts.setAllowJavaEncodings(true);
domOpts.setExpandEntityRefererences(true);
domOpts.setValidate(isValidating());
document = DOMUtilities.loadDocument(in, domOpts, getResource().getEntityResolver());
needsToCreateDOM = false;
} catch (RuntimeException t_rex) {
throw t_rex;
} catch (IOException iox) {
throw iox;
} catch (Exception ex) {
throw new WrappedException(ex);
}
}
/**
* @see com.ibm.etools.emf2xml.Renderer#doSave(OutputStream, Map)
*/
public void doSave(OutputStream outputStream, Map options) throws IOException {
createDOMTreeIfNecessary();
serializeDocument(outputStream);
}
/**
* Subclasses should override if adapters are not cached within this renderer, e.g., they are
* stored in notifying Nodes
*/
protected boolean managesDOMAdapters() {
return true;
}
protected void initDOMAdapterRegistry() {
if (domAdapterRegistry == null)
domAdapterRegistry = new HashMap();
}
public void registerDOMAdapter(Node node, EMF2DOMAdapter adapter) {
domAdapterRegistry.put(node, adapter);
}
public EMF2DOMAdapter getExistingDOMAdapter(Node node) {
return (EMF2DOMAdapter) domAdapterRegistry.get(node);
}
public void removeDOMAdapter(Node aNode, EMF2DOMAdapter anAdapter) {
domAdapterRegistry.remove(aNode);
}
/**
* @see com.ibm.etools.emf2xml.Renderer#prepareToAddContents()
*/
public void prepareToAddContents() {
// createDOMTreeIfNecessary();
}
protected Node createDOMTree() {
createDocument();
EMF2DOMAdapter adapter = createRootDOMAdapter();
adapter.updateDOM();
needsToCreateDOM = false;
return document;
}
protected EMF2DOMAdapter createRootDOMAdapter() {
EMF2DOMAdapter root = new EMF2DOMAdapterImpl(getResource(), document, this, getResource().getRootTranslator());
registerDOMAdapter(document, root);
return root;
}
protected void createDOMTreeIfNecessary() {
if (needsToCreateDOM)
createDOMTree();
}
/**
* Create a new Document given
*
* @aResource.
*/
protected void createDocument() {
TranslatorResource res = getResource();
res.setDefaults();
try {
document = DOMUtilities.createNewDocument(res.getDoctype(), res.getPublicId(), res.getSystemId());
} catch (ParserConfigurationException e) {
throw new WrappedException(e);
} catch (SAXException e) {
throw new WrappedException(e);
} catch (IOException e) {
throw new WrappedException(e);
}
}
public void serializeDocument(OutputStream out) throws IOException {
/*
* OutputFormat format = createOutputFormat(); Serializer serializer =
* SerializerFactory.getSerializerFactory(Method.XML).makeSerializer(out, format);
* serializer.asDOMSerializer().serialize(document);
*/
try {
TransformerFactory factory = TransformerFactory.newInstance();
/*
* try { factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); } catch
* (IllegalArgumentException x) { }
*/
Transformer transformer = factory.newTransformer();
transformer.setOutputProperty(OutputKeys.ENCODING, getResource().getEncoding());
transformer.setOutputProperty(OutputKeys.VERSION, getResource().getXMLVersion());
transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); //$NON-NLS-1$
if (getResource().getPublicId() != null)
transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, getResource().getPublicId());
if (getResource().getSystemId() != null)
transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, getResource().getSystemId());
transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$
DOMSource source = new DOMSource(document.getDocumentElement());
/* source.setSystemId(getResource().getSystemId()); */
transformer.transform(source, new StreamResult(out));
} catch (TransformerConfigurationException e) {
Logger.getLogger().logError(e);
} catch (TransformerFactoryConfigurationError e) {
Logger.getLogger().logError(e);
} catch (TransformerException e) {
Logger.getLogger().logError(e);
} finally {
}
}
/*
* protected OutputFormat createOutputFormat() { OutputFormat format = new OutputFormat();
* format.setIndenting(true); format.setLineSeparator(DOMUtilities.NEWLINE_STRING);
* //$NON-NLS-1$ format.setEncoding(getResource().getEncoding());
* format.setVersion(getResource().getXMLVersion()); return format; }
*/
public void replaceDocumentType(String docTypeName, String publicId, String systemId) {
Revisit.revisit();
Document newDoc = null;
// Need be able to update the doctype directly on the existing document; right now can't
// because
// of limitations on parser neutral apis
try {
newDoc = DOMUtilities.createNewDocument(docTypeName, publicId, systemId);
} catch (ParserConfigurationException e) {
throw new WrappedException(e);
} catch (SAXException e) {
throw new WrappedException(e);
} catch (IOException e) {
throw new WrappedException(e);
}
replaceNode(document.getDocumentElement(), newDoc, newDoc);
readapt(document, newDoc);
document = newDoc;
}
protected void replaceNode(Node oldChild, Node newParent, Document newDoc) {
Node newChild = newDoc.importNode(oldChild, false);
newParent.appendChild(newChild);
readapt(oldChild, newChild);
NodeList children = oldChild.getChildNodes();
int length = children.getLength();
for (int i = 0; i < length; i++) {
replaceNode(children.item(i), newChild, newDoc);
}
}
public void preUnload() {
EMF2DOMAdapter adapter = (EMF2DOMAdapter) EcoreUtil.getAdapter(resource.eAdapters(), EMF2DOMAdapter.ADAPTER_CLASS);
if (adapter != null) {
adapter.removeAdapters(adapter.getNode());
}
}
protected void readapt(Node oldChild, Node newChild) {
EMF2DOMAdapter adapter = getExistingDOMAdapter(oldChild);
if (adapter != null) {
registerDOMAdapter(newChild, adapter);
// Some nodes are managed by the parent and thus the
// node should not be set on the parent adapter
if (adapter.getNode() == oldChild)
adapter.setNode(newChild);
}
}
public int getVersionID() {
return getResource().getVersionID();
}
}