| /******************************************************************************* |
| * Copyright (c) 2013 itemis AG. |
| * 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: |
| * itemis AG - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.rmf.reqif10.common.util; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.IOException; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.apache.xerces.impl.Constants; |
| import org.eclipse.emf.common.notify.Notification; |
| import org.eclipse.emf.common.notify.Notifier; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.Resource.Diagnostic; |
| import org.eclipse.emf.ecore.util.EContentAdapter; |
| import org.eclipse.emf.ecore.xmi.XMLHelper; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecore.xmi.XMLSave; |
| import org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl; |
| import org.eclipse.rmf.reqif10.XhtmlContent; |
| import org.eclipse.rmf.reqif10.xhtml.XhtmlPackage; |
| |
| public class ReqIF10XHTMLContentAdapter extends EContentAdapter { |
| String xmlString = null; |
| XMLResource resource = null; |
| static final String UTF8 = "UTF-8"; //$NON-NLS-1$ |
| XhtmlContent xhtmlContent = null; |
| |
| public String getXhtmlString() { |
| if (null == xmlString) { |
| updateXhtmlString(); |
| } |
| |
| return xmlString; |
| } |
| |
| public void setXhtmlString(String xhtmlString) throws IOException { |
| // set object tree in model |
| updateXhtmlObjects(xhtmlString); |
| // the xhtml String is updated automatically from updated xhtml objects |
| // TODO: analyze if it would be sufficient not to recreate the xhtml string from the xhtml object structure |
| } |
| |
| public EList<Diagnostic> getErrors() { |
| return resource.getErrors(); |
| } |
| |
| public EList<Diagnostic> getWarnings() { |
| return resource.getWarnings(); |
| } |
| |
| @Override |
| public boolean isAdapterForType(Object type) { |
| return ReqIF10XHTMLContentAdapter.class == type; |
| } |
| |
| @Override |
| public void notifyChanged(Notification notification) { |
| super.notifyChanged(notification); |
| Object notifier = notification.getNotifier(); |
| if (notifier instanceof XhtmlContent) { |
| updateXhtmlString(); |
| } |
| } |
| |
| private void updateXhtmlString() { |
| assert null != xhtmlContent; |
| EObject xmlRoot = xhtmlContent.getXhtml(); |
| |
| if (null != xmlRoot) { |
| try { |
| ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); |
| |
| XMLResource resource = getResource(); |
| Map<Object, Object> options = new HashMap<Object, Object>(); |
| options.put(XMLResource.OPTION_ROOT_OBJECTS, Collections.singletonList(xmlRoot)); |
| resource.save(byteArrayOutputStream, options); |
| |
| xmlString = new String(byteArrayOutputStream.toByteArray(), UTF8); |
| } catch (IOException ioe) { |
| assert false : "We should always be able to update the xhtml string from the given object model"; //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| private void updateXhtmlObjects(String xmlString) throws IOException { |
| assert null != xhtmlContent; |
| if (null == xmlString) { |
| // unset the xhtmlContent |
| xhtmlContent.unsetXhtml(); |
| } else { |
| // parse the string |
| |
| Resource resource = getResource(); |
| resource.load(new ByteArrayInputStream(xmlString.getBytes(UTF8)), null); |
| EList<EObject> contents = resource.getContents(); |
| if (0 < contents.size()) { |
| EObject rootObject = contents.get(0); |
| xhtmlContent.setXhtml(rootObject); |
| } |
| } |
| |
| } |
| |
| private XMLResource getResource() { |
| if (null == resource) { |
| resource = new NestedXMLResourceImpl(); |
| |
| } else { |
| resource.getContents().clear(); |
| } |
| return resource; |
| } |
| |
| @Override |
| public void setTarget(Notifier target) { |
| super.setTarget(target); |
| if (target instanceof XhtmlContent) { |
| xhtmlContent = (XhtmlContent) target; |
| } |
| } |
| |
| private class NestedXMLResourceImpl extends XMLResourceImpl { |
| @Override |
| protected XMLHelper createXMLHelper() { |
| XMLHelper helper = super.createXMLHelper(); |
| // make sure that no namespace prefix is created during serialization |
| EMap<String, String> prefixToNamespaceMap = helper.getPrefixToNamespaceMap(); |
| prefixToNamespaceMap.put("", XhtmlPackage.eNS_URI); //$NON-NLS-1$ |
| helper.setPrefixToNamespaceMap(prefixToNamespaceMap); |
| |
| // make sure that missing namespace declaration is mapped to Xhtml |
| helper.pushContext(); |
| helper.addPrefix("", XhtmlPackage.eNS_URI);//$NON-NLS-1$ |
| return helper; |
| } |
| |
| @Override |
| protected XMLSave createXMLSave() { |
| return new XMLSaveImpl(createXMLHelper()) { |
| @Override |
| protected Object writeTopObject(EObject top) { |
| EClass eClass = top.eClass(); |
| String name = helper.getQName(eClass); |
| doc.startElement(name); |
| Object mark = doc.mark(); |
| root = top; |
| saveElementID(top); |
| return mark; |
| } |
| }; |
| } |
| |
| @Override |
| protected void init() { |
| // make sure that the xhtml package is registered |
| Object dummy = XhtmlPackage.eINSTANCE; |
| setEncoding(UTF8); |
| Map<Object, Object> loadOptions = getDefaultLoadOptions(); |
| loadOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); |
| loadOptions.put(XMLResource.OPTION_USE_DEPRECATED_METHODS, Boolean.FALSE); |
| // avoid creation of document root element |
| loadOptions.put(XMLResource.OPTION_SUPPRESS_DOCUMENT_ROOT, Boolean.TRUE); |
| // performance improvement: delays the attachment of adapters until all elements are loaded. |
| loadOptions.put(XMLResource.OPTION_DEFER_ATTACHMENT, Boolean.TRUE); |
| |
| Map<String, Object> parserProperties = new HashMap<String, Object>(); |
| parserProperties.put(Constants.XERCES_PROPERTY_PREFIX + Constants.BUFFER_SIZE_PROPERTY, 1024); |
| |
| Map<String, Boolean> parserFeatures = new HashMap<String, Boolean>(); |
| parserFeatures.put(Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACES_FEATURE, true); |
| parserFeatures.put(Constants.SAX_FEATURE_PREFIX + Constants.NAMESPACE_PREFIXES_FEATURE, false); |
| loadOptions.put(XMLResource.OPTION_PARSER_FEATURES, parserFeatures); |
| loadOptions.put(XMLResource.OPTION_PARSER_PROPERTIES, parserProperties); |
| |
| Map<Object, Object> saveOptions = getDefaultSaveOptions(); |
| saveOptions.put(XMLResource.OPTION_EXTENDED_META_DATA, Boolean.TRUE); |
| saveOptions.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE); |
| saveOptions.put(XMLResource.OPTION_SAVE_TYPE_INFORMATION, Boolean.FALSE); |
| saveOptions.put(XMLResource.OPTION_USE_ENCODED_ATTRIBUTE_STYLE, Boolean.TRUE); |
| saveOptions.put(XMLResource.OPTION_USE_DEPRECATED_METHODS, Boolean.FALSE); |
| super.init(); |
| } |
| } |
| |
| } |