blob: c6d062be24323d29a53dd04b00fd591ff11ae670 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2016 IBM 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
*
*******************************************************************************/
package org.eclipse.dltk.launching;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.environment.IEnvironment;
import org.eclipse.dltk.core.environment.IExecutionEnvironment;
import org.eclipse.dltk.core.environment.IFileHandle;
import org.eclipse.dltk.internal.launching.DLTKLaunchingPlugin;
import org.eclipse.dltk.internal.launching.DebugRunnerDelegate;
import org.eclipse.dltk.internal.launching.IInterpreterInstallExtensionContainer;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.emf.ecore.resource.URIConverter;
import org.eclipse.emf.ecore.util.EcoreUtil;
import org.eclipse.emf.ecore.xmi.XMIResource;
import org.eclipse.emf.ecore.xmi.XMLResource;
import org.eclipse.emf.ecore.xmi.impl.XMIResourceImpl;
/**
* Abstract implementation of a interpreter install.
* <p>
* Clients implementing interpreter installs must subclass this class.
* </p>
*
* @since 2.0
*/
public abstract class AbstractInterpreterInstall
implements IInterpreterInstall, IInterpreterInstallExtensionContainer {
private IInterpreterInstallType fType;
private String fId;
private String fName;
private IFileHandle fInstallLocation;
private LibraryLocation[] fSystemLibraryDescriptions;
private String fInterpreterArgs;
private EnvironmentVariable[] fEnvironmentVariables;
// whether change events should be fired
private boolean fNotify = true;
private void firePropertyChangeEvent(PropertyChangeEvent event) {
if (fNotify) {
ScriptRuntime.fireInterpreterChanged(event);
}
}
/**
* Constructs a new interpreter install.
*
* @param type
* The type of this interpreter install. Must not be
* <code>null</code>
* @param id
* The unique identifier of this interpreter instance Must not be
* <code>null</code>.
* @throws IllegalArgumentException
* if any of the required parameters are <code>null</code>.
*/
public AbstractInterpreterInstall(IInterpreterInstallType type, String id) {
if (type == null || id == null) {
throw new IllegalArgumentException();
}
fType = type;
fId = id;
}
@Override
public String getId() {
return fId;
}
@Override
public String getNatureId() {
return fType.getNatureId();
}
@Override
public String getName() {
return fName;
}
@Override
public void setName(String name) {
if (!name.equals(fName)) {
PropertyChangeEvent event = new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_NAME, fName,
name);
fName = name;
firePropertyChangeEvent(event);
}
}
@Override
public IFileHandle getInstallLocation() {
// return PlatformFileUtils
// .findAbsoluteOrEclipseRelativeFile(fInstallLocation);
return fInstallLocation;
}
@Override
public IFileHandle getRawInstallLocation() {
return fInstallLocation;
}
@Override
public IEnvironment getEnvironment() {
if (fInstallLocation != null)
return fInstallLocation.getEnvironment();
return null;
}
/*
* @see org.eclipse.dltk.launching.IInterpreterInstall#getEnvironmentId()
*/
@Override
public String getEnvironmentId() {
if (fInstallLocation != null)
return fInstallLocation.getEnvironmentId();
return null;
}
@Override
public IExecutionEnvironment getExecEnvironment() {
IEnvironment environment = getEnvironment();
if (environment != null) {
return environment.getAdapter(IExecutionEnvironment.class);
}
return null;
}
@Override
public void setInstallLocation(IFileHandle installLocation) {
if (!installLocation.equals(fInstallLocation)) {
PropertyChangeEvent event = new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_INSTALL_LOCATION,
fInstallLocation, installLocation);
fInstallLocation = installLocation;
firePropertyChangeEvent(event);
}
}
@Override
public IInterpreterInstallType getInterpreterInstallType() {
return fType;
}
@Override
public LibraryLocation[] getLibraryLocations() {
return fSystemLibraryDescriptions;
}
@Override
public void setLibraryLocations(LibraryLocation[] locations) {
if (locations == fSystemLibraryDescriptions) {
return;
}
LibraryLocation[] newLocations = locations;
if (newLocations == null) {
newLocations = getInterpreterInstallType()
.getDefaultLibraryLocations(getInstallLocation(),
getEnvironmentVariables(), null);
}
LibraryLocation[] prevLocations = fSystemLibraryDescriptions;
if (prevLocations == null) {
prevLocations = getInterpreterInstallType()
.getDefaultLibraryLocations(getInstallLocation(),
getEnvironmentVariables(), null);
}
if (newLocations.length == prevLocations.length) {
int i = 0;
boolean equal = true;
while (i < newLocations.length && equal) {
equal = newLocations[i].equals(prevLocations[i]);
i++;
}
if (equal) {
return;
}
}
PropertyChangeEvent event = new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_LIBRARY_LOCATIONS,
prevLocations, newLocations);
fSystemLibraryDescriptions = locations;
firePropertyChangeEvent(event);
}
/**
* Whether this Interpreter should fire property change notifications.
*
* @param notify
*/
protected void setNotify(boolean notify) {
fNotify = notify;
}
@Override
public boolean equals(Object object) {
if (object instanceof IInterpreterInstall) {
IInterpreterInstall interpreter = (IInterpreterInstall) object;
return getInterpreterInstallType()
.equals(interpreter.getInterpreterInstallType())
&& getId().equals(interpreter.getId());
}
return false;
}
@Override
public int hashCode() {
return getInterpreterInstallType().hashCode() + getId().hashCode();
}
@Override
public String[] getInterpreterArguments() {
String args = getInterpreterArgs();
if (args == null) {
return null;
}
ExecutionArguments ex = new ExecutionArguments(args, ""); //$NON-NLS-1$
return ex.getInterpreterArgumentsArray();
}
@Override
public void setInterpreterArguments(String[] args) {
if (args == null) {
setInterpreterArgs(null);
} else {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < args.length; i++) {
String string = args[i];
buf.append(string);
buf.append(' ');
}
setInterpreterArgs(buf.toString().trim());
}
}
@Override
public String getInterpreterArgs() {
return fInterpreterArgs;
}
@Override
public void setInterpreterArgs(String args) {
if (fInterpreterArgs == null) {
if (args == null) {
return;
}
} else if (fInterpreterArgs.equals(args)) {
return;
}
PropertyChangeEvent event = new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_Interpreter_ARGUMENTS,
fInterpreterArgs, args);
fInterpreterArgs = args;
firePropertyChangeEvent(event);
}
/**
* Throws a core exception with an error status object built from the given
* message, lower level exception, and error code.
*
* @param message
* the status message
* @param exception
* lower level exception associated with the error, or
* <code>null</code> if none
* @param code
* error code
* @throws CoreException
* the "abort" core exception
*
*/
protected void abort(String message, Throwable exception, int code)
throws CoreException {
throw new CoreException(new Status(IStatus.ERROR,
DLTKLaunchingPlugin.getUniqueIdentifier(), code, message,
exception));
}
// IBuiltinModuleProvider
@Override
public String[] getBuiltinModules() {
return null;
}
@Override
public String getBuiltinModuleContent(String name) {
return null;
}
@Override
public long lastModified() {
return 0;
}
protected IInterpreterRunner getDebugInterpreterRunner() {
return new DebugRunnerDelegate(this);
}
@Override
public IInterpreterRunner getInterpreterRunner(String mode) {
if (mode.equals(ILaunchManager.DEBUG_MODE)) {
return getDebugInterpreterRunner();
}
return null;
}
@Override
public EnvironmentVariable[] getEnvironmentVariables() {
return fEnvironmentVariables;
}
@Override
public void setEnvironmentVariables(EnvironmentVariable[] variables) {
PropertyChangeEvent event = new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_ENVIRONMENT_VARIABLES,
this.fEnvironmentVariables, variables);
this.fEnvironmentVariables = variables;
firePropertyChangeEvent(event);
}
private XMLResource resource = null;
/**
* @since 2.0
*/
protected XMIResource createResource() {
final XMIResourceImpl r = new XMIResourceImpl();
r.setEncoding(ENCODING);
return r;
}
private static final String ENCODING = "UTF-8"; //$NON-NLS-1$
/**
* @since 2.0
*/
@Override
public EObject findExtension(EClass clazz) {
if (resource != null) {
for (EObject object : resource.getContents()) {
if (clazz.equals(object.eClass())) {
return object;
}
}
}
return null;
}
/**
* @since 2.0
*/
@Override
public EObject replaceExtension(EClass clazz, EObject value) {
if (value != null) {
Assert.isLegal(clazz.equals(value.eClass()));
}
if (resource == null) {
resource = createResource();
}
for (ListIterator<EObject> i = resource.getContents().listIterator(); i
.hasNext();) {
EObject object = i.next();
if (clazz.equals(object.eClass())) {
if (value != null) {
i.set(value);
} else {
i.remove();
}
firePropertyChangeEvent(new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_EXTENSIONS,
Collections.singletonList(object),
value != null ? Collections.singletonList(value)
: null));
return object;
}
}
if (value != null) {
resource.getContents().add(value);
firePropertyChangeEvent(new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_EXTENSIONS,
null, Collections.singletonList(value)));
}
return null;
}
/**
* @since 2.0
*/
@Override
public List<EObject> copyExtensions() {
if (resource != null && !resource.getContents().isEmpty()) {
Collection<EObject> copy = EcoreUtil
.copyAll(resource.getContents());
if (copy instanceof List<?>) {
return (List<EObject>) copy;
} else {
return new ArrayList<>(copy);
}
} else {
return Collections.emptyList();
}
}
/**
* @since 2.0
*/
@Override
public List<EObject> getExtensions() {
if (resource != null && !resource.getContents().isEmpty()) {
return new ArrayList<>(resource.getContents());
} else {
return Collections.emptyList();
}
}
/**
* @since 2.0
*/
@Override
public void setExtensions(List<EObject> value) {
final List<EObject> oldValue;
if (resource == null) {
resource = createResource();
oldValue = null;
} else {
oldValue = new ArrayList<>(resource.getContents());
resource.getContents().clear();
}
resource.getContents().addAll(value);
firePropertyChangeEvent(new PropertyChangeEvent(this,
IInterpreterInstallChangedListener.PROPERTY_EXTENSIONS,
oldValue, value));
}
/**
* @since 2.0
*/
@Override
public String saveExtensions() {
if (resource != null && !resource.getContents().isEmpty()) {
StringWriter stringWriter = new StringWriter();
try {
Map<String, Object> saveOptions = new HashMap<>();
saveOptions.put(XMLResource.OPTION_DECLARE_XML, Boolean.FALSE);
saveOptions.put(XMLResource.OPTION_FORMATTED, Boolean.FALSE);
resource.save(new URIConverter.WriteableOutputStream(
stringWriter, ENCODING), saveOptions);
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
return stringWriter.toString();
} else {
return null;
}
}
/**
* @since 2.0
*/
@Override
public void loadExtensions(String value) {
if (value != null && value.length() != 0) {
if (resource == null) {
resource = createResource();
}
try {
resource.load(
new URIConverter.ReadableInputStream(value, ENCODING),
null);
} catch (IOException e) {
if (DLTKCore.DEBUG) {
e.printStackTrace();
}
}
} else {
if (resource != null) {
resource.getContents().clear();
}
}
}
}