/*
jBilling - The Enterprise Open Source Billing System
Copyright (C) 2003-2011 Enterprise jBilling Software Ltd. and Emiliano Conde
This file is part of jbilling.
jbilling is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
jbilling 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 Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with jbilling. If not, see <http://www.gnu.org/licenses/>.
*/
package com.sapienter.jbilling.server.rule.task;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.xmlrules.DigesterLoader;
import org.apache.log4j.Logger;
import org.drools.compiler.PackageBuilder;
import org.drools.rule.Package;
import org.drools.util.DroolsStreamUtils;
import org.xml.sax.SAXException;
import com.sapienter.jbilling.common.Util;
import com.sapienter.jbilling.server.pluggableTask.PluggableTask;
import com.sapienter.jbilling.server.pluggableTask.TaskException;
import com.sapienter.jbilling.server.pluggableTask.admin.ParameterDescription;
/**
* Provides implementation for parsing the rulesGenerate input data as
* XML using Digester. Also compiles the rules generated by the
* subclass. Relative path names are assumed to be from the
* 'jbilling/resource/rules' directory.
*
* Parameters:
* - 'config_filename' (default: 'rules-generator-config.xml') - the
* configuration file.
* - 'output_filename' - where the compiled package will be saved.
*/
public abstract class AbstractGeneratorTask extends PluggableTask
implements IRulesGenerator {
public static final ParameterDescription PARAM_CONFIG_FILENAME =
new ParameterDescription("config_filename", false, ParameterDescription.Type.STR);
public static final ParameterDescription PARAM_OUTPUT_FILENAME =
new ParameterDescription("output_filename", true, ParameterDescription.Type.STR);
private static final String PARAM_CONFIG_FILENAME_DEFAULT = "rules-generator-config.xml";
private static final Logger LOG = Logger.getLogger(AbstractGeneratorTask.class);
private Object data;
private String rules;
public AbstractGeneratorTask() {
super();
}
//initializer for pluggable params
{
descriptions.add(PARAM_CONFIG_FILENAME);
descriptions.add(PARAM_OUTPUT_FILENAME);
}
/**
* Parses and validates the XML input data.
*/
public void unmarshal(String objects) throws TaskException {
try {
// get the configuration filename
String configFilename = PARAM_CONFIG_FILENAME_DEFAULT;
if (parameters.get(PARAM_CONFIG_FILENAME.getName()) != null) {
configFilename = (String) parameters.get(PARAM_CONFIG_FILENAME.getName());
}
// if the filename is relative, prepend default directory
configFilename = getAbsolutePath(configFilename);
LOG.debug("Config filename: " + configFilename);
// load the parsing rules
Digester digester = DigesterLoader.createDigester(new URL("file:///" + configFilename));
digester.setUseContextClassLoader(true);
// parse the input string
//digester.setValidating(true);
data = digester.parse(new StringReader(objects));
} catch (IOException ioe) {
LOG.error("Error parsing XML file: " + ioe.toString());
throw new TaskException(ioe);
} catch (SAXException saxe) {
LOG.error("Error parsing XML file: " + saxe.toString());
throw new TaskException(saxe);
}
}
/**
* Compiles and saves the rules. Calls the subclass to generate
* the rules.
*/
public void process() throws TaskException {
// get the subclass to generate the rules from the data
rules = generateRules(data);
LOG.debug("Generated rules: \n" + rules);
// compile the rules into a binary package
PackageBuilder builder = new PackageBuilder();
try {
builder.addPackageFromDrl(new StringReader(rules));
} catch (Exception e) {
LOG.error("Error building drools package.");
throw new TaskException(e);
}
if(builder.hasErrors()) {
String error = "Error building drools package: \n" +
builder.getErrors().toString();
LOG.error(error);
throw new TaskException(error);
}
Package pkg = builder.getPackage();
// get output filename
if (parameters.get(PARAM_OUTPUT_FILENAME.getName()) == null) {
throw new TaskException("No '" + PARAM_OUTPUT_FILENAME.getName() +
"' parameter specified.");
}
String outputFilename = (String) parameters.get(PARAM_OUTPUT_FILENAME.getName());
// if the filename is relative, prepend default directory
outputFilename = getAbsolutePath(outputFilename);
LOG.debug("Output filename: " + outputFilename);
// write to file
//ObjectOutputStream out = null;
FileOutputStream fout = null;
try {
//out = new ObjectOutputStream(new FileOutputStream(outputFilename));
//out.writeObject(pkg);
fout = new FileOutputStream(outputFilename);
DroolsStreamUtils.streamOut(fout, pkg);
} catch (FileNotFoundException fnfe) {
LOG.error("Error writing rules package file.");
throw new TaskException(fnfe);
} catch (IOException ioe) {
LOG.error("Error writing rules package file.");
throw new TaskException(ioe);
} finally {
if (fout != null) {
try {
fout.close();
} catch (IOException ioe) {
}
}
}
}
/**
* Subclass implements this method to generate the rules to be
* compiled. Gets passed the objects created by Digester.
*/
protected abstract String generateRules(Object objects)
throws TaskException;
/**
* Prepends default directory if filename is relative.
*/
protected String getAbsolutePath(String filename) {
if (!(new File(filename)).isAbsolute()) {
filename = Util.getSysProp("base_dir") + "rules/" +
filename;
}
return filename;
}
/**
* For testing
*/
public Object getData() {
return data;
}
/**
* For testing
*/
public String getRules() {
return rules;
}
}