eu.esdihumboldt.hale.io.html.HtmlMappingExporter.java Source code

Java tutorial

Introduction

Here is the source code for eu.esdihumboldt.hale.io.html.HtmlMappingExporter.java

Source

/*
 * Copyright (c) 2013 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.io.html;

import java.awt.Dimension;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.jface.viewers.IContentProvider;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.PlatformUI;
import org.eclipse.zest.core.viewers.GraphViewer;
import org.eclipse.zest.core.widgets.Graph;
import org.eclipse.zest.core.widgets.GraphNode;

import com.google.common.io.Files;

import eu.esdihumboldt.hale.common.align.io.impl.AbstractAlignmentWriter;
import eu.esdihumboldt.hale.common.align.model.Alignment;
import eu.esdihumboldt.hale.common.align.model.Cell;
import eu.esdihumboldt.hale.common.core.io.IOProviderConfigurationException;
import eu.esdihumboldt.hale.common.core.io.ProgressIndicator;
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.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.ui.HaleUI;
import eu.esdihumboldt.hale.ui.common.graph.content.CellGraphContentProvider;
import eu.esdihumboldt.hale.ui.common.graph.labels.GraphLabelProvider;
import eu.esdihumboldt.hale.ui.util.DisplayThread;
import eu.esdihumboldt.hale.ui.util.graph.OffscreenGraph;
import eu.esdihumboldt.util.Identifiers;

//import org.eclipse.draw2d.geometry.Dimension;

/**
 * Export a Mapping to HTML for documentation purposes.
 * 
 * @author Kevin Mais
 */
public class HtmlMappingExporter extends AbstractAlignmentWriter
        implements ProjectInfoAware, HtmlMappingTemplateConstants {

    private VelocityContext context;
    private VelocityEngine velocityEngine;
    private ProjectInfo projectInfo;
    private File templateFile;
    private File tempDir;
    private Alignment alignment;
    private Identifiers<Cell> cellIds;

    private IOReporter reporter;

    @Override
    public boolean isCancelable() {
        return false;
    }

    /**
     * @see eu.esdihumboldt.hale.common.core.io.project.ProjectInfoAware#setProjectInfo(eu.esdihumboldt.hale.common.core.io.project.ProjectInfo)
     */
    @Override
    public void setProjectInfo(ProjectInfo projectInfo) {
        this.projectInfo = projectInfo;
    }

    @Override
    protected String getDefaultTypeName() {
        return "HTML mapping documentation";
    }

    @Override
    protected IOReport execute(ProgressIndicator progress, IOReporter reporter)
            throws IOProviderConfigurationException, IOException {
        this.reporter = reporter;

        context = new VelocityContext();
        cellIds = new Identifiers<Cell>(Cell.class, false);

        alignment = getAlignment();

        URL headlinePath = this.getClass().getResource("bg-headline.png"); //$NON-NLS-1$
        URL cssPath = this.getClass().getResource("style.css"); //$NON-NLS-1$
        URL linkPath = this.getClass().getResource("int_link.png"); //$NON-NLS-1$
        URL tooltipIcon = this.getClass().getResource("tooltip.gif"); //$NON-NLS-1$
        final String filesSubDir = FilenameUtils
                .removeExtension(FilenameUtils.getName(getTarget().getLocation().getPath())) + "_files"; //$NON-NLS-1$
        final File filesDir = new File(FilenameUtils.getFullPath(getTarget().getLocation().getPath()), filesSubDir);

        filesDir.mkdirs();
        context.put(FILE_DIRECTORY, filesSubDir);

        try {
            init();
        } catch (Exception e) {
            return reportError(reporter, "Initializing error", e);
        }
        File cssOutputFile = new File(filesDir, "style.css");
        FileUtils.copyFile(getInputFile(cssPath), cssOutputFile);

        // create headline picture
        File headlineOutputFile = new File(filesDir, "bg-headline.png"); //$NON-NLS-1$
        FileUtils.copyFile(getInputFile(headlinePath), headlineOutputFile);

        File linkOutputFile = new File(filesDir, "int_link.png"); //$NON-NLS-1$
        FileUtils.copyFile(getInputFile(linkPath), linkOutputFile);

        File tooltipIconFile = new File(filesDir, "tooltip.png"); //$NON-NLS-1$
        FileUtils.copyFile(getInputFile(tooltipIcon), tooltipIconFile);

        File htmlExportFile = new File(getTarget().getLocation().getPath());
        if (projectInfo != null) {
            Date date = new Date();
            DateFormat dfm = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT);

            // associate variables with information data
            String exportDate = dfm.format(date);
            context.put(EXPORT_DATE, exportDate);

            if (projectInfo.getCreated() != null) {
                String created = dfm.format(projectInfo.getCreated());
                context.put(CREATED_DATE, created);
            }

            context.put(PROJECT_INFO, projectInfo);
        }

        if (alignment != null) {
            Collection<TypeCellInfo> typeCellInfos = new ArrayList<TypeCellInfo>();
            Collection<? extends Cell> cells = alignment.getTypeCells();
            Iterator<? extends Cell> it = cells.iterator();
            while (it.hasNext()) {
                final Cell cell = it.next();
                // this is the collection of type cell info
                TypeCellInfo typeCellInfo = new TypeCellInfo(cell, alignment, cellIds, filesSubDir);
                typeCellInfos.add(typeCellInfo);
            }
            // put the full collection of type cell info to the context (for the
            // template)
            context.put(TYPE_CELL_INFOS, typeCellInfos);
            createImages(filesDir);
        }

        context.put(TOOLTIP, getParameter(TOOLTIP).as(boolean.class));

        Template template;
        try {
            template = velocityEngine.getTemplate(templateFile.getName(), "UTF-8");
        } catch (Exception e) {
            return reportError(reporter, "Could not load template", e);
        }

        FileWriter fileWriter = new FileWriter(htmlExportFile);
        template.merge(context, fileWriter);
        fileWriter.close();

        reporter.setSuccess(true);
        return reporter;
    }

    /**
     * Initialize temporary directory and template engine.
     * 
     * @throws Exception if an error occurs during the initialization
     */
    private void init() throws Exception {
        synchronized (this) {
            if (velocityEngine == null) {
                velocityEngine = new VelocityEngine();

                // create a temporary directory
                tempDir = Files.createTempDir();

                templateFile = new File(tempDir, "template.vm");
                URL templatePath = getClass().getResource("template.html");
                OutputStream outputStream = new BufferedOutputStream(new FileOutputStream(templateFile));
                InputStream inputStream = templatePath.openStream();

                // copies the InputStream into OutputStream
                IOUtils.copy(inputStream, outputStream);

                inputStream.close();
                outputStream.close();

                tempDir.deleteOnExit();
                templateFile.deleteOnExit();

                velocityEngine.setProperty("file.resource.loader.path", tempDir.getAbsolutePath());
                // initialize VelocityEngine
                velocityEngine.init();
            }
        }
    }

    private void createImages(File filesDir) {
        Collection<? extends Cell> cells = alignment.getCells();
        Iterator<? extends Cell> ite = cells.iterator();
        while (ite.hasNext()) {
            Cell cell = ite.next();
            saveImageToFile(cell, filesDir);
        }
    }

    private void saveImageToFile(final Cell cell, File filesDir) {
        Display display;
        if (Display.getCurrent() != null) {
            // use the current display if available
            display = Display.getCurrent();
        } else {
            try {
                // use workbench display if available
                display = PlatformUI.getWorkbench().getDisplay();
            } catch (Throwable e) {
                // use a dedicated display thread if no workbench is
                // available
                display = DisplayThread.getInstance().getDisplay();
            }
        }

        // creates a unique id for each cell
        String cellId = cellIds.getId(cell);

        final File file = new File(filesDir, "img_" + cellId + ".png");

        display.syncExec(new Runnable() {

            @Override
            public void run() {
                OffscreenGraph offscreenGraph = new OffscreenGraph(600, 200) {

                    @Override
                    protected void configureViewer(GraphViewer viewer) {
                        IContentProvider contentProvider = new CellGraphContentProvider();
                        GraphLabelProvider labelProvider = new GraphLabelProvider(null,
                                HaleUI.getServiceProvider());
                        viewer.setContentProvider(contentProvider);
                        viewer.setLabelProvider(labelProvider);
                        viewer.setInput(cell);
                    }
                };

                Graph graph = offscreenGraph.getGraph();
                Dimension dimension = computeSize(graph);

                // minimum width = 600
                offscreenGraph.resize(dimension.width > 600 ? dimension.width : 600, dimension.height);

                try {
                    offscreenGraph.saveImage(new BufferedOutputStream(new FileOutputStream(file)), null);
                } catch (Exception e) {
                    reporter.error(new IOMessageImpl("Can not create image", e));
                } finally {
                    offscreenGraph.dispose();
                }
            }
        });
    }

    private Dimension computeSize(Graph graph) {
        @SuppressWarnings("unchecked")
        List<GraphNode> graphNodes = graph.getNodes();
        int height = 0;
        int width = 0;
        List<GraphNode> tempSourceList = new ArrayList<GraphNode>();
        List<GraphNode> tempTargetList = new ArrayList<GraphNode>();
        for (GraphNode node : graphNodes) {
            int sourceConnections = node.getSourceConnections().size();
            int targetConnections = node.getTargetConnections().size();
            if (sourceConnections == 0 && targetConnections == 1) {
                tempSourceList.add(node);
            } else if (sourceConnections >= 1 && targetConnections >= 1) {
                width = width + node.getFigure().getBounds().width + 10;
                height = height + node.getFigure().getBounds().height;
            } else {
                tempTargetList.add(node);
            }
        }
        int accuSourceWidth = 0;
        int accuSourceHeight = 0;
        int accuHeight = 0;
        for (GraphNode node : tempSourceList) {
            Rectangle rec = node.getFigure().getBounds();
            int sourceWidth = rec.width;
            int sourceHeight = rec.height;

            accuSourceHeight = accuSourceHeight + sourceHeight + 10;

            if (accuSourceWidth < sourceWidth) {
                accuSourceWidth = sourceWidth;
            }
            if (accuHeight < accuSourceHeight) {
                accuHeight = accuSourceHeight;
            }

        }

        int accuTargetWidth = 0;
        int accuTargetHeight = 0;
        for (GraphNode node : tempTargetList) {
            Rectangle rec = node.getFigure().getBounds();
            int targetWidth = rec.width;
            int targetHeight = rec.height;

            accuTargetHeight = accuTargetHeight + targetHeight + 10;

            if (accuTargetWidth < targetWidth) {
                accuTargetWidth = targetWidth;
            }
            if (accuHeight < accuTargetHeight) {
                accuHeight = accuTargetHeight;
            }
        }
        width = width + accuSourceWidth + accuTargetWidth + 30;
        height = accuHeight + 15;

        Dimension dimension = new Dimension();
        dimension.setSize(width, height);

        return dimension;
    }

    private File getInputFile(URL url) throws IOException, FileNotFoundException {
        File file = new File(tempDir.toString() + FilenameUtils.getName(url.toString()));
        OutputStream outputStream = new FileOutputStream(file);
        IOUtils.copy(url.openStream(), outputStream);
        outputStream.close();
        return file;
    }

    private IOReport reportError(IOReporter reporter, String message, Exception e) {
        reporter.error(new IOMessageImpl(message, e));
        reporter.setSuccess(false);
        return reporter;
    }
}