All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.innoventsolutions.birt.service.BirtEngineService Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (C) 2020 Innovent Solutions
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 ******************************************************************************/
package com.innoventsolutions.birt.service;

import java.io.File;
import java.io.FilenameFilter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.Level;

import javax.annotation.PostConstruct;

import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.core.framework.Platform;
import org.eclipse.birt.report.engine.api.EngineConfig;
import org.eclipse.birt.report.engine.api.EngineConstants;
import org.eclipse.birt.report.engine.api.IReportEngine;
import org.eclipse.birt.report.engine.api.IReportEngineFactory;

import com.innoventsolutions.birt.config.BirtConfig;
import com.innoventsolutions.birt.exception.BirtStarterException;
import com.innoventsolutions.birt.exception.BirtStarterException.BirtErrorCode;

import lombok.extern.slf4j.Slf4j;

/**
 * Wraps off a BIRT Engine Service.
 *  Supports either BIRT Open Source libraries or
 *  Commercial BIRT libraries from OpenText.
 *  Use of OpenText libraries requires configuration of BIRT_HOME
 *  
 * @author Scott Rosenbaum / Steve Schafer
 *
 */
@Slf4j
public class BirtEngineService {

	private final BirtConfig birtProperties;
	private IReportEngine engine = null;

	public BirtEngineService(final BirtConfig birtProperties) {
		this.birtProperties = birtProperties;
	}

	@PostConstruct
	public IReportEngine getEngine() throws BirtStarterException {
		if (engine == null) {
			log.info("Instantiate Report Engine");
			this.engine = getReportEngine();
		}
		return engine;
	}

	// Pass up required configuration parameters, does it make sense to just have
	// the calling classes use the configuration directly?
	public String getBaseImageURL() {
		return birtProperties.getBaseImageURL();
	}

	public File getOutputDir() {
		return birtProperties.getOutputDir();
	}

	public File getWorkspace() {
		return birtProperties.getWorkspace();
	}

	public File getDesignDir() {
		return birtProperties.getDesignDir();
	}

	private IReportEngine getReportEngine() throws BirtStarterException {

		log.info("getReportEngine");
		final EngineConfig config = new EngineConfig();
		log.info(birtProperties.toString());
		if (birtProperties.getBirtRuntimeHome() != null) {
			final String birtHome = birtProperties.getBirtRuntimeHome().getAbsolutePath();
			if (birtProperties.isActuate()) {
				config.setBIRTHome(birtHome);
			} else {
				config.setEngineHome(birtHome);
			}
		}
		if (birtProperties.getResourceDir() != null) {
			config.setResourcePath(birtProperties.getResourceDir().getAbsolutePath());
		}
		final String scriptlibFileNames = getScriptLibFileNames();
		if (scriptlibFileNames != null) {
			config.setProperty(EngineConstants.WEBAPP_CLASSPATH_KEY, scriptlibFileNames);
		}
		configureLogging(config);
		IReportEngine birtEngine =birtProperties.isActuate() ? getActuateReportEngine(config) : getReportEngine(config);
		
		return birtEngine;
	}

	private void configureLogging(final EngineConfig config) throws BirtStarterException {
		// control debug of BIRT components.
		final File loggingDirFile = birtProperties.getLoggingDir() == null ? new File("./log") : birtProperties.getLoggingDir();
		if (!loggingDirFile.exists()) {
			loggingDirFile.mkdirs();
		}
		config.setLogConfig(loggingDirFile.getAbsolutePath(), Level.WARNING);
	}

	private static IReportEngine getReportEngine(final EngineConfig config) throws BirtStarterException {
		log.info("before Platform startup");
		try {
			Platform.startup(config);
		} catch (final BirtException e) {
			throw new BirtStarterException(BirtErrorCode.PLATFORM_START, "Failed to start platform", e);
		}
		log.info("after Platform startup");
		final IReportEngineFactory factory = (IReportEngineFactory) Platform
				.createFactoryObject(IReportEngineFactory.EXTENSION_REPORT_ENGINE_FACTORY);
		if (factory == null) {
			log.error("Could not create report engine factory");
			throw new BirtStarterException(BirtErrorCode.PLATFORM_START, "Failed to create Factory");
		}
		final IReportEngine engine = factory.createReportEngine(config);
		if (engine == null) {
			log.error("Could not create report engine");
			throw new BirtStarterException(BirtErrorCode.PLATFORM_START, "Failed to create Engine");
		}
		return engine;
	}

	private static IReportEngine getActuateReportEngine(final EngineConfig config) throws BirtStarterException {
		try {
			Platform.startup(config);
		} catch (final BirtException e) {
			throw new BirtStarterException(BirtErrorCode.PLATFORM_START, "Failed to start platform", e);
		}
		final Object factoryObjectForReflection = Platform
				.createFactoryObject("com.actuate.birt.report.engine.ActuateReportEngineFactory"
				/* IActuateReportEngineFactory. EXTENSION_ACTUATE_REPORT_ENGINE_FACTORY */
				);
		// when using the Actuate Report Engine Factory, the return type is
		// not exposed publicly, so you cannot instantiate the factory
		// under normal conditions.
		// but we can use reflection to call the createReportEngine method
		// and get the commercial report engine running as opposed to the
		// open source one, which
		// will give access to all the commercial emitters
		final Class factoryClass = factoryObjectForReflection.getClass();
		final Method[] methods = factoryClass.getDeclaredMethods();
		IReportEngine reportEngine = null;
		for (final Method m : methods) {
			final String name = m.getName();
			m.setAccessible(true);
			if (name.equals("createReportEngine")) {
				try {
					reportEngine = (IReportEngine) m.invoke(factoryObjectForReflection, config);
				} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
					throw new BirtStarterException(BirtErrorCode.PLATFORM_START, "Failed to create report engine", e);
				}
			}
		}
		return reportEngine;
	}

	/*
	 * The engine needs to see a list of each jar file concatenated as a string
	 * using the standard file system separator to divide the files
	 */
	private String getScriptLibFileNames() {
		if (birtProperties.getScriptLibDir() == null) {
			return null;
		}
		if (!birtProperties.getScriptLibDir().exists()) {
			birtProperties.getScriptLibDir().mkdirs();
		}
		final File[] files = birtProperties.getScriptLibDir().listFiles(new JarFilter());
		final StringBuilder sb = new StringBuilder();
		String sep = "";
		final String fileSeparatorString = new String(new char[] { File.pathSeparatorChar });
		if (files != null) {
			for (int i = 0; i < files.length; i++) {
				sb.append(sep);
				sep = fileSeparatorString;
				sb.append(files[i].getAbsolutePath());
			}
		}
		return sb.toString();
	}

	private static class JarFilter implements FilenameFilter {
		private final String extension = ".jar";

		@Override
		public boolean accept(final File dir, final String name) {
			return name.toLowerCase().endsWith(extension);
		}
	}

	@SuppressWarnings("deprecation")
	public void shutdown() {
		// there is really no place this can be done
		log.info("engine shutdown");
		// TODO Figure out how to shutdown engine
		engine.shutdown();
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy