Added support for validating EMF models against built-in constraints
diff --git a/plugins/org.eclipse.epsilon.emc.emf.dt/src/org/eclipse/epsilon/emc/emf/dt/EmfModelConfigurationDialog.java b/plugins/org.eclipse.epsilon.emc.emf.dt/src/org/eclipse/epsilon/emc/emf/dt/EmfModelConfigurationDialog.java
index dbeab1d..67c6cd3 100644
--- a/plugins/org.eclipse.epsilon.emc.emf.dt/src/org/eclipse/epsilon/emc/emf/dt/EmfModelConfigurationDialog.java
+++ b/plugins/org.eclipse.epsilon.emc.emf.dt/src/org/eclipse/epsilon/emc/emf/dt/EmfModelConfigurationDialog.java
@@ -111,6 +111,7 @@
 	private final static String PROPERTY_METAMODEL_FILE = EmfModel.PROPERTY_METAMODEL_FILE;

 

 	protected Button expandButton;

+	protected Button validateButton;

 	private Text modelFileText;

 	private TableViewer metamodelList;

 

@@ -161,6 +162,7 @@
 			}

 		}

 		expandButton.setSelection(new Boolean(properties.getProperty(EmfModel.PROPERTY_EXPAND)).booleanValue());

+		validateButton.setSelection(new Boolean(properties.getProperty(EmfModel.PROPERTY_VALIDATE, "false")).booleanValue());

 

 		metamodelList.refresh();

 	}

@@ -206,6 +208,7 @@
 		// Persist values that are used directly to construct an instance of EmfModel (legacy - only one metamodel was supported)

 		properties.put(EmfModel.PROPERTY_METAMODEL_URI, sbURIMetamodels.toString());

 		properties.put(EmfModel.PROPERTY_EXPAND, expandButton.getSelection() + "");

+		properties.put(EmfModel.PROPERTY_VALIDATE, validateButton.getSelection() + "");

 		properties.put(PROPERTY_IS_METAMODEL_FILE_BASED, "".equals(sbURIMetamodels.toString()));

 

 		// Create and persist URI values that are needed to construct an instance of EmfModel

@@ -221,7 +224,7 @@
 		expandButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

 		expandButton.setText("Include external references");

 		expandButton.setSelection(true);

-	

+		

 		GridData expandButtonData = new GridData();

 		expandButtonData.horizontalSpan = 2;

 		expandButton.setLayoutData(expandButtonData);

@@ -234,6 +237,15 @@
 		GridData reuseUnmodifiedFileBasedMetamodelsButtonData = new GridData();

 		reuseUnmodifiedFileBasedMetamodelsButtonData.horizontalSpan = 2;

 		reuseUnmodifiedFileBasedMetamodelsButton.setLayoutData(reuseUnmodifiedFileBasedMetamodelsButtonData);

+

+		validateButton = new Button(groupContent, SWT.CHECK);

+		validateButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));

+		validateButton.setText("Validate model");

+		validateButton.setSelection(false);

+		

+		GridData validateButtonData = new GridData();

+		validateButtonData.horizontalSpan = 2;

+		validateButton.setLayoutData(validateButtonData);

 		

 		groupContent.layout();

 		groupContent.pack();

diff --git a/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/AbstractEmfModel.java b/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/AbstractEmfModel.java
index 7461e08..144ae7c 100644
--- a/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/AbstractEmfModel.java
+++ b/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/AbstractEmfModel.java
@@ -20,6 +20,8 @@
 import java.util.function.Predicate;

 import java.util.stream.Collectors;

 import java.util.stream.StreamSupport;

+

+import org.eclipse.emf.common.util.Diagnostic;

 import org.eclipse.emf.common.util.EList;

 import org.eclipse.emf.common.util.URI;

 import org.eclipse.emf.ecore.EClass;

@@ -596,6 +598,32 @@
 		return null;

 	}

 	

+	public void validate() throws EolModelLoadingException {

+		List<Resource> resources = new ArrayList<>();

+		if (modelImpl != null) {

+			if (modelImpl.getResourceSet() != null) resources.addAll(modelImpl.getResourceSet().getResources());

+			else resources.add(modelImpl);

+		}

+		

+		for (Resource resource : modelImpl.getResourceSet().getResources()) {

+			// Report errors/warnings in the resources' getErrors() / getWarnings()

+			if (!resource.getErrors().isEmpty() || !resource.getWarnings().isEmpty()) {

+				List<Resource.Diagnostic> resourceDiagnostics = new ArrayList<>();

+				resourceDiagnostics.addAll(resource.getErrors());

+				resourceDiagnostics.addAll(resource.getWarnings());

+				Resource.Diagnostic diagnostic = resourceDiagnostics.get(0);

+				throw new EolModelLoadingException(new Exception(diagnostic.getMessage() + " (" + diagnostic.getLocation() + "@" + diagnostic.getLine() + ")"), this);

+			}

+		

+			// Validate using EMF's validators

+			List<Diagnostic> diagnostics = EmfUtil.validate(resource).getChildren().stream().filter(d -> d.getSeverity() != Diagnostic.INFO).collect(Collectors.toList());

+			if (!diagnostics.isEmpty()) {

+				Diagnostic diagnostic = diagnostics.get(0);

+				throw new EolModelLoadingException(new Exception(diagnostic.getMessage()), this);

+			}

+		}

+	}

+	

 	public boolean isExpand() {

 		return expand;

 	}

diff --git a/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/EmfModel.java b/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/EmfModel.java
index ff8a056..81952cc 100644
--- a/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/EmfModel.java
+++ b/plugins/org.eclipse.epsilon.emc.emf/src/org/eclipse/epsilon/emc/emf/EmfModel.java
@@ -102,6 +102,15 @@
 	 */

 	public static final String PROPERTY_REUSE_UNMODIFIED_FILE_BASED_METAMODELS = "reuseUnmodifiedFileBasedMetamodels";

 

+	/**

+	 * One of the keys used to construct the first argument to {@link EmfModel#load(StringProperties, String)}.

+	 * 

+	 * This key is a Boolean value that if set to <code>true</code>

+	 * it triggers validation of all the resources in the model's

+	 * resource set after loading (default is <code>false</code>)

+	 */

+	public static final String PROPERTY_VALIDATE = "validate";

+	

 	protected List<URI> metamodelUris = new ArrayList<>();

 	protected List<EPackage> packages;

 	

@@ -114,7 +123,8 @@
 	protected URI modelUri;

 	protected List<URI> metamodelFileUris = new ArrayList<>();

 	protected boolean useExtendedMetadata = false;

-

+	protected boolean validate = false;

+	

 	protected boolean reuseUnmodifiedFileBasedMetamodels = true;

 	protected static Map<String, List<EPackage>> fileBasedMetamodels = new HashMap<>();

 	protected static Map<String, Long> fileBasedMetamodelTimestamps = new HashMap<>();

@@ -169,6 +179,7 @@
 		this.metamodelUris = toURIList(properties.getProperty(PROPERTY_METAMODEL_URI));

 		setMetamodelFileUris(toURIList(properties.getProperty(PROPERTY_FILE_BASED_METAMODEL_URI)));

 		setReuseUnmodifiedFileBasedMetamodels(properties.getBooleanProperty(PROPERTY_REUSE_UNMODIFIED_FILE_BASED_METAMODELS, reuseUnmodifiedFileBasedMetamodels));

+		setValidate(properties.getBooleanProperty(PROPERTY_VALIDATE, false));

 		

 		load();

 	}

@@ -176,6 +187,7 @@
 	@Override

 	protected void loadModel() throws EolModelLoadingException {

 		loadModelFromUri();

+		if (validate) validate();

 		setupContainmentChangeListeners();

 	}

 

@@ -689,4 +701,12 @@
 			return false;

 		}

 	}

+	

+	public boolean isValidate() {

+		return validate;

+	}

+	

+	public void setValidate(boolean validate) {

+		this.validate = validate;

+	}

 }

diff --git a/plugins/org.eclipse.epsilon.eol.dt/src/org/eclipse/epsilon/eol/dt/launching/EclipseContextManager.java b/plugins/org.eclipse.epsilon.eol.dt/src/org/eclipse/epsilon/eol/dt/launching/EclipseContextManager.java
index 4ddb4f6..6dcbd40 100644
--- a/plugins/org.eclipse.epsilon.eol.dt/src/org/eclipse/epsilon/eol/dt/launching/EclipseContextManager.java
+++ b/plugins/org.eclipse.epsilon.eol.dt/src/org/eclipse/epsilon/eol/dt/launching/EclipseContextManager.java
@@ -77,16 +77,17 @@
 		setup(context);

 	}

 	

-	public static void setup(IEolContext context, ILaunchConfiguration configuration, IProgressMonitor progressMonitor, ILaunch launch) throws EolRuntimeException {

+	public static void setup(IEolContext context, ILaunchConfiguration configuration, IProgressMonitor progressMonitor, ILaunch launch) throws Exception {

 		setup(context, configuration, progressMonitor, launch, true);

 	}

 	

-	public static void setup(IEolContext context, ILaunchConfiguration configuration, IProgressMonitor progressMonitor, ILaunch launch, boolean loadModels) throws EolRuntimeException {

+	public static void setup(IEolContext context, ILaunchConfiguration configuration, IProgressMonitor progressMonitor, ILaunch launch, boolean loadModels) throws Exception {

+		loadParameters(context, configuration);

+		setup(context, progressMonitor);

 		if (loadModels) {

 			loadModels(context,configuration,progressMonitor);

 		}

-		loadParameters(context, configuration);

-		setup(context, progressMonitor);

+		

 	}

 	

 	private static void loadIo(IEolContext context) {

@@ -149,7 +150,7 @@
 		

 	}

 	

-	private static void loadModels(IEolContext context, ILaunchConfiguration configuration, IProgressMonitor progressMonitor) {

+	private static void loadModels(IEolContext context, ILaunchConfiguration configuration, IProgressMonitor progressMonitor) throws Exception {

 		String subtask = "Loading models";

 		progressMonitor.subTask(subtask);

 		progressMonitor.beginTask(subtask, 100);

@@ -168,27 +169,22 @@
 			properties.load(modelDescriptor);

 			

 			IModel model = null;

-

-			try {

-				model = ModelTypeExtension.forType(properties.getProperty("type")).createModel();

-				model.load(properties, relativePath -> {

-					try {

-						IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(relativePath));

-						if (file != null) { 

-							return file.getLocation().toOSString(); 

-						}

+			

+			model = ModelTypeExtension.forType(properties.getProperty("type")).createModel();

+			model.load(properties, relativePath -> {

+				try {

+					IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(new Path(relativePath));

+					if (file != null) { 

+						return file.getLocation().toOSString(); 

 					}

-					catch (Exception ex) { LogUtil.log("Error while resolving absolute path for " + relativePath, ex); }

-					

-					return EclipseUtil.getWorkspacePath() + relativePath;

-				});

+				}

+				catch (Exception ex) { LogUtil.log("Error while resolving absolute path for " + relativePath, ex); }

 				

-				context.getModelRepository().addModel(model);

-			}

-			catch (Exception e) {

-				EpsilonConsole.getInstance().getErrorStream().print(e.toString());

-				LogUtil.log(e);

-			}

+				return EclipseUtil.getWorkspacePath() + relativePath;

+			});

+			

+			context.getModelRepository().addModel(model);

+			

 		}

 		

 		progressMonitor.done();		

diff --git a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/exceptions/models/EolModelLoadingException.java b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/exceptions/models/EolModelLoadingException.java
index 8eb6e2b..15992da 100644
--- a/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/exceptions/models/EolModelLoadingException.java
+++ b/plugins/org.eclipse.epsilon.eol.engine/src/org/eclipse/epsilon/eol/exceptions/models/EolModelLoadingException.java
@@ -20,5 +20,10 @@
 		super(internal);

 		this.model = model;

 	}

-

+	

+	@Override

+	public String getReason() {

+		return "Error whilst loading model " + model.getName() + ": " + super.getReason();

+	}

+	

 }

diff --git a/plugins/org.eclipse.epsilon.workflow.emf/ant/org/eclipse/epsilon/workflow/tasks/emf/LoadEmfModelTask.java b/plugins/org.eclipse.epsilon.workflow.emf/ant/org/eclipse/epsilon/workflow/tasks/emf/LoadEmfModelTask.java
index aa84508..b2fc35d 100644
--- a/plugins/org.eclipse.epsilon.workflow.emf/ant/org/eclipse/epsilon/workflow/tasks/emf/LoadEmfModelTask.java
+++ b/plugins/org.eclipse.epsilon.workflow.emf/ant/org/eclipse/epsilon/workflow/tasks/emf/LoadEmfModelTask.java
@@ -34,6 +34,7 @@
 	protected boolean reuseUnmodifiedMetamodelFile = true;

 	protected boolean cached = true;

 	protected boolean concurrent = false;

+	protected boolean validate = false;

 	

 	@Override

 	public IModel loadModel() throws BuildException {

@@ -50,6 +51,7 @@
 		properties.put(EmfModel.PROPERTY_CACHED, cached + "");

 		properties.put(EmfModel.PROPERTY_CONCURRENT, concurrent + "");

 		properties.put(EmfModel.PROPERTY_REUSE_UNMODIFIED_FILE_BASED_METAMODELS, reuseUnmodifiedMetamodelFile + "");

+		properties.put(EmfModel.PROPERTY_VALIDATE, validate + "");

 		

 		if (metamodelUri != null) {

 			properties.put(EmfModel.PROPERTY_METAMODEL_URI, EmfUtil.createUri(metamodelUri));

@@ -188,5 +190,13 @@
 	public void setConcurrent(boolean concurrent) {

 		this.concurrent = concurrent;

 	}

+	

+	public void setValidate(boolean validate) {

+		this.validate = validate;

+	}

+	

+	public boolean isValidate() {

+		return validate;

+	}

 }