diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java index 64b26a8d8e0..cb7fce3aac1 100644 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/DMNCompilerImpl.java @@ -113,8 +113,7 @@ public DMNModel compile(Definitions dmndefs) { private void processItemDefinitions(DMNCompilerContext ctx, DMNFEELHelper feel, DMNModelImpl model, Definitions dmndefs) { dmndefs.getItemDefinition().stream().forEach(x->processItemDefQNameURIs(x)); - List ordered = new ArrayList<>( dmndefs.getItemDefinition() ); - ordered.sort( new ItemDefinitionDependenciesComparator(model.getNamespace()) ); + List ordered = new ItemDefinitionDependenciesSorter(model.getNamespace()).sort(dmndefs.getItemDefinition()); for ( ItemDefinition id : ordered ) { ItemDefNodeImpl idn = new ItemDefNodeImpl( id ); diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesComparator.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesComparator.java deleted file mode 100644 index 1e2a4705208..00000000000 --- a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesComparator.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates. - * - * 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.kie.dmn.core.compiler; - -import java.util.Comparator; - -import javax.xml.namespace.QName; - -import org.kie.dmn.model.v1_1.ItemDefinition; - -/** - * Note: this comparator imposes orderings that are inconsistent with equals. - * - */ -public class ItemDefinitionDependenciesComparator implements Comparator { - - private final String modelNamespace; - - public ItemDefinitionDependenciesComparator(String modelNamespace) { - this.modelNamespace = modelNamespace; - } - - /** - * Note: this comparator imposes orderings that are inconsistent with equals. - */ - @Override - public int compare(ItemDefinition o1, ItemDefinition o2) { - QName qname1 = new QName(modelNamespace, o1.getName()); - QName qname2 = new QName(modelNamespace, o2.getName()); - if ( recurseFind(o1, qname2) ){ - return 1; - } else if ( recurseFind(o2, qname1) ) { - return -1; - } else { - return 0; - } - } - - private boolean recurseFind(ItemDefinition o1, QName qname2) { - if ( o1.getTypeRef() != null ) { - if ( o1.getTypeRef().equals(qname2) ) { - return true; - } - } - for ( ItemDefinition ic : o1.getItemComponent() ) { - if ( recurseFind(ic, qname2) ) { - return true; - } - } - return false; - } - -} diff --git a/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesSorter.java b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesSorter.java new file mode 100644 index 00000000000..abc965b939b --- /dev/null +++ b/kie-dmn/kie-dmn-core/src/main/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesSorter.java @@ -0,0 +1,108 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.kie.dmn.core.compiler; + +import java.util.ArrayList; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.kie.dmn.model.v1_1.ItemDefinition; + +public class ItemDefinitionDependenciesSorter { + + private final String modelNamespace; + + public ItemDefinitionDependenciesSorter(String modelNamespace) { + this.modelNamespace = modelNamespace; + } + + /** + * Return a new list of ItemDefinition sorted by dependencies (required dependencies comes first) + */ + public List sort(List ins) { + // this method approximates a topological sort. + + List todos = new ArrayList<>(ins); + List ordered = new ArrayList<>(ins.size()); + + while ( todos.size() > 0 ) { + ItemDefinition c1 = todos.get(0); + for ( int i = 1; i < todos.size(); i++) { + ItemDefinition other = todos.get(i); + QName otherQName = new QName(modelNamespace, other.getName()); + if ( recurseFind(c1, otherQName) ) { + c1 = other; + } + } + ordered.add(c1); + todos.remove(c1); + } + return ordered; + } + + private static boolean recurseFind(ItemDefinition o1, QName qname2) { + if ( o1.getTypeRef() != null ) { + if ( o1.getTypeRef().equals(qname2) ) { + return true; + } + } + for ( ItemDefinition ic : o1.getItemComponent() ) { + if ( recurseFind(ic, qname2) ) { + return true; + } + } + return false; + } + + private static boolean directFind(ItemDefinition o1, QName qname2) { + if ( o1.getTypeRef() != null ) { + if ( o1.getTypeRef().equals(qname2) ) { + return true; + } + } + for ( ItemDefinition ic : o1.getItemComponent() ) { + if ( ic.getTypeRef() == null ) { + // anon inner type + if ( directFind(ic, qname2) ) { + return true; + } + } else if ( ic.getTypeRef().equals(qname2) ) { + return true; + } + } + return false; + } + + public static void displayDependencies(List ins, String namespaceURI) { + for ( ItemDefinition in : ins ) { + System.out.println(in.getName()); + List others = new ArrayList<>(ins); + others.remove(in); + for ( ItemDefinition other : others ) { + QName otherQName = new QName(namespaceURI, other.getName()); + if ( directFind(in, otherQName) ) { + System.out.println(" direct depends on: "+other.getName()); + } else if ( recurseFind(in, otherQName) ) { + System.out.println(" indir. depends on: "+other.getName()); + } + } + } + + } + +} diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesComparatorTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesComparatorTest.java deleted file mode 100644 index f8828417a3b..00000000000 --- a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesComparatorTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2016 Red Hat, Inc. and/or its affiliates. - * - * 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.kie.dmn.core.compiler; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import javax.xml.namespace.QName; - -import org.junit.Test; -import org.kie.dmn.api.marshalling.v1_1.DMNMarshaller; -import org.kie.dmn.backend.marshalling.v1_1.DMNMarshallerFactory; -import org.kie.dmn.model.v1_1.ItemDefinition; - -import static org.hamcrest.Matchers.*; -import static org.junit.Assert.assertThat; - - -public class ItemDefinitionDependenciesComparatorTest { - - private static final String TEST_NS = "https://www.drools.org/"; - private static final DMNMarshaller marshaller = DMNMarshallerFactory.newDefaultMarshaller(); - - private ItemDefinition build(String name, ItemDefinition... components) { - ItemDefinition res = new ItemDefinition(); - res.setName(name); - for ( ItemDefinition ic : components ) { - ItemDefinition c = new ItemDefinition(); - c.setName("_" + name + "-" + ic.getName()); - c.setTypeRef(new QName(TEST_NS, ic.getName())); - res.getItemComponent().add(c); - } - return res; - } - - @Test - public void testGeneric() { - ItemDefinition a = build("a"); - - ItemDefinition b = build("b"); - - ItemDefinition c = build("c", a, b); - - ItemDefinition d = build("d", c); - - List originalList = Arrays.asList(new ItemDefinition[]{d,c,b,a}); - - List orderedList = new ArrayList<>(originalList); - orderedList.sort(new ItemDefinitionDependenciesComparator(TEST_NS)); - - assertThat(orderedList.subList(0, 2), containsInAnyOrder(a,b)); - assertThat(orderedList.subList(2, 4), contains(c,d)); - } - - -} diff --git a/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesTest.java b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesTest.java new file mode 100644 index 00000000000..9a64db21036 --- /dev/null +++ b/kie-dmn/kie-dmn-core/src/test/java/org/kie/dmn/core/compiler/ItemDefinitionDependenciesTest.java @@ -0,0 +1,154 @@ +/* + * Copyright 2016 Red Hat, Inc. and/or its affiliates. + * + * 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.kie.dmn.core.compiler; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import javax.xml.namespace.QName; + +import org.junit.Test; +import org.kie.dmn.api.marshalling.v1_1.DMNMarshaller; +import org.kie.dmn.backend.marshalling.v1_1.DMNMarshallerFactory; +import org.kie.dmn.model.v1_1.ItemDefinition; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + + +public class ItemDefinitionDependenciesTest { + + private static final String TEST_NS = "https://www.drools.org/"; + private static final DMNMarshaller marshaller = DMNMarshallerFactory.newDefaultMarshaller(); + + private ItemDefinition build(String name, ItemDefinition... components) { + ItemDefinition res = new ItemDefinition(); + res.setName(name); + for ( ItemDefinition ic : components ) { + ItemDefinition c = new ItemDefinition(); + c.setName("_" + name + "-" + ic.getName()); + c.setTypeRef(new QName(TEST_NS, ic.getName())); + res.getItemComponent().add(c); + } + return res; + } + + private List orderingStrategy(List ins) { + return new ItemDefinitionDependenciesSorter(TEST_NS).sort(ins); + } + + @Test + public void testGeneric() { + ItemDefinition a = build("a"); + + ItemDefinition b = build("b"); + + ItemDefinition c = build("c", a, b); + + ItemDefinition d = build("d", c); + + List originalList = Arrays.asList(new ItemDefinition[]{d,c,b,a}); + + List orderedList = orderingStrategy(originalList); + + assertThat(orderedList.subList(0, 2), containsInAnyOrder(a,b)); + assertThat(orderedList.subList(2, 4), contains(c,d)); + } + + @Test + public void testGeneric2() { + ItemDefinition z = build("z"); + + ItemDefinition b = build("b"); + + ItemDefinition a = build("a", z); + + List originalList = Arrays.asList(new ItemDefinition[]{z,b,a}); + + List orderedList = orderingStrategy(originalList); + + assertTrue("Index of z < a", orderedList.indexOf(z) < orderedList.indexOf(a)); + } + + @Test + public void test1() { + ItemDefinition tCollateralRiskCategory = build("tCollateralRiskCategory"); + ItemDefinition tCreditRiskCategory = build("tCreditRiskCategory"); + ItemDefinition tAffordabilityCategory = build("tAffordabilityCategory"); + ItemDefinition tLoanRecommendation = build("tLoanRecommendation"); + ItemDefinition tLoan = build("tLoan"); + ItemDefinition tAge = build("tAge"); + ItemDefinition temploementStatus = build("temploementStatus"); + ItemDefinition tCreditScore = build("tCreditScore"); + ItemDefinition tRiskCategory = build("tRiskCategory"); + ItemDefinition tIncomeRisk = build("tIncomeRisk"); + ItemDefinition tBorrowe = build("tBorrowe", tAge, temploementStatus); + ItemDefinition tPrequalification = build("tPrequalification"); + + List originalList = Arrays.asList(new ItemDefinition[]{ + tCollateralRiskCategory, + tCreditRiskCategory , + tAffordabilityCategory , + tLoanRecommendation , + tLoan , + tAge , + temploementStatus , + tCreditScore , + tRiskCategory , + tIncomeRisk , + tBorrowe , + tPrequalification + }); + + List orderedList = orderingStrategy(originalList); + + assertTrue("Index of tAge < tBorrowe", orderedList.indexOf(tAge) < orderedList.indexOf(tBorrowe)); + assertTrue("Index of temploementStatus < tBorrowe", orderedList.indexOf(temploementStatus) < orderedList.indexOf(tBorrowe)); + } + + @Test + public void test2() { + ItemDefinition tMortgageType = build("tMortgageType"); + ItemDefinition tObjective = build("tObjective"); + ItemDefinition tRequested = build("tRequested", tMortgageType, tObjective); + ItemDefinition tProduct = build("tProduct"); + ItemDefinition tProductCollection = build("tProductCollection", tProduct); + ItemDefinition tConformanceType = build("tConformanceType"); + ItemDefinition tLoanTypes = build("tLoanTypes", tMortgageType, tConformanceType); + + List originalList = Arrays.asList(new ItemDefinition[]{ + tRequested, + tProduct, + tProductCollection, + tMortgageType, + tObjective, + tConformanceType, + tLoanTypes + }); + + List orderedList = orderingStrategy(originalList); + + assertTrue("Index of tMortgageType < tRequested", orderedList.indexOf(tMortgageType) < orderedList.indexOf(tRequested)); + assertTrue("Index of tObjective < tRequested", orderedList.indexOf(tObjective) < orderedList.indexOf(tRequested)); + + assertTrue("Index of tProduct < tProductCollection", orderedList.indexOf(tProduct) < orderedList.indexOf(tProductCollection)); + + assertTrue("Index of tMortgageType < tLoanTypes", orderedList.indexOf(tMortgageType) < orderedList.indexOf(tLoanTypes)); + assertTrue("Index of tConformanceType < tLoanTypes", orderedList.indexOf(tConformanceType) < orderedList.indexOf(tLoanTypes)); + } +}