// ============================================================================
//
// Copyright (C) 2006-2016 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.commons.emf;
import java.io.File;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.apache.log4j.Logger;
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.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.talend.i18n.Messages;
import org.talend.model.emf.CwmResourceFactory;
/**
* @author scorreia This class creates the EMF resources and save them. All resources are stored in a ResourceSet (which
* can be changed with the setter and getter methods). By default, path are platform relative.
*
* This class also offers some static methods to help handling resources.
*
*/
public final class EMFUtil {
private static Logger log = Logger.getLogger(EMFUtil.class);
/** the encoding for xml files. */
public static final String ENCODING = "UTF-8"; //$NON-NLS-1$
/** the options needed for saving the resources. */
private final Map<String, Object> options;
/**
* Whether path are platform relative.
*/
private boolean usePlatformRelativePath = true;
/** Static initialization of all EMF packages needed for the application. Done only once. */
static {
initialize();
}
private ResourceSet resourceSet;
private String lastErrorMessage = null;
/**
* This CTOR initializes all packages and create a resource set.
*
* @param fileExtensions the list of extensions (without the dot).
*/
public EMFUtil() {
// set the options
options = new HashMap<String, Object>();
options.put(XMIResource.OPTION_DECLARE_XML, Boolean.TRUE);
options.put(XMIResource.OPTION_ENCODING, ENCODING);
// the OPTION_DEFER_IDREF_RESOLUTION option needs at least EMF 2.3.1 to work correctly
// see https://bugs.eclipse.org/bugs/show_bug.cgi?id=216009
// options.put(XMIResource.OPTION_DEFER_IDREF_RESOLUTION, Boolean.TRUE);
// Obtain a new resource set
resourceSet = new ResourceSetImpl();
}
/**
* Method "initialize" initializes EMF factories, packages and file extensions.
*/
public static void initialize() {
// Initialize the enterprise factories
FactoriesUtil.initializeAllFactories();
// Initialize the enterprise packages
FactoriesUtil.initializeAllPackages();
// Register the XMI resource factory for the .enterprise extension
Resource.Factory.Registry reg = Resource.Factory.Registry.INSTANCE;
final Collection<String> fileExtensions = FactoriesUtil.getExtensions();
Map<String, Object> m = reg.getExtensionToFactoryMap();
for (String extension : fileExtensions) {
m.put(extension, new CwmResourceFactory());
}
}
/**
* Creates a new Resource in the ResourceSet. The file will be actually written when the save() method will be
* called. By default, paths are platform relative. In order to call this method outside an Eclipse platform, set
* the usePlatformRelativePath boolean to false.
*
* @param uri the uri of the file in which the pool will be stored
* @param eObject the pool that contains objects.
* @return true (as per the general contract of the <tt>Collection.add</tt> method).
*/
public boolean addPoolToResourceSet(String uri, EObject eObject) {
return usePlatformRelativePath ? addPoolToResourceSet(URI.createPlatformResourceURI(uri, false), eObject)
: addPoolToResourceSet(URI.createURI(uri), eObject);
}
/**
* Creates a new Resource in the ResourceSet. The file will be actually written when the save() method will be
* called. Do not use this method is you need to save with platform relative URIs.
*
* @param file the file in which the pool will be stored
* @param eObject the pool that contains objects.
* @return true (as per the general contract of the <tt>Collection.add</tt> method).
*/
public boolean addPoolToResourceSet(File file, EObject eObject) {
return addPoolToResourceSet(URI.createFileURI(file.getAbsolutePath()), eObject);
}
/**
* Creates a new Resource in the ResourceSet. The file will be actually written when the save() method will be
* called.
*
* @param uri the uri of the file in which the pool will be stored
* @param eObject the pool that contains objects.
* @return true (as per the general contract of the <tt>Collection.add</tt> method).
*/
public boolean addPoolToResourceSet(URI uri, EObject eObject) {
Resource res = resourceSet.createResource(uri);
if (res == null) {
lastErrorMessage = Messages.getString("EMFUtil.NoFactoryFound") + uri; //$NON-NLS-1$
return false;
}
return res.getContents().add(eObject);
}
/**
* Saves each resource of the resource set.
*
* @return true if ok
*/
public boolean save() {
boolean ok = true;
Iterator<Resource> r = resourceSet.getResources().iterator();
while (r.hasNext()) {
Resource ress = r.next();
try {
ress.save(options);
if (log.isDebugEnabled()) {
log.debug("Resource saved in:" + ress.getURI());//$NON-NLS-1$
}
} catch (IOException e) {
log.error(Messages.getString("EMFUtil.errorSave") + ress.getURI().toString(), e);//$NON-NLS-1$
// possible cause is a missing factory initialization and filename extension.
ok = false;
}
}
return ok;
}
/**
* @return the resource set (never null)
*/
public ResourceSet getResourceSet() {
return resourceSet;
}
/**
* @param set the resource set (MUST not be null)
*/
public void setResourceSet(ResourceSet set) {
assert set != null;
if (set != null) {
resourceSet = set;
}
}
/**
* @return
*/
public Map<String, Object> getOptions() {
return options;
}
/**
* Method "getLastErrorMessage".
*
* @return the last error message or null when no error happened since the creation of this object.
*/
public String getLastErrorMessage() {
return this.lastErrorMessage;
}
/**
* Utility method.
*
* Changes the uri of a given resource. The new uri is formed with the name of the input resource's uri appended to
* the path outputUri.
*
* @param res the input resource
* @param destinationUri the destination directory
* @return the new uri.
*/
public static URI changeUri(Resource res, URI destinationUri) {
URI uri = res.getURI();
URI newUri = destinationUri.appendSegment(uri.lastSegment());
res.setURI(newUri);
return newUri;
}
/**
* Utility method.
*
* Method "saveResource" saves the given resource. This method is a helper for saving quickly a given resource and
* all its related resources (if any).
*
* @param resource the resource to save
* @return true if no problem
*/
public static boolean saveResource(Resource resource) {
return saveSingleResource(resource);
}
/**
* Utility method.
*
* Method "saveSingleResource" saves the given resource only. This method is a helper for saving quickly a given
* resource. It does not saved the related resources. This could result in an exception when other related resources
* should be saved with this resource.
*
* @param resource the resource to save
* @return true if no problem
*/
public static boolean saveSingleResource(Resource resource) {
boolean save = true;
try {
Map<String, Object> options = new HashMap<String, Object>();
options.put(XMIResource.OPTION_DECLARE_XML, Boolean.TRUE);
options.put(XMIResource.OPTION_ENCODING, ENCODING);
resource.save(options);
if (log.isDebugEnabled()) {
log.debug("Resource saved in:" + resource.getURI());//$NON-NLS-1$
}
} catch (IOException e) {
log.error(Messages.getString("EMFUtil.errorSave") + resource.getURI().toString(), e);//$NON-NLS-1$
save = false;
}
return save;
}
/**
* Getter for usePlatformRelativePath.
*
* @return the usePlatformRelativePath
*/
public boolean isUsePlatformRelativePath() {
return this.usePlatformRelativePath;
}
/**
* Sets the usePlatformRelativePath.
*
* @param usePlatformRelativePath the usePlatformRelativePath to set
*/
public void setUsePlatformRelativePath(boolean usePlatformRelativePath) {
this.usePlatformRelativePath = usePlatformRelativePath;
}
}