/** * The contents of this file are subject to the OpenMRS Public License * Version 1.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://license.openmrs.org * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the * License for the specific language governing rights and limitations * under the License. * * Copyright (C) OpenMRS, LLC. All Rights Reserved. */ package org.openmrs.arden.impl; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.util.Date; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.openmrs.api.APIException; import org.openmrs.api.context.Context; import org.openmrs.arden.ArdenBaseLexer; import org.openmrs.arden.ArdenBaseParser; import org.openmrs.arden.ArdenBaseTreeParser; import org.openmrs.arden.ArdenService; import org.openmrs.arden.MLMObject; import antlr.BaseAST; /** * Arden-related services * * @author Vibha Anand * @version 1.0 */ public class ArdenServiceImpl implements ArdenService { private final Log log = LogFactory.getLog(getClass()); public ArdenServiceImpl() { } /** * @param file - mlm file to be parsed */ public void compileFile(String file, String outFolder) { try { // if we have at least one command-line argument if (file.length() > 0) { log.debug("Parsing file" + file); // for each directory/file specified on the command line doFile(new File(file), outFolder); // parse it } } catch (Exception e) { log.error(e.getStackTrace()); } } /** * @param f - parse a file or a directory */ private void doFile(File f, String outFolder) throws Exception { boolean retVal = true; try { // If this is a directory, walk each file/dir in that directory if (f.isDirectory()) { String files[] = f.list(); for (int i = 0; i < files.length; i++) { doFile(new File(f, files[i]), outFolder); } } // otherwise, if this is a mlm file, parse it! else if (f.getName().substring(f.getName().length() - 4).equals(".mlm")) { log.info("Parsing file name:" + f.getName()); retVal = parseFile(new FileInputStream(f), f.getName(), outFolder); if (!retVal) { System.out.println("Please correct the compiler error!"); } } } catch (Exception e) { log.error(e.getMessage()); } } /** * @param s * @param fn */ private boolean parseFile(InputStream s, String fn, String outFolder) throws Exception { boolean retVal = true; try { Date Today = new Date(); String cfn; String packagePrefix = Context.getAdministrationService().getGlobalProperty("logic.default.packageName"); if (StringUtils.isEmpty(packagePrefix)) packagePrefix = "org.openmrs.logic.rule"; MLMObject ardObj = new MLMObject(Context.getLocale(), null); // Create a scanner that reads from the input stream passed to us ArdenBaseLexer lexer = new ArdenBaseLexer(s); // Create a parser that reads from the scanner ArdenBaseParser parser = new ArdenBaseParser(lexer); // start parsing at the compilation unit rule parser.startRule(); BaseAST t = (BaseAST) parser.getAST(); if (log.isDebugEnabled()) log.debug(t.toStringTree()); // prints maintenance ArdenBaseTreeParser treeParser = new ArdenBaseTreeParser(); String maintenance = treeParser.maintenance(t, ardObj); cfn = ardObj.getClassName(); String packageFolderName = packagePrefix.replace('.', File.separatorChar); File packageFolder = new File(outFolder, packageFolderName); if (!packageFolder.exists()) packageFolder.mkdirs(); // make sure that the file is stored in the correct folder based on the package OutputStream os = new FileOutputStream(new File(packageFolder, cfn + ".java")); Writer w = new OutputStreamWriter(os); log.info("Writing to file - " + cfn + ".java"); w.write("/********************************************************************" + "\n Translated from - " + fn + " on " + Today.toString() + "\n\n"); w.write(maintenance); t = (BaseAST) t.getNextSibling(); // Move to library if (log.isDebugEnabled()) log.debug(t.toStringTree()); // prints library String library = treeParser.library(t, ardObj); w.write(library); w.write("\n********************************************************************/\n"); w.write("package " + packagePrefix + ";\n\n"); w.write("import java.util.ArrayList;\n"); w.write("import java.util.HashMap;\n"); w.write("import java.util.List;\n"); w.write("import java.util.Map;\n"); w.write("import java.util.Set;\n"); w.write("import org.apache.commons.logging.Log;\n"); w.write("import org.apache.commons.logging.LogFactory;\n"); w.write("import org.openmrs.Patient;\n"); w.write("import org.openmrs.api.context.Context;\n"); w.write("import org.openmrs.arden.MlmRule;\n"); w.write("import org.openmrs.logic.LogicContext;\n"); w.write("import org.openmrs.logic.LogicCriteriaImpl;\n"); w.write("import org.openmrs.logic.LogicException;\n"); w.write("import org.openmrs.logic.LogicService;\n"); w.write("import org.openmrs.logic.result.Result;\n"); w.write("import org.openmrs.logic.result.Result.Datatype;\n"); w.write("import org.openmrs.logic.rule.RuleParameterInfo;\n"); w.write("import org.openmrs.logic.Duration;\n"); w.write("import java.util.StringTokenizer;\n\n"); w.write("import org.openmrs.api.ConceptService;\n"); w.write("import java.text.SimpleDateFormat;\n"); String classname = ardObj.getClassName(); w.write("public class " + classname + " implements MlmRule{\n\n"); // Start of class w.write("\tprivate Patient patient;\n\tprivate String firstname;\n"); w.write("\tprivate ArrayList<String> actions;\n"); w.write("\tprivate HashMap<String, String> userVarMap;\n\n"); w.write("\tprivate HashMap <String, Result> resultLookup;\n\n"); w.write("\tprivate Log log = LogFactory.getLog(this.getClass());\n"); w.write("\tprivate LogicService logicService = Context.getLogicService();\n\n"); w.flush(); /************************************************************************************** * Implement the other interface methods */ String str = ""; w.write("\t/*** @see org.openmrs.logic.rule.Rule#getDuration()*/\n\t" + "public int getDuration() {\n\t\treturn 60*30; // 30 minutes\n\t}\n\n"); w.write("\t/*** @see org.openmrs.logic.rule.Rule#getDatatype(String)*/\n\t" + "public Datatype getDatatype(String token) {\n\t" + "\treturn Datatype.TEXT;\n\t}\n\n"); w.write("\t/*** @see org.openmrs.logic.rule.Rule#getParameterList()*/\n\t" + "public Set<RuleParameterInfo> getParameterList() {\n\t\treturn null;\n\t}\n\n"); w.write("\t/*** @see org.openmrs.logic.rule.Rule#getDependencies()*/\n\t" + "public String[] getDependencies() {\n\t\treturn new String[] { };\n\t}\n\n"); w.write("\t/*** @see org.openmrs.logic.rule.Rule#getTTL()*/\n\t" + "public int getTTL() {\n\t\treturn 0; //60 * 30; // 30 minutes\n\t}\n\n"); w.write("\t/*** @see org.openmrs.logic.rule.Rule#getDatatype(String)*/\n\t" + "public Datatype getDefaultDatatype() {\n\t\treturn Datatype.CODED;\n\t}\n\n"); str = ardObj.getAuthor(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getAuthor()*/\n" + "\tpublic String getAuthor(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getCitations(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getCitations()*/\n" + "\tpublic String getCitations(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getDate(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getDate()*/\n" + "\tpublic String getDate(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getExplanation(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getExplanation()*/\n" + "\tpublic String getExplanation(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getInstitution(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getInstitution()*/\n" + "\tpublic String getInstitution(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getKeywords(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getKeywords()*/\n" + "\tpublic String getKeywords(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getLinks(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getLinks()*/\n" + "\tpublic String getLinks(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getPurpose(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getPurpose()*/\n" + "\tpublic String getPurpose(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getSpecialist(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getSpecialist()*/\n" + "\tpublic String getSpecialist(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getTitle(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getTitle()*/\n" + "\tpublic String getTitle(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); double d = ardObj.getVersion(); w.write("\t/*** @see org.openmrs.arden.MlmRule#getVersion()*/\n" + "\tpublic Double getVersion(){\n" + "\t\treturn " + d + ";\n" + "\t}\n\n"); str = ardObj.getType(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getType()*/\n" + "\tpublic String getType(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); /**************************************************************************************/ t = (BaseAST) t.getNextSibling(); // Move to Knowledge log.debug(t.toStringTree()); // prints knowledge @SuppressWarnings("unused") String knowledge_text = treeParser.knowledge_text(t, ardObj); /************************************************** Write Knowledge dependent section **********************************************/ Integer p = ardObj.getPriority(); w.write("\t/*** @see org.openmrs.arden.MlmRule#getPriority()*/\n" + "\tpublic Integer getPriority(){\n" + "\t\treturn " + p + ";\n" + "\t}\n\n"); str = ardObj.getData(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getData()*/\n" + "\tpublic String getData(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getLogic(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getLogic()*/\n" + "\tpublic String getLogic(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); str = ardObj.getAction(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getAction()*/\n" + "\tpublic String getAction(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); Integer ageMin = ardObj.getAgeMin(); w.write("\t/*** @see org.openmrs.arden.MlmRule#getAgeMin()*/\n" + "\tpublic Integer getAgeMin(){\n" + "\t\treturn " + ageMin + ";\n" + "\t}\n\n"); str = ardObj.getAgeMinUnits(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getAgeMinUnits()*/\n" + "\tpublic String getAgeMinUnits(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); Integer ageMax = ardObj.getAgeMax(); w.write("\t/*** @see org.openmrs.arden.MlmRule#getAgeMax()*/\n" + "\tpublic Integer getAgeMax(){\n" + "\t\treturn " + ageMax + ";\n" + "\t}\n\n"); str = ardObj.getAgeMaxUnits(); if (str != null && str.length() == 0) { str = null; } if (str != null) { str = "\"" + str + "\""; } w.write("\t/*** @see org.openmrs.arden.MlmRule#getAgeMaxUnits()*/\n" + "\tpublic String getAgeMaxUnits(){\n" + "\t\treturn " + str + ";\n" + "\t}\n\n"); w.write("\tprivate static boolean containsIgnoreCase(Result key,List<Result> lst){\n"); w.write("\t\tfor(Result element:lst){\n"); w.write("\t\t\tif(key != null&&key.toString().equalsIgnoreCase(element.toString())){\n"); w.write("\t\t\t\treturn true;\n"); w.write("\t\t\t}\n"); w.write("\t\t}\n"); w.write("\t\treturn false;\n"); w.write("\t}\n"); w.write("\tprivate static String toProperCase(String str){\n\n"); w.write("\t\tif(str == null || str.length()<1){\n"); w.write("\t\t\treturn str;\n"); w.write("\t\t}\n\n"); w.write("\t\tStringBuffer resultString = new StringBuffer();\n"); w.write("\t\tString delimiter = \" \";\n"); w.write("\t\tStringTokenizer tokenizer = new StringTokenizer(str,delimiter,true);\n"); w.write("\t\tString currToken = null;\n\n"); w.write("\t\twhile(tokenizer.hasMoreTokens()){\n"); w.write("\t\t\tcurrToken = tokenizer.nextToken();\n"); w.write("\t\t\tif(!currToken.equals(delimiter)){\n"); w.write("\t\t\t\tif(currToken.length()>0){\n"); w.write("\t\t\t\t\tcurrToken = currToken.substring(0, 1).toUpperCase()\n"); w.write("\t\t\t\t\t+ currToken.substring(1).toLowerCase();\n"); w.write("\t\t\t\t}\n"); w.write("\t\t\t}\n"); w.write("\t\t\tresultString.append(currToken);\n"); w.write("\t\t}\n"); w.write("\t\treturn resultString.toString();\n"); w.write("\t}\n"); /** * ************************************************************************************* * ********************************************* */ // Move back to knowledge tree to actually start converting data // logic action t = (BaseAST) parser.getAST(); t = (BaseAST) t.getNextSibling().getNextSibling(); // Move to // Knowledge log.debug(t.toStringTree()); // prints knowledge @SuppressWarnings("unused") String knowledge = treeParser.knowledge(t, ardObj); /** *********************************************************************************** */ ardObj.PrintEvaluateList("data"); // To Debug retVal = ardObj.WriteEvaluate(w, classname); if (retVal) { ardObj.WriteAction(w); w.append("}"); // end class w.flush(); w.close(); } else { //delete the compiled file so far w.flush(); w.close(); boolean success = (new File("src/api/org/openmrs/logic/rule/" + cfn + ".java")).delete(); if (!success) { System.out.println("Incomplete compiled file " + cfn + ".java cannot be deleted!"); } } } catch (Exception e) { log.error(e); } finally { s.close(); } return retVal; } /** * @see org.openmrs.arden.ArdenService#compile(java.lang.String, java.lang.String) */ public void compile(String ardenRuleDefinition, String outputDir) throws APIException { try { InputStream inputStream = new ByteArrayInputStream(ardenRuleDefinition.getBytes()); parseFile(inputStream, "ConceptDerived", outputDir); } catch (Exception e) { throw new APIException("Unable to compile the arden arden rule definition"); } } }