/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.dg.latex; import java.awt.Color; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Enumeration; import java.util.Hashtable; import java.util.List; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.dg.DGGenerator; import org.openflexo.dg.ProjectDocGenerator; import org.openflexo.dg.rm.ComponentLatexFileResource; import org.openflexo.dg.rm.ComponentLibraryLatexFileResource; import org.openflexo.dg.rm.DKVModelLatexFileResource; import org.openflexo.dg.rm.DMEOEntityLatexFileResource; import org.openflexo.dg.rm.DMModelLatexFileResource; import org.openflexo.dg.rm.DefinitionsLatexFileResource; import org.openflexo.dg.rm.GeneratedFileResourceFactory; import org.openflexo.dg.rm.MenuLatexFileResource; import org.openflexo.dg.rm.OperationLatexFileResource; import org.openflexo.dg.rm.ProcessLatexFileResource; import org.openflexo.dg.rm.ProjectLatexFileResource; import org.openflexo.dg.rm.ReadersGuideLatexFileResource; import org.openflexo.dg.rm.WorkflowLatexFileResource; import org.openflexo.foundation.cg.DGRepository; import org.openflexo.foundation.cg.templates.CGTemplate; import org.openflexo.foundation.cg.templates.CGTemplates; import org.openflexo.foundation.dkv.DKVModel; import org.openflexo.foundation.dm.DMModel; import org.openflexo.foundation.dm.eo.DMEOEntity; import org.openflexo.foundation.dm.eo.DMEORepository; import org.openflexo.foundation.ie.cl.ComponentDefinition; import org.openflexo.foundation.ie.cl.FlexoComponentLibrary; import org.openflexo.foundation.ie.cl.OperationComponentDefinition; import org.openflexo.foundation.ie.cl.PopupComponentDefinition; import org.openflexo.foundation.ie.cl.TabComponentDefinition; import org.openflexo.foundation.ie.menu.FlexoNavigationMenu; import org.openflexo.foundation.rm.FlexoProject; import org.openflexo.foundation.rm.ResourceType; import org.openflexo.foundation.rm.cg.CGRepositoryFileResource; import org.openflexo.foundation.toc.PredefinedSection; import org.openflexo.foundation.toc.TOCEntry; import org.openflexo.foundation.wkf.FlexoProcess; import org.openflexo.foundation.wkf.FlexoWorkflow; import org.openflexo.foundation.wkf.node.OperationNode; import org.openflexo.generator.PackagedResourceToCopyGenerator; import org.openflexo.generator.exception.GenerationException; import org.openflexo.generator.exception.TemplateNotFoundException; import org.openflexo.localization.FlexoLocalization; import org.openflexo.logging.FlexoLogger; import org.openflexo.toolbox.FileResource; import org.openflexo.toolbox.FileUtils; import org.openflexo.toolbox.FileUtils.CopyStrategy; import org.openflexo.toolbox.LogListener; import org.openflexo.toolbox.ToolBox; public class ProjectDocLatexGenerator extends ProjectDocGenerator { private static final String LATEX_MACRO_LIBRARY_NAME = "doc_macro_library.vm"; private static final String LATEX_EXTRAS_DIRECTORY = "LatexExtras"; private static final String LATEX_EMBEDDED_DIRECTORY = "LatexEmbedded"; private static final String PROJECT_TEMPLATE_NAME = "project.tex.vm"; private static final String EOENTITY_TEMPLATE_NAME = "eoentity.tex.vm"; private static final String PAGE_TEMPLATE_NAME = "page.tex.vm"; private static final String POPUP_TEMPLATE_NAME = "popup.tex.vm"; private static final String TAB_TEMPLATE_NAME = "tab.tex.vm"; private static final String WKF_TEMPLATE_NAME = "workflow.tex.vm"; private static final String PROCESS_TEMPLATE_NAME = "process.tex.vm"; private static final String OPERATION_TEMPLATE_NAME = "operation.tex.vm"; private static final String CL_TEMPLATE_NAME = "componentlibrary.tex.vm"; private static final String DKV_TEMPLATE_NAME = "dkvmodel.tex.vm"; private static final String DM_TEMPLATE_NAME = "dmmodel.tex.vm"; private static final String MENU_TEMPLATE_NAME = "menu.tex.vm"; private static final String READERS_TEMPLATE_NAME = "readersguide.tex.vm"; private static final String DEFINITIONS_TEMPLATE_NAME = "definitions.tex.vm"; private static final String ROLES_TEMPLATE_NAME = "roles.tex.vm"; protected static final Logger logger = FlexoLogger.getLogger(ProjectDocLatexGenerator.class.getPackage().getName()); private DGLatexGenerator<FlexoProject> rootGenerator; private DGLatexGenerator<FlexoWorkflow> workflowGenerator; private DGLatexGenerator<FlexoComponentLibrary> clGenerator; private DGLatexGenerator<DKVModel> dkvGenerator; private DGLatexGenerator<DMModel> dmGenerator; private DGLatexGenerator<FlexoNavigationMenu> menuGenerator; private DGLatexGenerator<FlexoProject> readersGuideGenerator; private DGLatexGenerator<FlexoProject> definitionsGenerator; private DGLatexGenerator<FlexoProject> rolesGenerator; private StylesAndImagesGenerator stylesAndImagesGenerator; private long latexTimeOutInMillis = 15000; private Hashtable<FlexoProcess, DGLatexGenerator<FlexoProcess>> processGenerators; private Hashtable<OperationNode, DGLatexGenerator<OperationNode>> operationGenerators; private Hashtable<ComponentDefinition, DGLatexGenerator<? extends ComponentDefinition>> componentGenerators; private Hashtable<DMEOEntity, DGLatexGenerator<DMEOEntity>> entityGenerators; private boolean hasBeenInitialized = false; public ProjectDocLatexGenerator(FlexoProject project, DGRepository repository) throws GenerationException { super(project, repository); processGenerators = new Hashtable<FlexoProcess, DGLatexGenerator<FlexoProcess>>(); operationGenerators = new Hashtable<OperationNode, DGLatexGenerator<OperationNode>>(); componentGenerators = new Hashtable<ComponentDefinition, DGLatexGenerator<? extends ComponentDefinition>>(); entityGenerators = new Hashtable<DMEOEntity, DGLatexGenerator<DMEOEntity>>(); } @Override public CGTemplates getDefaultTemplates() { return getProject().getGeneratedDoc().getTemplates(); } @Override public Logger getGeneratorLogger() { return logger; } public String getMainColor() { StringBuilder sb = new StringBuilder(); Color c = getProject().getCssSheet().getTextColor(); sb.append(Math.round(c.getRed() * 10000d / 255) / 10000d); sb.append(','); sb.append(Math.round(c.getGreen() * 10000d / 255) / 10000d); sb.append(','); sb.append(Math.round(c.getBlue() * 10000d / 255) / 10000d); return sb.toString(); } @Override public String getFileExtension() { return DGLatexGenerator.getLatexFileExtension(); } /** * Overrides buildResourcesAndSetGenerators * * @see org.openflexo.dg.DGGenerator#buildResourcesAndSetGenerators(DGRepository, java.util.Vector) */ @Override public void buildResourcesAndSetGenerators(DGRepository repository, Vector<CGRepositoryFileResource> resources) { hasBeenInitialized = true; if (rootGenerator == null) { rootGenerator = new DGLatexGenerator<FlexoProject>(this, getProject(), PROJECT_TEMPLATE_NAME); } if (workflowGenerator == null && getProject().getFlexoWorkflow(false) != null) { workflowGenerator = new DGLatexGenerator<FlexoWorkflow>(this, getProject().getFlexoWorkflow(), WKF_TEMPLATE_NAME, getProject() .getFlexoWorkflow().getFullyQualifiedName(), DGGenerator.nameForObjectNoExt(getProject().getFlexoWorkflow(), repository), repository.getTocRepository() .getTOCEntryWithID(PredefinedSection.PredefinedSectionType.PROCESSES)); } if (clGenerator == null && getProject().getFlexoComponentLibrary(false) != null) { clGenerator = new DGLatexGenerator<FlexoComponentLibrary>(this, getProject().getFlexoComponentLibrary(), CL_TEMPLATE_NAME); } if (dmGenerator == null && getProject().getDataModel(false) != null) { dmGenerator = new DGLatexGenerator<DMModel>(this, getProject().getDataModel(), DM_TEMPLATE_NAME); } if (dkvGenerator == null && getProject().getDKVModel(false) != null) { dkvGenerator = new DGLatexGenerator<DKVModel>(this, getProject().getDKVModel(), DKV_TEMPLATE_NAME); // The DKV DKVModelLatexFileResource dkvRes = GeneratedFileResourceFactory.createNewDKVLatexFileResource(repository, dkvGenerator); resources.add(dkvRes); TOCEntry entry = dkvGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, dkvRes); } } if (menuGenerator == null && getProject().getFlexoNavigationMenu(false) != null) { menuGenerator = new DGLatexGenerator<FlexoNavigationMenu>(this, getProject().getFlexoNavigationMenu(), MENU_TEMPLATE_NAME); // The Menu MenuLatexFileResource menuRes = GeneratedFileResourceFactory.createNewMenuLatexFileResource(repository, menuGenerator); resources.add(menuRes); TOCEntry entry = menuGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, menuRes); } } if (readersGuideGenerator == null) { readersGuideGenerator = new DGLatexGenerator<FlexoProject>(this, getProject(), READERS_TEMPLATE_NAME, "ReadersGuide", DGGenerator.nameForReadersGuideNoExt(getRepository()), getRepository().getTOCEntryWithID( PredefinedSection.PredefinedSectionType.READERS_GUIDE)); } if (definitionsGenerator == null) { definitionsGenerator = new DGLatexGenerator<FlexoProject>(this, getProject(), DEFINITIONS_TEMPLATE_NAME, "Definitions", DGGenerator.nameForDefinitionsNoExt(getRepository()), getRepository().getTOCEntryWithID( PredefinedSection.PredefinedSectionType.DEFINITIONS)); } if (rolesGenerator == null) { rolesGenerator = new DGLatexGenerator<FlexoProject>(this, getProject(), ROLES_TEMPLATE_NAME, "Roles", DGGenerator.nameForDefinitionsNoExt(getRepository()), getRepository().getTOCEntryWithID( PredefinedSection.PredefinedSectionType.ROLES)); } if (stylesAndImagesGenerator == null) { stylesAndImagesGenerator = new StylesAndImagesGenerator(this, getProject()); } // The root file ProjectLatexFileResource projectRes = GeneratedFileResourceFactory.createNewProjectLatexFileResource(repository, rootGenerator); resources.add(projectRes); // The compound generators buildResourcesAndSetGeneratorsForWorkflow(repository, resources); buildResourcesAndSetGeneratorsForComponentLibrary(repository, resources); buildResourcesAndSetGeneratorsForDataModel(repository, resources); ReadersGuideLatexFileResource readersRes = GeneratedFileResourceFactory.createNewReadersGuideLatexFileResource(repository, readersGuideGenerator); TOCEntry entry = readersGuideGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, readersRes); } resources.add(readersRes); DefinitionsLatexFileResource definitionRes = GeneratedFileResourceFactory.createNewDefinitionsLatexFileResource(repository, definitionsGenerator); entry = definitionsGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, definitionRes); } resources.add(definitionRes); stylesAndImagesGenerator.buildResourcesAndSetGenerators(repository, resources); screenshotsGenerator.buildResourcesAndSetGenerators(repository, resources); buildResourcesAndSetGeneratorsForCopiedResources(resources); buildResourcesAndSetGeneratorsForCopyOfPackagedResources(resources); } /** * @param repository * @param resources */ private void buildResourcesAndSetGeneratorsForDataModel(DGRepository repository, Vector<CGRepositoryFileResource> resources) { // The Datamodel itself if (getProject().getDataModel(false) != null) { DMModelLatexFileResource dmRes = GeneratedFileResourceFactory.createNewDMModelLatexFileResource(repository, dmGenerator); resources.add(dmRes); TOCEntry entry = dmGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, dmRes); } Hashtable<DMEOEntity, DGLatexGenerator<DMEOEntity>> generators = new Hashtable<DMEOEntity, DGLatexGenerator<DMEOEntity>>(); // All the EOEntities Enumeration<DMEORepository> en = getProject().getDataModel().getDMEORepositories().elements(); while (en.hasMoreElements()) { DMEORepository eoRep = en.nextElement(); resetSecondaryProgressWindow(eoRep.getEntitiesForEOEntity().size()); Enumeration<DMEOEntity> en1 = eoRep.getEntitiesForEOEntity().elements(); while (en1.hasMoreElements()) { DMEOEntity entity = en1.nextElement(); if (entity == null || entity.getDontGenerate()) { continue; } DGLatexGenerator<DMEOEntity> generator = getEntityGenerator(entity); refreshSecondaryProgressWindow(FlexoLocalization.localizedForKey("generating") + " " + entity.getName(), false); if (generator != null) { generators.put(entity, generator); DMEOEntityLatexFileResource res = GeneratedFileResourceFactory.createNewEOEntityLatexFileResource(repository, generator); resources.add(res); entry = generator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, res); } } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not instanciate EOEntityDocGenerator for " + entity.getName()); } } } } entityGenerators = generators; } } private static final Vector<FileResource> fileResourceToCopy = new Vector<FileResource>(); static { FileResource latexExtrasDirectory = new FileResource(LATEX_EXTRAS_DIRECTORY); for (String fileName : latexExtrasDirectory.list(FileUtils.CVSFileNameFilter)) { fileResourceToCopy.add(new FileResource(LATEX_EXTRAS_DIRECTORY + "/" + fileName)); } if (ToolBox.getPLATFORM() != ToolBox.WINDOWS) { FileResource latexEmbeddedDirectory = new FileResource(LATEX_EMBEDDED_DIRECTORY); for (String fileName : latexEmbeddedDirectory.list(FileUtils.CVSFileNameFilter)) { fileResourceToCopy.add(new FileResource(LATEX_EMBEDDED_DIRECTORY + "/" + fileName)); } } } private void buildResourcesAndSetGeneratorsForCopyOfPackagedResources(Vector<CGRepositoryFileResource> resources) { for (FileResource fileResource : fileResourceToCopy) { PackagedResourceToCopyGenerator<DGRepository> generator = getFileResourceGenerator(fileResource); generator.buildResourcesAndSetGenerators(getRepository(), resources); } } /** * @param repository * @param resources */ private void buildResourcesAndSetGeneratorsForComponentLibrary(DGRepository repository, Vector<CGRepositoryFileResource> resources) { // The component library itself if (getProject().getFlexoComponentLibrary(false) != null) { ComponentLibraryLatexFileResource clRes = GeneratedFileResourceFactory.createNewComponentLibraryLatexFileResource(repository, clGenerator); resources.add(clRes); TOCEntry entry = clGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, clRes); } Hashtable<ComponentDefinition, DGLatexGenerator<? extends ComponentDefinition>> generators = new Hashtable<ComponentDefinition, DGLatexGenerator<? extends ComponentDefinition>>(); // All the components Vector<ComponentDefinition> components = getProject().getFlexoComponentLibrary().getRootFolder().getAllComponents(); resetSecondaryProgressWindow(components.size()); for (ComponentDefinition cd : components) { if (cd == null || cd.getDontGenerate()) { continue; } DGLatexGenerator<? extends ComponentDefinition> generator = getComponentGenerator(cd); refreshSecondaryProgressWindow(FlexoLocalization.localizedForKey("generating") + " " + cd.getName(), false); if (generator != null) { generators.put(cd, generator); ComponentLatexFileResource<? extends ComponentDefinition> res = GeneratedFileResourceFactory .createNewComponentLatexFileResource(repository, generator); resources.add(res); entry = generator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, res); } } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not instanciate ComponentDocGenerator for " + cd); } } } componentGenerators = generators; } } /** * @param repository * @param resources */ private void buildResourcesAndSetGeneratorsForWorkflow(DGRepository repository, Vector<CGRepositoryFileResource> resources) { // The Workflow itself if (getProject().getFlexoWorkflow(false) != null) { WorkflowLatexFileResource wkfResource = GeneratedFileResourceFactory.createNewWorkflowLatexFileResource(repository, workflowGenerator); resources.add(wkfResource); TOCEntry entry = workflowGenerator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, wkfResource); } Hashtable<FlexoProcess, DGLatexGenerator<FlexoProcess>> generators = new Hashtable<FlexoProcess, DGLatexGenerator<FlexoProcess>>(); // All its processes Vector<FlexoProcess> processes = getProject().getAllLocalFlexoProcesses(); resetSecondaryProgressWindow(processes.size()); for (FlexoProcess process : processes) { if (process == null || process.getDontGenerate()) { continue; } DGLatexGenerator<FlexoProcess> generator = getProcessGenerator(process); refreshSecondaryProgressWindow(FlexoLocalization.localizedForKey("generating") + " " + process.getName(), false); if (generator != null) { generators.put(process, generator); ProcessLatexFileResource res = GeneratedFileResourceFactory.createNewProcessLatexFileResource(repository, generator); resources.add(res); entry = generator.getTOCEntry(); if (entry != null) { associateEntryWithResource(entry, res); } } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not instanciate ProcessDocGenerator for " + process); } } buildResourcesAndSetGeneratorsForProcess(repository, resources, process); } processGenerators = generators; } } /** * @param repository * @param resources * @param process * @return */ private void buildResourcesAndSetGeneratorsForProcess(DGRepository repository, Vector<CGRepositoryFileResource> resources, FlexoProcess process) { Hashtable<OperationNode, DGLatexGenerator<OperationNode>> generators = new Hashtable<OperationNode, DGLatexGenerator<OperationNode>>(); Vector<OperationNode> operations = process.getAllEmbeddedOperationNodes(); for (OperationNode node : operations) { if (node == null || node.getDontGenerate()) { continue; } DGLatexGenerator<OperationNode> generator = getOperationGenerator(node); if (generator != null) { generators.put(node, generator); OperationLatexFileResource res = GeneratedFileResourceFactory.createNewOperationLatexFileResource(repository, generator); resources.add(res); } else { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not instanciate OperationDocGenerator for " + node); } } } operationGenerators = generators; } @Override public void copyAdditionalFiles() throws IOException { super.copyAdditionalFiles(); FileUtils.copyDirToDir(getProject().getImportedImagesDir(), getRootOutputDirectory(), CopyStrategy.REPLACE_OLD_ONLY); FileUtils.copyContentDirToDir(getProject().getLatexToEmbedDirectory(), getRootOutputDirectory(), CopyStrategy.REPLACE_OLD_ONLY); } @Override public boolean hasBeenInitialized() { return hasBeenInitialized; } /** * @param process * @return */ private DGLatexGenerator<FlexoProcess> getProcessGenerator(FlexoProcess process) { DGLatexGenerator<FlexoProcess> returned = processGenerators.get(process); if (returned == null) { processGenerators.put(process, returned = new DGLatexGenerator<FlexoProcess>(this, process, PROCESS_TEMPLATE_NAME)); } return returned; } /** * @param node * @return */ private DGLatexGenerator<OperationNode> getOperationGenerator(OperationNode node) { DGLatexGenerator<OperationNode> returned = operationGenerators.get(node); if (returned == null) { operationGenerators.put(node, returned = new DGLatexGenerator<OperationNode>(this, node, OPERATION_TEMPLATE_NAME)); } return returned; } public DGLatexGenerator<DMEOEntity> getEntityGenerator(DMEOEntity entity) { DGLatexGenerator<DMEOEntity> returned = entityGenerators.get(entity); if (returned == null) { entityGenerators.put(entity, returned = new DGLatexGenerator<DMEOEntity>(this, entity, EOENTITY_TEMPLATE_NAME)); } return returned; } public ProjectLatexFileResource getProjectDocResource() { return (ProjectLatexFileResource) getProject().resourceForKey(ResourceType.LATEX_FILE, ProjectLatexFileResource.nameForRepositoryAndProject(this.getRepository(), getProject())); } /** * @param process * @return */ private DGLatexGenerator<? extends ComponentDefinition> getComponentGenerator(ComponentDefinition cd) { DGLatexGenerator<? extends ComponentDefinition> returned = componentGenerators.get(cd); if (returned == null) { if (cd instanceof PopupComponentDefinition) { componentGenerators.put(cd, returned = new DGLatexGenerator<PopupComponentDefinition>(this, (PopupComponentDefinition) cd, POPUP_TEMPLATE_NAME)); } else if (cd instanceof OperationComponentDefinition) { componentGenerators.put(cd, returned = new DGLatexGenerator<OperationComponentDefinition>(this, (OperationComponentDefinition) cd, PAGE_TEMPLATE_NAME)); } else if (cd instanceof TabComponentDefinition) { componentGenerators.put(cd, returned = new DGLatexGenerator<TabComponentDefinition>(this, (TabComponentDefinition) cd, TAB_TEMPLATE_NAME)); } else if (logger.isLoggable(Level.SEVERE)) { logger.severe("components of type " + cd.getClass().getName() + " are not handled"); } } return returned; } protected long lastLogUpdate; /** * @throws IOException * */ public File generatePDF(String latexCommand) throws IOException { boolean endedWithSuccess = true; File projectFile = getProjectDocResource().getFile(); Process p = null; try { getRepository().notifyPostBuildStart(); if (latexCommand.toLowerCase().indexOf("texify") > -1) { try { String[] command = new String[4]; command[0] = latexCommand; command[1] = "-b"; command[2] = "-p"; command[3] = projectFile.getAbsolutePath(); if (logger.isLoggable(Level.INFO)) { logger.info("Executing " + command[0] + " with args " + command[1] + " " + command[2] + " " + command[3]); } p = Runtime.getRuntime().exec(command, null, projectFile.getParentFile()); final InputStream is = p.getInputStream(); Thread readThread = new Thread(new Runnable() { /** * Overrides run * * @see java.lang.Runnable#run() */ @Override public void run() { InputStreamReader isr = new InputStreamReader(is); BufferedReader reader = new BufferedReader(isr); String line; List<LogListener> listeners = new ArrayList<LogListener>(logListeners); try { while ((line = reader.readLine()) != null) { for (LogListener l : listeners) { l.log(line); } if (logger.isLoggable(Level.FINE)) { logger.fine(line); } lastLogUpdate = System.currentTimeMillis(); } } catch (IOException e) { e.printStackTrace(); } } }); readThread.start(); final InputStream errIs = p.getErrorStream(); Thread errReadThread = new Thread(new Runnable() { /** * Overrides run * * @see java.lang.Runnable#run() */ @Override public void run() { InputStreamReader isr = new InputStreamReader(errIs); BufferedReader reader = new BufferedReader(isr); String line; List<LogListener> listeners = new ArrayList<LogListener>(logListeners); try { while ((line = reader.readLine()) != null) { for (LogListener l : listeners) { l.err(line); } if (logger.isLoggable(Level.FINE)) { logger.fine(line); } lastLogUpdate = System.currentTimeMillis(); } } catch (IOException e) { e.printStackTrace(); } } }); errReadThread.start(); final Thread current = Thread.currentThread(); Thread timeout = new Thread(new Runnable() { /** * Overrides run * * @see java.lang.Runnable#run() */ @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { return; } if (System.currentTimeMillis() - lastLogUpdate > getLatexTimeOutInMillis()) { current.interrupt(); if (logger.isLoggable(Level.WARNING)) { logger.warning("pdflatex timeout: no log for " + getLatexTimeOutInMillis() / 1000 + " seconds."); } return; } } } }); lastLogUpdate = System.currentTimeMillis(); timeout.start(); p.waitFor(); timeout.interrupt(); } catch (IOException e) { e.printStackTrace(); endedWithSuccess = false; } catch (InterruptedException e) { e.printStackTrace(); endedWithSuccess = false; if (p != null) { p.destroy(); } } } else { for (int i = 0; i < 3 && endedWithSuccess; i++) { try { String[] command = new String[3]; command[0] = latexCommand; command[1] = "-interaction=nonstopmode"; command[2] = projectFile.getAbsolutePath(); if (logger.isLoggable(Level.INFO)) { logger.info("Executing " + command[0] + " with args " + command[1] + " " + command[2]); } p = Runtime.getRuntime().exec(command, null, projectFile.getParentFile()); final InputStream is = p.getInputStream(); Thread readThread = new Thread(new Runnable() { /** * Overrides run * * @see java.lang.Runnable#run() */ @Override public void run() { InputStreamReader isr = new InputStreamReader(is); BufferedReader reader = new BufferedReader(isr); String line; List<LogListener> listeners = new ArrayList<LogListener>(logListeners); try { while ((line = reader.readLine()) != null) { for (LogListener l : listeners) { l.log(line); } lastLogUpdate = System.currentTimeMillis(); } } catch (IOException e) { e.printStackTrace(); } } }); readThread.start(); final InputStream errIs = p.getErrorStream(); Thread errReadThread = new Thread(new Runnable() { /** * Overrides run * * @see java.lang.Runnable#run() */ @Override public void run() { InputStreamReader isr = new InputStreamReader(errIs); BufferedReader reader = new BufferedReader(isr); String line; List<LogListener> listeners = new ArrayList<LogListener>(logListeners); try { while ((line = reader.readLine()) != null) { for (LogListener l : listeners) { l.err(line); } if (logger.isLoggable(Level.FINE)) { logger.fine(line); } lastLogUpdate = System.currentTimeMillis(); } } catch (IOException e) { e.printStackTrace(); } } }); errReadThread.start(); final Thread current = Thread.currentThread(); Thread timeout = new Thread(new Runnable() { /** * Overrides run * * @see java.lang.Runnable#run() */ @Override public void run() { while (true) { try { Thread.sleep(1000); } catch (InterruptedException e) { return; } if (System.currentTimeMillis() - lastLogUpdate > getLatexTimeOutInMillis()) { current.interrupt(); if (logger.isLoggable(Level.WARNING)) { logger.warning("pdflatex timeout: no log for " + getLatexTimeOutInMillis() / 1000 + " seconds."); } return; } } } }); lastLogUpdate = System.currentTimeMillis(); timeout.start(); p.waitFor(); timeout.interrupt(); } catch (IOException e) { e.printStackTrace(); endedWithSuccess = false; } catch (InterruptedException e) { e.printStackTrace(); endedWithSuccess = false; } } } } finally { if (p != null) { p.destroy();// We kill the process } getRepository().notifyPostBuildStop(); } if (endedWithSuccess) { File generated = new File(projectFile.getParentFile(), projectFile.getName().substring(0, projectFile.getName().length() - 3) + "pdf").getCanonicalFile(); File out = getRepository().getPostBuildFile().getCanonicalFile(); if (!generated.exists()) { if (logger.isLoggable(Level.WARNING)) { logger.warning("Could not find generated PDF file at " + generated.getAbsolutePath()); } return null; } if (!generated.equals(out)) { FileUtils.copyFileToFile(generated, out); } return out; } else { return null; } } public String getPdfName() { return getRepository().getPostProductName(); } public long getLatexTimeOutInMillis() { if (latexTimeOutInMillis <= 0) { latexTimeOutInMillis = 15000; } return latexTimeOutInMillis; } public void setLatexTimeOutInMillis(long latexTimeOutInMillis) { this.latexTimeOutInMillis = latexTimeOutInMillis; } /** * {@inheritDoc} */ @Override public List<CGTemplate> getVelocityMacroTemplates() { List<CGTemplate> result = new ArrayList<CGTemplate>(); try { result.add(templateWithName(LATEX_MACRO_LIBRARY_NAME)); } catch (TemplateNotFoundException e) { logger.warning("Should include velocity macro template for project generator but template is not found '" + LATEX_MACRO_LIBRARY_NAME + "'"); e.printStackTrace(); } return result; } }