/* * 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.impl; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URI; import java.net.URISyntaxException; import java.text.MessageFormat; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import eu.esdihumboldt.hale.common.core.io.ExportProvider; import eu.esdihumboldt.hale.common.core.io.HaleIO; import eu.esdihumboldt.hale.common.core.io.IOProviderConfigurationException; import eu.esdihumboldt.hale.common.core.io.PathUpdate; import eu.esdihumboldt.hale.common.core.io.ProgressIndicator; import eu.esdihumboldt.hale.common.core.io.impl.AbstractIOProvider; import eu.esdihumboldt.hale.common.core.io.project.ProjectIO; import eu.esdihumboldt.hale.common.core.io.project.model.Project; import eu.esdihumboldt.hale.common.core.io.project.model.ProjectFile; import eu.esdihumboldt.hale.common.core.io.project.model.ProjectFileInfo; 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.report.impl.IOMessageImpl; import eu.esdihumboldt.hale.common.core.io.supplier.DefaultInputSupplier; import eu.esdihumboldt.util.io.InputStreamDecorator; /** * Reads a project file * * @author Simon Templer */ public class DefaultProjectReader extends AbstractProjectReader { /** * Input stream for a ZIP entry */ private static class EntryInputStream extends InputStreamDecorator { private final ZipInputStream zip; /** * Create an input stream for a ZIP entry * * @param zip the ZIP input stream */ public EntryInputStream(ZipInputStream zip) { super(zip); this.zip = zip; } /** * @see InputStreamDecorator#close() */ @Override public void close() throws IOException { // instead of closing the stream, close the entry zip.closeEntry(); } } // private static final ALogger log = ALoggerFactory.getLogger(DefaultProjectReader.class); /** * If the project shall be read from a ZIP archive */ private final boolean archive; /** * @param archive if the project shall be read from a ZIP archive */ public DefaultProjectReader(boolean archive) { super(); this.archive = archive; } /** * @see AbstractIOProvider#execute(ProgressIndicator, IOReporter) */ @Override protected IOReport execute(ProgressIndicator progress, IOReporter reporter) throws IOProviderConfigurationException, IOException { progress.begin("Load project", ProgressIndicator.UNKNOWN); InputStream in = getSource().getInput(); if (archive) { // read from archive ZipInputStream zip = new ZipInputStream(new BufferedInputStream(in)); try { ZipEntry entry; while ((entry = zip.getNextEntry()) != null) { String name = entry.getName(); progress.setCurrentTask(MessageFormat.format("Load {0}", name)); if (name.equals(ProjectIO.PROJECT_FILE)) { try { setProjectChecked(Project.load(new EntryInputStream(zip)), reporter); } catch (Exception e) { // fail if main project file cannot be loaded throw new IOProviderConfigurationException( "Source is no valid project archive", e); } } else { ProjectFile file = getProjectFiles().get(name); if (file != null) { try { file.load(new EntryInputStream(zip)); } catch (Exception e) { reporter.error(new IOMessageImpl( "Error while loading project file {0}, file will be reset.", e, -1, -1, name)); // reset file file.reset(); } } } } } finally { zip.close(); } } else { // read from XML try { setProjectChecked(Project.load(in), reporter); } catch (Exception e) { // fail if main project file cannot be loaded throw new IOProviderConfigurationException("Source is no valid project file", e); } finally { in.close(); } } URI oldProjectLocation; if (getProject().getSaveConfiguration() == null) { oldProjectLocation = getSource().getLocation(); } else { oldProjectLocation = URI.create(getProject().getSaveConfiguration() .getProviderConfiguration().get(ExportProvider.PARAM_TARGET).as(String.class)); } PathUpdate update = new PathUpdate(oldProjectLocation, getSource().getLocation()); // check if there are any external project files listed if (getProjectFiles() != null) { // only if project files set at all for (ProjectFileInfo fileInfo : getProject().getProjectFiles()) { ProjectFile projectFile = getProjectFiles().get(fileInfo.getName()); if (projectFile != null) { URI location = fileInfo.getLocation(); location = update.findLocation(location, false, DefaultInputSupplier.SCHEME_LOCAL .equals(getSource().getLocation().getScheme()), false); if (location == null && getSource().getLocation() != null) { // not able to resolve location, try defaults instead // 1st try: appending file name to project location try { URI candidate = new URI(getSource().getLocation().toString() + "." + fileInfo.getName()); if (HaleIO.testStream(candidate, true)) { location = candidate; } } catch (URISyntaxException e) { // ignore } // 2nd try: file name next to project if (location != null) { try { String projectLoc = getSource().getLocation().toString(); int index = projectLoc.lastIndexOf('/'); if (index > 0) { URI candidate = new URI(projectLoc.substring(0, index + 1) + fileInfo.getName()); if (HaleIO.testStream(candidate, true)) { location = candidate; } } } catch (URISyntaxException e) { // ignore } } } boolean fileSuccess = false; if (location != null) { try { DefaultInputSupplier dis = new DefaultInputSupplier(location); try (InputStream input = dis.getInput()) { projectFile.load(input); fileSuccess = true; } catch (Exception e) { throw e; // hand down } } catch (Exception e) { reporter.error(new IOMessageImpl("Loading project file failed", e)); } } if (!fileSuccess) { reporter.error(new IOMessageImpl( "Error while loading project file {0}, file will be reset.", null, -1, -1, fileInfo.getName())); projectFile.reset(); } } else { reporter.info( new IOMessageImpl("No handler for external project file {0} found.", null, -1, -1, fileInfo.getName())); } } } // clear project infos /* * XXX was there any particular reason why this was done? I suspect it * was done so when saving the project this information is not saved * again as-is, but on the basis of actual files written. However, this * case is handled in the project writer already. * * As this information is in fact necessary when trying to identify * certain files like the alignment, clearing the list of project files * was commented out. */ // getProject().getProjectFiles().clear(); progress.end(); reporter.setSuccess(true); return reporter; } }