blob: c739f2e174d0e268b3500129dfce953075a29f4a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011 itemis GmbH.
* 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:
* Nirmal Sasidharan - initial API and implementation
* François Rey - better use of EMF reflective API
******************************************************************************/
package org.eclipse.rmf.reqif10.common.util;
import java.util.Collection;
import java.util.GregorianCalendar;
import javax.xml.datatype.XMLGregorianCalendar;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.impl.ResourceImpl;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.rmf.reqif10.AttributeDefinition;
import org.eclipse.rmf.reqif10.AttributeDefinitionBoolean;
import org.eclipse.rmf.reqif10.AttributeDefinitionDate;
import org.eclipse.rmf.reqif10.AttributeDefinitionEnumeration;
import org.eclipse.rmf.reqif10.AttributeDefinitionInteger;
import org.eclipse.rmf.reqif10.AttributeDefinitionReal;
import org.eclipse.rmf.reqif10.AttributeDefinitionString;
import org.eclipse.rmf.reqif10.AttributeDefinitionXHTML;
import org.eclipse.rmf.reqif10.AttributeValue;
import org.eclipse.rmf.reqif10.AttributeValueBoolean;
import org.eclipse.rmf.reqif10.AttributeValueDate;
import org.eclipse.rmf.reqif10.AttributeValueEnumeration;
import org.eclipse.rmf.reqif10.AttributeValueInteger;
import org.eclipse.rmf.reqif10.AttributeValueReal;
import org.eclipse.rmf.reqif10.AttributeValueString;
import org.eclipse.rmf.reqif10.AttributeValueXHTML;
import org.eclipse.rmf.reqif10.DatatypeDefinition;
import org.eclipse.rmf.reqif10.EnumValue;
import org.eclipse.rmf.reqif10.Identifiable;
import org.eclipse.rmf.reqif10.ReqIF;
import org.eclipse.rmf.reqif10.ReqIF10Package;
import org.eclipse.rmf.reqif10.SpecElementWithAttributes;
import org.eclipse.rmf.reqif10.SpecType;
/**
* This class contains various static helper methods for working with ReqIf data objects. Amongst others, we solve a
* number of issues that would be better served proper OOP (e.g. {@link #getTheValue(AttributeValue)}. However, we
* decided not to touch the generated code. We decided to use reflection over long if-then-else blocks to
* <p>
* This class is not intended to be instantiated.
*
* @author jastram
*/
public class ReqIF10Util {
/**
* This class is not designed to be instantiated.
*/
private ReqIF10Util() {
throw new InstantiationError("This class is not designed to be instantiated."); //$NON-NLS-1$
}
/**
* Returns the root ReqIF object for the corresponding EObject or null if none exists. This method simply traverses
* the object tree to the root - there may be more efficient ways for finding the root ReqIF.
*
* @return the root {@link ReqIF} object or null if none found.
*/
public static ReqIF getReqIF(Object obj) {
// TODO: replace and test by EcoreUtil.getRootContainer();
if (!(obj instanceof EObject)) {
return null;
}
while (((EObject) obj).eContainer() != null) {
obj = ((EObject) obj).eContainer();
}
if (obj instanceof ReqIF) {
return (ReqIF) obj;
}
return null;
}
/**
* Retrieves the Value from the given AttributeValue. We would prefer to have an abstract getTheValue() method on
* AttributeValue, but EMF doesn't support this. Thus, each subclass of AttributeValue has its own getTheValue()
* method. This convenience method returns the value.
*/
public static Object getTheValue(AttributeValue attributeValue) {
EStructuralFeature theValueFeature = getTheValueFeature(attributeValue);
return attributeValue.eGet(theValueFeature);
}
/**
* Reflectively sets the value.
*
* @param attributeValue
*/
@SuppressWarnings("unchecked")
public static void setTheValue(AttributeValue attributeValue, Object value) {
if (attributeValue instanceof AttributeValueEnumeration) {
EList<EnumValue> enumValues = ((AttributeValueEnumeration) attributeValue).getValues();
enumValues.clear();
enumValues.addAll((Collection<? extends EnumValue>) value);
} else {
EStructuralFeature theValueFeature = getTheValueFeature(attributeValue);
attributeValue.eSet(theValueFeature, value);
}
}
/**
* Retrieves the value for the given {@link AttributeValue} from the {@link SpecElementWithAttributes}.
*/
public static AttributeValue getAttributeValue(SpecElementWithAttributes specElement, AttributeDefinition attributeDefinition) {
for (AttributeValue value : specElement.getValues()) {
AttributeDefinition definition = getAttributeDefinition(value);
if (attributeDefinition.equals(definition)) {
return value;
}
}
return null;
}
/**
* Finds the {@link AttributeValue} for the given {@link SpecElementWithUserDefinedAttributes}. If it does not exist
* yet, it is created (but not attached to the specElement). If an attributeDefinition with the label does not
* exist, null is returned.
* <p>
* If a default value is available, it is set as well.
*/
public static AttributeValue getAttributeValueForLabel(SpecElementWithAttributes element, String label) {
if (label == null) {
return null;
}
// find the AttributeDefinition for the label
SpecType type = ReqIF10Util.getSpecType(element);
if (type == null) {
return null;
}
AttributeDefinition attrDef = null;
for (AttributeDefinition ad : type.getSpecAttributes()) {
if (label.equals(ad.getLongName())) {
attrDef = ad;
break;
}
}
if (attrDef == null) {
return null;
}
// return existing value or a new one
AttributeValue av = getAttributeValue(element, attrDef);
return av != null ? av : createAttributeValue(attrDef);
}
/**
* Returns the AttributeDefinition for a given value.
*/
public static AttributeDefinition getAttributeDefinition(AttributeValue attributeValue) {
EStructuralFeature theDefinitionFeature = getDefinitionFeature(attributeValue);
return (AttributeDefinition) attributeValue.eGet(theDefinitionFeature);
}
/**
* Returns the {@link DatatypeDefinition} for the given {@link AttributeDefinition} (Would be so much easier with
* inheritance).
*/
public static DatatypeDefinition getDatatypeDefinition(AttributeDefinition attributeDefinition) {
// Using generated code instead of literal value "type"
// A model change will should raise a compiler error
String featureName = ReqIF10Package.eINSTANCE.getAttributeDefinitionString_Type().getName();
return (DatatypeDefinition) reflectiveGet(attributeDefinition, featureName);
}
/**
* Returns the {@link DatatypeDefinition} for the given {@link AttributeValue}.
*
* @return the corresponding {@link DatatypeDefinition} or null if it cannot be determined.
*/
public static DatatypeDefinition getDatatypeDefinition(AttributeValue value) {
if (value == null) {
return null;
}
AttributeDefinition ad = getAttributeDefinition(value);
if (ad == null) {
return null;
}
return getDatatypeDefinition(ad);
}
public static SpecType getSpecType(SpecElementWithAttributes specElement) {
// Using generated code instead of literal value "type"
// A model change will should raise a compiler error
String featureName = ReqIF10Package.eINSTANCE.getSpecObject_Type().getName();
return (SpecType) reflectiveGet(specElement, featureName);
}
public static SpecType getSpecType(AttributeDefinition ad) {
return (SpecType) ad.eContainer();
}
/**
* Helper method that uses EMF reflective API to retrieve a feature given its name.
*/
public static EStructuralFeature getFeature(EObject object, String featureName) {
return object.eClass().getEStructuralFeature(featureName);
}
/**
* Helper method that uses EMF reflective API to retrieve the value for a given feature name.
*/
public static Object reflectiveGet(EObject object, String featureName) {
return object.eGet(getFeature(object, featureName));
}
/**
* Helper method that uses EMF reflective API to set the value for a given feature name.
*/
public static void reflectiveSet(EObject object, String featureName, Object value) {
object.eSet(getFeature(object, featureName), value);
}
/**
* Returns the "the value" feature for the given attributeValue. For instance, for an {@link AttributeValueString}
* it returns {@link Reqif10Package.Literals#ATTRIBUTE_VALUE_STRING__THE_VALUE}. The one exception is
* {@link AttributeValueEnumeration}, where the feature name is "values", rather than "the value".
*
* @throws IllegalArgumentException
* for unknown {@link AttributeValue}s.
*/
public static EStructuralFeature getDefinitionFeature(AttributeValue attributeValue) {
// This implementation may be tedious to write but has the advantage
// of raising compiler errors if the model changes.
// The much shorter and reflective version would not:
//return getFeature(attributeValue, "definition"); //$NON-NLS-1$
if (attributeValue instanceof AttributeValueBoolean) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_BOOLEAN__DEFINITION;
} else if (attributeValue instanceof AttributeValueDate) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_DATE__DEFINITION;
} else if (attributeValue instanceof AttributeValueInteger) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_INTEGER__DEFINITION;
} else if (attributeValue instanceof AttributeValueReal) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_REAL__DEFINITION;
} else if (attributeValue instanceof AttributeValueString) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_STRING__DEFINITION;
} else if (attributeValue instanceof AttributeValueXHTML) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_XHTML__DEFINITION;
} else if (attributeValue instanceof AttributeValueEnumeration) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_ENUMERATION__DEFINITION;
} else {
throw new IllegalArgumentException("Unknown AttributeValue: " + attributeValue); //$NON-NLS-1$
}
}
/**
* Returns the "the value" feature for the given attributeValue. For instance, for an {@link AttributeValueString}
* it returns {@link Reqif10Package.Literals#ATTRIBUTE_VALUE_STRING__THE_VALUE}. The one exception is
* {@link AttributeValueEnumeration}, where the feature name is "values", rather than "the value".
*
* @throws IllegalArgumentException
* for unknown {@link AttributeValue}s.
*/
public static EStructuralFeature getTheValueFeature(AttributeValue attributeValue) {
// This implementation may be tedious to write but has the advantage
// of raising compiler errors if the model changes.
// The much shorter and reflective version would not:
//return getFeature(attributeValue, attributeValue instanceof AttributeValueEnumeration ? "values" : "theValue"); //$NON-NLS-1$
if (attributeValue instanceof AttributeValueBoolean) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_BOOLEAN__THE_VALUE;
} else if (attributeValue instanceof AttributeValueDate) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_DATE__THE_VALUE;
} else if (attributeValue instanceof AttributeValueInteger) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_INTEGER__THE_VALUE;
} else if (attributeValue instanceof AttributeValueReal) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_REAL__THE_VALUE;
} else if (attributeValue instanceof AttributeValueString) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_STRING__THE_VALUE;
} else if (attributeValue instanceof AttributeValueXHTML) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_XHTML__THE_VALUE;
} else if (attributeValue instanceof AttributeValueEnumeration) {
return ReqIF10Package.Literals.ATTRIBUTE_VALUE_ENUMERATION__VALUES;
} else {
throw new IllegalArgumentException("Unknown AttributeValue: " + attributeValue); //$NON-NLS-1$
}
}
/**
* Returns the "defaultValue" feature for the given attributeDefinition. For instance, for an
* {@link AttributeDefinitionString} it returns
* {@link Reqif10Package.Literals#ATTRIBUTE_DEFINITION_STRING__DEFAULT_VALUE}.
*
* @throws IllegalArgumentException
* for an unknown {@link AttributeDefinition}.
*/
public static EStructuralFeature getDefaultValueFeature(AttributeDefinition attributeDefinition) {
// This implementation may be tedious to write but has the advantage
// of raising compiler errors if the model changes.
// The much shorter and reflective version would not:
//return getFeature(attributeDefinition, "defaultValue"); //$NON-NLS-1$
if (attributeDefinition instanceof AttributeDefinitionBoolean) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_BOOLEAN__DEFAULT_VALUE;
} else if (attributeDefinition instanceof AttributeDefinitionDate) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_DATE__DEFAULT_VALUE;
} else if (attributeDefinition instanceof AttributeDefinitionInteger) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_INTEGER__DEFAULT_VALUE;
} else if (attributeDefinition instanceof AttributeDefinitionReal) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_REAL__DEFAULT_VALUE;
} else if (attributeDefinition instanceof AttributeDefinitionString) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_STRING__DEFAULT_VALUE;
} else if (attributeDefinition instanceof AttributeDefinitionXHTML) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_XHTML__DEFAULT_VALUE;
} else if (attributeDefinition instanceof AttributeDefinitionEnumeration) {
return ReqIF10Package.Literals.ATTRIBUTE_DEFINITION_ENUMERATION__DEFAULT_VALUE;
} else {
throw new IllegalArgumentException("Unknown AttributeDefinition: " + attributeDefinition); //$NON-NLS-1$
}
}
/**
* Returns an empty value of the correct type for the given {@link AttributeDefinition}. Note that we do not use the
* command stack here.
*/
public static AttributeValue createAttributeValue(AttributeDefinition attributeDefinition) {
if (attributeDefinition == null) {
return null;
} else {
// Get the default value class, and instantiate it
EStructuralFeature defaultValueFeature = getDefaultValueFeature(attributeDefinition);
EClass attributeValueClass = (EClass) defaultValueFeature.getEType();
AttributeValue value = (AttributeValue) EcoreUtil.create(attributeValueClass);
// Set the link back to the definition object
value.eSet(getDefinitionFeature(value), attributeDefinition);
// Set the value to the default value if any
AttributeValue defaultValue = (AttributeValue) attributeDefinition.eGet(defaultValueFeature);
if (defaultValue != null) {
setTheValue(value, getTheValue(defaultValue));
}
return value;
}
}
/**
* Ensures that the {@link Identifiable}'s ID is unique, with respect to the given {@link ResourceImpl}. This method
* is not using a command, assuming that the {@link Identifiable} is not yet attached to the model.
* <p>
* All (real) children are processed as well.
*/
public static void ensureIdIsUnique(Resource resource, Identifiable identifiable) {
// FIXME unfinished code
// if (resource == null) {
// return;
// }
// if (identifiable.getIdentifier() == null || resource.getEObject(identifiable.getIdentifier()) != null) {
// identifiable.setIdentifier("rmf-" + UUID.randomUUID()); //$NON-NLS-1$
// }
//
// // Also process the children
// for (EObject obj : identifiable.eContents()) {
// if (obj instanceof Identifiable) {
// ensureIdIsUnique(resource, (Identifiable) obj);
// }
// }
}
public static Collection<?> ensureIdIsUnique(Resource resource, Collection<?> collection) {
return collection;
// FIXME unfinished code
// if (resource == null) {
// System.err.println("Cannot ensure unique IDs without resource."); //$NON-NLS-1$
// return collection;
// }
// Collection<?> newCollection = EcoreUtil.copyAll(collection);
// for (Object object : newCollection) {
// if (object instanceof Identifiable) {
// Identifiable identifiable = (Identifiable) object;
// if (identifiable.getIdentifier() == null || resource.getEObject(identifiable.getIdentifier()) != null) {
// identifiable.setIdentifier("rmf-" + UUID.randomUUID()); //$NON-NLS-1$
// }
// EObject eobject = (EObject) object;
// Collection<?> newContents = ensureIdIsUnique(resource, eobject.eContents());
// eobject.eContents().clear();
// eobject.eContents().addAll((Collection<? extends EObject>) newContents);
// }
// }
// return newCollection;
}
/**
* This method returns the current date as an {@link XMLGregorianCalendar} object already formatted into a
* Specification conform format.
*
* @return the current date/time formatted for ReqIF
*/
public static GregorianCalendar getReqIFLastChange() {
return new GregorianCalendar();
}
}