/* * 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: * Data Harmonisation Panel <http://www.dhpanel.eu> */ package eu.esdihumboldt.hale.common.headless.scavenger; import java.io.File; import java.io.IOException; import java.util.Collection; import java.util.HashSet; import java.util.Properties; import java.util.Set; import org.eclipse.core.runtime.content.IContentType; import de.fhg.igd.slf4jplus.ALogger; import de.fhg.igd.slf4jplus.ALoggerFactory; import eu.esdihumboldt.hale.common.core.io.HaleIO; import eu.esdihumboldt.hale.common.core.io.extension.IOProviderDescriptor; import eu.esdihumboldt.hale.common.core.io.project.ProjectIO; import eu.esdihumboldt.hale.common.core.io.project.ProjectInfo; import eu.esdihumboldt.hale.common.core.io.project.ProjectReader; import eu.esdihumboldt.hale.common.core.io.project.model.Project; import eu.esdihumboldt.hale.common.core.io.report.IOReport; import eu.esdihumboldt.hale.common.core.io.supplier.FileIOSupplier; import eu.esdihumboldt.hale.common.core.report.ReportHandler; import eu.esdihumboldt.hale.common.headless.report.ReportFile; /** * Represents a project residing in a specific folder and its configuration. The * configuration is stored in a file in the project folder. * * @param <C> the update context type * @author Simon Templer */ public class ProjectReference<C> { private static final ALogger log = ALoggerFactory.getLogger(ProjectReference.class); /** * The name of the project configuration file in the project folder. */ public static final String CONFIG_FILE_NAME = "project.properties"; /** * The name of the log file in the project folder, containing the reports * from loading the project. */ public static final String REPORT_FILE_NAME = "project-load.log"; /** * The configuration file. */ private final ProjectProperties config; /** * The project information, if the project was loaded. */ private Project projectInfo; /** * The project folder */ private final File projectFolder; /** * The project identifier. */ private final String projectId; /** * @param projectFolder the project folder * @param overrideProjectFile the name of the project file if it should * override the configuration, otherwise <code>null</code> * @param projectId the project identifier * @param defaultSettings the properties with default project settings, may * be <code>null</code> * @throws IOException if accessing the project configuration file failed */ public ProjectReference(final File projectFolder, final String overrideProjectFile, final String projectId, Properties defaultSettings) throws IOException { this.projectFolder = projectFolder; this.projectId = projectId; config = new ProjectProperties(new File(projectFolder, CONFIG_FILE_NAME), defaultSettings); // override project file name if (overrideProjectFile != null) { config.setProjectFileName(overrideProjectFile); } } /** * Force an update by resetting the loaded project information. * * @param context the update context */ public void forceUpdate(C context) { projectInfo = null; update(context); } /** * Updates the project status from the configuration and if needed loads the * project and transformation environment and adds or removes the * transformation environment. * * @param context the update context */ public void update(C context) { File projectFile = getProjectFile(); if (projectFile == null || !projectFile.exists()) { // no project file // reset any runtime information projectInfo = null; onNotAvailable(context, projectId); } else { File reportFile = getLoadReportFile(); if ((projectInfo == null || isForceClearReports()) && reportFile.exists()) { // delete old reports reportFile.delete(); } // store reports in file ReportFile rf = new ReportFile(reportFile); // load project info if not yet done if (projectInfo == null) { projectInfo = loadProjectInfo(projectFile, rf); } if (projectInfo == null) { // can't load project onFailure(context, projectId); } else { onSuccess(context, projectId, projectFile, projectInfo, rf); } } } /** * States if the report file should be deleted in {@link #update(Object)} * even if the project info is already loaded. * * @return if the report file should be deleted for an already loaded * project */ protected boolean isForceClearReports() { return false; } /** * Called when the project was successfully loaded in * {@link #update(Object)}. * * @param context the update context * @param projectId the project identifier * @param projectFile the project file * @param project the loaded project * @param reportFile the report file to publish any additional reports to */ protected void onSuccess(C context, String projectId, File projectFile, Project project, ReportFile reportFile) { // do nothing } /** * Called when the project failed to load in {@link #update(Object)}. * * @param context the update context * @param projectId the project identifier */ protected void onFailure(C context, String projectId) { // do nothing } /** * Called when the project file is not available in {@link #update(Object)}. * * @param context the update context * @param projectId the project identifier */ protected void onNotAvailable(C context, String projectId) { // do nothing } /** * Get the project information if available. * * @return the projectInfo */ public ProjectInfo getProjectInfo() { return projectInfo; } /** * Get the loaded project if available. * * @return the project */ protected Project getProject() { return projectInfo; } /** * Set the internal project. * * @param project the project to set */ protected void setProject(Project project) { this.projectInfo = project; } /** * Get the file the reports for loading the project are stored in. * * @return the report file */ public File getLoadReportFile() { return new File(projectFolder, REPORT_FILE_NAME); } /** * Load project information. * * @param projectFile the project file * @param reportHandler the report handler * @return the project info or <code>null</code> if the project file could * not be loaded */ protected Project loadProjectInfo(File projectFile, ReportHandler reportHandler) { FileIOSupplier in = new FileIOSupplier(projectFile); ProjectReader reader = HaleIO .findIOProvider(ProjectReader.class, in, projectFile.getName()); reader.setSource(in); try { IOReport report = reader.execute(null); reportHandler.publishReport(report); } catch (Exception e) { log.error( "Failed to load project information for project at " + projectFile.getAbsolutePath(), e); return null; } return reader.getProject(); } /** * Get the project file is possible. * * @return the project file or <code>null</code> */ public File getProjectFile() { String projectFile = config.getProjectFileName(); if (projectFile != null) { // check if the file actually exists File file = new File(projectFolder, projectFile); if (!file.exists()) { log.info("Project file no longer exists, scanning for new project file."); projectFile = null; projectInfo = null; } } if (projectFile == null) { // determine the project file automatically projectFile = ProjectIO.findProjectFile(projectFolder, getSupportedExtensions()); config.setProjectFileName(projectFile); } if (projectFile == null) { return null; } return new File(projectFolder, projectFile); } /** * @return the project folder */ public File getProjectFolder() { return projectFolder; } /** * @return the project settings */ protected ProjectProperties getConfig() { return config; } /** * Get the supported file extensions for projects. * * @return the set of file extensions (with leading dot) */ protected Set<String> getSupportedExtensions() { Collection<IOProviderDescriptor> providers = HaleIO .getProviderFactories(ProjectReader.class); // collect supported content types Set<String> supportedExtensions = new HashSet<String>(); for (IOProviderDescriptor factory : providers) { for (IContentType type : factory.getSupportedTypes()) { String[] extensions = type.getFileSpecs(IContentType.FILE_EXTENSION_SPEC); if (extensions != null) { for (String ext : extensions) { supportedExtensions.add('.' + ext); } } } } return supportedExtensions; } }