/**
   * Loads the rule dictionary from the specified dictionaryPath
   *
   * @param dictionaryLocation The full path to the .rules file.
   * @return A rule dictionary object
   * @see readDictionary http://docs.oracle.com/cd/E23943_01/apirefs.1111/e10663/toc.htm
   */
  public static RuleDictionary loadRuleDictionary(String dictionaryLocation) throws Exception {
    RuleDictionary dict = null;
    Reader reader = null;
    Writer writer = null;

    try {
      reader = new FileReader(new File(dictionaryLocation));
      dict = RuleDictionary.readDictionary(reader, new DecisionPointDictionaryFinder(null));
      List<SDKWarning> warnings = new ArrayList<SDKWarning>();

      dict.update(warnings);
      if (warnings.size() > 0) {
        System.err.println("Validation warnings: " + warnings);
      }

    } finally {
      if (reader != null) {
        try {
          reader.close();
        } catch (IOException ioe) {
          ioe.printStackTrace();
        }
      }
      if (writer != null) {
        try {
          writer.close();
        } catch (IOException ioe) {
          ioe.printStackTrace();
        }
      }
    }

    return dict;
  }
  /**
   * Creates a new Rules Dictionary in memory
   *
   * @param dictionaryName A name for the dictionary, used as a className
   * @param dictionaryPackage A name for the dictionary package, used as a java package name.
   */
  public static RuleDictionary createDictionaryInMemory(
      String dictionaryName, String dictionaryPackage) throws SDKException {

    RuleDictionary dictionary =
        RuleDictionary.createDictionary(dictionaryName, new DecisionPointDictionaryFinder());
    dictionary.setName(dictionaryName);
    dictionary.setPackage(dictionaryPackage);

    return dictionary;
  }
  /**
   * Demonstrates how to add a java fact to a dictionary data model
   *
   * @param dictionary An existing dictionary
   * @param javaclass A java bean class
   */
  public static RuleDictionary addFactsToDictionary(RuleDictionary dictionary, Class bean)
      throws SDKException {

    DataModel dataModel = dictionary.getDataModel();
    dataModel.addJavaClass(bean, false, null, null, null, null);
    return dictionary;
  }
  /**
   * Update the rule dictionary from the specified dictionaryPath
   *
   * @param A rule dictionary object
   * @return boolean true if the update was successful otherwise false.
   * @see See writeDictionary http://docs.oracle.com/cd/E23943_01/apirefs.1111/e10663/toc.htm
   */
  public static boolean updateRuleDictionary(RuleDictionary dictionary) throws Exception {

    UndoableEdit undo = null;
    List<SDKWarning> warnings = new ArrayList<SDKWarning>();
    boolean rc = false;

    try {
      undo = dictionary.update(warnings);
      rc = true;
    } catch (ConcurrentUpdateException e) {
      dictionary.rollback();
    } catch (SDKException e) {
      dictionary.rollback();
    }
    return rc;
  }
  /**
   * Stores the rule dictionary from the specified dictionaryPath
   *
   * @param A rule dictionary object
   * @param dictionaryLocation The full path to the .rules file.
   * @see See writeDictionary http://docs.oracle.com/cd/E23943_01/apirefs.1111/e10663/toc.htm
   */
  public static void storeRuleDictionary(RuleDictionary dictionary, String dictionaryLocation)
      throws Exception {

    List<SDKWarning> warnings = new ArrayList<SDKWarning>();
    List<SDKException> errors = new ArrayList<SDKException>();

    dictionary.validate(errors, warnings);

    if (warnings.size() > 0) {
      System.err.println("Validation warnings: " + warnings);
    }

    if (errors.size() > 0) {

      System.err.println("Validation errors: " + errors);
      System.out.println("Skipping write of rule dictionary");

    } else {

      StringWriter swriter = new StringWriter();
      dictionary.writeDictionary(swriter);
      Writer writer = null;
      try {
        writer =
            new OutputStreamWriter(new FileOutputStream(new File(dictionaryLocation)), "UTF-8");
        writer.write(swriter.toString());
      } finally {
        if (writer != null)
          try {
            writer.close();
          } catch (IOException e) {
            System.out.println("Warning: Unable to close dictionary writer.");
          }
      }
    }
  }
  public static void main(String args[]) throws Exception {

    // location for an existing dictionary
    final String dictionaryLocation = "./oracle/rules/rulesexampleproject/MyRulesDictionary.rules";

    // Load an existing dictionary, create a session handle in case JDeveloper or some other
    // user is also editing the dictionary.

    RuleDictionary dictionary = loadRuleDictionary(dictionaryLocation).createHandle();

    // Delete the existing model, in case we ran previously
    dictionary.getDataModel().clear();

    // Add a new Java Fact to the dictionary
    dictionary = addFactsToDictionary(dictionary, rulesproject.ItemT.class);

    // Add a new bucketset to the dictionary
    BucketSet licenseBucketSet = addBucketSet(dictionary);

    // Associate the new BucketSet with new Fact field
    associateBucketSetToFact(licenseBucketSet, "ItemT", "productWeight", dictionary.getDataModel());

    // update dictionary
    if (!updateRuleDictionary(dictionary)) System.out.println("UNABLE to update dictionary.");

    // check for existing ruleset named MyRuleSet
    RuleSet myRuleSet = dictionary.getRuleSet("MyRuleSet");

    // if it does exist, because we ran before, remove it
    if (myRuleSet != null) {
      dictionary.removeRuleSet("MyRuleSet");
      if (!updateRuleDictionary(dictionary)) System.out.println("UNABLE to update dictionary.");
      System.out.println("Removed old ruleset");
    }

    // Add a new Ruleset
    myRuleSet = dictionary.createEmptyRuleSet("MyRuleSet");
    if (!updateRuleDictionary(dictionary)) System.out.println("UNABLE to update dictionary.");

    // Add a new 'if-then' rule to the RuleSet
    addNewRuleToRuleset(myRuleSet);
    if (!updateRuleDictionary(dictionary)) System.out.println("UNABLE to update dictionary.");

    // Add a decisionTable with rules that use the Bucketset
    addDecisiontTableRuleToRuleset(dictionary, licenseBucketSet, myRuleSet);

    // Update and rewrite the dictionary file

    boolean success = updateRuleDictionary(dictionary);
    if (success) {
      storeRuleDictionary(dictionary, dictionaryLocation);
      System.out.println("Wrote dictionary to filesystem");
    } else System.out.println("Unable to update dictionary");
  }
  public static BucketSet addAgeBucketSet(RuleDictionary dictionary) throws Exception {
    DataModel model = dictionary.getDataModel();

    // Create a new bucketset holding product weight descriptions
    BucketSetTable bucketSetTable = model.getBucketSetTable();
    BucketSet ageBucketSet = bucketSetTable.getByName("Age");

    if (ageBucketSet != null) {
      System.out.println("Age BucketSet already exists, skipping add");
    } else {
      ageBucketSet = bucketSetTable.add();
      ageBucketSet.setName("Age");
      ageBucketSet.setForm(BucketSet.FORM_RANGE);
      ageBucketSet.setType("int");

      ageBucketSet.add("<0").setAlias("Minor");
      ageBucketSet.add("<18").setAlias("Junior");
      ageBucketSet.add("<50").setAlias("Middle");
      ageBucketSet.add("<75").setAlias("Senior");
    }
    return ageBucketSet;
  }
  /* This method demonstrates how to add a new BucketSet to a dictionary data model
   *
   * @param   dict             An existing rules dictionary object
   */
  public static BucketSet addBucketSet(RuleDictionary dictionary) throws Exception {

    DataModel model = dictionary.getDataModel();

    // Create a new bucketset holding product weight descriptions
    BucketSetTable bucketSetTable = model.getBucketSetTable();

    BucketSet productWeightBucketSet = bucketSetTable.getByName("ShipWeightType");

    if (productWeightBucketSet != null) {

      System.out.println("ShipWeightType BucketSet already exists, skipping add");
    } else {

      productWeightBucketSet = bucketSetTable.add();
      productWeightBucketSet.setName("ShipWeightType");
      productWeightBucketSet.setForm(BucketSet.FORM_LOV);
      productWeightBucketSet.add("Light");
      productWeightBucketSet.add("Heavy");
      productWeightBucketSet.add("VeryHeavy");
    }
    return productWeightBucketSet;
  }
  public static void main(String[] args) throws SDKException, Exception {
    final String dictionaryLocation = "./oracle/rules/com/sella/products/InsuranceProducts.rules";
    String dictionaryName = "InsuranceProducts";
    String dictionaryPackage = "com.sella.products";
    RuleDictionary dictionary =
        RuleUtil.createDictionaryInMemory(dictionaryName, dictionaryPackage);

    // Delete the existing model
    dictionary.getDataModel().clear();

    // Add a new Java Fact to the dictionary
    dictionary = RuleUtil.addFactsToDictionary(dictionary, Person.class);
    dictionary = RuleUtil.addFactsToDictionary(dictionary, Person.PolicyType.class);
    dictionary = RuleUtil.addFactsToDictionary(dictionary, Product.class);

    // Add a new bucketset to the dictionary
    BucketSet ageBucketSet = addAgeBucketSet(dictionary);

    // Associate the new BucketSet with new Fact field
    RuleUtil.associateBucketSetToFact(ageBucketSet, "Person", "age", dictionary.getDataModel());

    // update dictionary
    if (!RuleUtil.updateRuleDictionary(dictionary)) {
      System.out.println("Dictionary update failed.");
    } else {
      System.out.println("Dictionary Updated.");
    }

    // Create 'Decision Function'
    DecisionFunction decisionFunction =
        createDecisionFunction(
            dictionary, "ProductRuleDecisionService", "com.sella.facts.Person", false, false);
    decisionFunction.getDecisionFunctionInputTable().get(0).setList(false);
    decisionFunction.getDecisionFunctionInputTable().get(0).setTree(false);

    // Add 'Decision Function' output parameter
    addDecisionFunctionOutput(decisionFunction);

    if (!RuleUtil.updateRuleDictionary(dictionary)) {
      System.out.println("Dictionary update failed.");
    } else {
      System.out.println("Dictionary Updated.");
    }

    // set 'Decision Function' output parameter type
    decisionFunction.getDecisionFunctionOutputTable().get(0).setList(true);

    if (!RuleUtil.updateRuleDictionary(dictionary)) {
      System.out.println("Dictionary update failed.");
    } else {
      System.out.println("Dictionary Updated.");
    }

    // check for existing ruleset named MyRuleSet
    RuleSet myRuleSet = dictionary.getRuleSet("ProductRuleDecisionService");

    // if it does exist, remove it
    if (myRuleSet != null) {
      dictionary.removeRuleSet("ProposalProductRules");
      if (!RuleUtil.updateRuleDictionary(dictionary)) {
        System.out.println("Dictionary update failed.");
      } else {
        System.out.println("Removed old ruleset");
      }
    } else {
      // Add a new Ruleset
      myRuleSet = dictionary.createEmptyRuleSet("ProductRuleDecisionService");
      if (!RuleUtil.updateRuleDictionary(dictionary)) {
        System.out.println("Dictionary update failed.");
      } else {
        System.out.println("Dictionary Updated.");
      }
    }

    // Add a decisionTable with rules that use the Bucketset
    addDecisiontTableRuleToRuleset(dictionary, ageBucketSet, myRuleSet);

    // Update and rewrite the dictionary file
    boolean success = RuleUtil.updateRuleDictionary(dictionary);
    if (success) {
      RuleUtil.storeRuleDictionary(dictionary, dictionaryLocation);
      System.out.println("Wrote dictionary to filesystem");
    } else {
      System.out.println("Unable to update dictionary");
    }
  }