/* * Copyright (c) 2010 Netcetera AG 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: * - Netcetera AG: initial implementation */ package ch.netcetera.eclipse.projectconfig.core.internal; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.List; import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.ILog; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Status; import org.osgi.framework.FrameworkUtil; import ch.netcetera.eclipse.common.io.IOUtil; import ch.netcetera.eclipse.common.text.ITextAccessor; import ch.netcetera.eclipse.projectconfig.core.IProjectConfigurationService; import ch.netcetera.eclipse.projectconfig.core.ProjectConfigurationScript; import ch.netcetera.eclipse.projectconfig.core.configurationcommands.IProjectConfigurationCommand; import ch.netcetera.eclipse.projectconfig.net.IProjectConfigurationClient; import ch.netcetera.eclipse.projectconfig.net.IProjectConfigurationScriptData; /** * Service that imports the remote workspace preferences. */ public class ProjectConfigurationService implements IProjectConfigurationService { private static final String PROTOCOL_PREFIX_FILE = "file"; private static final String PROTOCOL_PREFIX_HTTP = "http"; private volatile IProjectConfigurationClient client; /** * Binds the {@link IProjectConfigurationClient} service reference. * * @param client the client service reference to bind */ public void bindClient(IProjectConfigurationClient client) { this.client = client; } /** * Unbinds the {@link IProjectConfigurationClient} service reference. * * @param client the client service reference to bind */ public void unbindClient(@SuppressWarnings("unused") IProjectConfigurationClient client) { this.client = null; } /** * {@inheritDoc} */ @Override public IStatus runConfigurationScript(List<IProject> projectList, String scriptUrl, ITextAccessor textAccessor, String pluginId, ILog log) { ProjectConfigurationScript script = new ProjectConfigurationScript(scriptUrl); IStatus status = getProjectPropertiesScript(script, textAccessor, pluginId, log); if (status.isOK()) { status = runScriptOnProjects(projectList, script, textAccessor, pluginId); } return status; } private IStatus getProjectPropertiesScript(ProjectConfigurationScript script, ITextAccessor textAccessor, String pluginId, ILog log) { IStatus status = Status.OK_STATUS; String commandFileUrl = script.getUrl(); if (commandFileUrl.toLowerCase().startsWith(PROTOCOL_PREFIX_HTTP)) { status = getProjectConfigurationScriptFromHTTP(script, textAccessor, pluginId, log); } else if (commandFileUrl.toLowerCase().startsWith(PROTOCOL_PREFIX_FILE)) { status = getProjectConfigurationScriptFromFile(script, textAccessor, pluginId, log); } return status; } /** * Gets the script file from a local (file://) source and parses it's commands and metadata. * * @param script the script object to which the commands and metadata shall be appended * @return the status */ private IStatus getProjectConfigurationScriptFromFile(ProjectConfigurationScript script, ITextAccessor textAccessor, String pluginId, ILog log) { IStatus importStatus = Status.OK_STATUS; String bundleSymbolicName = FrameworkUtil.getBundle(this.getClass()).getSymbolicName(); InputStream inputStream = null; try { File sourceFile = new File(new URI(script.getUrl())); if (sourceFile.canRead()) { try { inputStream = new FileInputStream(sourceFile); ProjectConfigurationParser.parse(script, inputStream, textAccessor, pluginId, log); } catch (FileNotFoundException e) { importStatus = wrapExceptionInErrorStatus(e); } catch (SecurityException e) { importStatus = wrapExceptionInErrorStatus(e); } finally { IOUtil.closeSilently(inputStream); } } else { importStatus = new Status(IStatus.ERROR, bundleSymbolicName, "Could not read local file."); } } catch (IOException e) { importStatus = new Status(IStatus.ERROR, bundleSymbolicName, e.getLocalizedMessage(), e); } catch (URISyntaxException e) { importStatus = new Status(IStatus.ERROR, bundleSymbolicName, e.getLocalizedMessage(), e); } return importStatus; } /** * Gets the script file from a remote (http(s)://) source and parses it's commands and metadata. * * @param script the script object to which the commands and metadata shall be appended * @return the status */ private IStatus getProjectConfigurationScriptFromHTTP(ProjectConfigurationScript script, ITextAccessor textAccessor, String pluginId, ILog log) { IStatus importStatus = Status.OK_STATUS; if (this.client != null) { try { IProjectConfigurationScriptData file = this.client.getProjectConfiguationScriptFileData(script.getUrl(), new NullProgressMonitor()); ProjectConfigurationParser.parse(script, new ByteArrayInputStream(file.getData()), textAccessor, pluginId, log); } catch (CoreException e) { importStatus = wrapExceptionInErrorStatus(e); } catch (IOException e) { importStatus = wrapExceptionInErrorStatus(e); } } else { String bundleSymbolicName = FrameworkUtil.getBundle(this.getClass()).getSymbolicName(); importStatus = new Status(IStatus.ERROR, bundleSymbolicName, "could not obtain client service."); } return importStatus; } /** * Runs the script passed on the projects passed. * * @param projectList the projects * @param script the script * @return the status */ private IStatus runScriptOnProjects(List<IProject> projectList, ProjectConfigurationScript script, ITextAccessor textAccessor, String pluginId) { IStatus status = Status.OK_STATUS; if (script != null && script.getCommandList() != null) { boolean statusOK = true; List<IProjectConfigurationCommand> commandList = script.getCommandList(); // run the commands of the script one after another on each projects for (IProjectConfigurationCommand command : commandList) { statusOK &= command.execute(projectList).isOK(); } if (!statusOK) { status = new Status(IStatus.WARNING, pluginId, textAccessor.getText("error.config")); } } else { status = new Status(IStatus.WARNING, pluginId, textAccessor.getText("error.config")); } return status; } /** * Wraps a {@link Throwable} in a {@link IStatus} instance with the status value {@link IStatus#ERROR}. * * @param t the {@link Throwable} to wrap * @return the {@link IStatus} instance */ private IStatus wrapExceptionInErrorStatus(Throwable t) { String bundleSymbolicName = FrameworkUtil.getBundle(this.getClass()).getSymbolicName(); return new Status(IStatus.ERROR, bundleSymbolicName, t.getLocalizedMessage(), t); } }