diff --git a/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/ActionCallMethodBuilder.java b/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/ActionCallMethodBuilder.java index 83806a5b7ea..8e7148c5474 100644 --- a/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/ActionCallMethodBuilder.java +++ b/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/ActionCallMethodBuilder.java @@ -43,6 +43,41 @@ public ActionCallMethodBuilder( RuleModel model, this.boundParams = boundParams; } + //ActionCallMethods do not support chained method invocations + public boolean supports( final String line ) { + final List splits = new ArrayList(); + int depth = 0; + int textDepth = 0; + boolean escape = false; + StringBuffer split = new StringBuffer(); + for ( char c : line.toCharArray() ) { + if ( depth == 0 && c == '.' ) { + splits.add( split.toString() ); + split = new StringBuffer(); + depth = 0; + textDepth = 0; + escape = false; + continue; + } else if ( c == '\\' ) { + escape = true; + split.append( c ); + continue; + } else if ( textDepth == 0 && c == '"' ) { + textDepth++; + } else if ( !escape && textDepth > 0 && c == '"' ) { + textDepth--; + } else if ( textDepth == 0 && c == '(' ) { + depth++; + } else if ( textDepth == 0 && c == ')' ) { + depth--; + } + split.append( c ); + escape = false; + } + splits.add( split.toString() ); + return splits.size() == 2; + } + public ActionCallMethod get( String variable, String methodName, String[] parameters ) { diff --git a/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceImpl.java b/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceImpl.java index 996475aa8b0..daef873c7fd 100644 --- a/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceImpl.java +++ b/drools-workbench-models/drools-workbench-models-commons/src/main/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceImpl.java @@ -2921,20 +2921,25 @@ private void parseRhs( final RuleModel m, } } - private ActionCallMethod getActionCallMethod( final RuleModel model, - final boolean isJavaDialect, - final Map boundParams, - final PackageDataModelOracle dmo, - final String line, - final String variable, - final String methodName ) { - - return new ActionCallMethodBuilder( model, - dmo, - isJavaDialect, - boundParams ).get( variable, - methodName, - unwrapParenthesis( line ).split( "," ) ); + private IAction getActionCallMethod( final RuleModel model, + final boolean isJavaDialect, + final Map boundParams, + final PackageDataModelOracle dmo, + final String line, + final String variable, + final String methodName ) { + final ActionCallMethodBuilder builder = new ActionCallMethodBuilder( model, + dmo, + isJavaDialect, + boundParams ); + if ( !builder.supports( line ) ) { + final FreeFormLine ffl = new FreeFormLine(); + ffl.setText( line ); + return ffl; + } + return builder.get( variable, + methodName, + unwrapParenthesis( line ).split( "," ) ); } private boolean isInsertedFact( final String[] lines, diff --git a/drools-workbench-models/drools-workbench-models-commons/src/test/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceUnmarshallingTest.java b/drools-workbench-models/drools-workbench-models-commons/src/test/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceUnmarshallingTest.java index b3a72b36bc4..2ef6e0bf5e2 100644 --- a/drools-workbench-models/drools-workbench-models-commons/src/test/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceUnmarshallingTest.java +++ b/drools-workbench-models/drools-workbench-models-commons/src/test/java/org/drools/workbench/models/commons/backend/rule/RuleModelDRLPersistenceUnmarshallingTest.java @@ -7314,6 +7314,254 @@ public void testLHSFormula() throws Exception { RuleModelDRLPersistenceImpl.getInstance().marshal( m ) ); } + @Test + //https://bugzilla.redhat.com/show_bug.cgi?id=1127303 + public void testRHSChainedMethodCalls1() throws Exception { + String drl = "package org.test;\n" + + "rule \"MyRule\"\n" + + "dialect \"mvel\"\n" + + "when\n" + + " Person( $n : name )\n" + + "then\n" + + " $n.toUpperCase().indexOf(\"S\", 1);\n" + + "end"; + + addModelField( "org.test.Person", + "this", + "org.test.Person", + DataType.TYPE_THIS ); + addModelField( "org.test.Person", + "name", + String.class.getName(), + DataType.TYPE_STRING ); + + when( dmo.getPackageName() ).thenReturn( "org.test" ); + + final RuleModel m = RuleModelDRLPersistenceImpl.getInstance().unmarshal( drl, + new ArrayList(), + dmo ); + + assertNotNull( m ); + + assertEquals( 1, + m.lhs.length ); + final IPattern p0 = m.lhs[ 0 ]; + assertTrue( p0 instanceof FactPattern ); + final FactPattern fp0 = (FactPattern) p0; + assertEquals( "Person", + fp0.getFactType() ); + + assertEquals( 1, + fp0.getNumberOfConstraints() ); + assertTrue( fp0.getConstraint( 0 ) instanceof SingleFieldConstraint ); + + final SingleFieldConstraint sfc1 = (SingleFieldConstraint) fp0.getConstraint( 0 ); + assertEquals( "Person", + sfc1.getFactType() ); + assertEquals( "name", + sfc1.getFieldName() ); + assertEquals( DataType.TYPE_STRING, + sfc1.getFieldType() ); + + assertEquals( 1, + m.rhs.length ); + final IAction a0 = m.rhs[ 0 ]; + assertTrue( a0 instanceof FreeFormLine ); + final FreeFormLine ffl1 = (FreeFormLine) a0; + assertEquals( "$n.toUpperCase().indexOf(\"S\", 1);", + ffl1.getText() ); + + //Check round-trip + assertEqualsIgnoreWhitespace( drl, + RuleModelDRLPersistenceImpl.getInstance().marshal( m ) ); + } + + @Test + //https://bugzilla.redhat.com/show_bug.cgi?id=1127303 + public void testRHSChainedMethodCalls2() throws Exception { + String drl = "package org.test;\n" + + "rule \"MyRule\"\n" + + "dialect \"mvel\"\n" + + "when\n" + + " Person( $n : name )\n" + + "then\n" + + " $n.toUpperCase().indexOf(\".\", 1);\n" + + "end"; + + addModelField( "org.test.Person", + "this", + "org.test.Person", + DataType.TYPE_THIS ); + addModelField( "org.test.Person", + "name", + String.class.getName(), + DataType.TYPE_STRING ); + + when( dmo.getPackageName() ).thenReturn( "org.test" ); + + final RuleModel m = RuleModelDRLPersistenceImpl.getInstance().unmarshal( drl, + new ArrayList(), + dmo ); + + assertNotNull( m ); + + assertEquals( 1, + m.lhs.length ); + final IPattern p0 = m.lhs[ 0 ]; + assertTrue( p0 instanceof FactPattern ); + final FactPattern fp0 = (FactPattern) p0; + assertEquals( "Person", + fp0.getFactType() ); + + assertEquals( 1, + fp0.getNumberOfConstraints() ); + assertTrue( fp0.getConstraint( 0 ) instanceof SingleFieldConstraint ); + + final SingleFieldConstraint sfc1 = (SingleFieldConstraint) fp0.getConstraint( 0 ); + assertEquals( "Person", + sfc1.getFactType() ); + assertEquals( "name", + sfc1.getFieldName() ); + assertEquals( DataType.TYPE_STRING, + sfc1.getFieldType() ); + + assertEquals( 1, + m.rhs.length ); + final IAction a0 = m.rhs[ 0 ]; + assertTrue( a0 instanceof FreeFormLine ); + final FreeFormLine ffl1 = (FreeFormLine) a0; + assertEquals( "$n.toUpperCase().indexOf(\".\", 1);", + ffl1.getText() ); + + //Check round-trip + assertEqualsIgnoreWhitespace( drl, + RuleModelDRLPersistenceImpl.getInstance().marshal( m ) ); + } + + @Test + //https://bugzilla.redhat.com/show_bug.cgi?id=1127303 + public void testRHSChainedMethodCalls3() throws Exception { + String drl = "package org.test;\n" + + "rule \"MyRule\"\n" + + "dialect \"mvel\"\n" + + "when\n" + + " Person( $n : name )\n" + + "then\n" + + " $n.toUpperCase().indexOf(\"(\", 1);\n" + + "end"; + + addModelField( "org.test.Person", + "this", + "org.test.Person", + DataType.TYPE_THIS ); + addModelField( "org.test.Person", + "name", + String.class.getName(), + DataType.TYPE_STRING ); + + when( dmo.getPackageName() ).thenReturn( "org.test" ); + + final RuleModel m = RuleModelDRLPersistenceImpl.getInstance().unmarshal( drl, + new ArrayList(), + dmo ); + + assertNotNull( m ); + + assertEquals( 1, + m.lhs.length ); + final IPattern p0 = m.lhs[ 0 ]; + assertTrue( p0 instanceof FactPattern ); + final FactPattern fp0 = (FactPattern) p0; + assertEquals( "Person", + fp0.getFactType() ); + + assertEquals( 1, + fp0.getNumberOfConstraints() ); + assertTrue( fp0.getConstraint( 0 ) instanceof SingleFieldConstraint ); + + final SingleFieldConstraint sfc1 = (SingleFieldConstraint) fp0.getConstraint( 0 ); + assertEquals( "Person", + sfc1.getFactType() ); + assertEquals( "name", + sfc1.getFieldName() ); + assertEquals( DataType.TYPE_STRING, + sfc1.getFieldType() ); + + assertEquals( 1, + m.rhs.length ); + final IAction a0 = m.rhs[ 0 ]; + assertTrue( a0 instanceof FreeFormLine ); + final FreeFormLine ffl1 = (FreeFormLine) a0; + assertEquals( "$n.toUpperCase().indexOf(\"(\", 1);", + ffl1.getText() ); + + //Check round-trip + assertEqualsIgnoreWhitespace( drl, + RuleModelDRLPersistenceImpl.getInstance().marshal( m ) ); + } + + @Test + //https://bugzilla.redhat.com/show_bug.cgi?id=1127303 + public void testRHSChainedMethodCalls4() throws Exception { + String drl = "package org.test;\n" + + "rule \"MyRule\"\n" + + "dialect \"mvel\"\n" + + "when\n" + + " Person( $n : name )\n" + + "then\n" + + " $n.toUpperCase().indexOf(\"\\\").\", 1);\n" + + "end"; + + addModelField( "org.test.Person", + "this", + "org.test.Person", + DataType.TYPE_THIS ); + addModelField( "org.test.Person", + "name", + String.class.getName(), + DataType.TYPE_STRING ); + + when( dmo.getPackageName() ).thenReturn( "org.test" ); + + final RuleModel m = RuleModelDRLPersistenceImpl.getInstance().unmarshal( drl, + new ArrayList(), + dmo ); + + assertNotNull( m ); + + assertEquals( 1, + m.lhs.length ); + final IPattern p0 = m.lhs[ 0 ]; + assertTrue( p0 instanceof FactPattern ); + final FactPattern fp0 = (FactPattern) p0; + assertEquals( "Person", + fp0.getFactType() ); + + assertEquals( 1, + fp0.getNumberOfConstraints() ); + assertTrue( fp0.getConstraint( 0 ) instanceof SingleFieldConstraint ); + + final SingleFieldConstraint sfc1 = (SingleFieldConstraint) fp0.getConstraint( 0 ); + assertEquals( "Person", + sfc1.getFactType() ); + assertEquals( "name", + sfc1.getFieldName() ); + assertEquals( DataType.TYPE_STRING, + sfc1.getFieldType() ); + + assertEquals( 1, + m.rhs.length ); + final IAction a0 = m.rhs[ 0 ]; + assertTrue( a0 instanceof FreeFormLine ); + final FreeFormLine ffl1 = (FreeFormLine) a0; + assertEquals( "$n.toUpperCase().indexOf(\"\\\").\", 1);", + ffl1.getText() ); + + //Check round-trip + assertEqualsIgnoreWhitespace( drl, + RuleModelDRLPersistenceImpl.getInstance().marshal( m ) ); + } + private void assertEqualsIgnoreWhitespace( final String expected, final String actual ) { final String cleanExpected = expected.replaceAll( "\\s+",