/* * Copyright (c) 2012 Data Harmonisation Panel * * All rights reserved. This program and the accompanying materials are made * available under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * You should have received a copy of the GNU Lesser General Public License * along with this distribution. If not, see <http://www.gnu.org/licenses/>. * * Contributors: * HUMBOLDT EU Integrated Project #030962 * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.common.core.io.project.extension.internal; import static com.google.common.base.Preconditions.checkState; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.io.IOUtils; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import de.fhg.igd.slf4jplus.ATransaction; import eu.esdihumboldt.hale.common.core.io.ExportProvider; import eu.esdihumboldt.hale.common.core.io.HaleIO; import eu.esdihumboldt.hale.common.core.io.IOAction; import eu.esdihumboldt.hale.common.core.io.IOAdvisor; import eu.esdihumboldt.hale.common.core.io.IOAdvisorRegister; import eu.esdihumboldt.hale.common.core.io.IOProvider; import eu.esdihumboldt.hale.common.core.io.ImportProvider; import eu.esdihumboldt.hale.common.core.io.Value; import eu.esdihumboldt.hale.common.core.io.extension.IOActionExtension; import eu.esdihumboldt.hale.common.core.io.extension.IOAdvisorExtension; import eu.esdihumboldt.hale.common.core.io.impl.LogProgressIndicator; import eu.esdihumboldt.hale.common.core.io.project.model.AdvisorProjectFile; import eu.esdihumboldt.hale.common.core.io.project.model.ProjectFile; import eu.esdihumboldt.hale.common.core.io.report.IOReport; import eu.esdihumboldt.hale.common.core.io.report.IOReporter; import eu.esdihumboldt.hale.common.core.io.supplier.FileIOSupplier; import eu.esdihumboldt.hale.common.core.io.supplier.LocatableInputSupplier; import eu.esdihumboldt.hale.common.core.io.supplier.LocatableOutputSupplier; import eu.esdihumboldt.hale.common.core.service.ServiceProvider; /** * Project file based on an I/O action * * @author Simon Templer */ public class ActionProjectFile implements AdvisorProjectFile { private static final ALogger log = ALoggerFactory.getLogger(ActionProjectFile.class); private final Map<String, Value> saveParameters; private final String saveProviderId; private final Map<String, Value> loadParameters; private final String loadProviderId; private final String loadActionId; private final String saveActionId; private File applyFile; private final ServiceProvider serviceProvider; private IOAdvisorRegister advisorRegister; /** * Create a project file based on an I/O action * * @param loadActionId the action identifier for loading the file * @param loadProviderId the provider identifier to use for loading the * file, may be <code>null</code> to use auto-detection * @param loadParameters the parameters for the I/O provider used for * loading the file * @param saveActionId the action identifier for saving the file * @param saveProviderId the provider identifier to use for saving the file * @param saveParameters the parameters for the I/O provider used for saving * the file * @param serviceProvider the service provider the I/O advisor should * retrieve services through */ public ActionProjectFile(String loadActionId, String loadProviderId, Map<String, Value> loadParameters, String saveActionId, String saveProviderId, Map<String, Value> saveParameters, ServiceProvider serviceProvider) { this.loadActionId = loadActionId; this.loadProviderId = loadProviderId; this.loadParameters = loadParameters; this.saveActionId = saveActionId; this.saveProviderId = saveProviderId; this.saveParameters = saveParameters; this.serviceProvider = serviceProvider; this.advisorRegister = IOAdvisorExtension.getInstance(); } @Override public void setAdvisorRegister(IOAdvisorRegister register) { this.advisorRegister = register; } /** * @see ProjectFile#load(InputStream) */ @Override public void load(InputStream in) throws Exception { if (applyFile != null && !applyFile.delete()) { applyFile.deleteOnExit(); } // direct the stream to a temporary file File tmpFile = File.createTempFile("project-file", null); OutputStream out = new BufferedOutputStream(new FileOutputStream(tmpFile)); try { IOUtils.copy(in, out); out.flush(); } finally { out.close(); in.close(); } applyFile = tmpFile; } /** * @see ProjectFile#apply() */ @SuppressWarnings("unchecked") @Override public void apply() { if (applyFile == null) { return; } try { // load the temporary file using an ImportProvider LocatableInputSupplier<? extends InputStream> tmpIn = new FileIOSupplier(applyFile); // get the action IOAction action = IOActionExtension.getInstance().get(loadActionId); checkState(ImportProvider.class.isAssignableFrom(action.getProviderType()), "Load action not compatible to ImportProvider"); // try specified provider ImportProvider provider = null; if (loadProviderId != null) { try { provider = (ImportProvider) HaleIO.createIOProvider(action.getProviderType(), null, loadProviderId); } catch (Exception e) { // ignore log.error( "Could not get specified import provider, trying auto-detection instead", e); } } // find provider if necessary if (provider == null) { provider = (ImportProvider) HaleIO.findIOProvider(action.getProviderType(), tmpIn, null); } if (provider == null) { throw new IllegalStateException( "No provider for loading project file found (Action ID " + action.getId() + ")"); } // find advisor @SuppressWarnings("rawtypes") IOAdvisor advisor = getLoadAdvisor(loadActionId, serviceProvider); checkState(advisor != null, "No advisor for loading project file found"); // configure provider // set given parameters setParameters(provider, loadParameters); // set source provider.setSource(tmpIn); // execute the provider executeProvider(provider, advisor); } catch (Exception e) { // project file apply fails currently are one logged (the project // reader is not involved with it) log.error("Error applying loaded project file", e); } finally { if (!applyFile.delete()) { applyFile.deleteOnExit(); applyFile = null; } } } /** * Get the advisor for loading the file. The default implementation uses the * {@link IOAdvisorExtension} to look for a matching advisor. * * @param loadActionId the action ID for loading the project file * @param serviceProvider the service provider for the advisor * @return the advisor */ protected IOAdvisor<?> getLoadAdvisor(String loadActionId, ServiceProvider serviceProvider) { return advisorRegister.findAdvisor(loadActionId, serviceProvider); } private void setParameters(IOProvider provider, Map<String, Value> parameters) { for (Entry<String, Value> entry : parameters.entrySet()) { provider.setParameter(entry.getKey(), entry.getValue()); } } private <P extends IOProvider> void executeProvider(P provider, IOAdvisor<P> advisor) throws Exception { IOReporter reporter = provider.createReporter(); ATransaction trans = log.begin(reporter.getTaskName()); try { // use advisor to configure provider advisor.prepareProvider(provider); advisor.updateConfiguration(provider); // execute IOReport report = provider.execute(new LogProgressIndicator()); // handle results if (report.isSuccess()) { advisor.handleResults(provider); } else { // TODO propagate report errors somehow? throw new IOException("Project file action was not successful"); } } finally { trans.end(); } } /** * @see ProjectFile#reset() */ @Override public void reset() { if (applyFile != null && !applyFile.delete()) { applyFile.deleteOnExit(); applyFile = null; } } /** * @see ProjectFile#store(LocatableOutputSupplier) */ @SuppressWarnings("unchecked") @Override public void store(final LocatableOutputSupplier<OutputStream> target) throws Exception { // get the action IOAction action = IOActionExtension.getInstance().get(saveActionId); checkState(ExportProvider.class.isAssignableFrom(action.getProviderType()), "Save action not compatible to ExportProvider"); // get specified provider ExportProvider provider = (ExportProvider) HaleIO.createIOProvider(action.getProviderType(), null, saveProviderId); if (provider == null) { throw new IllegalStateException("No provider for saving project file found"); } // find advisor @SuppressWarnings("rawtypes") IOAdvisor advisor = advisorRegister.findAdvisor(saveActionId, serviceProvider); checkState(advisor != null, "No advisor for saving project file found"); // configure provider // set given parameters setParameters(provider, saveParameters); // set target provider.setTarget(target); // execute the provider -> error is propagated outside (so project // writer knows of it) executeProvider(provider, advisor); } }