1 | /* |
2 | * Copyright 2007 brunella ltd |
3 | * |
4 | * Licensed under the LGPL Version 3 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * |
7 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
8 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
11 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
12 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
13 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
14 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
15 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
16 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
17 | * THE POSSIBILITY OF SUCH DAMAGE. |
18 | */ |
19 | package sf.qof.parser; |
20 | |
21 | import java.util.ArrayList; |
22 | import java.util.Collections; |
23 | import java.util.Comparator; |
24 | import java.util.List; |
25 | |
26 | import sf.qof.exception.ValidationException; |
27 | |
28 | /** |
29 | * Helper class to combine partial definitions. |
30 | */ |
31 | public class PartialDefinitionCombiner { |
32 | |
33 | /** |
34 | * Combines partial definitions. |
35 | * |
36 | * @param definitionList a list of <code>Definition</code> objects. May contain partial definitions |
37 | * that will be combined |
38 | * @return a list of containing full definitions |
39 | * @throws sq.qof.exception.ValidationException if duplicate partial definitions are found |
40 | */ |
41 | public static List<? extends Definition> combine(List<? extends Definition> definitionList) { |
42 | List<Definition> partialDefinitions = new ArrayList<Definition>(); |
43 | List<Definition> fullDefinitions = new ArrayList<Definition>(); |
44 | |
45 | for (Definition definition : definitionList) { |
46 | if (definition.isPartialDefinition()) { |
47 | partialDefinitions.add(definition); |
48 | } else { |
49 | fullDefinitions.add(definition); |
50 | } |
51 | } |
52 | |
53 | if (partialDefinitions.size() == 0) { |
54 | return definitionList; |
55 | } |
56 | |
57 | // sort the list |
58 | Collections.sort(partialDefinitions, new DefinitionComparator()); |
59 | |
60 | validatePartialDefinitions(partialDefinitions); |
61 | |
62 | int index = 0; |
63 | while (index < partialDefinitions.size()) { |
64 | Definition partialDefinition = partialDefinitions.get(index++); |
65 | if (partialDefinition.getPartialDefinitionPart() == 1) { |
66 | int numberOfParts = numberOfParts(partialDefinitions, index - 1); |
67 | if (partialDefinition instanceof ResultDefinition) { |
68 | ResultDefinition partialResultDefiniton = (ResultDefinition)partialDefinition; |
69 | ResultDefinitionImpl resultDefiniton = new ResultDefinitionImpl(); |
70 | resultDefiniton.setType(partialResultDefiniton.getType()); |
71 | resultDefiniton.setField(partialResultDefiniton.getField()); |
72 | resultDefiniton.setConstructorParameter(partialResultDefiniton.getConstructorParameter()); |
73 | resultDefiniton.setIsMapKey(partialResultDefiniton.isMapKey()); |
74 | if (partialResultDefiniton.getColumns() != null) { |
75 | String[] columns = new String[numberOfParts]; |
76 | resultDefiniton.setColumns(columns); |
77 | columns[0] = partialResultDefiniton.getColumns()[0]; |
78 | for (int i = 1; i < numberOfParts; i++) { |
79 | columns[i] = ((ResultDefinition)partialDefinitions.get(index++)).getColumns()[0]; |
80 | } |
81 | } else { |
82 | int[] indexes = new int[numberOfParts]; |
83 | resultDefiniton.setIndexes(indexes); |
84 | indexes[0] = partialResultDefiniton.getIndexes()[0]; |
85 | for (int i = 1; i < numberOfParts; i++) { |
86 | indexes[i] = ((ResultDefinition)partialDefinitions.get(index++)).getIndexes()[0]; |
87 | } |
88 | } |
89 | fullDefinitions.add(resultDefiniton); |
90 | } else { |
91 | ParameterDefinition partialParameterDefiniton = (ParameterDefinition)partialDefinition; |
92 | ParameterDefinitionImpl parameterDefiniton = new ParameterDefinitionImpl(); |
93 | parameterDefiniton.setType(partialParameterDefiniton.getType()); |
94 | parameterDefiniton.setField(partialParameterDefiniton.getField()); |
95 | parameterDefiniton.setNames(partialParameterDefiniton.getNames()); |
96 | parameterDefiniton.setParameter(partialParameterDefiniton.getParameter()); |
97 | int[] indexes = new int[numberOfParts]; |
98 | parameterDefiniton.setIndexes(indexes); |
99 | indexes[0] = partialParameterDefiniton.getIndexes()[0]; |
100 | for (int i = 1; i < numberOfParts; i++) { |
101 | indexes[i] = ((ParameterDefinition)partialDefinitions.get(index++)).getIndexes()[0]; |
102 | } |
103 | fullDefinitions.add(parameterDefiniton); |
104 | } |
105 | } |
106 | } |
107 | |
108 | return fullDefinitions; |
109 | } |
110 | |
111 | private static int numberOfParts(List<Definition> list, int start) { |
112 | String type = makeEmptyIfNull(list.get(start).getType()); |
113 | String group = makeEmptyIfNull(list.get(start).getPartialDefinitionGroup()); |
114 | int i = 1; |
115 | while (i + start < list.size()) { |
116 | if (!type.equals(makeEmptyIfNull(list.get(start + i).getType())) || |
117 | !group.equals(makeEmptyIfNull(list.get(start + i).getPartialDefinitionGroup()))) { |
118 | break; |
119 | } |
120 | i++; |
121 | } |
122 | return i; |
123 | } |
124 | |
125 | private static String makeEmptyIfNull(String string) { |
126 | return string == null ? "" : string; |
127 | } |
128 | |
129 | private static void validatePartialDefinitions(List<Definition> partialDefinitions) { |
130 | DefinitionComparator comparator = new DefinitionComparator(); |
131 | Definition lastDefinition = partialDefinitions.get(0); |
132 | for (int i = 1; i < partialDefinitions.size(); i++) { |
133 | Definition currentDefinition = partialDefinitions.get(i); |
134 | if (comparator.compare(lastDefinition, currentDefinition) == 0 ) { |
135 | throw new ValidationException("Duplicate partial definition"); |
136 | } |
137 | lastDefinition = currentDefinition; |
138 | } |
139 | } |
140 | |
141 | private static class DefinitionComparator implements Comparator<Definition> { |
142 | public int compare(Definition o1, Definition o2) { |
143 | int cmp; |
144 | String type1 = o1.getType(); |
145 | String type2 = o2.getType(); |
146 | if (type1 != null) { |
147 | cmp = type1.compareTo(type2); |
148 | } else if (type2 != null) { |
149 | cmp = -type2.compareTo(type1); |
150 | } else { |
151 | cmp = 0; |
152 | } |
153 | if (cmp != 0) { |
154 | return cmp; |
155 | } |
156 | String group1 = o1.getPartialDefinitionGroup(); |
157 | String group2 = o2.getPartialDefinitionGroup(); |
158 | if (group1 != null) { |
159 | cmp = group1.compareTo(group2); |
160 | } else if (group2 != null) { |
161 | cmp = -group2.compareTo(group1); |
162 | } else { |
163 | cmp = 0; |
164 | } |
165 | if (cmp != 0) { |
166 | return cmp; |
167 | } |
168 | return o1.getPartialDefinitionPart() - o2.getPartialDefinitionPart(); |
169 | } |
170 | } |
171 | } |