public void build(
      final RuleBuildContext context,
      final BoundIdentifiers usedIdentifiers,
      final Declaration[] previousDeclarations,
      final Declaration[] localDeclarations,
      final PredicateConstraint predicate,
      final PredicateDescr predicateDescr,
      final AnalysisResult analysis) {
    MVELDialect dialect = (MVELDialect) context.getDialect(context.getDialect().getId());

    try {
      Map<String, Class<?>> declIds =
          context.getDeclarationResolver().getDeclarationClasses(context.getRule());

      Pattern p = (Pattern) context.getBuildStack().peek();
      if (p.getObjectType() instanceof ClassObjectType) {
        declIds.put("this", ((ClassObjectType) p.getObjectType()).getClassType());
      }

      MVELCompilationUnit unit =
          dialect.getMVELCompilationUnit(
              (String) predicateDescr.getContent(),
              analysis,
              previousDeclarations,
              localDeclarations,
              null,
              context);

      MVELPredicateExpression expr =
          new MVELPredicateExpression(unit, context.getDialect().getId());
      predicate.setPredicateExpression(expr);

      MVELDialectRuntimeData data =
          (MVELDialectRuntimeData)
              context
                  .getPkg()
                  .getDialectRuntimeRegistry()
                  .getDialectData(context.getDialect().getId());
      data.addCompileable(predicate, expr);

      expr.compile(context.getPackageBuilder().getRootClassLoader());
    } catch (final Exception e) {
      context
          .getErrors()
          .add(
              new DescrBuildError(
                  context.getParentDescr(),
                  predicateDescr,
                  e,
                  "Unable to build expression for 'inline-eval' : "
                      + e.getMessage()
                      + "'"
                      + predicateDescr.getContent()
                      + "'\n"
                      + e.getMessage()));
    }
  }
示例#2
0
  private void attachPattern(
      final BuildContext context, final BuildUtils utils, final Pattern pattern)
      throws InvalidPatternException {

    // Set pattern offset to the appropriate value
    pattern.setOffset(context.getCurrentPatternOffset());

    final List<Constraint> alphaConstraints = new LinkedList<Constraint>();
    final List<Constraint> betaConstraints = new LinkedList<Constraint>();
    final List<Behavior> behaviors = new LinkedList<Behavior>();

    this.createConstraints(context, utils, pattern, alphaConstraints, betaConstraints);

    // Create BetaConstraints object
    context.setBetaconstraints(betaConstraints);

    // set behaviors list
    behaviors.addAll(pattern.getBehaviors());
    context.setBehaviors(behaviors);

    if (pattern.getSource() != null) {
      context.setAlphaConstraints(alphaConstraints);
      final int currentOffset = context.getCurrentPatternOffset();

      PatternSource source = pattern.getSource();

      ReteooComponentBuilder builder = utils.getBuilderFor(source);

      builder.build(context, utils, source);
      // restoring offset
      context.setCurrentPatternOffset(currentOffset);
    }

    if (pattern.getSource() == null || context.getCurrentEntryPoint() != EntryPoint.DEFAULT) {
      attachAlphaNodes(context, utils, pattern, alphaConstraints);

      if (context.getCurrentEntryPoint() != EntryPoint.DEFAULT) {
        context.setObjectSource(
            (ObjectSource)
                utils.attachNode(
                    context,
                    new PropagationQueuingNode(
                        context.getNextId(), context.getObjectSource(), context)));
        // the entry-point specific network nodes are attached, so, set context to default
        // entry-point
        context.setCurrentEntryPoint(EntryPoint.DEFAULT);
      }
    }

    // last thing to do is increment the offset, since if the pattern has a source,
    // offset must be overriden
    context.incrementCurrentPatternOffset();
  }
示例#3
0
  private void createConstraints(
      BuildContext context,
      BuildUtils utils,
      Pattern pattern,
      List<Constraint> alphaConstraints,
      List<Constraint> betaConstraints) {

    final List<?> constraints = pattern.getConstraints();

    // check if cross products for identity patterns should be disabled
    checkRemoveIdentities(context, pattern, betaConstraints);

    // checks if this pattern is nested inside a NOT CE
    final boolean isNegative = isNegative(context);

    for (final Iterator<?> it = constraints.iterator(); it.hasNext(); ) {
      final Object object = it.next();
      // Check if its a declaration
      if (object instanceof Declaration) {
        // nothing to be done
        continue;
      }

      final Constraint constraint = (Constraint) object;
      if (constraint.getType().equals(Constraint.ConstraintType.ALPHA)) {
        alphaConstraints.add(constraint);
      } else if (constraint.getType().equals(Constraint.ConstraintType.BETA)) {
        betaConstraints.add(constraint);
        if (isNegative
            && context.getRuleBase().getConfiguration().getEventProcessingMode()
                == EventProcessingOption.STREAM
            && pattern.getObjectType().isEvent()
            && constraint.isTemporal()) {
          checkDelaying(context, constraint);
        }
      } else {
        throw new RuntimeDroolsException(
            "Unknown constraint type: "
                + constraint.getType()
                + ". This is a bug. Please contact development team.");
      }
    }
  }
示例#4
0
  /**
   * @param context
   * @param pattern
   * @param betaConstraints
   */
  private void checkRemoveIdentities(
      final BuildContext context, final Pattern pattern, final List<Constraint> betaConstraints) {
    if (context.getRuleBase().getConfiguration().isRemoveIdentities()
        && pattern.getObjectType().getClass() == ClassObjectType.class) {
      // Check if this object type exists before
      // If it does we need stop instance equals cross product
      final Class<?> thisClass = ((ClassObjectType) pattern.getObjectType()).getClassType();
      for (final Iterator<Pattern> it = context.getObjectType().iterator(); it.hasNext(); ) {
        final Pattern previousPattern = it.next();
        final Class<?> previousClass =
            ((ClassObjectType) previousPattern.getObjectType()).getClassType();
        if (thisClass.isAssignableFrom(previousClass)) {
          betaConstraints.add(new InstanceNotEqualsConstraint(previousPattern));
        }
      }

      // Must be added after the checking, otherwise it matches against itself
      context.getObjectType().add(pattern);
    }
  }
示例#5
0
  @Override
  protected void initDeclaredMask(BuildContext context, LeftTupleSource leftInput) {
    if (context == null || context.getLastBuiltPatterns() == null) {
      // only happens during unit tests
      rightDeclaredMask = Long.MAX_VALUE;
      super.initDeclaredMask(context, leftInput);
      return;
    }

    if (!(rightInput instanceof RightInputAdapterNode)) {
      Pattern pattern = context.getLastBuiltPatterns()[0]; // right input pattern
      ObjectType objectType = pattern.getObjectType();

      if (!(objectType instanceof ClassObjectType)) {
        // InitialFact has no type declaration and cannot be property specific
        // Only ClassObjectType can use property specific
        rightDeclaredMask = Long.MAX_VALUE;
      }

      Class objectClass = ((ClassObjectType) objectType).getClassType();
      if (isPropertyReactive(context, objectClass)) {
        rightListenedProperties = pattern.getListenedProperties();
        List<String> settableProperties = getSettableProperties(context.getRuleBase(), objectClass);
        rightDeclaredMask = calculatePositiveMask(rightListenedProperties, settableProperties);
        rightDeclaredMask |= constraints.getListenedPropertyMask(settableProperties);
        rightNegativeMask = calculateNegativeMask(rightListenedProperties, settableProperties);
      } else {
        // if property reactive is not on, then accept all modification propagations
        rightDeclaredMask = Long.MAX_VALUE;
      }
    } else {
      rightDeclaredMask = Long.MAX_VALUE;
      // There would have been no right input pattern, so swap current to first, so leftInput can
      // still work
      context.setLastBuiltPattern(context.getLastBuiltPatterns()[0]);
    }

    super.initDeclaredMask(context, leftInput);
  }
  private void createResultBind(
      final Pattern pattern,
      int index,
      InternalReadAccessor arrayReader,
      AccumulateFunctionCallDescr fc,
      AccumulateFunction function) {
    // bind function result on the result pattern
    Declaration declr = pattern.addDeclaration(fc.getBind());

    Class<?> type = function.getResultType();

    // this bit is different, notice its the ArrayElementReader that we wire up to, not the
    // declaration.
    ArrayElementReader reader = new ArrayElementReader(arrayReader, index, type);
    declr.setReadAccessor(reader);
  }
  @Test
  public void test1() {
    KnowledgePackage pkg1 = getKnowledgePackage1();
    KnowledgePackage pkg2 = getKnowledgePackage1();
    KnowledgePackage pkg3 = getKnowledgePackage2();

    Rule rule1 = ((KnowledgePackageImp) pkg1).pkg.getRule("rule1");
    Rule rule2 = ((KnowledgePackageImp) pkg2).pkg.getRule("rule1");
    Rule rule3 = ((KnowledgePackageImp) pkg3).pkg.getRule("rule1");

    // test return value
    Pattern p1 = (Pattern) rule1.getLhs().getChildren().get(0);
    VariableConstraint rvc1 = (VariableConstraint) p1.getConstraints().get(0);
    ReturnValueExpression rve1 = ((ReturnValueRestriction) rvc1.getRestriction()).getExpression();

    Pattern p2 = (Pattern) rule2.getLhs().getChildren().get(0);
    VariableConstraint rvc2 = (VariableConstraint) p2.getConstraints().get(0);
    ReturnValueExpression rve2 = ((ReturnValueRestriction) rvc2.getRestriction()).getExpression();

    assertNotSame(rve1, rve2);
    assertEquals(rve1, rve2);

    Pattern p3 = (Pattern) rule3.getLhs().getChildren().get(0);
    VariableConstraint rvc3 = (VariableConstraint) p3.getConstraints().get(0);
    ReturnValueExpression rve3 = ((ReturnValueRestriction) rvc3.getRestriction()).getExpression();

    assertNotSame(rve1, rve3);
    assertThat(rve1, not(equalTo(rve3)));

    // test inline eval
    PredicateConstraint pc1 = (PredicateConstraint) p1.getConstraints().get(1);
    PredicateExpression pe1 = (PredicateExpression) pc1.getPredicateExpression();

    PredicateConstraint pc2 = (PredicateConstraint) p2.getConstraints().get(1);
    PredicateExpression pe2 = (PredicateExpression) pc2.getPredicateExpression();
    assertNotSame(pe1, pe2);
    assertEquals(pe1, pe2);

    PredicateConstraint pc3 = (PredicateConstraint) p3.getConstraints().get(1);
    PredicateExpression pe3 = (PredicateExpression) pc3.getPredicateExpression();
    assertNotSame(pe1, pe3);
    assertThat(pe1, not(equalTo(pe3)));

    // test eval
    EvalCondition ec1 = (EvalCondition) rule1.getLhs().getChildren().get(1);
    EvalExpression ee1 = (EvalExpression) ec1.getEvalExpression();

    EvalCondition ec2 = (EvalCondition) rule2.getLhs().getChildren().get(1);
    EvalExpression ee2 = (EvalExpression) ec2.getEvalExpression();
    assertNotSame(ee1, ee2);
    assertEquals(ee1, ee2);

    EvalCondition ec3 = (EvalCondition) rule3.getLhs().getChildren().get(1);
    EvalExpression ee3 = (EvalExpression) ec3.getEvalExpression();
    assertNotSame(ee1, ee3);
    assertThat(ee1, not(equalTo(ee3)));

    // test consequence
    assertNotSame(rule1.getConsequence(), rule2.getConsequence());
    assertEquals(rule1.getConsequence(), rule2.getConsequence());
    assertNotSame(rule1.getConsequence(), rule3.getConsequence());
    assertThat(rule1.getConsequence(), not(equalTo(rule3.getConsequence())));

    // check LHS equals
    assertNotSame(rule1.getLhs(), rule2.getLhs());
    assertEquals(rule1.getLhs(), rule2.getLhs());

    assertNotSame(rule1.getLhs(), rule3.getLhs());
    assertThat(rule1.getLhs(), not(equalTo(rule3.getLhs())));
  }
  @SuppressWarnings("unchecked")
  @Test
  public void testSimpleTemplate() throws Exception {
    TemplateContainer tc =
        new TemplateContainer() {
          private Column[] columns =
              new Column[] {
                new LongColumn("column1"), new LongColumn("column2"), new StringColumn("column3")
              };

          public Column[] getColumns() {
            return columns;
          }

          public String getHeader() {
            return null;
          }

          public Map<String, RuleTemplate> getTemplates() {
            Map<String, RuleTemplate> templates = new HashMap<String, RuleTemplate>();
            RuleTemplate ruleTemplate = new RuleTemplate("template1", this);
            ruleTemplate.addColumn("column1 == 10");
            ruleTemplate.addColumn("column2 < 5 || > 20");
            ruleTemplate.addColumn("column3 == \"xyz\"");
            templates.put("template1", ruleTemplate);
            return templates;
          }

          public Column getColumn(String name) {
            return columns[Integer.parseInt(name.substring(6)) - 1];
          }
        };
    DefaultTemplateRuleBase ruleBase = new DefaultTemplateRuleBase(tc);
    Package[] packages = ruleBase.newStatefulSession().getRuleBase().getPackages();
    assertEquals(1, packages.length);
    Map<String, String> globals = packages[0].getGlobals();
    assertEquals(DefaultGenerator.class.getName(), globals.get("generator"));
    Rule[] rules = packages[0].getRules();
    assertEquals(1, rules.length);
    assertEquals("template1", rules[0].getName());
    GroupElement lhs = rules[0].getLhs();
    // when
    //  r : Row()
    //  column1 : Column(name == "column1")
    //  exists LongCell(row == r, column == column1, value == 10)
    //  column2 : Column(name == "column2")
    //  exists LongCell(row == r, column == column2, value < 5 | > 20)
    //  column3 : Column(name == "column3")
    //  exists StringCell(row == r, column == column3, value == "xyz")
    assertEquals(7, lhs.getChildren().size());
    org.drools.rule.Pattern pattern = (org.drools.rule.Pattern) lhs.getChildren().get(1);
    assertEquals(1, pattern.getConstraints().size());
    Constraint constraint = pattern.getConstraints().get(0);
    GroupElement exists = (GroupElement) lhs.getChildren().get(2);
    pattern = (org.drools.rule.Pattern) exists.getChildren().get(0);
    assertEquals(3, pattern.getConstraints().size());
    IndexableConstraint vconstraint = (IndexableConstraint) pattern.getConstraints().get(1);
    assertEquals(Column.class, vconstraint.getFieldIndex().getExtractor().getExtractToClass());
    assertEquals("column1", vconstraint.getRequiredDeclarations()[0].getIdentifier());
    pattern = (org.drools.rule.Pattern) lhs.getChildren().get(3);
    assertEquals(1, pattern.getConstraints().size());
    constraint = pattern.getConstraints().get(0);
    exists = (GroupElement) lhs.getChildren().get(4);
    pattern = (org.drools.rule.Pattern) exists.getChildren().get(0);
    assertEquals(3, pattern.getConstraints().size());
    vconstraint = (IndexableConstraint) pattern.getConstraints().get(1);
    assertEquals(Column.class, vconstraint.getFieldIndex().getExtractor().getExtractToClass());
    assertEquals("column2", vconstraint.getRequiredDeclarations()[0].getIdentifier());
    pattern = (org.drools.rule.Pattern) lhs.getChildren().get(5);
    assertEquals(1, pattern.getConstraints().size());
    constraint = pattern.getConstraints().get(0);
    exists = (GroupElement) lhs.getChildren().get(6);
    pattern = (org.drools.rule.Pattern) exists.getChildren().get(0);
    assertEquals(3, pattern.getConstraints().size());
    vconstraint = (IndexableConstraint) pattern.getConstraints().get(1);
    assertEquals(Column.class, vconstraint.getFieldIndex().getExtractor().getExtractToClass());
    assertEquals("column3", vconstraint.getRequiredDeclarations()[0].getIdentifier());
  }
示例#9
0
  public void attachAlphaNodes(
      final BuildContext context,
      final BuildUtils utils,
      final Pattern pattern,
      List<Constraint> alphaConstraints)
      throws InvalidPatternException {

    // Drools Query ObjectTypeNode never has memory, but other ObjectTypeNode/AlphaNoesNodes may (if
    // not in sequential),
    // so need to preserve, so we can restore after this node is added. LeftMemory  and Terminal
    // remain the same once set.

    boolean objectMemory = context.isObjectTypeNodeMemoryEnabled();
    boolean alphaMemory = context.isAlphaMemoryAllowed();

    ObjectType objectType = pattern.getObjectType();

    if (pattern.getObjectType() instanceof ClassObjectType) {
      // Is this the query node, if so we don't want any memory
      if (DroolsQuery.class == ((ClassObjectType) pattern.getObjectType()).getClassType()) {
        context.setTupleMemoryEnabled(false);
        context.setObjectTypeNodeMemoryEnabled(false);
        context.setTerminalNodeMemoryEnabled(false);
        context.setAlphaNodeMemoryAllowed(false);
      }
    }

    context.setObjectSource(
        (ObjectSource)
            utils.attachNode(
                context,
                new EntryPointNode(context.getNextId(), context.getRuleBase().getRete(), context)));

    ObjectTypeNode otn =
        new ObjectTypeNode(
            context.getNextId(), (EntryPointNode) context.getObjectSource(), objectType, context);
    if (objectType.isEvent()
        && EventProcessingOption.STREAM.equals(
            context.getRuleBase().getConfiguration().getEventProcessingMode())) {
      long expirationOffset = getExpiratioOffsetForType(context, objectType);
      if (expirationOffset != -1) {
        // expiration policy is set, so use it
        otn.setExpirationOffset(expirationOffset);
      } else {
        // otherwise calculate it based on behaviours and temporal constraints
        for (Behavior behavior : pattern.getBehaviors()) {
          if (behavior.getExpirationOffset() != -1) {
            expirationOffset = Math.max(behavior.getExpirationOffset(), expirationOffset);
          }
        }
        long distance = context.getTemporalDistance().getExpirationOffset(pattern);
        if (distance == -1) {
          // it means the rules have no temporal constraints, or
          // the constraints require events to be hold forever. In this
          // case, we allow type declarations to override the implicit
          // expiration offset by defining an expiration policy with the
          // @expires tag
          otn.setExpirationOffset(expirationOffset);
        } else {
          otn.setExpirationOffset(Math.max(distance, expirationOffset));
        }
      }
    }

    context.setObjectSource((ObjectSource) utils.attachNode(context, otn));

    for (final Iterator<Constraint> it = alphaConstraints.iterator(); it.hasNext(); ) {
      final AlphaNodeFieldConstraint constraint = (AlphaNodeFieldConstraint) it.next();

      context.pushRuleComponent(constraint);
      context.setObjectSource(
          (ObjectSource)
              utils.attachNode(
                  context,
                  new AlphaNode(
                      context.getNextId(),
                      (AlphaNodeFieldConstraint) constraint,
                      context.getObjectSource(),
                      context)));
      context.popRuleComponent();
    }

    // now restore back to original values
    context.setObjectTypeNodeMemoryEnabled(objectMemory);
    context.setAlphaNodeMemoryAllowed(alphaMemory);
  }
示例#10
0
  private Accumulator[] buildExternalFunctions(
      final RuleBuildContext context,
      final AccumulateDescr accumDescr,
      MVELDialect dialect,
      Map<String, Declaration> decls,
      Map<String, Declaration> sourceOuterDeclr,
      BoundIdentifiers boundIds,
      boolean readLocalsFromTuple) {
    Accumulator[] accumulators;
    List<AccumulateFunctionCallDescr> functions = accumDescr.getFunctions();

    accumulators = new Accumulator[functions.size()];
    // creating the custom array reader
    InternalReadAccessor arrayReader = new SelfReferenceClassFieldReader(Object[].class, "this");

    int index = 0;
    Pattern pattern = (Pattern) context.getBuildStack().peek();
    for (AccumulateFunctionCallDescr func : functions) {
      // build an external function executor
      AccumulateFunction function =
          context.getConfiguration().getAccumulateFunction(func.getFunction());
      if (function == null) {
        context.addError(
            new DescrBuildError(
                accumDescr,
                context.getRuleDescr(),
                null,
                "Unknown accumulate function: '"
                    + func.getFunction()
                    + "' on rule '"
                    + context.getRuleDescr().getName()
                    + "'. All accumulate functions must be registered before building a resource."));
        return null;
      }

      // if there is a binding, create the binding
      if (func.getBind() != null) {
        if (pattern.getDeclaration(func.getBind()) != null) {
          context.addError(
              new DescrBuildError(
                  context.getParentDescr(),
                  accumDescr,
                  null,
                  "Duplicate declaration for variable '"
                      + func.getBind()
                      + "' in the rule '"
                      + context.getRule().getName()
                      + "'"));
        } else {
          createResultBind(pattern, index, arrayReader, func, function);
        }
      }

      final AnalysisResult analysis =
          dialect.analyzeExpression(
              context,
              accumDescr,
              func.getParams().length > 0 ? func.getParams()[0] : "\"\"",
              boundIds);

      MVELCompilationUnit unit =
          dialect.getMVELCompilationUnit(
              func.getParams().length > 0 ? func.getParams()[0] : "\"\"",
              analysis,
              getUsedDeclarations(decls, analysis),
              getUsedDeclarations(sourceOuterDeclr, analysis),
              null,
              context,
              "drools",
              KnowledgeHelper.class,
              readLocalsFromTuple);

      accumulators[index++] = new MVELAccumulatorFunctionExecutor(unit, function);
    }
    return accumulators;
  }