blob: 706021a5b22d707f379f09ef2dd437baf5dd9e41 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2015 Borland Software 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:
* Borland Software Corporation - initial API and implementation
* Christopher Gerking - bug 427237
*******************************************************************************/
package org.eclipse.m2m.internal.qvt.oml.runtime.launch;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.common.util.WrappedException;
import org.eclipse.emf.ecore.EClassifier;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.EReference;
import org.eclipse.emf.ecore.EStructuralFeature;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.m2m.internal.qvt.oml.common.MDAConstants;
import org.eclipse.m2m.internal.qvt.oml.common.MdaException;
import org.eclipse.m2m.internal.qvt.oml.common.launch.TargetUriData;
import org.eclipse.m2m.internal.qvt.oml.compiler.CompilerUtils;
import org.eclipse.m2m.internal.qvt.oml.emf.util.EmfUtil;
import org.eclipse.m2m.internal.qvt.oml.emf.util.ModelContent;
import org.eclipse.m2m.internal.qvt.oml.emf.util.StatusUtil;
import org.eclipse.m2m.internal.qvt.oml.emf.util.WorkspaceUtils;
import org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtTransformation;
import org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtTransformation.TransformationParameter;
import org.eclipse.m2m.internal.qvt.oml.runtime.project.QvtTransformation.TransformationParameter.DirectionKind;
import org.eclipse.m2m.internal.qvt.oml.runtime.project.TransformationUtil;
import org.eclipse.osgi.util.NLS;
public class QvtValidator {
public static enum ValidationType {
FULL_VALIDATION,
LIGHTWEIGHT_VALIDATION
}
private QvtValidator() {
}
public static IStatus validateTransformation(QvtTransformation transformation, List<TargetUriData> targetUris, String traceFilePath,
boolean useTrace, boolean isIncrementalUpdate, ValidationType validationType) throws MdaException {
IStatus result = StatusUtil.makeOkStatus();
if (!TransformationUtil.isRunnable(transformation)) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_TransformationMissedEntryOp,
transformation.getModuleName()));
}
ResourceSet validationRS = CompilerUtils.cloneResourceSet(transformation.getURI(), transformation.getResourceSet());
Iterator<TargetUriData> itrTargetData = targetUris.iterator();
for (TransformationParameter transfParam : transformation.getParameters()) {
if (!itrTargetData.hasNext()) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_EmptyInputTransfParam,
transfParam.getName()));
}
IStatus nextStatus = validateTransformationParameter(transfParam, itrTargetData.next(), validationRS, validationType, isIncrementalUpdate);
if (nextStatus.getSeverity() > result.getSeverity()) {
result = nextStatus;
}
}
if (isIncrementalUpdate) {
IStatus traceStatus;
if (validationType == ValidationType.LIGHTWEIGHT_VALIDATION) {
traceStatus = validateTraceObjectLightweight(traceFilePath, validationRS);
} else {
traceStatus = validateTraceObject(traceFilePath, validationRS);
}
if (StatusUtil.isError(traceStatus)) {
return traceStatus;
}
if (traceStatus.getSeverity() > result.getSeverity()) {
result = traceStatus;
}
}
if (useTrace) {
IStatus traceStatus = validateTrace(traceFilePath, validationRS);
if (StatusUtil.isError(traceStatus)) {
return traceStatus;
}
if (traceStatus.getSeverity() > result.getSeverity()) {
result = traceStatus;
}
}
return result;
}
public static IStatus validateTransformation(QvtTransformation transformation, List<ModelContent> inModels,
String traceFileName) throws MdaException {
IStatus result = StatusUtil.makeOkStatus();
if (!TransformationUtil.isRunnable(transformation)) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_TransformationMissedEntryOp,
transformation.getModuleName()));
}
Iterator<ModelContent> itrInObjs = inModels.iterator();
for (TransformationParameter transfParam : transformation.getParameters()) {
if (transfParam.getDirectionKind() == DirectionKind.IN
|| transfParam.getDirectionKind() == DirectionKind.INOUT) {
if (!itrInObjs.hasNext()) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_MissedInputTransfParam,
transfParam.getName()));
}
IStatus nextStatus = validateTransformationParameterIn(transfParam, itrInObjs.next());
if (nextStatus.getSeverity() > result.getSeverity()) {
result = nextStatus;
}
}
}
StringBuffer superfluousParams = new StringBuffer();
while (itrInObjs.hasNext()) {
if (superfluousParams.length() > 0) {
superfluousParams.append(", "); //$NON-NLS-1$
}
ModelContent obj = itrInObjs.next();
if (obj != null && !obj.getContent().isEmpty()) {
superfluousParams.append(EmfUtil.getFullName(obj.getContent().get(0).eClass()));
}
}
if (superfluousParams.length() > 0) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_SuperfluousInputTransfParam, superfluousParams.toString()));
}
if (traceFileName != null) {
IStatus traceStatus = validateTrace(traceFileName, transformation.getResourceSet());
if (StatusUtil.isError(traceStatus)) {
return traceStatus;
}
if (traceStatus.getSeverity() > result.getSeverity()) {
result = traceStatus;
}
}
return result;
}
private static IStatus validateTransformationParameter(TransformationParameter transfParam, TargetUriData targetData, ResourceSet validationRS,
final ValidationType validationType, boolean isIncrementalUpdate) {
if (transfParam.getMetamodels().isEmpty()) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_EmptyInputTransfParam,
transfParam.getName()));
}
if (targetData.getContentProvider() != null) {
return StatusUtil.makeOkStatus();
}
if (transfParam.getDirectionKind() == DirectionKind.IN) {
if (validationType == ValidationType.LIGHTWEIGHT_VALIDATION) {
return validateTransformationParameterInLightweight(transfParam, targetData, validationRS);
} else {
return validateTransformationParameterIn(transfParam, targetData, validationRS);
}
}
if (transfParam.getDirectionKind() == DirectionKind.INOUT) {
if (validationType == ValidationType.LIGHTWEIGHT_VALIDATION) {
return validateTransformationParameterInOutLightweight(transfParam, targetData, validationRS);
} else {
return validateTransformationParameterInOut(transfParam, targetData, validationRS);
}
}
if (validationType == ValidationType.LIGHTWEIGHT_VALIDATION) {
return validateTransformationParameterOutLightweight(transfParam, targetData, validationRS, isIncrementalUpdate);
} else {
return validateTransformationParameterOut(transfParam, targetData, validationRS, isIncrementalUpdate);
}
}
private static IStatus validateTrace(String traceFilePath, ResourceSet validationRS) {
try {
if (traceFilePath == null || traceFilePath.length() == 0) {
return StatusUtil.makeErrorStatus(Messages.QvtValidator_NoTraceFile);
}
else {
URI traceUri = URI.createURI(traceFilePath);
IStatus result = canSaveEx(null, StatusUtil.makeOkStatus(), traceUri, validationRS);
if (StatusUtil.isError(result)) {
return result;
}
if (!traceFilePath.endsWith(MDAConstants.QVTO_TRACEFILE_EXTENSION_WITH_DOT)) {
if (result.getSeverity() < IStatus.WARNING) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_NoTraceFileExtension, MDAConstants.QVTO_TRACEFILE_EXTENSION_WITH_DOT));
}
}
return result;
}
}
catch (Exception e) {
return StatusUtil.makeErrorStatus(e.getMessage(), e);
}
}
private static IStatus validateTraceObjectLightweight(String traceFilePath, ResourceSet validationRS) {
URI sourceUri = EmfUtil.makeUri(traceFilePath);
if (sourceUri == null) {
return StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_InvalidTraceObjectUri, traceFilePath));
}
if (!EmfUtil.isUriExists(sourceUri, validationRS, false)) {
return StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_InvalidTraceObjectUri, traceFilePath));
}
return StatusUtil.makeOkStatus();
}
private static IStatus validateTraceObject(String traceFilePath, ResourceSet validationRS) {
URI sourceUri = EmfUtil.makeUri(traceFilePath);
ModelContent in = null;
try {
in = EmfUtil.loadModel(sourceUri, validationRS);
}
catch (Exception e) {
}
if (in == null) {
return StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_InvalidTraceObjectUri, traceFilePath));
}
else {
if (validationRS == null) {
EmfUtil.cleanupResourceSet(in.getResourceSet());
}
}
return StatusUtil.makeOkStatus();
}
private static IStatus validateTransformationParameterIn(TransformationParameter transfParam, TargetUriData targetData, ResourceSet validationRS) {
if (transfParam.getEntryType() != null) {
EClassifier classifier = transfParam.getEntryType();
URI sourceUri = EmfUtil.makeUri(targetData.getUriString());
EObject in = null;
try {
ModelContent loadModel = EmfUtil.loadModel(sourceUri, validationRS);
in = (loadModel != null && !loadModel.getContent().isEmpty() ? loadModel.getContent().get(0) : null);
}
catch (Exception e) {
}
if (in == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidSourceUri, targetData.getUriString(), transfParam.getName()));
}
ResourceSet inputRs = (validationRS == null ? in.eResource().getResourceSet() : null);
try {
try {
in = EmfUtil.resolveSource(in, classifier);
}
catch (WrappedException e) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidSourceUri, targetData.getUriString(), transfParam.getName()));
}
if (!EmfUtil.isAssignableFrom(classifier, in.eClass()) || !classifier.isInstance(in)) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_IncompatibleInputTypes, new Object[] {
EmfUtil.getFullName(in.eClass()),
EmfUtil.getFullName(classifier),
transfParam.getName()
}));
}
}
finally {
if (inputRs != null) {
EmfUtil.cleanupResourceSet(inputRs);
}
}
}
else {
EPackage metamodel = transfParam.getMetamodels().get(0);
URI sourceUri = EmfUtil.makeUri(targetData.getUriString());
ModelContent in = null;
try {
in = EmfUtil.loadModel(sourceUri, validationRS);
}
catch (Exception e) {
}
if (in == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidSourceUri, targetData.getUriString(), transfParam.getName()));
}
ResourceSet inputRs = (validationRS == null ? in.getResourceSet() : null);
try {
in = in.getResolvedContent(metamodel);
}
catch (WrappedException e) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidSourceUri, targetData.getUriString(), transfParam.getName()));
}
finally {
if (inputRs != null) {
EmfUtil.cleanupResourceSet(inputRs);
}
}
/*
* See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=216903 (QVT run configuration should consider all objects in selected model)
*
if (EcoreUtil.getRootContainer(in.eClass()) != metamodel) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_IncompatibleInputMetamodels,
EmfUtil.getFullName(in.eClass()),
EmfUtil.getMetamodelName(metamodel)
));
}
*/
}
return StatusUtil.makeOkStatus();
}
private static IStatus validateTransformationParameterInLightweight(TransformationParameter transfParam, TargetUriData targetData, ResourceSet validationRS) {
URI sourceUri = EmfUtil.makeUri(targetData.getUriString());
if (sourceUri == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidSourceUri, targetData.getUriString(), transfParam.getName()));
}
if (!EmfUtil.isUriExists(sourceUri, validationRS, false)) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidSourceUri, targetData.getUriString(), transfParam.getName()));
}
return StatusUtil.makeOkStatus();
}
private static IStatus validateTransformationParameterIn(TransformationParameter transfParam, ModelContent in) {
if (transfParam.getMetamodels().isEmpty()) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_EmptyInputTransfParam, transfParam.getName()));
}
if (transfParam.getEntryType() != null) {
EClassifier classifier = transfParam.getEntryType();
EObject inObj = (in != null && !in.getContent().isEmpty() ? in.getContent().get(0) : null);
if (inObj == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_IncompatibleInputTypes, new Object[] {
"<null>", //$NON-NLS-1$
EmfUtil.getFullName(classifier),
transfParam.getName()
}));
}
else if (!EmfUtil.isAssignableFrom(classifier, inObj.eClass()) || !classifier.isInstance(inObj)) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_IncompatibleInputTypes, new Object[] {
EmfUtil.getFullName(inObj.eClass()),
EmfUtil.getFullName(classifier),
transfParam.getName()
}));
}
}
else {
// EPackage metamodel = transfParam.getMetamodels().get(0);
//
// if (EcoreUtil.getRootContainer(in.eClass()) != metamodel) {
// return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_IncompatibleInputMetamodels,
// EmfUtil.getFullName(in.eClass()),
// EmfUtil.getMetamodelName(metamodel)
// ));
// }
}
return StatusUtil.makeOkStatus();
}
private static IStatus validateTransformationParameterInOut(TransformationParameter transfParam, TargetUriData targetData, ResourceSet validationRS) {
IStatus result = validateTransformationParameterIn(transfParam, targetData, validationRS);
if (result.getSeverity() >= IStatus.WARNING) {
return result;
}
URI sourceUri = URI.createURI(targetData.getUriString());
result = canSaveEx(transfParam, result, sourceUri, validationRS);
return result;
}
private static IStatus validateTransformationParameterInOutLightweight(TransformationParameter transfParam, TargetUriData targetData, ResourceSet validationRS) {
IStatus result = validateTransformationParameterInLightweight(transfParam, targetData, validationRS);
if (result.getSeverity() >= IStatus.WARNING) {
return result;
}
URI sourceUri = URI.createURI(targetData.getUriString());
result = canSaveEx(transfParam, result, sourceUri, validationRS);
return result;
}
private static IStatus validateTransformationParameterOut(TransformationParameter transfParam, TargetUriData targetData,
ResourceSet validationRS, boolean isIncrementalUpdate) {
URI destUri = EmfUtil.makeUri(targetData.getUriString());
if (destUri == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidTargetUri,
targetData.getUriString(), transfParam.getName()));
}
IStatus result = StatusUtil.makeOkStatus();
switch(targetData.getTargetType()) {
case NEW_MODEL: {
if (EmfUtil.isUriExists(destUri, validationRS, true)) {
if (result.getSeverity() < IStatus.WARNING) {
if (EmfUtil.isUriExistsAsEObject(destUri, validationRS, true)) {
if (!isIncrementalUpdate) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationExists,
destUri, transfParam.getName()));
}
}
else {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationExistsNonEObject,
destUri, transfParam.getName()));
}
}
}
IStatus canSave = canSave(transfParam, destUri, validationRS);
if (StatusUtil.isError(canSave)) {
return canSave;
}
if (canSave.getSeverity() > result.getSeverity()) {
result = canSave;
}
if (destUri.hasFragment()) {
if (result.getSeverity() < IStatus.WARNING) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_NewDestinationHasFragment,
destUri.fragment(), transfParam.getName()));
}
}
break;
}
case EXISTING_CONTAINER: {
ModelContent loadModel = EmfUtil.loadModel(destUri, validationRS);
EObject eContainer = (loadModel != null && !loadModel.getContent().isEmpty() ? loadModel.getContent().get(0) : null);
if (eContainer == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidTargetUri,
destUri, transfParam.getName()));
}
result = canSaveEx(transfParam, result, destUri, validationRS);
if (StatusUtil.isError(result)) {
return result;
}
String feature = targetData.getFeature();
if (feature == null || feature.trim().length() == 0) {
if (!isIncrementalUpdate && result.getSeverity() < IStatus.WARNING) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationExists,
destUri, transfParam.getName()));
}
}
else {
EStructuralFeature eFeature = eContainer.eClass().getEStructuralFeature(feature);
if (eFeature instanceof EReference == false) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidFeature,
feature, transfParam.getName()));
}
EReference ref = (EReference)eFeature;
if (!ref.isChangeable()) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidFeature,
ref.getName(), transfParam.getName()));
}
// no need for the check since always whole model extent is saved
// EClassifier refType = ref.getEType();
// if (!EmfUtil.isAssignableFrom(refType, classifier)) {
// return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_IncompatibleInputTypes,
// EmfUtil.getFullName(classifier), EmfUtil.getFullName(refType)));
// }
}
break;
}
case INPLACE:
return StatusUtil.makeErrorStatus(Messages.QvtValidator_InplaceConfigNotSupported);
}
return result;
}
private static IStatus validateTransformationParameterOutLightweight(TransformationParameter transfParam, TargetUriData targetData,
ResourceSet validationRS, boolean isIncrementalUpdate) {
URI destUri = EmfUtil.makeUri(targetData.getUriString());
if (destUri == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_InvalidTargetUri,
targetData.getUriString(), transfParam.getName()));
}
IStatus result = StatusUtil.makeOkStatus();
switch(targetData.getTargetType()) {
case NEW_MODEL: {
if (!isIncrementalUpdate && EmfUtil.isUriExists(destUri, validationRS, true)) {
if (result.getSeverity() < IStatus.WARNING) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationExists,
destUri, transfParam.getName()));
}
}
IStatus canSave = canSave(transfParam, destUri, validationRS);
if (StatusUtil.isError(canSave)) {
return canSave;
}
if (canSave.getSeverity() > result.getSeverity()) {
result = canSave;
}
if (destUri.hasFragment()) {
if (result.getSeverity() < IStatus.WARNING) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_NewDestinationHasFragment,
destUri.fragment(), transfParam.getName()));
}
}
break;
}
case EXISTING_CONTAINER: {
result = canSaveEx(transfParam, result, destUri, validationRS);
if (StatusUtil.isError(result)) {
return result;
}
String feature = targetData.getFeature();
if (feature == null || feature.trim().length() == 0) {
if (!isIncrementalUpdate && result.getSeverity() < IStatus.WARNING) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationExists,
destUri, transfParam.getName()));
}
}
break;
}
case INPLACE:
return StatusUtil.makeErrorStatus(Messages.QvtValidator_InplaceConfigNotSupported);
}
return result;
}
private static IStatus canSave(TransformationParameter transfParam, URI destUri, ResourceSet validationRS) {
URIConverter uriConverter = (validationRS != null ? validationRS.getURIConverter() : URIConverter.INSTANCE);
URI converted = uriConverter.normalize(destUri);
IStatus okStatus = StatusUtil.makeOkStatus();
String scheme = converted.scheme();
if (converted.isFile()) {
if (!"file".equals(scheme) && !"platform".equals(scheme)) { //$NON-NLS-1$ //$NON-NLS-2$
if (transfParam == null) {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_UriNotFile,
new Object[] {destUri, scheme}));
}
else {
return StatusUtil.makeErrorStatus(NLS.bind(Messages.QvtValidator_UriNotFileParam,
new Object[] {destUri, scheme, transfParam.getName()}));
}
}
}
return okStatus;
}
private static IStatus canSaveEx(TransformationParameter transfParam, IStatus result, URI destUri, ResourceSet validationRS) {
IFile file = WorkspaceUtils.getWorkspaceFile(destUri);
if (file != null && file.exists() && file.isReadOnly()) {
if (result.getSeverity() < IStatus.WARNING) {
if (transfParam == null) {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationReadonly, destUri));
}
else {
result = StatusUtil.makeWarningStatus(NLS.bind(Messages.QvtValidator_DestinationReadonlyParam,
destUri, transfParam.getName()));
}
}
}
IStatus canSave = canSave(transfParam, destUri, validationRS);
if (StatusUtil.isError(canSave)) {
return canSave;
}
return result;
}
}