Package com.alexnederlof.jasperreport

Source Code of com.alexnederlof.jasperreport.JasperReporter

package com.alexnederlof.jasperreport;

/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable
* law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
* for the specific language governing permissions and limitations under the License.
*/

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;

import net.sf.jasperreports.engine.DefaultJasperReportsContext;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.design.JRCompiler;
import net.sf.jasperreports.engine.design.JRJdtCompiler;
import net.sf.jasperreports.engine.xml.JRReportSaxParserFactory;

import org.apache.commons.lang.Validate;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.logging.Log;
import org.codehaus.plexus.compiler.util.scan.InclusionScanException;
import org.codehaus.plexus.compiler.util.scan.SourceInclusionScanner;
import org.codehaus.plexus.compiler.util.scan.StaleSourceScanner;
import org.codehaus.plexus.compiler.util.scan.mapping.SourceMapping;
import org.codehaus.plexus.compiler.util.scan.mapping.SuffixMapping;

/**
* This plugin compiles jasper source files to the target folder. While doing so, it keeps the
* folder structure in tact.
*
* @goal jasper
* @phase process-resources
* @requiresDependencyResolution compile
*/
public class JasperReporter extends AbstractMojo {

  static final String ERROR_JRE_COMPILE_ERROR =
      "Some Jasper reports could not be compiled. See log above for details.";

  /**
   * This is the java compiler used
   *
   * @parameter default-value="net.sf.jasperreports.engine.design.JRJdtCompiler"
   * @required
   */
  private String compiler;

  /**
   * This is where the .jasper files are written.
   *
   * @parameter property="${project.build.outputDirectory}/jasper"
   */
  private File outputDirectory;

  /**
   * This is where the xml report design files should be.
   *
   * @parameter default-value="src/main/jasperreports"
   */
  private File sourceDirectory;

  /**
   * The extension of the source files to look for. Finds files with a .jrxml extension by
   * default.
   *
   * @parameter default-value=".jrxml"
   */
  private String sourceFileExt;

  /**
   * The extension of the compiled report files. Creates files with a .jasper extension by
   * default.
   *
   * @parameter default-value=".jasper"
   */
  private String outputFileExt;

  /**
   * Check the source files before compiling. Default value is true.
   *
   * @parameter default-value="true"
   */
  private boolean xmlValidation;

  /**
   * If verbose is on the plug-in will report which reports it is compiling and which files are
   * being skipped.
   *
   * @parameter default-value="false"
   */
  private boolean verbose;

  /**
   * The number of threads the reporting will use. Default is 4 which is good for a lot of reports
   * on a hard drive (in stead of SSD). If you only have a few, or if you have SSD, it might be
   * faster to set it to 2.
   *
   * @parameter default-value=4
   */
  private int numberOfThreads;

    /**
     * @parameter property="project.compileClasspathElements"
     */
    private List<String> classpathElements;

    /**
   * Use this parameter to add additional properties to the Jasper compiler. For example.
   *
   * <pre>
   * {@code
   * <configuration>
   *   ...
   *     <additionalProperties>
   *       <net.sf.jasperreports.awt.ignore.missing.font>true
   *      </net.sf.jasperreports.awt.ignore.missing.font>
   *          <net.sf.jasperreports.default.pdf.font.name>Courier</net.sf.jasperreports.default.pdf.font.name>
   *          <net.sf.jasperreports.default.pdf.encoding>UTF-8</net.sf.jasperreports.default.pdf.encoding>
   *          <net.sf.jasperreports.default.pdf.embedded>true</net.sf.jasperreports.default.pdf.embedded>
       </additionalProperties>
   * </configuration>
   * }
   * </pre>
   * @parameter
   */
  private Map<String, String> additionalProperties;

  private Log log;

  public JasperReporter() {
  }

  @Override
  public void execute() throws MojoExecutionException {
    log = getLog();

    if (verbose) {
            logConfiguration(log);
        }

    checkOutDirWritable(outputDirectory);

    SourceMapping mapping = new SuffixMapping(sourceFileExt, outputFileExt);
        Set<File> sources = jxmlFilesToCompile(mapping);
        if (sources.isEmpty()) {
            log.info( "Nothing to compile - all Jasper reports are up to date" );
        } else {
            log.info( "Compiling " + sources.size() + " Jasper reports design files." );

            List<CompileTask> tasks = generateTasks(sources, mapping);
            if (tasks.isEmpty()) {
                log.info("Nothing to compile");
                return;
            }

            ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
            Thread.currentThread().setContextClassLoader(getClassLoader(classLoader));
            try {
                configureJasper();
                executeTasks(tasks);
            } finally {
                if (classLoader != null) {
                    Thread.currentThread().setContextClassLoader(classLoader);
                }
            }
        }
  }

  /**
     * Determines source files to be compiled.
     *
     * @param mapping
     * @return set of jxml files to compile
     * @throws MojoExecutionException
     */
    protected Set<File> jxmlFilesToCompile(SourceMapping mapping) throws MojoExecutionException {
        Validate.isTrue(sourceDirectory.isDirectory(), sourceDirectory.getName() + " is not a directory");

        try {
            SourceInclusionScanner scanner = new StaleSourceScanner();
            scanner.addSourceMapping(mapping);
            return scanner.getIncludedSources(sourceDirectory, outputDirectory);
        } catch (InclusionScanException e) {
            throw new MojoExecutionException("Error scanning source root: \'" + sourceDirectory + "\'.", e);
        }
    }

  private void logConfiguration(Log log) {
    log.info("Generating Jasper reports");
    log.info("Output dir: " + outputDirectory.getAbsolutePath());
    log.info("Source dir: " + sourceDirectory.getAbsolutePath());
    log.info("Output ext: " + outputFileExt);
    log.info("Source ext: " + sourceFileExt);
    log.info("Addition properties: " + additionalProperties);
    log.info("XML Validation: " + xmlValidation);
    log.info("JasperReports Compiler: " + compiler);
    log.info("Number of threads: " + numberOfThreads);
    log.info("classpathElements: " + classpathElements);
  }

  /**
   * Check if the output directory exist and is writable. If not, try to create an output dir and
   * see if that is writable.
   *
   * @param outputDirectory
   * @throws MojoExecutionException
   */
  private void checkOutDirWritable(File outputDirectory) throws MojoExecutionException {
    if (outputDirectory.exists()) {
      if (outputDirectory.canWrite()) {
        return;
      }
      else {
        throw new MojoExecutionException("The output dir exists but was not writable. "
            + "Try running maven with the 'clean' goal.");
      }
    }
    checkIfOutputCanBeCreated();
    checkIfOutputDirIsWritable();
    if (verbose) {
      log.info("Output dir check OK");
    }
  }

  private void configureJasper() {
    DefaultJasperReportsContext jrContext = DefaultJasperReportsContext.getInstance();

        jrContext.setProperty(JRReportSaxParserFactory.COMPILER_XML_VALIDATION, String.valueOf(xmlValidation));
    jrContext.setProperty(JRCompiler.COMPILER_PREFIX, compiler == null ? JRJdtCompiler.class.getName() : compiler);
    jrContext.setProperty(JRCompiler.COMPILER_KEEP_JAVA_FILE, Boolean.FALSE.toString());

    if (additionalProperties != null) {
      configureAdditionalProperties(JRPropertiesUtil.getInstance(jrContext));
    }

  }

    private ClassLoader getClassLoader(ClassLoader classLoader) throws MojoExecutionException {
        List<URL> classpath = new ArrayList<URL>();
    if (classpathElements != null) {
      for (String element : classpathElements) {
        try {
          File f = new File(element);
          classpath.add(f.toURI().toURL());
          log.debug("Added to classpath " + element);
        } catch (Exception e) {
          throw new MojoExecutionException("Error setting classpath " + element + " " + e.getMessage());
        }
      }
    }

        URL[] urls = classpath.toArray(new URL[classpath.size()]);
        return new URLClassLoader(urls, classLoader);
    }

    private void configureAdditionalProperties(JRPropertiesUtil propertiesUtil) {
    for (Map.Entry<String, String> additionalProperty : additionalProperties.entrySet()) {
      propertiesUtil.setProperty(additionalProperty.getKey(), additionalProperty.getValue());
    }
  }

  private void checkIfOutputCanBeCreated() throws MojoExecutionException {
    if (!outputDirectory.mkdirs()) {
      throw new MojoExecutionException(this, "Output folder could not be created", "Outputfolder "
          + outputDirectory.getAbsolutePath() + " is not a folder");
    }
  }

  private void checkIfOutputDirIsWritable() throws MojoExecutionException {
    if (!outputDirectory.canWrite()) {
      throw new MojoExecutionException(this, "Could not write to output folder",
          "Could not write to output folder: " + outputDirectory.getAbsolutePath());
    }
  }

  private String getRelativePath(String root, File file) throws MojoExecutionException {
        try {
            return file.getCanonicalPath().substring(root.length() + 1);
        } catch (IOException e) {
            throw new MojoExecutionException("Could not getCanonicalPath from file " + file, e);
        }
    }

  private List<CompileTask> generateTasks(Set<File> sources, SourceMapping mapping) throws MojoExecutionException {
    List<CompileTask> tasks = new LinkedList<CompileTask>();
    try {
        String root = sourceDirectory.getCanonicalPath();

        for (File src : sources) {
            String srcName = getRelativePath(root, src);
            try {
                File destination = mapping.getTargetFiles(outputDirectory, srcName).iterator().next();
                createDestination(destination.getParentFile());
                tasks.add(new CompileTask(src, destination, log, verbose));
            } catch (InclusionScanException e) {
                throw new MojoExecutionException("Error compiling report design : " + src, e);
            }
        }
     } catch (IOException e) {
              throw new MojoExecutionException("Could not getCanonicalPath from source directory " + sourceDirectory, e);
          }
    return tasks;
  }

  private void createDestination(File destinationDirectory) throws MojoExecutionException {
        if (!destinationDirectory.exists()) {
            if (destinationDirectory.mkdirs()) {
                log.debug("Created directory " + destinationDirectory.getName());
            } else {
                throw new MojoExecutionException("Could not create directory " + destinationDirectory.getName() );
            }
        }
  }

  private void executeTasks(List<CompileTask> tasks) throws MojoExecutionException {
    try {
      long t1 = System.currentTimeMillis();
      List<Future<Void>> output = Executors.newFixedThreadPool(numberOfThreads)
        .invokeAll(tasks);
      long time = (System.currentTimeMillis() - t1);
      log.info("Generated " + output.size() + " jasper reports in " + (time / 1000.0) + " seconds");
      checkForExceptions(output);
    }
    catch (InterruptedException e) {
      log.error("Failed to compile Japser reports: Interrupted!", e);
      throw new MojoExecutionException("Error while compiling Jasper reports", e);
    }
    catch (ExecutionException e) {
      if (e.getCause() instanceof JRException) {
        throw new MojoExecutionException(ERROR_JRE_COMPILE_ERROR, e);
      }
      else {
        throw new MojoExecutionException("Error while compiling Jasper reports", e);
      }
    }
  }

  private void checkForExceptions(List<Future<Void>> output) throws InterruptedException, ExecutionException {
    for (Future<Void> future : output) {
      future.get();
    }
  }

}
TOP

Related Classes of com.alexnederlof.jasperreport.JasperReporter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.