| /******************************************************************************* |
| * Copyright (c) 2008-2011 Chair for Applied Software Engineering, |
| * Technische Universitaet Muenchen. |
| * 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: |
| * Otto von Wesendonk, Edgar Mueller - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.emf.emfstore.internal.server.connection.xmlrpc.util; |
| |
| import java.io.BufferedOutputStream; |
| import java.io.IOException; |
| import java.io.OutputStream; |
| import java.io.OutputStreamWriter; |
| import java.util.HashMap; |
| import java.util.LinkedHashSet; |
| import java.util.Set; |
| |
| import org.apache.commons.lang.StringUtils; |
| import org.apache.ws.commons.util.Base64; |
| import org.apache.ws.commons.util.Base64.Encoder; |
| import org.apache.ws.commons.util.Base64.EncoderOutputStream; |
| import org.apache.xmlrpc.serializer.TypeSerializerImpl; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.resource.impl.ResourceImpl; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.xmi.XMIResource; |
| import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionElement; |
| import org.eclipse.emf.emfstore.common.extensionpoint.ESExtensionPoint; |
| import org.eclipse.emf.emfstore.internal.common.CommonUtil; |
| import org.eclipse.emf.emfstore.internal.common.model.IdEObjectCollection; |
| import org.eclipse.emf.emfstore.internal.common.model.ModelElementId; |
| import org.eclipse.emf.emfstore.internal.common.model.util.ModelUtil; |
| import org.eclipse.emf.emfstore.internal.server.exceptions.SerializationException; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.ChangePackage; |
| import org.eclipse.emf.emfstore.internal.server.model.versioning.FileBasedChangePackage; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * Serializer for EObjects. |
| * |
| * @author ovonwesen |
| * @author emueller |
| */ |
| public class EObjectSerializer extends TypeSerializerImpl { |
| |
| private static final String SELF_CONTAINMENT_CHECK_OPTION = "SelfContainmentCheck"; //$NON-NLS-1$ |
| private static final String SERIALIZATION_OPTIONS_EXT = "org.eclipse.emf.emfstore.common.model.serializationOptions"; //$NON-NLS-1$ |
| /** |
| * EObject Tag for parsing. |
| */ |
| public static final String EOBJECT_TAG = "EObject"; //$NON-NLS-1$ |
| private static final String EX_EOBJECT_TAG = "ex:" + EOBJECT_TAG; //$NON-NLS-1$ |
| private static boolean containmentCheckEnabled; |
| private static boolean serializationOptionsInitialized; |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void write(ContentHandler pHandler, Object pObject) throws SAXException { |
| initSerializationOptions(); |
| startElements(pHandler); |
| final char[] buffer = new char[1024]; |
| final Encoder encoder = new Base64.SAXEncoder(buffer, 0, null, pHandler); |
| try { |
| URIConverter.WriteableOutputStream uws = null; |
| final OutputStream ostream = new EncoderOutputStream(encoder); |
| final BufferedOutputStream bos = new BufferedOutputStream(ostream); |
| try { |
| EObject eObject = (EObject) pObject; |
| XMIResource resource = (XMIResource) eObject.eResource(); |
| |
| if (eObject instanceof FileBasedChangePackage) { |
| final ChangePackage changePackage = FileBasedChangePackage.class.cast(eObject) |
| .toInMemoryChangePackage(); |
| eObject = changePackage; |
| } |
| |
| if (eObject instanceof IdEObjectCollection && resource != null) { |
| OutputStreamWriter writer = null; |
| try { |
| writer = new OutputStreamWriter(bos, CommonUtil.getEncoding()); |
| uws = new URIConverter.WriteableOutputStream(writer, CommonUtil.getEncoding()); |
| final Resource res = eObject.eResource(); |
| checkResource(res); |
| res.save(uws, ModelUtil.getResourceSaveOptions()); |
| } finally { |
| if (writer != null) { |
| writer.close(); |
| } |
| } |
| } else { |
| EObject copy; |
| resource = createXmiResource(); |
| |
| if (eObject instanceof IdEObjectCollection) { |
| copy = ModelUtil.copyIdEObjectCollection((IdEObjectCollection) eObject, resource); |
| setResourceIds(eObject, resource); |
| } else { |
| copy = ModelUtil.clone(eObject); |
| } |
| |
| resource.getContents().add(copy); |
| checkResource(resource); |
| resource.save(bos, ModelUtil.getResourceSaveOptions()); |
| } |
| } catch (final SerializationException e) { |
| throw new SAXException(e); |
| } finally { |
| bos.close(); |
| if (uws != null) { |
| uws.close(); |
| } |
| } |
| } catch (final Base64.SAXIOException e) { |
| throw e.getSAXException(); |
| } catch (final IOException e) { |
| throw new SAXException(e); |
| } |
| endElements(pHandler); |
| } |
| |
| private static XMIResource createXmiResource() { |
| final XMIResource resource = (XMIResource) new ResourceSetImpl().createResource(ModelUtil.VIRTUAL_URI); |
| ((ResourceImpl) resource).setIntrinsicIDToEObjectMap(new HashMap<String, EObject>()); |
| return resource; |
| } |
| |
| /** |
| * @param eObject |
| * @param resource |
| */ |
| private void setResourceIds(EObject eObject, XMIResource resource) { |
| final IdEObjectCollection collection = (IdEObjectCollection) eObject; |
| for (final EObject element : collection.getAllModelElements()) { |
| if (ModelUtil.isIgnoredDatatype(element)) { |
| continue; |
| } |
| final ModelElementId elementId = collection.getModelElementId(element); |
| resource.setID(element, elementId.getId()); |
| } |
| } |
| |
| /** |
| * @param pHandler |
| * @throws SAXException |
| */ |
| private void endElements(ContentHandler pHandler) throws SAXException { |
| pHandler.endElement(StringUtils.EMPTY, EOBJECT_TAG, EX_EOBJECT_TAG); |
| pHandler.endElement(StringUtils.EMPTY, VALUE_TAG, VALUE_TAG); |
| } |
| |
| /** |
| * @param pHandler |
| * @throws SAXException |
| */ |
| private void startElements(ContentHandler pHandler) throws SAXException { |
| pHandler.startElement(StringUtils.EMPTY, VALUE_TAG, VALUE_TAG, ZERO_ATTRIBUTES); |
| pHandler.startElement(StringUtils.EMPTY, EOBJECT_TAG, EX_EOBJECT_TAG, ZERO_ATTRIBUTES); |
| } |
| |
| private void checkResource(Resource resource) throws SerializationException { |
| if (!containmentCheckEnabled) { |
| return; |
| } |
| |
| if (resource.getContents().size() != 1) { |
| throw new SerializationException(Messages.EObjectSerializer_UnexpectedNumberOfEObjects); |
| } |
| final EObject root = resource.getContents().get(0); |
| final Set<EObject> allChildEObjects = CommonUtil.getNonTransientContents(root); |
| final Set<EObject> allEObjects = new LinkedHashSet<EObject>(allChildEObjects); |
| allEObjects.add(root); |
| for (final EObject eObject : allEObjects) { |
| if (resource != eObject.eResource()) { |
| throw new SerializationException(Messages.EObjectSerializer_NonSelfContainedResource); |
| } |
| if (eObject.eIsProxy()) { |
| throw new SerializationException(Messages.EObjectSerializer_UnresolvedProxy); |
| } |
| } |
| } |
| |
| /** |
| * Initializes the serialization options. |
| */ |
| private static void initSerializationOptions() { |
| |
| if (serializationOptionsInitialized) { |
| return; |
| } |
| final ESExtensionElement element = new ESExtensionPoint( |
| SERIALIZATION_OPTIONS_EXT).getFirst(); |
| |
| if (element != null) { |
| containmentCheckEnabled = element.getBoolean(SELF_CONTAINMENT_CHECK_OPTION); |
| } |
| |
| serializationOptionsInitialized = true; |
| } |
| } |