| /** |
| ******************************************************************************** |
| * Copyright (c) 2015-2021 Robert Bosch GmbH and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Robert Bosch GmbH - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.amalthea.model.emf; |
| |
| import java.io.IOException; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.zip.ZipFile; |
| |
| import org.eclipse.app4mc.amalthea.model.AmaltheaIndex; |
| import org.eclipse.emf.common.CommonPlugin; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.xmi.XMLHelper; |
| import org.eclipse.emf.ecore.xmi.XMLResource; |
| import org.eclipse.emf.ecore.xmi.impl.XMIHelperImpl; |
| import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl; |
| |
| public class AmaltheaResource extends XMIResourceImpl { |
| |
| public AmaltheaResource() { |
| super(); |
| addDefaults(); |
| } |
| |
| public AmaltheaResource(final URI uri) { |
| super(uri); |
| addDefaults(); |
| } |
| |
| private void addDefaults() { |
| getDefaultSaveOptions().put(XMLResource.OPTION_ENCODING, "UTF-8"); |
| // Add some performance tweaks to improve loading of big models |
| // http://sdqweb.ipd.kit.edu/wiki/EMF_Model_Loading_Performance_Tweaks |
| getDefaultLoadOptions().put(XMLResource.OPTION_DEFER_ATTACHMENT, Boolean.TRUE); |
| getDefaultLoadOptions().put(XMLResource.OPTION_DEFER_IDREF_RESOLUTION, Boolean.TRUE); |
| getDefaultLoadOptions().put(XMLResource.OPTION_USE_XML_NAME_TO_FEATURE_MAP, new HashMap<>()); |
| |
| // Also store defaults (this option has no effect on enums) |
| getDefaultLoadOptions().put(XMLResource.OPTION_KEEP_DEFAULT_CONTENT, Boolean.TRUE); |
| getDefaultSaveOptions().put(XMLResource.OPTION_KEEP_DEFAULT_CONTENT, Boolean.TRUE); |
| |
| // Use AmaltheaResourceHandler |
| getDefaultLoadOptions().put(XMLResource.OPTION_RESOURCE_HANDLER, new AmaltheaResourceHandler()); |
| getDefaultSaveOptions().put(XMLResource.OPTION_RESOURCE_HANDLER, new AmaltheaResourceHandler()); |
| } |
| |
| // Zip option |
| // - can be set explicitly to avoid computation (with problematic URI to file conversion) |
| // - will be computed otherwise |
| |
| private boolean computeZipOption = true; |
| |
| @Override |
| public boolean useZip() { |
| // if not already set then compute and cache value |
| if (computeZipOption) { |
| setUseZip(isZipFile(getURI())); |
| } |
| |
| return super.useZip(); |
| } |
| |
| @Override |
| public void setUseZip(boolean useZip) { |
| super.setUseZip(useZip); |
| |
| // if explicitly set then do not compute value |
| computeZipOption = false; |
| } |
| |
| private boolean isZipFile(final URI uri) { |
| boolean result = false; |
| |
| URI fileURI = convertToAbsoluteFileURI(uri); |
| if (fileURI != null) { |
| String fileString = fileURI.toFileString(); |
| if (fileString != null) { |
| try (ZipFile f = new ZipFile(fileString)) { |
| // zipped file detected |
| result = true; |
| } catch (IOException e) { |
| // IOException includes ZipException -> not a zip file |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| private URI convertToAbsoluteFileURI(final URI uri) { |
| URI result; |
| |
| // Try to convert to absolute file URI |
| result = CommonPlugin.asLocalURI(uri); |
| |
| // Resulting URI still relative? |
| if (result.isRelative()) { |
| // Try with normalize URI |
| result = getURIConverter().normalize(uri); |
| result = CommonPlugin.asLocalURI(result); |
| } |
| |
| return result; |
| } |
| |
| /** |
| * @see org.eclipse.emf.ecore.xmi.impl.XMLResourceImpl#useUUIDs() |
| */ |
| @Override |
| protected boolean useUUIDs() { |
| return false; |
| } |
| |
| @Override |
| protected boolean useIDs() { |
| return true; |
| } |
| |
| protected void resetIDMaps() { |
| synchronized(this) { |
| idToEObjectMap = null; |
| eObjectToIDMap = null; |
| } |
| } |
| |
| @Override |
| protected EObject getEObjectByID(String id) { |
| if (id == null) |
| return null; |
| |
| // first: check extrinsic IDs map (only available while saving model) |
| |
| if (idToEObjectMap != null) { |
| EObject eObject = idToEObjectMap.get(id); |
| if (eObject != null) { |
| return eObject; |
| } |
| } |
| |
| // second: check intrinsic IDs map (only available while loading model) |
| |
| Map<String, EObject> map = getIntrinsicIDToEObjectMap(); |
| if (map != null) { |
| EObject eObject = map.get(id); |
| if (eObject != null) { |
| return eObject; |
| } |
| } |
| |
| // third: check Amalthea index |
| |
| return AmaltheaIndex.getEObjectByID(this, id); |
| |
| // ----------------------------------------------------------------------------------- |
| // Load option is OPTION_DEFER_IDREF_RESOLUTION = true |
| // |
| // -> no fallback solution if ID is not stored in cache(s) |
| // |
| // This prevents time consuming iterations (especially in case of very large models) |
| // ----------------------------------------------------------------------------------- |
| |
| } |
| |
| /* |
| * @see org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl#createXMLHelper() |
| */ |
| @Override |
| protected XMLHelper createXMLHelper() { |
| |
| // Overwrite creation of HREFs (required for serialized references) |
| // - internal reference -> prefix # |
| // - cross-document reference -> prefix amlt:/# |
| |
| return new XMIHelperImpl(this) { |
| @Override |
| protected URI getHREF(Resource otherResource, EObject obj) { |
| String prefix = (resource == otherResource) ? "#" : "amlt:/#"; |
| return URI.createURI(prefix + getIDREF(obj), true); |
| } |
| }; |
| } |
| |
| } |