/*
* Copyright 2010 JBoss Inc
*
* Licensed 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.
*/
package org.jboss.drools.guvnor.importgenerator;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.text.MessageFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.jboss.drools.guvnor.importgenerator.utils.FileIOHelper;
import org.joda.time.DateTime;
import org.joda.time.Minutes;
import org.joda.time.Seconds;
/**
* a BRMS import file generator for drl and xml decision table files
*/
public class ImportFileGenerator implements Constants {
class Logger{
public void debug(String msg){if (msg.contains("%"))System.out.print(msg);else System.out.println(msg);}
public void error(String msg, Throwable t){System.err.println(msg); t.printStackTrace();}
public void trace(String msg){System.out.println(msg);}
}
protected final Logger logger=new Logger();
private Configuration config=null;
private String BASE_DIR = System.getProperty("user.dir");
public enum PackageObjectType {PACKAGE, PACKAGE_SNAPSHOT, MODEL}
public enum RuleObjectType {RULE, SNAPSHOT_RULE}
/* this is so the Mojo compiler doesnt balk if it sees generateImportFile() with the packages param */
private Map<String, PackageFile> packages;
public void setPackages(Map<String, PackageFile> packages){
this.packages=packages;
}
private String generateImportFile() throws IOException {
// go through each replacer definition creating drl template replacements
//TODO: what is the org.drools.io.RuleSetReader ??? is this what Guvnor uses this to read the .drl file parts?
String draftStateReferenceUUID = GeneratedData.generateUUID();
String categoryReferenceUUID = GeneratedData.generateUUID();
//reporting only
int cok = 0, terror = 0, total = 0;
StringBuffer packageContents = new StringBuffer();
StringBuffer snapshotContents = new StringBuffer();
double i = 0;
// reorder so that globalArea is first
LinkedHashMap<String, PackageFile> packages2=new LinkedHashMap<String, PackageFile>();
if (packages.get("globalArea")!=null){
packages2.put("globalArea", packages.get("globalArea"));
packages.remove("globalArea");
}
for(Entry<String, PackageFile> e:packages.entrySet())
packages2.put(e.getKey(), e.getValue());
this.packages=packages2;
for (Map.Entry<String, PackageFile> packagesEntry : packages.entrySet()) {
String packageName = packagesEntry.getKey();
double pct = (int) (++i / (double) packages.size() * 100);
logger.debug(new DecimalFormat("##0").format(pct) + "% - " + packageName);
PackageFile packageFile = packagesEntry.getValue();
Map<String, Object> context = new HashMap<String, Object>();
context.put("draftStateReferenceUUID", draftStateReferenceUUID);
context.put("categoryReferenceUUID", categoryReferenceUUID);
context.put("packageFile", packageFile);
//extract the rule contents
StringBuffer ruleContents = new StringBuffer();
StringBuffer snapshotRuleContents = new StringBuffer();
Map<String, Rule> rules = packageFile.getRules();
packageFile.buildPackage();
for (Map.Entry<String, Rule> rulesEntry : rules.entrySet()) {
// String ruleName = rulesEntry.getKey();
Rule rule = (Rule) rulesEntry.getValue();
context.put("file", rule.getFile());
context.put("rule", rule);
// String format = FilenameUtils.getExtension(rule.getFile().getName());
// String format=;
context.put("format", rule.getFormat());
//inject the rule values into the rule template
ruleContents.append(MessageFormat.format(readTemplate(MessageFormat.format(TEMPLATES_RULE, rule.getFormat().toLowerCase())), getRuleObjects(context/*, RuleObjectType.RULE*/)));
//inject the snapshot rule values in the the snapshot rule template
snapshotRuleContents.append(MessageFormat.format(readTemplate(MessageFormat.format(TEMPLATES_SNAPSHOT_RULE, rule.getFormat().toLowerCase())), getRuleObjects(context/*, RuleObjectType.SNAPSHOT_RULE*/)));
}
String modelTemplate = readTemplate(TEMPLATES_MODEL);
for (Model model : packageFile.getModelFiles()) {
context.put("model", model);
ruleContents.append(MessageFormat.format(modelTemplate, getPackageObjects(context, new StringBuffer(model.getContent()), PackageObjectType.MODEL)));
}
// If no models in directory but parameter specified then upload the parameterized model
// String modelRefTemplate = readTemplate(TEMPLATES_MODEL_REF);
// PackageFile globalArea=packages.get("globalArea");
// if (null!=globalArea && globalArea.getModelFiles().size()>0){
// for(Model model:globalArea.getModelFiles()){
// // add a model_ref to the actual package to the globalArea models uuid
// context.put("model", model);
// ruleContents.append(MessageFormat.format(modelRefTemplate, getPackageObjects(context, new StringBuffer(model.getContent()), PackageObjectType.MODEL_REF)));
// }
// }
// // If no models in directory but parameter specified then upload the parameterized model
// if (packageFile.getModelFiles().size() <= 0 && config.getModelFile() != null) {
// File modelFile = new File(config.getModelFile());
// String modelFileContent = FileIOHelper.readAllAsBase64(modelFile);
// context.put("model", new Model(modelFile, modelFileContent));
// ruleContents.append(MessageFormat.format(modelTemplate, getPackageObjects(context, new StringBuffer(modelFileContent), PackageObjectType.MODEL)));
// }
//inject the rule(s) into the package into the package contents
String packageTemplate = readTemplate(TEMPLATES_PACKAGE);// FileUtils.readAll(new FileInputStream(new File(TEMPLATES_FOLDER, TEMPLATES_PACKAGE)));
packageContents.append(MessageFormat.format(packageTemplate, getPackageObjects(context, ruleContents, PackageObjectType.PACKAGE)));
//inject the snapshot values into the snapshot contents
if (config.getSnapshotName() != null) {
snapshotContents.append(MessageFormat.format(readTemplate(TEMPLATES_SNAPSHOT), getPackageObjects(context, snapshotRuleContents, PackageObjectType.PACKAGE_SNAPSHOT)));
}
//display status of each packageFile
total++;
if (packageFile.hasErrors()) {
terror++;
if (packageFile.hasCompilationErrors()) {
// cerror++;
logger.debug(" - [COMPILATION/DEPENDENCY ERRORS]");
logger.trace(packageFile.getCompilationErrors().trim());
logger.trace(packageFile.getDependencyErrors().trim());
} else if (packageFile.hasDependencyErrors()) {
// derror++;
logger.debug(" - [DEPENDENCY ERRORS]");
logger.trace(packageFile.getDependencyErrors().trim());
}
} else {
cok++; //increment the "total rules compiled successfully"
logger.debug(" - [OK]");
}
}
//replace the placemarkers with the package data
String parentContents = MessageFormat.format(readTemplate(TEMPLATES_PARENT), new Object[]{
packageContents
, categoryReferenceUUID
, draftStateReferenceUUID
, GeneratedData.getTimestamp()
, getSnapshotContents(snapshotContents)
});
//write a summary report
logger.debug("==========================");
logger.debug("=== PACKAGE SUMMARY ===");
logger.debug("==========================");
logger.debug(" Rules compiled OK: " + NumberFormat.getInstance().format(cok));
logger.debug(" Errors: " + NumberFormat.getInstance().format(terror));
logger.debug(" ____");
logger.debug(" Total: " + NumberFormat.getInstance().format(total));
logger.debug("==========================");
return parentContents;
}
/**
* returns a drools-5.0 formatted xml file for use with a drools 5.0 knowledge agent
*
* @param packages
* @return
*/
public String generateKnowledgeAgentInitFile(Map<String, PackageFile> packages) {
StringBuffer kagentInitContents = new StringBuffer();
String kagentChildTemplate = readTemplate(TEMPLATES_KAGENT_CHILD_INIT);
StringBuffer kagentChildContents = new StringBuffer();
for (Map.Entry<String, PackageFile> packagesEntry : packages.entrySet()) {
String packageName = packagesEntry.getKey();
PackageFile packageFile = packagesEntry.getValue();
kagentChildContents.append(MessageFormat.format(kagentChildTemplate,
new Object[]{config.getKagentChangeSetServer(),
packageFile.getName() + "/" + config.getSnapshotName(), "PKG"}));
}
String kagentParentTemplate = readTemplate(TEMPLATES_KAGENT_PARENT_INIT);
kagentInitContents.append(MessageFormat.format(kagentParentTemplate, new Object[]{kagentChildContents.toString()}));
return kagentInitContents.toString();
}
private StringBuffer getSnapshotContents(StringBuffer snapshotContents) {
if (config.getSnapshotName() != null) {
return snapshotContents;
}
return new StringBuffer("");
}
private String readTemplate(String templateConst) {
String path = TEMPLATES_FOLDER + "/" + templateConst;
try {
InputStream in = getClass().getClassLoader().getResourceAsStream(path);
if (null != in) {
return IOUtils.toString(in);
} else {
File file = new File(new File(BASE_DIR, /*"src/main/resources/"+*/TEMPLATES_FOLDER), templateConst);
try {
return FileUtils.readFileToString(file);
} catch (IOException e) {
throw new IllegalArgumentException("Error reading file (" + file +")", e);
}
}
} catch (IOException e) {
throw new IllegalArgumentException("Problem reading path (" + path + ").", e);
}
}
private Object[] getPackageObjects(Map<String, Object> context, StringBuffer contents, PackageObjectType type) throws IOException {
List<String> objects = new LinkedList<String>();
PackageFile packageFile = (PackageFile) context.get("packageFile");
switch (type) {
// case MODEL_REF:
// Model modelRef = (Model) context.get("model");
// objects.add(modelRef.getFile().getName().substring(0, modelRef.getFile().getName().lastIndexOf(".")));//wrapper title
// objects.add(getCreator());//creator
// objects.add(contents.toString());// packageFile.getModelAsBase64());//content
// objects.add(modelRef.getUuid());//uuid
// objects.add(modelRef.getFile().getName());//filename
// objects.add((String) context.get("draftStateReferenceUUID"));//state
// objects.add(GeneratedData.getTimestamp());//timestamp
// objects.add(packageFile.getName()); //package name
// break;
case MODEL:
Model model = (Model) context.get("model");
objects.add(model.getFile().getName().substring(0, model.getFile().getName().lastIndexOf(".")));//wrapper title
objects.add(getCreator());//creator
objects.add(contents.toString());// packageFile.getModelAsBase64());//content
objects.add(GeneratedData.generateUUID());//uuid
objects.add(model.getFile().getName());//filename
objects.add((String) context.get("draftStateReferenceUUID"));//state
objects.add(GeneratedData.getTimestamp());//timestamp
objects.add(packageFile.getName()); //package name
break;
case PACKAGE:
objects.add(packageFile.getName());
objects.add(getCreator());
objects.add(packageFile.getImports());
objects.add(contents.toString());
objects.add(GeneratedData.generateUUID());
objects.add(GeneratedData.generateUUID());
objects.add(GeneratedData.generateUUID());
objects.add((String) context.get("draftStateReferenceUUID"));
objects.add(GeneratedData.getTimestamp());
break;
case PACKAGE_SNAPSHOT:
objects.add(packageFile.getName());
objects.add(packageFile.getName().substring(packageFile.getName().lastIndexOf(".") + 1));// //aka the title
objects.add(config.getSnapshotName());
objects.add(getCreator()); //3
objects.add(packageFile.getImports()); //4
objects.add(contents.toString()); //5
objects.add((String) context.get("draftStateReferenceUUID"));
objects.add(GeneratedData.getTimestamp()); //7
//objects.add(FileIOHelper.toBase64(DroolsHelper.compileRuletoPKG(packageFile))); //8
objects.add(FileIOHelper.toBase64(packageFile.toByteArray()));
objects.add(GeneratedData.generateUUID()); //snapshot uuid
objects.add(GeneratedData.generateUUID()); //snapshot base+predecessor uuid
objects.add(GeneratedData.generateUUID()); //assets uuid
objects.add(GeneratedData.generateUUID()); //assets base+predecessor uuid
objects.add(GeneratedData.generateUUID()); //drools uuid
objects.add(GeneratedData.generateUUID()); //drools base+predecessor uuid
break;
}
return objects.toArray(new Object[objects.size()]);
}
private Object[] getRuleObjects(Map<String, Object> context/*, RuleObjectType type*/) {
List<String> objects = new LinkedList<String>();
PackageFile packageFile = (PackageFile) context.get("packageFile");
Rule rule = (Rule) context.get("rule");
objects.add(rule.getRuleName());
objects.add(packageFile.getName());
objects.add(rule.getContent());
objects.add(GeneratedData.generateUUID()); //rule uuid
objects.add((String) context.get("draftStateReferenceUUID"));
objects.add((String) context.get("categoryReferenceUUID"));
objects.add(getCreator());
objects.add(GeneratedData.getTimestamp());
objects.add(rule.getFormat());
objects.add(GeneratedData.generateUUID()); //base version + predecessor (currently only used in snapshot)
if ("xls".equalsIgnoreCase((String) context.get("format"))) {
objects.add(((File) context.get("file")).getName());
}
return objects.toArray(new Object[]{});
}
private String getCreator() {
if (config.getCreator() != null) {
return config.getCreator();
}
return DEFAULT_CREATOR;
}
public void run(Configuration options) {
try {
SimpleDateFormat fmt = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date startd = new Date();
DateTime start = new DateTime(startd);
this.config = options;
// BASE_DIR = options.getBaseDir();
logger.debug("Running BRMS Import Generator (started " + fmt.format(startd) + "):");
logger.debug("Scanning directories...");
Map<String, PackageFile> details = PackageFile.buildPackages(options);
logger.debug("Generating 'Guvnor import data'...");
setPackages(details);
String guvnorImport = generateImportFile();
File guvnorImportFile = getFile(options.getOutputFile());
logger.debug("Writing 'Guvnor import data to disk' (" + guvnorImportFile.getAbsolutePath() + ")");
IOUtils.write(guvnorImport.getBytes(), new FileOutputStream(guvnorImportFile));
if (options.getKagentChangeSetFile() != null) {
logger.debug("Generating 'Knowledge agent changeset' data...");
String kagentChangeSet = generateKnowledgeAgentInitFile(details);
File kagentChangeSetFile = getFile(options.getKagentChangeSetFile());
logger.debug("Writing 'Knowledge agent changeset' to disk (" + kagentChangeSetFile.getAbsolutePath() + ")");
IOUtils.write(kagentChangeSet.getBytes(), new FileOutputStream(kagentChangeSetFile));
}
DateTime end = new DateTime(System.currentTimeMillis());
int m = Minutes.minutesBetween(start, end).getMinutes();
int s = Seconds.secondsBetween(start, end).getSeconds() - (m * 60);
logger.debug("Finished in (" + m + "m" + s + "s)");
} catch (IOException e) {
logger.error("", e);
}
}
private File getFile(String fileLoc) {
if (fileLoc.startsWith("/") || fileLoc.startsWith("~")) {
return new File(fileLoc);
} else {
return new File(BASE_DIR, fileLoc);
}
}
}