/*******************************************************************************
* Copyright (c) 2009, 2017 xored software, Inc. 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:
* xored software, Inc. - initial API and Implementation (Alex Panchenko)
*******************************************************************************/
package org.eclipse.dltk.tcl.internal.tclchecker;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.PreferencesLookupDelegate;
import org.eclipse.dltk.core.environment.EnvironmentManager;
import org.eclipse.dltk.core.environment.IEnvironment;
import org.eclipse.dltk.tcl.core.TclPlugin;
import org.eclipse.dltk.tcl.tclchecker.model.configs.CheckerConfig;
import org.eclipse.dltk.tcl.tclchecker.model.configs.CheckerEnvironmentInstance;
import org.eclipse.dltk.tcl.tclchecker.model.configs.CheckerInstance;
import org.eclipse.dltk.tcl.tclchecker.model.configs.ConfigsPackage;
import org.eclipse.dltk.validators.core.ValidatorRuntime;
import org.eclipse.dltk.validators.internal.core.ValidatorsCore;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceFactoryImpl;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
public class TclCheckerConfigUtils {
public static interface ICheckerPredicate {
boolean evaluate(CheckerInstance instance);
}
public static final ICheckerPredicate ALL = new ICheckerPredicate() {
@Override
public boolean evaluate(CheckerInstance instance) {
return true;
}
@Override
public String toString() {
return "TclCheckerConfigUtils.ALL"; //$NON-NLS-1$
}
};
public static final ICheckerPredicate AUTO = new ICheckerPredicate() {
@Override
public boolean evaluate(CheckerInstance instance) {
return instance.isAutomatic();
}
@Override
public String toString() {
return "TclCheckerConfigUtils.AUTO"; //$NON-NLS-1$
}
};
public static class ValidatorInstanceRef {
public ValidatorInstanceRef(CheckerEnvironmentInstance environmentInstance, CheckerConfig config) {
this.environmentInstance = environmentInstance;
this.config = config;
}
public final CheckerEnvironmentInstance environmentInstance;
public final CheckerConfig config;
}
public static class ValidatorInstanceResponse {
public ValidatorInstanceResponse(IEnvironment environment, Resource resource) {
this.environment = environment;
this.resource = resource;
}
public final IEnvironment environment;
public final Resource resource;
public final List<ValidatorInstanceRef> instances = new ArrayList<>();
public ResourceSet getResourceSet() {
return resource.getResourceSet();
}
/**
* @return
*/
public String getEnvironmentId() {
return environment.getId();
}
public boolean isEmpty() {
return instances.isEmpty();
}
private List<CheckerConfig> commonConfigurations = null;
public List<CheckerConfig> getCommonConfigurations() {
if (commonConfigurations != null) {
return commonConfigurations;
}
commonConfigurations = new ArrayList<>();
TclCheckerConfigUtils.collectConfigurations(commonConfigurations, resource);
final EList<Resource> resources = resource.getResourceSet().getResources();
for (Resource r : resources.toArray(new Resource[resources.size()])) {
if (r != resource) {
TclCheckerConfigUtils.collectConfigurations(commonConfigurations, r);
}
}
return commonConfigurations;
}
}
/**
* Retrieves the TclChecker configuration for the specified project or
* <code>null</code> if not found (not configured) for the environment of
* this project.
*
* @param project
* @return
*/
public static ValidatorInstanceResponse getConfiguration(IScriptProject project, ICheckerPredicate predicate) {
if (project != null && project.getProject() != null) {
return getConfiguration(project.getProject(), predicate);
} else {
return null;
}
}
/**
* Retrieves the TclChecker configuration for the specified project or
* <code>null</code> if not found (not configured) for the environment of
* this project.
*
* @param project
* @return
*/
public static ValidatorInstanceResponse getConfiguration(IProject project, ICheckerPredicate predicate) {
final String environmentId;
if (project != null) {
environmentId = EnvironmentManager.getEnvironmentId(project);
if (environmentId == null) {
return null;
}
} else {
return null;
}
final String configurationContent = new PreferencesLookupDelegate(project).getString(ValidatorsCore.PLUGIN_ID,
ValidatorRuntime.PREF_CONFIGURATION);
final Resource resource = loadConfiguration(configurationContent);
IEnvironment environment = EnvironmentManager.getEnvironmentById(environmentId);
if (environment == null) {
environment = EnvironmentManager.getLocalEnvironment();
} else if (!environment.isLocal()) {
final ProjectScope context = new ProjectScope(project);
if (DLTKCore.ENABLED.equals(
context.getNode(TclPlugin.PLUGIN_ID).get(TclPlugin.PREF_LOCAL_VALIDATOR, DLTKCore.DISABLED))) {
final ValidatorInstanceResponse response = new ValidatorInstanceResponse(
EnvironmentManager.getLocalEnvironment(), resource);
findConfiguration(response, predicate);
if (!response.instances.isEmpty()) {
return response;
}
}
}
final ValidatorInstanceResponse response = new ValidatorInstanceResponse(environment, resource);
findConfiguration(response, predicate);
return response;
}
private static void findConfiguration(ValidatorInstanceResponse response, ICheckerPredicate predicate) {
loadContributedConfigurations(response.getResourceSet());
for (EObject object : response.resource.getContents()) {
if (object instanceof CheckerInstance) {
final CheckerInstance instance = (CheckerInstance) object;
if (predicate.evaluate(instance)) {
final CheckerEnvironmentInstance environmentInstance = instance
.findEnvironment(response.getEnvironmentId());
if (environmentInstance != null && environmentInstance.getExecutablePath() != null
&& environmentInstance.getExecutablePath().trim().length() != 0) {
CheckerConfig favorite = instance.getFavorite();
if (favorite == null && !instance.getConfigs().isEmpty()) {
favorite = instance.getConfigs().get(0);
}
if (favorite == null && !response.getCommonConfigurations().isEmpty()) {
favorite = response.getCommonConfigurations().get(0);
}
if (favorite != null) {
response.instances.add(new ValidatorInstanceRef(environmentInstance, favorite));
}
}
}
}
}
}
public static ValidatorInstanceResponse getConfiguration(IEnvironment environment, ICheckerPredicate predicate) {
if (environment == null) {
return null;
}
final Resource resource = loadConfiguration(
ValidatorsCore.getDefault().getPluginPreferences().getString(ValidatorRuntime.PREF_CONFIGURATION));
final ValidatorInstanceResponse response = new ValidatorInstanceResponse(environment, resource);
findConfiguration(response, predicate);
return response;
}
private static class ValidatorConfigResource extends XMIResourceImpl implements IContributedResource {
public ValidatorConfigResource(URI uri) {
super(uri);
}
private int priority;
@Override
public int getOrder() {
return priority;
}
@Override
public void setOrder(int value) {
this.priority = value;
}
}
private static class ValidatorConfigResourceFactory extends XMIResourceFactoryImpl {
@Override
public Resource createResource(URI uri) {
return new ValidatorConfigResource(uri);
}
}
public static Resource loadConfiguration(String content) {
final ResourceSet resourceSet = new ResourceSetImpl();
resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap()
.put(Resource.Factory.Registry.DEFAULT_EXTENSION, new ValidatorConfigResourceFactory());
resourceSet.getPackageRegistry().put(ConfigsPackage.eNS_URI, ConfigsPackage.eINSTANCE);
Resource resource = resourceSet.createResource(URI.createURI(ConfigsPackage.eNS_URI));
if (content != null && content.length() != 0) {
try {
final Map<String, Object> loadOptions = new HashMap<>();
loadOptions.put(XMLResource.OPTION_RECORD_UNKNOWN_FEATURE, Boolean.TRUE);
resource.load(new URIConverter.ReadableInputStream(content, ENCODING), loadOptions);
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
}
if (!resource.isLoaded()) {
resource.getContents().clear();
}
return resource;
}
public static final String ENCODING = "UTF-8"; //$NON-NLS-1$
public static String saveConfiguration(Resource resource) throws IOException {
final StringWriter writer = new StringWriter();
final Map<String, Object> saveOptions = new HashMap<>();
saveOptions.put(XMLResource.OPTION_FORMATTED, Boolean.FALSE);
resource.save(new URIConverter.WriteableOutputStream(writer, ENCODING), saveOptions);
return writer.toString();
}
public static List<Resource> loadContributedConfigurations(ResourceSet resourceSet) {
final IConfigurationElement[] elements = Platform.getExtensionRegistry()
.getConfigurationElementsFor(TclCheckerConstants.CONFIGURATION_EXTENSION_POINT_NAME);
if (elements.length != 0) {
final List<Resource> result = new ArrayList<>();
for (IConfigurationElement element : elements) {
final String pathName = "/" + element.getContributor().getName() //$NON-NLS-1$
+ "/" + element.getAttribute("resource"); //$NON-NLS-1$ //$NON-NLS-2$
final URI uri = URI.createPlatformPluginURI(pathName, true);
Resource r = resourceSet.getResource(uri, false);
if (r != null) {
continue;
}
r = resourceSet.createResource(uri);
try {
r.load(null);
result.add(r);
if (r instanceof IContributedResource) {
try {
((IContributedResource) r).setOrder(Integer.parseInt(element.getAttribute("order")));
} catch (NumberFormatException e) {
// ignore
}
}
} catch (IOException e) {
// TODO log error
resourceSet.getResources().remove(r);
}
}
return result;
} else {
return Collections.emptyList();
}
}
public static void collectConfigurations(List<CheckerConfig> instances, Resource r) {
for (EObject object : r.getContents()) {
if (object instanceof CheckerConfig) {
instances.add((CheckerConfig) object);
}
}
}
}