blob: 8f87bbd7f769b0faeeb5ffd350ee4f3fd9578792 [file] [log] [blame]
//------------------------------------------------------------------------------
// Copyright (c) 2005, 2006 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 implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.persistence;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import org.eclipse.emf.common.CommonPlugin;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.InternalEObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.xmi.XMLHelper;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMISaveImpl;
import org.eclipse.epf.resourcemanager.ResourceManager;
import com.ibm.uma.MethodElement;
import com.ibm.uma.MethodUnit;
/**
* @author Phong Nguyen Le
* @since 1.0
*/
public class MultiFileXMISaveImpl extends XMISaveImpl {
public static final String SAVE_SEPARATELY_CLASS_SET = "SAVE_SEPARATELY_CLASS_SET"; //$NON-NLS-1$
/**
* Save options to force saving all resources in the resource set, whether they have been modified or unchanged.
* Its value must be a string "true" or "false"
*/
public static final String SAVE_ALL = "SAVE_ALL"; //$NON-NLS-1$
/**
* Save option to save objects of the save type together in the same file if
* MultiFileUtil.createFileURI() returns the same URI for them.
*/
public static final String SAVE_TOGETHER_CLASS_SET = "SAVE_TOGETHER_CLASS_SET"; //$NON-NLS-1$
public static final String BACK_UP_BEFORE_SAVE = "BACK_UP_BEFORE_SAVE"; //$NON-NLS-1$
public static final String DISCARD_UNRESOLVED_REFERENCES = "DISCARD_UNRESOLVED_REFERENCES"; //$NON-NLS-1$
static final String MODIFIED_RESOURCE_SET = "MODIFIED_RESOURCE_SET"; //$NON-NLS-1$
/**
* Save option to specify a TxRecord to log the transactional data for
* fail-safe persistence
*
* @see com.ibm.uma.util.IMethodLibraryPersister.FailSafeMethodLibraryPersister
* @see TxRecord
*/
static final String TX_RECORD = "TX_RECORD"; //$NON-NLS-1$
public static final String MULTI_FILE = "MULTI_FILE"; //$NON-NLS-1$
/**
* Save option to refresh the workspace when new resource is created and saved.
* Its value must be a string "true" or "false"
*/
public static final String REFRESH_NEW_RESOURCE = "REFRESH_NEW_RESOURCE"; //$NON-NLS-1$
/**
* Save option to check the resource for modifiable before saving it.
* Its value must be a string "true" or "false"
*/
public static final String CHECK_MODIFY = "CHECK_MODIFY"; //$NON-NLS-1$
// private Resource resource;
private Set saveSeparatelyClassSet;
private Map options;
/**
* @param helper
*/
public MultiFileXMISaveImpl(XMLHelper helper) {
super(helper);
}
XMLHelper getXMLHelper() {
return helper;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl#init(org.eclipse.emf.ecore.xmi.XMLResource,
* java.util.Map)
*/
protected void init(XMLResource resource, Map opts) {
super.init(resource, opts);
if (escape != null) {
// use MyEscape to ignore whitespaces
//
escape = new MyEscape();
}
saveSeparatelyClassSet = (Set) opts.get(SAVE_SEPARATELY_CLASS_SET);
options = opts;
ResourceSet resourceSet = resource.getResourceSet();
if (resourceSet == null) {
resourceSet = new MultiFileResourceSetImpl();
resourceSet.getResources().add(resource);
}
}
boolean canSaveSeparately(Object obj) {
return MultiFileSaveUtil.hasOwnResource(obj, saveSeparatelyClassSet);
}
private String getUmaHREF(Resource resource, InternalEObject o) {
if (o.eIsProxy()
&& o.eProxyURI().scheme().equals(MultiFileURIConverter.SCHEME)) {
return o.eProxyURI().toString();
}
String href = null;
if (o instanceof MethodElement) {
href = helper.getHREF(o);
// TODO: need to check why helper.getHREF() returns null for some
// MethodElements
}
if (href == null) {
return MultiFileSaveUtil.getHREF(resource, o);
}
return href;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.emf.ecore.xmi.impl.XMLSaveImpl#saveFeatures(org.eclipse.emf.ecore.EObject)
*/
protected boolean saveFeatures(EObject o) {
try {
MultiFileXMIResourceImpl resource = (MultiFileXMIResourceImpl) o
.eResource();
if (resource != null) {
EObject container = o.eContainer();
InternalEObject internalEObject = ((InternalEObject) o);
if (o instanceof MethodElement && canSaveSeparately(o)
&& container != null) {
boolean containsNewFeature = (resource == container
.eResource());
MethodElement e = (MethodElement) o;
URI uri = MultiFileSaveUtil
.createFileURI((MethodElement) o);
if (containsNewFeature) {
if (!internalEObject.eIsProxy()) {
resource = (MultiFileXMIResourceImpl) MultiFileSaveUtil
.save(o, uri, options);
}
} else {
// check if there is a ResourceDescriptor for this
// element
// create a new one if needed
//
ResourceManager resMgr = MultiFileSaveUtil
.getResourceManager(container.eResource());
if (resMgr != null
&& resMgr.getResourceDescriptor(e.getGuid()) == null) {
// make sure that no other ResourceManager has a
// ResourceDescriptor for this element
//
MultiFileURIConverter uriConverter = (MultiFileURIConverter) resource
.getResourceSet().getURIConverter();
if (uriConverter
.findResourceDescriptor(e.getGuid()) == null) {
MultiFileSaveUtil.registerWithResourceManager(
resMgr, e, resource.getFinalURI());
}
}
}
String href = getUmaHREF(resource, internalEObject); // MultiFileSaveUtil.getHREF(resource,
// o);
doc.addAttribute(XMLResource.HREF, href);
endSaveFeatures(o, 0, null);
return true;
}
if (o instanceof ResourceManager
&& helper.getResource() != resource) {
String href = getUmaHREF(resource, internalEObject); // MultiFileSaveUtil.getHREF(resource,
// o);
doc.addAttribute(XMLResource.HREF, href);
endSaveFeatures(o, 0, null);
return true;
}
}
return super.saveFeatures(o);
} catch (RuntimeException e) {
CommonPlugin.INSTANCE.log(e);
if (MultiFileSaveUtil.DEBUG) {
e.printStackTrace();
System.err.println("ERROR saving feature: " + o); //$NON-NLS-1$
System.err.println(" Feature resource: " + o.eResource()); //$NON-NLS-1$
}
throw e;
}
}
/*
* protected String getDatatypeValue(Object value, EStructuralFeature f,
* boolean isAttribute) { if (value != null && value instanceof String) {
* String str = (String)value; if (str.indexOf("\r") > 0) { str =
* str.replaceAll("\r", ""); return super.getDatatypeValue(str, f,
* isAttribute); } }; return super.getDatatypeValue(value, f, isAttribute); }
*/
public static class MyEscape extends Escape {
protected final char[] GREATER = { '&', 'g', 't', ';' };
protected final char[] BLANK = {};
public MyEscape() {
super();
}
/*
* Converts: & to &amp; < to &lt; " to &quot; \t to &#x9; \n to &#xA; \r
* to &#xD;
*/
public String convert(String input) {
boolean changed = false;
int inputLength = input.length();
grow(inputLength);
input.getChars(0, inputLength, value, 0);
int pos = 0;
char ch = 0;
while (inputLength-- > 0) {
ch = value[pos];
switch (ch) {
case '&':
pos = replace(pos, AMP, inputLength);
changed = true;
break;
case '<':
pos = replace(pos, LESS, inputLength);
changed = true;
break;
case '>':
pos = replace(pos, GREATER, inputLength);
changed = true;
break;
case '"':
pos = replace(pos, QUOTE, inputLength);
changed = true;
break;
default:
/*
* if (!XMLChar.isValid(ch)) { throw new
* RuntimeException("An invalid XML character (Unicode: 0x" +
* Integer.toHexString(ch)+") was found in the element
* content:" +input); }
*/
pos++;
break;
}
}
return changed ? new String(value, 0, pos) : input;
}
/**
* Converts: & to &amp; < to &lt; > to &gt; " to &quot; \n to
* platform-dependent line breaking character
*/
public String convertText(String input) {
boolean changed = false;
int inputLength = input.length();
grow(inputLength);
input.getChars(0, inputLength, value, 0);
int pos = 0;
while (inputLength-- > 0) {
switch (value[pos]) {
case '&':
pos = replace(pos, AMP, inputLength);
changed = true;
break;
case '<':
pos = replace(pos, LESS, inputLength);
changed = true;
break;
case '>':
pos = replace(pos, GREATER, inputLength);
changed = true;
break;
case '"':
pos = replace(pos, QUOTE, inputLength);
changed = true;
break;
case '\r':
pos = replace(pos, BLANK, inputLength);
changed = true;
break;
case '\n':
pos = replace(pos, LINE_FEED, inputLength);
changed = true;
break;
default:
pos++;
break;
}
}
return changed ? new String(value, 0, pos) : input;
}
/*
* Taken from XMLSaveImpl$Escape.convertText, and added conversion of >
* This is used for XLIFF's - change it's name so it doesn't impact EMF
* saving Convert: & to &amp; < to &lt; " to &quot; \n to line separator
*/
public String myConvertText(String input) {
boolean changed = false;
int inputLength = input.length();
grow(inputLength);
input.getChars(0, inputLength, value, 0);
int pos = 0;
while (inputLength-- > 0) {
switch (value[pos]) {
case '&':
pos = replace(pos, AMP, inputLength);
changed = true;
break;
case '<':
pos = replace(pos, LESS, inputLength);
changed = true;
break;
case '>':
pos = replace(pos, GREATER, inputLength);
changed = true;
break;
case '"':
pos = replace(pos, QUOTE, inputLength);
changed = true;
break;
case '\n': {
pos = replace(pos, LINE_FEED, inputLength);
changed = true;
break;
}
default:
pos++;
break;
}
}
return changed ? new String(value, 0, pos) : input;
}
}
public static boolean checkModifyRequired(Map options) {
Object opt = options.get(MultiFileXMISaveImpl.CHECK_MODIFY);
return opt != null ? Boolean.valueOf(opt.toString()).booleanValue() : false;
}
}