/*
* 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.doc.user.examples.internal.content;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.Callable;
import org.apache.velocity.VelocityContext;
import org.eclipse.help.IHelpContentProducer;
import org.osgi.framework.Version;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Multimap;
import com.google.common.io.Files;
import de.fhg.igd.slf4jplus.ALogger;
import de.fhg.igd.slf4jplus.ALoggerFactory;
import de.fhg.igd.slf4jplus.ATransaction;
import eu.esdihumboldt.hale.common.align.io.AlignmentReader;
import eu.esdihumboldt.hale.common.align.io.AlignmentWriter;
import eu.esdihumboldt.hale.common.align.io.impl.LoadAlignmentAdvisor;
import eu.esdihumboldt.hale.common.align.model.Alignment;
import eu.esdihumboldt.hale.common.core.io.HaleIO;
import eu.esdihumboldt.hale.common.core.io.IOAdvisor;
import eu.esdihumboldt.hale.common.core.io.IOProvider;
import eu.esdihumboldt.hale.common.core.io.extension.IOProviderDescriptor;
import eu.esdihumboldt.hale.common.core.io.extension.IOProviderExtension;
import eu.esdihumboldt.hale.common.core.io.project.ProjectInfo;
import eu.esdihumboldt.hale.common.core.io.project.ProjectInfoAware;
import eu.esdihumboldt.hale.common.core.io.project.model.IOConfiguration;
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.DefaultInputSupplier;
import eu.esdihumboldt.hale.common.core.io.supplier.FileIOSupplier;
import eu.esdihumboldt.hale.common.schema.SchemaSpaceID;
import eu.esdihumboldt.hale.common.schema.io.SchemaIO;
import eu.esdihumboldt.hale.common.schema.io.impl.LoadSchemaAdvisor;
import eu.esdihumboldt.hale.doc.user.examples.internal.ExamplesConstants;
import eu.esdihumboldt.hale.doc.user.examples.internal.extension.ExampleProject;
import eu.esdihumboldt.hale.doc.user.examples.internal.extension.ExampleProjectExtension;
import eu.esdihumboldt.hale.doc.util.content.AbstractVelocityContent;
/**
* Examples content producer.
*
* @author Simon Templer
*/
public class ExamplesContent extends AbstractVelocityContent implements ExamplesConstants {
private static final ALogger log = ALoggerFactory.getLogger(ExamplesContent.class);
private static final String TEMPLATE_OVERVIEW = "overview";
private static final String TEMPLATE_PROJECT = "project";
/**
* Provider ID of the mapping exporter XXX instead store the descriptor?
*/
private static final String ID_MAPPING_EXPORT = "eu.esdihumboldt.hale.io.html.svg.mapping";
private File tempMappingDir;
private AlignmentWriter mappingDocExport;
/**
* States if {@link #mappingDocExport} was already initialized (or tried to)
*/
private boolean mappingDocExportInitialized = false;
/**
* @see IHelpContentProducer#getInputStream(String, String, Locale)
*/
@Override
public InputStream getInputStream(String pluginID, String href, Locale locale) {
ATransaction trans = log.begin("Generating examples help content");
try {
if (href.startsWith(PATH_PREFIX_PROJECT)) {
// references a project
// determine the project id
String projectId = href.substring(PATH_PREFIX_PROJECT.length());
// strip everything after a ?
int ind = projectId.indexOf('?');
if (ind >= 0) {
projectId = projectId.substring(0, ind);
}
// strip the .*htm? ending
if (projectId.endsWith("html") || projectId.endsWith("htm")) {
projectId = projectId.substring(0, projectId.lastIndexOf('.'));
}
if (projectId.endsWith(PATH_SUFFIX_MAPPINGDOC)) {
projectId = projectId.substring(0,
projectId.length() - PATH_SUFFIX_MAPPINGDOC.length());
return getMappingContent(projectId);
}
ExampleProject project = ExampleProjectExtension.getInstance().get(projectId);
if (project != null) {
return getProjectContent(project);
}
// Auxiliary mapping documentation files
ind = projectId.indexOf('/'); // XXX no / may be contained in
// project id
String path = projectId.substring(ind + 1);
projectId = projectId.substring(0, ind);
return getMappingFileContent(projectId, path);
}
else if (href.startsWith(PATH_OVERVIEW)) {
return getOverviewContent();
}
} finally {
trans.end();
}
return null;
}
/**
* Create the overview content.
*
* @return the overview page content
*/
private InputStream getOverviewContent() {
try {
return getContentFromTemplate("overview", TEMPLATE_OVERVIEW,
new Callable<VelocityContext>() {
@Override
public VelocityContext call() throws Exception {
VelocityContext context = new VelocityContext();
context.put("projects",
ExampleProjectExtension.getInstance().getElements());
return context;
}
});
} catch (Exception e) {
log.error("Error creating example project overview", e);
return null;
}
}
/**
* Get the project page content.
*
* @param project the project
* @return the project page content
*/
private InputStream getProjectContent(final ExampleProject project) {
try {
return getContentFromTemplate(project.getId(), TEMPLATE_PROJECT,
new Callable<VelocityContext>() {
@Override
public VelocityContext call() throws Exception {
VelocityContext context = new VelocityContext();
context.put("project", project);
return context;
}
});
} catch (Exception e) {
log.error("Error creating project page", e);
return null;
}
}
/**
* @see AbstractVelocityContent#getTemplate(String)
*/
@Override
protected InputStream getTemplate(String templateId) throws Exception {
if (TEMPLATE_PROJECT.equals(templateId)) {
return ExamplesContent.class.getResourceAsStream("project.html");
}
return ExamplesContent.class.getResourceAsStream(PATH_OVERVIEW);
}
/**
* Get the content of a auxiliary mapping file.
*
* @param projectId the project id
* @param path the file path
* @return the file content or <code>null</code>
*/
private InputStream getMappingFileContent(String projectId, String path) {
if (tempMappingDir == null) {
return null;
}
File candidate = new File(tempMappingDir, path);
if (candidate.exists()) {
try {
return new FileInputStream(candidate);
} catch (FileNotFoundException e) {
return null;
}
}
return null;
}
/**
* Get the mapping documentation content for an example project.
*
* @param projectId the project ID
* @return the mapping documentation content stream or <code>null</code>
*/
private InputStream getMappingContent(String projectId) {
if (!mappingDocExportInitialized) {
mappingDocExport = HaleIO.createIOProvider(AlignmentWriter.class, null,
ID_MAPPING_EXPORT);
if (mappingDocExport == null) {
log.error("Could not create mapping documentation exporter.");
}
mappingDocExportInitialized = true;
}
if (mappingDocExport == null) {
// no mapping documentation export possible
return null;
}
if (tempMappingDir == null) {
tempMappingDir = Files.createTempDir();
tempMappingDir.deleteOnExit();
}
// the file of the mapping documentation
File mappingDoc = new File(tempMappingDir, projectId + ".html");
if (!mappingDoc.exists()) {
ATransaction trans = log.begin("Generate example mapping documentation");
try {
// create the mapping documentation
ExampleProject exampleProject = ExampleProjectExtension.getInstance()
.get(projectId);
final Project project = (Project) exampleProject.getInfo();
// determine alignment location - contained in project file, not
// a resource
URI alignmentLoc = exampleProject.getAlignmentLocation();
if (alignmentLoc == null) {
// no alignment present
return null;
}
// store configurations per action ID
Multimap<String, IOConfiguration> confs = HashMultimap.create();
for (IOConfiguration conf : project.getResources()) {
confs.put(conf.getActionId(), conf);
}
// load schemas
// source schemas
LoadSchemaAdvisor source = new LoadSchemaAdvisor(SchemaSpaceID.SOURCE);
for (IOConfiguration conf : confs.get(SchemaIO.ACTION_LOAD_SOURCE_SCHEMA)) {
source.setConfiguration(conf);
executeProvider(source, conf.getProviderId(), null);
}
// target schemas
LoadSchemaAdvisor target = new LoadSchemaAdvisor(SchemaSpaceID.TARGET);
for (IOConfiguration conf : confs.get(SchemaIO.ACTION_LOAD_TARGET_SCHEMA)) {
target.setConfiguration(conf);
executeProvider(target, conf.getProviderId(), null);
}
// load alignment
// manual loading needed, as we can't rely on the environment
// alignment advisor
DefaultInputSupplier alignmentIn = new DefaultInputSupplier(alignmentLoc);
AlignmentReader reader = HaleIO.findIOProvider(AlignmentReader.class, alignmentIn,
alignmentLoc.getPath());
LoadAlignmentAdvisor alignmentAdvisor = new LoadAlignmentAdvisor(null,
source.getSchemaSpace(), target.getSchemaSpace(),
exampleProject.getUpdater());
reader.setSource(alignmentIn);
executeProvider(alignmentAdvisor, null, reader);
Alignment alignment = alignmentAdvisor.getAlignment();
if (alignment != null) {
// save alignment docu
synchronized (mappingDocExport) { // only a single instance
mappingDocExport.setAlignment(alignment);
mappingDocExport.setTarget(new FileIOSupplier(mappingDoc));
if (mappingDocExport instanceof ProjectInfoAware) {
ProjectInfo smallInfo = new ProjectInfo() {
@Override
public String getName() {
return project.getName();
}
@Override
public Date getModified() {
return null;
}
@Override
public Version getHaleVersion() {
return null;
}
@Override
public String getDescription() {
return project.getDescription();
}
@Override
public Date getCreated() {
return null;
}
@Override
public String getAuthor() {
return project.getAuthor();
}
};
((ProjectInfoAware) mappingDocExport).setProjectInfo(smallInfo); // project);
}
mappingDocExport.execute(null);
}
mappingDoc.deleteOnExit();
}
} catch (Throwable e) {
log.error("Error generating mapping documentation for example project", e);
return null;
} finally {
trans.end();
}
}
if (mappingDoc.exists()) {
try {
return new FileInputStream(mappingDoc);
} catch (FileNotFoundException e) {
return null;
}
}
else
return null;
}
/**
* Execute the I/O provider given or specified by the given provider ID.
*
* @param advisor the advisor to use for configuration of the provider and
* handling the results
* @param providerId the ID of the provider to execute, may be
* <code>null</code> if provider is set
* @param provider the provider to execute
* @throws Exception if executing the provider fails or if a provider with
* the given ID is not found
*/
@SuppressWarnings("unchecked")
private void executeProvider(@SuppressWarnings("rawtypes") IOAdvisor advisor, String providerId,
IOProvider provider) throws Exception {
if (provider == null) {
// find and create the provider
IOProviderDescriptor descriptor = IOProviderExtension.getInstance()
.getFactory(providerId);
if (descriptor != null) {
provider = descriptor.createExtensionObject();
}
else {
throw new IllegalStateException(
"I/O provider with ID " + providerId + " not found");
}
}
// use advisor to configure provider
advisor.prepareProvider(provider);
advisor.updateConfiguration(provider);
// execute
IOReport report = provider.execute(null);
// handle results
if (report.isSuccess()) {
advisor.handleResults(provider);
}
}
}