Validator.java 9.29 KB
Newer Older
package org.etsi.mts.tdl.constraints.evl;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Platform;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.EPackage;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.epsilon.common.parse.Region;
import org.eclipse.epsilon.common.parse.problem.ParseProblem;
import org.eclipse.epsilon.common.util.StringProperties;
import org.eclipse.epsilon.emc.emf.EmfModel;
import org.eclipse.epsilon.emc.emf.EmfUtil;
import org.eclipse.epsilon.emc.emf.InMemoryEmfModel;
import org.eclipse.epsilon.eol.EolModule;
import org.eclipse.epsilon.eol.exceptions.EolRuntimeException;
import org.eclipse.epsilon.eol.exceptions.models.EolModelLoadingException;
import org.eclipse.epsilon.eol.models.IModel;
import org.eclipse.epsilon.eol.tools.MathTool;
import org.eclipse.epsilon.eol.types.AbstractToolNativeTypeDelegate;
import org.eclipse.epsilon.eol.types.EolClasspathNativeTypeDelegate;
import org.eclipse.epsilon.etl.EtlModule;
import org.eclipse.epsilon.evl.EvlModule;
import org.eclipse.epsilon.evl.IEvlFixer;
import org.eclipse.epsilon.evl.execute.UnsatisfiedConstraint;
import org.eclipse.epsilon.profiling.Profiler;
import org.eclipse.epsilon.profiling.ProfilerTargetSummary;
import org.eclipse.epsilon.profiling.ProfilingExecutionListener;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.resource.XtextResource;
import org.etsi.mts.tdl.tdlPackage;
import org.etsi.mts.tdl.structuredobjectives.StructuredObjectivesPackage;
import org.etsi.mts.tdl.extendedconfigurations.ExtendedConfigurationsPackage;
import org.osgi.framework.Bundle;


@SuppressWarnings("unused")
public class Validator {
	
	private static final List<EPackage> packages = List.of(tdlPackage.eINSTANCE, StructuredObjectivesPackage.eINSTANCE, ExtendedConfigurationsPackage.eINSTANCE);
	public List<UnsatisfiedConstraint> validate(Resource r) throws Exception {
		List<UnsatisfiedConstraint> violations = new ArrayList<>();
		String prefix = "tdl-generated-ETSI-ES-203-119-";
		String suffix = "-fixed.evl";
		//TODO: Change versions to published? 
		List<String> constraints = List.of(
				prefix+"1-V1.5.1"+suffix,
				prefix+"4-V1.4.1"+suffix,
				prefix+"7-V1.2.1"+suffix
				);
		try {
			//TODO: This is very important otherwise all kinds of weird problems might occur (in case it may be put in the handler as well)
			EcoreUtil.resolveAll(r);
			//TODO: Run all, maintain generated and fixed for differencing between versions and manual interventions
			//FIXED: Meta-models not resolved in plugin mode? -> fixed
			IModel tdlModel = getTDLModel(r, true, false);
			tdlModel.load();
			List<IModel> dependencies = new ArrayList<>();
			//TODO: this can cause duplicate definitions, resolveAll above makes this unnecessary
//			System.out.println("Loading validation dependencies for: "+r.getURI().path());
//			for (Resource d : r.getResourceSet().getResources()) {
//				if (d!=r) {
//					System.out.println("  Loading "+d.getURI().path());
//					IModel dModel = getTDLModel(d, true, false);
//					dModel.load();
//					dependencies.add(dModel);
//				}
//			}
//			String source = "epsilon/constraints/tdl.evl";
			for (String part : constraints) {
				String source = "epsilon/constraints/"+part;
				java.net.URI uri = new File(source).toURI();
				//FIXED: also for TO? -> should work with all now
				if (Platform.isRunning()) {
					//System.out.println("Running as plugin...");
					Bundle bundle = Platform.getBundle("org.etsi.mts.tdl.constraints");
					URL url = bundle.getEntry(source);
					uri = url.toURI();
				} else {
					//WS
					String binPath=this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath();
					String projectPath = new File(binPath).getParent();
					uri = new File(projectPath+"/"+source).toURI();
				
				EvlModule module = new EvlModule();
				module.parse(uri);
				
				//DONE: For some reason default classpath delegate does not work -> add custom delegate
//				module.getContext().getNativeTypeDelegates().add(new EolClasspathNativeTypeDelegate());
				module.getContext().getNativeTypeDelegates().add(new XtextBridgeNativeTypeDelegate());
				//FIXED: Defer warnings in case necessary -> not at present
//				module.getContext().setWarningStream(new PrintStream("Epsilon.log"));
				
				//TODO: integrate error reporting
				if (module.getParseProblems().size() > 0) {
					System.err.println("Parse errors occured...");
					for (ParseProblem problem : module.getParseProblems()) {
						System.err.println(problem.toString());
					}
				}
				
//				dumpConstraints(module);
				module.getContext().getModelRepository().addModel(tdlModel);
				
				//add dependencies
				module.getContext().getModelRepository().addModels(dependencies);
				
				//execute
				module.execute();
				
				EvlModule m = (EvlModule) module;
				violations.addAll(m.getContext().getUnsatisfiedConstraints());
				
				//filter only within resource
				violations = violations.stream()
					.filter(v -> ((EObject)v.getInstance()).eResource() == r)
					.collect(Collectors.toList());
				dumpViolations(violations);
				
				//TODO: Needed? New API does not provide it
//				module.reset();
			}
			tdlModel.dispose();
			for (IModel d : dependencies) {
				d.dispose();
			}
			
		} catch (URISyntaxException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (Exception e) {
			//TODO: Error message refinements
			System.err.println(e.getMessage()
					.replaceAll("\n.+epsilon/", "\n  at (epsilon/")
//					.replaceAll("\\.", "")
//					.replaceAll("evl@", "evl:")
//					.replaceAll(":(\\d+).+", ":$1)")
//					.replaceAll("-", "")
//					.replaceAll("\n.+/", "\n  at (")
					);
			throw(e);
//			e.printStackTrace();
		}
		return violations;
	}

	private void dumpViolations(List<UnsatisfiedConstraint> violations) {
		for (UnsatisfiedConstraint constraint : violations) {
			System.out.println("  " + constraint.getMessage());
			//TODO: this can only work with XtextResources
			if (((EObject) constraint.getInstance()).eResource() instanceof XtextResource) {
				ICompositeNode node = NodeModelUtils.findActualNodeFor((EObject) constraint.getInstance());
				String text = "Line "+node.getStartLine()+"-"+node.getEndLine()+ ": "+node.getText().trim();
				System.out.println("    " + text);
			} else {
				//TODO: handle other resources
			}
		}
	}

	private void dumpConstraints(EvlModule module) {
		//Dump -> extract to separate functionality
		for (var cx : module.getDeclaredConstraintContexts()) {
			System.out.println(cx);
			for (var cs : cx.getConstraints()) {
				System.out.println("  "+cs);
				System.out.println("    check:"+getSnippet(module.getFile(), cs.getCheckBlock().getBody().getRegion()));
				System.out.println("    message:"+getSnippet(module.getFile(), cs.getMessageBlock().getBody().getRegion()));
			}
		}
	}

	private String getSnippet(File file, Region region) {
		String snippet = "";
		try {
			List<String> lines = Files.readAllLines(Path.of(file.getPath()));
			lines.add(0, "");
			lines = lines.subList(region.getStart().getLine(), region.getEnd().getLine()+1);
//			System.out.println(lines);
			lines.set(lines.size()-1, lines.get(lines.size()-1).substring(0, region.getEnd().getColumn()));
			lines.set(0, lines.get(0).substring(region.getStart().getColumn()-1));
			lines = lines.stream()
					.filter(l -> !l.trim().startsWith("//"))
					.collect(Collectors.toList());
			snippet = String.join(" ", lines)
					.replaceAll("\\s+", " ")
					;
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	//TODO: extract to shared library
	public IModel getTDLModel(Resource resource, boolean read, boolean write) throws Exception {
		EmfModel model;
		//FIXED: meta-models not resolved in plugin mode? -> seems to work now
//		model = new InMemoryEmfModel(resource);
		model = new InMemoryEmfModel("TDL", resource, packages);
		model.setStoredOnDisposal(write);
		model.setReadOnLoad(read);
		model.setCachingEnabled(true);
		model.setMetamodelUris(List.of(tdlPackage.eNS_URI, StructuredObjectivesPackage.eNS_URI, ExtendedConfigurationsPackage.eNS_URI));