blob: 259af094c2d656e2711a70170c44001d1d9c90fc [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2021 Christoph Läubrich and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Christoph Läubrich - initial API and implementation
*******************************************************************************/
package org.eclipse.pde.internal.core.target;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLConnection;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.osgi.util.NLS;
import org.eclipse.pde.core.target.ITargetDefinition;
import org.eclipse.pde.core.target.ITargetHandle;
public class RemoteTargetHandle implements ITargetHandle {
private enum RemoteState {
UNKNWON, EXISTS, NOT_FOUND, FAILED;
}
private static final String FILE_SCHEMA = "file:"; //$NON-NLS-1$
private static final Map<URI, RemoteTargetHandle> REMOTE_HANDLES = new ConcurrentHashMap<>();
/**
* URI scheme for local targets
*/
static final String SCHEME = "remote"; //$NON-NLS-1$
private final URI uri;
private RemoteState state;
private RemoteTargetHandle(URI uri) {
this.uri = uri;
}
@Override
public String getMemento() throws CoreException {
return SCHEME + ":" + uri.toASCIIString(); //$NON-NLS-1$
}
@Override
public boolean exists() {
synchronized (this) {
if (state == RemoteState.UNKNWON) {
try {
if ("file".equalsIgnoreCase(uri.getScheme())) { //$NON-NLS-1$
File file = new File(uri);
state = file.isFile() ? RemoteState.EXISTS : RemoteState.NOT_FOUND;
} else {
URLConnection connection = uri.toURL().openConnection();
if (connection instanceof HttpURLConnection) {
HttpURLConnection http = (HttpURLConnection) connection;
try {
http.setInstanceFollowRedirects(true);
http.setRequestMethod("HEAD"); //$NON-NLS-1$
int code = http.getResponseCode() / 100;
state = code == 2 ? RemoteState.EXISTS : RemoteState.NOT_FOUND;
} finally {
http.disconnect();
}
} else {
connection.getInputStream().close();
state = RemoteState.EXISTS;
}
}
} catch (IOException e) {
state = RemoteState.FAILED;
}
}
return state == RemoteState.EXISTS;
}
}
@Override
public ITargetDefinition getTargetDefinition() throws CoreException {
TargetDefinition definition = new TargetDefinition(this);
try (InputStream stream = uri.toURL().openStream()) {
synchronized (this) {
state = RemoteState.EXISTS;
}
definition.setContents(stream);
} catch (MalformedURLException e) {
throw new CoreException(
Status.error(NLS.bind(Messages.RemoteTargetHandle_malformed_URL, uri, e.getMessage()), e));
} catch (IOException e) {
throw new CoreException(
Status.error(NLS.bind(Messages.RemoteTargetHandle_ioproblem, uri, e.getMessage()), e));
}
return definition;
}
public static RemoteTargetHandle get(String uri) throws CoreException {
Objects.requireNonNull(uri);
try {
IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
URI resolvedUri = new URI(convertRawToUri(manager.performStringSubstitution(uri)));
RemoteTargetHandle handle = REMOTE_HANDLES.computeIfAbsent(resolvedUri, RemoteTargetHandle::new);
synchronized (handle) {
if (handle.state != RemoteState.EXISTS) {
// if it has failed or not found, reset the state here it
// might has changed in the meantime ...
handle.state = RemoteState.UNKNWON;
}
}
return handle;
} catch (URISyntaxException e) {
throw new CoreException(Status.error(NLS.bind(Messages.RemoteTargetHandle_invalid_URI, e.getMessage()), e));
}
}
static String convertRawToUri(String resolvePath) {
// We need to convert windows path separators here...
resolvePath = resolvePath.replace('\\', '/');
String lc = resolvePath.toLowerCase();
if (lc.startsWith(FILE_SCHEMA) && lc.charAt(FILE_SCHEMA.length()) != '/') {
// according to rfc a file URI must always start with a slash
resolvePath = FILE_SCHEMA + '/' + resolvePath.substring(FILE_SCHEMA.length());
}
return resolvePath;
}
}