blob: bf6f027faed52077cbeca284010a30e9791d85a6 [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.export.xml.services;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EAttribute;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EDataType;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
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.sdo.EDataObject;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xml.type.XMLTypeFactory;
import org.eclipse.emf.ecore.xml.type.XMLTypePackage;
import org.eclipse.epf.dataexchange.util.ContentProcessor;
import org.eclipse.epf.dataexchange.util.ILogger;
import org.eclipse.epf.export.xml.XmlExportResources;
import org.eclipse.epf.library.services.LibraryProcessor;
import org.eclipse.epf.xml.uma.BreakdownElement;
import org.eclipse.epf.xml.uma.ContentCategoryPackage;
import org.eclipse.epf.xml.uma.ContentPackage;
import org.eclipse.epf.xml.uma.DocumentRoot;
import org.eclipse.epf.xml.uma.MethodElement;
import org.eclipse.epf.xml.uma.MethodLibrary;
import org.eclipse.epf.xml.uma.MethodPackage;
import org.eclipse.epf.xml.uma.MethodPlugin;
import org.eclipse.epf.xml.uma.ProcessComponent;
import org.eclipse.epf.xml.uma.ProcessPackage;
import org.eclipse.epf.xml.uma.UmaFactory;
import org.eclipse.epf.xml.uma.UmaPackage;
import org.eclipse.epf.xml.uma.VariabilityType;
import org.eclipse.epf.xml.uma.WorkOrder;
import org.eclipse.epf.xml.uma.WorkOrderType;
import org.eclipse.epf.xml.uma.util.UmaResourceFactoryImpl;
import commonj.sdo.Type;
/**
* XmlLibrary represents a method library loaded from a specified xml file
* The xml file should be valid to the xml schema for MethodLibrary
*
* @author Jinhua Xi
* @since 1.0
*
*/
public class XmlLibrary {
private String filePath;
private ILogger logger;
private ContentProcessor contentProc = null;
private MethodLibrary rootObject;
// map of content category package for each plugin id
private Map contentCategoryPkgMap = new HashMap();
// map of created elements, guid - EDataObject
Map elementsMap = new HashMap();
public XmlLibrary(ContentProcessor contentProc, ILogger logger, String filePath) {
this.contentProc = contentProc;
this.logger = logger;
this.filePath = filePath;
}
public EDataObject getRoot() {
return this.rootObject;
}
public String getFilePath() {
return this.filePath;
}
/**
* get an array of plugin ids in the library
* @return
*/
public String[] getPluginIds() {
List plugins = rootObject.getMethodPlugin();
String[] ids = new String[plugins.size()];
for (int i = 0; i < plugins.size(); i++ ) {
ids[i] = ((MethodPlugin)plugins.get(i)).getId();
}
return ids;
}
public EDataObject createLibrary(String id, String name) {
MethodLibrary root = UmaFactory.eINSTANCE.createMethodLibrary();
return create(id, name, root);
}
public void load() {
try {
ResourceSet resourceSet = new ResourceSetImpl();
// Get the URI of the model file.
//
URI fileURI = URI.createFileURI(this.filePath);
// Create a resource for this file.
//
//Resource resource = resourceSet.createResource(fileURI);
Resource resource = new UmaResourceFactoryImpl().createResource(fileURI);
resourceSet.getResources().add(resource);
resource.load(new HashMap());
//Resource resource = resourceSet.getResource(fileURI, false);
//EClass eClass = ExtendedMetaData.INSTANCE.getDocumentRoot(umaPackage);
DocumentRoot root = (DocumentRoot)resource.getContents().get(0);
for (Iterator itr = root.eContents().iterator(); itr.hasNext(); ) {
Object o = itr.next();
if ( o instanceof MethodLibrary ) {
this.rootObject = (MethodLibrary)o;
break;
}
}
//System.out.println("Resource loaded");
} catch (IOException e) {
logger.logError(
XmlExportResources.getString("XmlExport.XmlLibrary.error_load_xml", filePath), e); //$NON-NLS-1$ //$NON-NLS-2$
}
}
/**
* create the library and return the root object
*
* @param filePath
* @return
*/
private MethodLibrary create(String id, String name, MethodElement root) {
// Create a resource set
//
ResourceSet resourceSet = new ResourceSetImpl();
// Get the URI of the model file.
//
URI fileURI = URI.createFileURI(this.filePath);
// Create a resource for this file.
//
//Resource resource = resourceSet.createResource(fileURI);
Resource resource = new UmaResourceFactoryImpl().createResource(fileURI);
resourceSet.getResources().add(resource);
// Add the initial model object to the contents.
// root.setId(id);
// root.setName(name);
setElement(id, root);
//this.rootObject = root;
if (root != null) {
resource.getContents().add(root);
}
try {
Map options = new HashMap();
options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
resource.save(options);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
if ( root instanceof MethodLibrary ) {
this.rootObject = (MethodLibrary)root;
}
return this.rootObject;
}
public EDataObject getContentCategoryPackage(String pluginId) {
ContentCategoryPackage pkg = (ContentCategoryPackage)contentCategoryPkgMap.get(pluginId);
if ( pkg != null ) {
return pkg;
}
MethodPlugin plugin = (MethodPlugin)getElement(pluginId);
if ( plugin == null ) {
logger.logWarning(XmlExportResources.getString("XmlExport.XmlLibrary.no_plugin", pluginId)); //$NON-NLS-1$
return null;
}
pkg = UmaFactory.eINSTANCE.createContentCategoryPackage();
pkg.setName("ContentCategories"); //$NON-NLS-1$
setElement(EcoreUtil.generateUUID(), pkg);
plugin.getMethodPackage().add(pkg);
contentCategoryPkgMap.put(pluginId, pkg);
return pkg;
}
public void save() throws Exception {
// Save the contents of the resource to the file system.
//
Map options = new HashMap();
options.put(XMLResource.OPTION_ENCODING, "UTF-8"); //$NON-NLS-1$
Resource resource = rootObject.eResource();
resource.save(options);
}
public EDataObject open() {
return rootObject;
}
public EDataObject getElement(String guid) {
return (EDataObject)elementsMap.get(guid);
}
public EDataObject getElement(Object obj) {
if ( obj instanceof MethodElement) {
return getElement( ((MethodElement)obj).getId());
}
return null;
}
public String getElementId(EDataObject obj) {
if ( obj instanceof MethodElement) {
return ((MethodElement)obj).getId();
}
return null;
}
private void setElement(String guid, EDataObject obj) {
//addElementToContainer(container, obj);
if ( !elementsMap.containsKey(guid) ) {
if ( obj instanceof MethodElement) {
((MethodElement)obj).setId(guid);
}
elementsMap.put(guid, obj);
}
}
// private void addElementToContainer(EDataObject container, EDataObject child) {
//
// try {
// if ( container == null ) {
// return;
// }
//
// if ( child instanceof MethodLibrary || child instanceof MethodPlugin || child instanceof MethodPackage ) {
// return;
// }
//
// while ( !(container instanceof MethodPackage) && (container != null) ) {
// container = container.eContainer();
// }
//
// if ( container instanceof ContentPackage ) {
// ((ContentPackage)container).getContentElement().add(child);
// } else if ( container instanceof ProcessPackage ) {
// ((ProcessPackage)container).getProcessElement().add(child);
// } else {
// System.out.println("Don't know how to set element " + child);
// }
// } catch (RuntimeException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
// }
/**
* create a child element with the specified guid
* @param container container of the element to be created
* @param umaFeatureName uma feature for the element to be created
* @param umaEClassName uma EClass name for the feature
* @param umaElementType uma element type for the element to be created
* @param guid guid of the element to be created
* @return EDataObject the Xml uma element
*/
public EDataObject createElement(EDataObject container, String umaFeatureName, String umaEClassName, String umaElementType, String guid) {
EDataObject obj = getElement(guid);
if ( obj == null ) {
if ( FeatureManager.INSTANCE.isUnneededRmcFeature(umaFeatureName) ) {
return null;
}
EStructuralFeature feature = FeatureManager.INSTANCE.getXmlFeature(container.eClass(), umaFeatureName, umaElementType);
if ( feature == null ) {
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.no_feature", //$NON-NLS-1$
container.eClass().getName(),
umaFeatureName));
return null;
}
// if ( !(feature instanceof EReference) ) {
// System.out.println("Error creating element: containment feature should be EReference type. " + feature.getName());
// //return null;
// }
// // this is an easier way, test it,
// // does not work since feature.getEType() returns the base element type, not the extended one
// // for example, it returns MethodPackage instead of ProcessPackage or ContentPackage
// // so we need to make our own map
// EClassifier c = feature.getEType();
// if ( !c.getName().equals(umaEClassName) ) {
// System.out.println("EClass name not match: " + c.getName() + " --- " + umaEClassName);
// }
EClass objClass = FeatureManager.INSTANCE.getXmlEClass(umaEClassName);
if ( objClass == null ) {
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.no_class", umaEClassName)); //$NON-NLS-1$
return null;
}
obj = (EDataObject)EcoreUtil.create(objClass);
setElement(guid, obj);
if ( obj instanceof WorkOrder ) {
// WorkOrder is not contained in a processPackage in xml model
// it's contained by the breakdownElement
// so we save the element id-object to the map and continue
// don't set the feature value
return obj;
}
// note: all element references are string type (id)
// package references are object references
if ( feature.isMany() ) {
List values = (List)container.eGet(feature);
try {
if ( feature instanceof EAttribute ) {
values.add(guid);
// need to put the object in a container
// for example, the ContaiedArtifacts
addToContainer(container, obj);
} else if ( feature instanceof EReference ) {
try {
values.add(obj);
} catch (RuntimeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} else {
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.error_create_element", //$NON-NLS-1$
feature.getName()));
}
} catch (RuntimeException e) {
logger.logError(
XmlExportResources.getString("XmlExport.XmlLibrary.error_set_value", //$NON-NLS-1$
obj, container), e);
//e.printStackTrace();
}
} else {
if ( feature instanceof EAttribute ) {
container.eSet(feature, guid);
addToContainer(container, obj);
} else if ( feature instanceof EReference ) {
container.eSet(feature, obj);
} else {
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.error_create_element", //$NON-NLS-1$
feature.getName()));
}
}
}
return obj;
}
private void addToContainer(EObject container, EObject obj) {
if ( container == null ) {
return;
}
if ( container instanceof ContentPackage ) {
((ContentPackage)container).getContentElement().add(obj);
} else if ( container instanceof ProcessPackage ) {
((ProcessPackage)container).getProcessElement().add(obj);
// } else if ( (obj instanceof Constraint) && (container instanceof MethodElement) ) {
// // the owner rule should be a containment 0..n feature, waiting for model fix
// //((MethodElement)container).setO
} else {
addToContainer(container.eContainer(), obj);
}
}
public void setAtributeFeatureValue(EDataObject obj, String featureName, Object value) throws Exception {
if ( obj == null || featureName == null || value == null ) {
return;
}
if ( value instanceof List || value instanceof EDataObject ) {
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.invalid_feature_value", //$NON-NLS-1$
featureName, value));
return;
}
// find the feature and set the value
EStructuralFeature feature = FeatureManager.INSTANCE.getXmlFeature(obj.eClass(), featureName);
if ( feature == null) {
// ignore missing features for WorkOrder
if ( !(obj instanceof WorkOrder) ) {
Object[] paras = new Object[]{featureName, obj, value};
logger.logWarning(XmlExportResources.getString("XmlExport.XmlLibrary.error_set_value_2", paras)); //$NON-NLS-1$
}
return;
}
if ( feature instanceof EAttribute) {
try {
if ( feature.getName().equals("variabilityType") ) { //$NON-NLS-1$
value = VariabilityType.get(value.toString());
} else if ( feature.getName().equals("linkType") ) { //$NON-NLS-1$
value = WorkOrderType.get(value.toString());
} else if ( value instanceof java.util.Date ) {
// convert java.util.Date to xml Date
value = getXmlDate((java.util.Date)value);
} else if ( (contentProc != null) && (obj instanceof MethodElement) && (value instanceof String) ) {
value = contentProc.resolveResourceFiles((MethodElement)obj, (String)value);
} else if ( value instanceof java.net.URI ) {
value = ((java.net.URI)value).getPath();
if (contentProc != null) {
contentProc.copyResource((String)value);
}
}
obj.eSet(feature, value);
} catch (RuntimeException e) {
Object[] paras = new Object[]{featureName, obj, value};
logger.logError(XmlExportResources.getString("XmlExport.XmlLibrary.error_set_value_2", paras), e); //$NON-NLS-1$
}
} else {
System.out.println(XmlExportResources.getString("XmlExport.XmlLibrary.error_set_value_3")); //$NON-NLS-1$
}
}
/**
* set the id references for the object
* @param obj EDataObject the object
* @param featureName String the feature of the object
* @param idValue String the id reference value of the feature
* @param valueType Type the object type of the reference. Need to have this to determine the xml feature in case the feature mappting is not unique
* @throws Exception
*/
public void setReferenceValue(EDataObject obj, String featureName, String idValue, Type valueType) throws Exception {
if ( obj == null || featureName == null || idValue == null ) {
return;
}
if ( FeatureManager.INSTANCE.isUnneededRmcFeature(featureName) ) {
return;
}
// find the feature and set the value
EStructuralFeature feature = FeatureManager.INSTANCE.getXmlFeature(obj.eClass(), featureName, valueType.getName());
if ( feature == null ) {
Object[] paras = new Object[]{featureName, obj, idValue};
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.error_set_reference", //$NON-NLS-1$
paras));
return;
}
String str = feature.getEType().getName();
if ( str.equals("String") ) { //$NON-NLS-1$
if ( feature.isMany() ) {
List l = (List)obj.eGet(feature);
if ( !l.contains(idValue) ) {
l.add(idValue);
}
} else {
obj.eSet(feature, idValue);
}
} else if ( feature == UmaPackage.eINSTANCE.getActivity_BreakdownElement()) {
// special handling for breakdown element. In uma, breakdown elements are under process packages
// in xml model, they are owned by the activity
EDataObject v = getElement(idValue);
if ( v instanceof BreakdownElement) {
EObject old_container = v.eContainer();
List l = (List)obj.eGet(feature);
if ( !l.contains(v) ) {
l.add(v);
}
// if the old container package is empty, delete it
if ( (old_container instanceof ProcessPackage) && (old_container.eContainer() instanceof ProcessComponent) ) {
if ( ((ProcessPackage)old_container).getProcessElement().size() == 0 ) {
((ProcessPackage)old_container.eContainer()).getMethodPackage().remove(old_container);
}
}
}
}
}
public Object getXmlDate(java.util.Date dt) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); //$NON-NLS-1$
String dtStr = sdf.format(dt);
dtStr = dtStr.replace(' ', 'T');
EDataType type = XMLTypePackage.eINSTANCE.getDateTime();
return XMLTypeFactory.eINSTANCE.createFromString(type, dtStr);
}
private String getString(Object obj) {
String str = ""; //$NON-NLS-1$
if ( obj instanceof MethodElement ) {
MethodElement me = (MethodElement)obj;
str = me.getType().getName() + ":" + me.getName(); //$NON-NLS-1$
} else if ( obj != null ) {
str = obj.toString();
}
return str;
}
/**
* fix the library so that it meets the uma library standards
*
*/
public void fixLibrary() {
fixGuid( (MethodElement)rootObject);
if ( rootObject instanceof MethodLibrary ) {
for (Iterator it = ((MethodLibrary)rootObject).getMethodPlugin().iterator(); it.hasNext(); ) {
fixPlugin((MethodPlugin)it.next());
}
} else if ( rootObject instanceof MethodPlugin ) {
fixPlugin((MethodPlugin)rootObject);
}
}
/**
* get a list of referenced plugins for the library.
* The referenced plugins does not include the ones inside this library.
* When importing, these plugins must be in the target library already.
* @return List a list of referenced plugins
*/
public List getReferencedPlugins(){
List externalPlugins = new ArrayList();
if ( !(rootObject instanceof MethodLibrary) ) {
return externalPlugins;
}
List selectedPlugins = new ArrayList();
for (Iterator it = ((MethodLibrary)rootObject).getMethodPlugin().iterator(); it.hasNext(); ) {
MethodPlugin plugin = (MethodPlugin)it.next();
String id = plugin.getId();
selectedPlugins.add(id);
if ( externalPlugins.contains(id) ) {
externalPlugins.remove(id);
}
for ( Iterator itr = plugin.getReferencedMethodPlugin().iterator(); itr.hasNext(); ) {
String ref = (String) itr.next();
if ( !selectedPlugins.contains(ref) && !externalPlugins.contains(ref) ) {
externalPlugins.add(ref);
}
}
}
return externalPlugins;
}
private void fixGuid(MethodElement element) {
if ( element == null ) {
return;
}
// if the xml element does not have an id specified, create a new one
String id = element.getId();
if ( id == null || id.equals("") ) { //$NON-NLS-1$
id = EcoreUtil.generateUUID();
element.setId(id);
String msg = XmlExportResources.getString("XmlExport.XmlLibrary.new_id", getString(element), id);
logger.logWarning(msg);
} else {
// check if the element has a unique id or not
Object old = getElement(id);
if ( (old != null) && (old != element) ) {
logger.logWarning(
XmlExportResources.getString("XmlExport.XmlLibrary.id_not_unique", id)); //$NON-NLS-1$
}
setElement(id, element);
}
// iterate the children
for ( Iterator it = element.eContents().iterator(); it.hasNext(); ) {
Object o = it.next();
if ( o instanceof MethodElement ) {
fixGuid((MethodElement)o);
}
}
}
private void fixPlugin(MethodPlugin plugin) {
// find all processes and make sure they are wrapped with a ProcessComponent,
// if not, create one.
// collect the processes to be fixed,
// don't fix within the iteration, may cause concurrent modification exeception
List procs = new ArrayList();
for ( Iterator it = plugin.eAllContents(); it.hasNext(); ) {
EObject o = (EObject)it.next();
if ( isProcess(o) ) {
procs.add(o);
}
}
if ( procs.size() > 0 ) {
for (Iterator it = procs.iterator(); it.hasNext(); ) {
fixProcess( (org.eclipse.epf.xml.uma.Process) it.next() );
}
}
}
/**
* In RMC, a process (Capability pattern and Delivery Process) can be reside in a ProcessPackage
* or a ProcessComponent. If it's in a processComponent, it is treated as a root level process.
* If it's in a ProcessPackage, it is treated as a local copy of another process.
* So we need to check the parent and see it this process is contained by a ProcessComponent.
* @param Obj
* @return boolean
*/
private boolean isProcess(EObject obj) {
if ( !(obj instanceof org.eclipse.epf.xml.uma.Process) ) {
return false;
}
obj = obj.eContainer();
if ( obj instanceof ProcessComponent ) {
return true;
}
// if it's immediate parent is not a ProcessComponent but it's within a ProcessComponent
// it's a local copy of the process
while ( ((obj=obj.eContainer()) != null) && (obj instanceof ProcessPackage) ) {
if ( obj instanceof ProcessComponent ) {
return false;
}
}
return true;
}
private void fixProcess(org.eclipse.epf.xml.uma.Process proc) {
EDataObject container = (EDataObject)proc.eContainer();
ProcessComponent pc = null;
if ( container instanceof ProcessComponent ) {
return;
}
if ( !(container instanceof ProcessPackage) ) {
String msg = XmlExportResources.getString("XmlExport.XmlLibrary.error_process_wrong_container", //$NON-NLS-1$
proc.getName(), container.getType().getName());
logger.logWarning(msg);
return;
}
pc = UmaFactory.eINSTANCE.createProcessComponent();
String id = getTargetParentId(proc.getId());
if ( id == null ) {
id = EcoreUtil.generateUUID();
}
pc.setId(id);
pc.setName(proc.getName());
((ProcessPackage)container).getProcessElement().remove(proc);
((ProcessPackage)container).getMethodPackage().add(pc);
pc.setProcess(proc);
}
/**
* if the process exists in the target library, get the process component id from the target library
*/
private String getTargetParentId(String id) {
EObject obj = LibraryProcessor.getInstance().getElement(id);
if ( obj != null ) {
obj = obj.eContainer();
if ( obj instanceof com.ibm.uma.MethodElement ) {
return ((com.ibm.uma.MethodElement)obj).getGuid();
}
}
return null;
}
public List getAllProcesses(MethodPackage pkg) {
List processes = new ArrayList();
_iteratePackageForProcesses(pkg, processes);
return processes;
}
private void _iteratePackageForProcesses(MethodPackage pkg,
List processes) {
if (pkg instanceof ProcessComponent) {
org.eclipse.epf.xml.uma.Process p = ((ProcessComponent) pkg).getProcess();
if (p != null && !processes.contains(p)) {
processes.add(p);
}
}
for (Iterator it = pkg.getMethodPackage().iterator(); it.hasNext();) {
_iteratePackageForProcesses((MethodPackage) it.next(), processes);
}
}
}