package org.eclipse.buckminster.fetcher.actor;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.buckminster.core.CorePlugin;
import org.eclipse.buckminster.core.actor.AbstractActor;
import org.eclipse.buckminster.core.actor.IActionContext;
import org.eclipse.buckminster.core.helpers.PropertyExpander;
import org.eclipse.buckminster.core.helpers.TextUtils;
import org.eclipse.buckminster.fetcher.IResourceFetcher;
import org.eclipse.buckminster.fetcher.Messages;
import org.eclipse.buckminster.fetcher.StreamProcessorFactory;
import org.eclipse.buckminster.runtime.BuckminsterException;
import org.eclipse.buckminster.runtime.MonitorUtils;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.osgi.util.NLS;
/**
* Buckminster's Actor to fetch resources from the web. It can uncompress
* archives, flatten and filter contents.
*
* @author Guillaume CHATELET
*/
public class FetcherActor extends AbstractActor {
private static final String INCLUDE = "include="; //$NON-NLS-1$
private static final String FETCHER_URL = "url"; //$NON-NLS-1$
private static final String FETCHER_TO_DIR = "dir"; //$NON-NLS-1$
private static final String FETCHER_OPTIONS = "options"; //$NON-NLS-1$
private static final String FETCHER_UNCOMPRESS = "uncompress"; //$NON-NLS-1$
private static final String FETCHER_FLATTEN = "flatten"; //$NON-NLS-1$
private static final String FETCHER_LOGIN = "login"; //$NON-NLS-1$
private static final String FETCHER_PASSWORD = "pass"; //$NON-NLS-1$
private static final String[] validProperties = { FETCHER_URL, FETCHER_TO_DIR, FETCHER_OPTIONS, FETCHER_LOGIN, FETCHER_PASSWORD };
private static final String[] validOptions = { FETCHER_FLATTEN, FETCHER_UNCOMPRESS };
private static final String PLUGIN_ID = "org.eclipse.buckminster.fetcher"; //$NON-NLS-1$
private PropertyExpander expander;
@Override
protected IStatus internalPerform(IActionContext ctx, IProgressMonitor monitor) throws CoreException {
monitor = MonitorUtils.ensureNotNull(monitor);
try {
expander = new PropertyExpander(ctx);
checkProperties();
monitor.beginTask(null, 1);
final IResourceFetcher resourceFetcher = getResourceFetcher();
final String login = getSafeProperty(FETCHER_LOGIN);
final String password = getSafeProperty(FETCHER_PASSWORD);
if (login != null && password != null)
resourceFetcher.setBasicAuthCredential(login, password);
resourceFetcher.fetch(monitor);
} catch (IOException e) {
Throwable t = BuckminsterException.unwind(e);
CorePlugin.getLogger().error(t, t.toString());
return new Status(IStatus.ERROR, PLUGIN_ID, e.getMessage());
} catch (CoreException e) {
Throwable t = BuckminsterException.unwind(e);
CorePlugin.getLogger().error(t, t.toString());
throw e;
} finally {
monitor.done();
}
return Status.OK_STATUS;
}
/**
* Checks the defined ActorProperties to warn user for misspelled keywords
*
* @throws CoreException
*/
private void checkProperties() throws CoreException {
HashSet<String> validSet = new HashSet<String>(Arrays.asList(validProperties));
final Map<String, String> actorProperties = getActiveContext().getAction().getActorProperties();
final Set<String> keySet = actorProperties.keySet();
for (String property : keySet) {
if (validSet.contains(property) == false) {
final StringBuffer buffer = new StringBuffer();
for (String validProperty : validSet)
buffer.append(validProperty).append(' ');
throw new IllegalStateException(NLS.bind(Messages.actorProperty_0_invalid_valid_are_1, property, buffer.toString()));
}
}
validSet.clear();
validSet.addAll(Arrays.asList(validOptions));
final HashSet<String> options = getOptions();
for (String option : options) {
if (validSet.contains(option) == false && option.startsWith(INCLUDE) == false) {
final StringBuffer buffer = new StringBuffer();
for (String validProperty : validSet)
buffer.append(validProperty).append(' ');
buffer.append(INCLUDE);
throw new IllegalStateException(NLS.bind(Messages.actorProperty_option_0_invalid_valid_are_1, option, buffer.toString()));
}
}
}
/**
* @return the destination directory if set or the component home otherwise
* @throws CoreException
*/
private String getDestinationDirectory() throws CoreException {
final String homePath = (String) getActiveContext().getProperties().get("buckminster.home"); //$NON-NLS-1$
final String toDir = getSafeProperty(FETCHER_TO_DIR);
if (toDir == null) {
return homePath;
}
if (new File(toDir).isAbsolute())
return toDir;
return homePath + toDir + File.separatorChar;
}
/**
* @return a list of regexp to use as include filter while uncompressing the
* archive.
* @throws CoreException
*/
private List<String> getIncludes() throws CoreException {
final List<String> includes = new ArrayList<String>();
final HashSet<String> options = getOptions();
for (String option : options) {
if (option.startsWith(INCLUDE)) {
int start = option.indexOf('=');
includes.add(option.substring(start + 1));
}
}
return includes;
}
/**
* @param url
* @return the name of the archive as stated by the provided url ie :
* http://www.example.com/download/file.tar.gz returns file.tar.gz
*/
private String getLocalFileNameFromUrl(URL url) {
return new File(url.getFile()).getName();
}
/**
* @return a set of options
* @throws CoreException
*/
private HashSet<String> getOptions() throws CoreException {
final HashSet<String> options = new HashSet<String>();
final String optionActorProperty = getSafeProperty(FETCHER_OPTIONS);
if (optionActorProperty == null)
return options;
final String[] split = optionActorProperty.split(";"); //$NON-NLS-1$
for (String option : split)
options.add(option);
return options;
}
/**
* @return the correct IResourceFetcher according to the uncompress flag.
* @throws MalformedURLException
* @throws CoreException
*/
private IResourceFetcher getResourceFetcher() throws MalformedURLException, CoreException {
final URL url = getUrl();
final String destinationDirectory = getDestinationDirectory();
if (shouldUncompress()) {
return StreamProcessorFactory.getUncompressInstance(url, destinationDirectory, getIncludes(), shouldFlatten());
}
// regular file copy
final String localFileName = getLocalFileNameFromUrl(url);
return StreamProcessorFactory.getCopyInstance(url, destinationDirectory, localFileName);
}
/**
* @param property
* @return an expanded property or null if property is not set
* @throws CoreException
*/
final private String getSafeProperty(String property) throws CoreException {
final String p = TextUtils.notEmptyTrimmedString(this.getActorProperty(property));
if (p == null)
return null;
return expander.expand(p);
}
/**
* @return the URL to use
* @throws MalformedURLException
* @throws CoreException
*/
private URL getUrl() throws MalformedURLException, CoreException {
return new URL(getSafeProperty(FETCHER_URL));
}
private boolean hasOption(String option) throws CoreException {
return getOptions().contains(option);
}
private boolean shouldFlatten() throws CoreException {
return hasOption(FETCHER_FLATTEN);
}
private boolean shouldUncompress() throws CoreException {
return hasOption(FETCHER_UNCOMPRESS);
}
}