1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.caleigo.core;
20
21
22 import java.util.*;
23
24 import org.caleigo.core.event.*;
25
26 /*** The CompositeQualifier is a Qualifier that contains a collection of other
27 * Qualifiers wrapping them as a single Qalifier effectively implementing the
28 * "Composite" design pattern. A CompositeQualifier can form either a union
29 * or an intersection of the contained Qualifiers which is defined at the
30 * creation.
31 *
32 * @author Dennis Zikovic
33 * @version 1.00
34 *
35 *//*
36 *
37 * WHEN WHO WHY & WHAT
38 * ------------------------------------------------------------------------------
39 * 2001-07-11 Dennis Zikovic Creation
40 */
41 public class CompositeQualifier extends Qualifier
42 {
43
44
45 /*** Used to state that all contained Qualifiers defines a union which means
46 * that they should be combined using using logical "OR".
47 */
48 public final static int UNION = 0;
49
50 /*** Used to state that all contained Qualifiers defines a intersection
51 * which means that they should be combined using using logical "AND".
52 */
53 public final static int INTERSECTION = 1;
54
55
56 private int mUnionType;
57 private List mQualifiers;
58
59 private transient RelayListener mRelayListener;
60
61
62
63 /*** Default constructor that creates a new CompositeQualifier forming an
64 * intersection of any added Qualifiers.
65 */
66 public CompositeQualifier()
67 {
68 this(INTERSECTION);
69 }
70
71 /*** Creates a new CompositeQualifier forming either an intersection or
72 * a union depending on the provided of the union type constant.
73 */
74 public CompositeQualifier(int unionType)
75 {
76 mUnionType = unionType;
77 mQualifiers = new ArrayList();
78 }
79
80 /*** Creates a new CompositeQualifier forming an intersection of the two
81 * provided Qualifiers.
82 */
83 public CompositeQualifier(Qualifier qualifier1, Qualifier qualifier2)
84 {
85 this(INTERSECTION);
86 this.add(qualifier1);
87 this.add(qualifier2);
88 }
89
90 /*** Creates a new CompositeQualifier forming either an intersection or
91 * a union depending on the defined of the unionType two provided
92 * Qualifiers.
93 */
94 public CompositeQualifier(Qualifier qualifier1, Qualifier qualifier2, int unionType)
95 {
96 this(unionType);
97 this.add(qualifier1);
98 this.add(qualifier2);
99 }
100
101
102
103 /*** This method returns true if the qualifier does select the
104 * provided entity object.
105 */
106 public boolean doesQualify(IEntity entity)
107 {
108
109 int qualCount = 0;
110 for(int j=0; j<this.getQualifierCount(); j++)
111 if(this.getQualifier(j).doesQualify(entity))
112 qualCount++;
113
114
115 if(mUnionType==INTERSECTION)
116 return qualCount==this.getQualifierCount();
117 else
118 return qualCount>=1;
119 }
120
121 /*** This method returns true if the qualifier can select entities
122 * of the type defined by the provided entity descriptor.
123 */
124 public boolean canQualify(IEntityDescriptor entityDescriptor)
125 {
126 boolean selects = false;
127 for(int j=0; !selects && j<mQualifiers.size(); j++)
128 selects = ((Qualifier)mQualifiers.get(j)).canQualify(entityDescriptor);
129 return selects;
130
131
132
133
134
135
136
137
138
139
140
141
142 }
143
144 /*** This abstract method must return true if the qualifier can select
145 * entities of the type defined by the provided entity descriptor without
146 * the nead of any complementary data. No other information than can be
147 * accessed through the provided entity descriptor should be neaded if
148 * this method returns true. This validates that the doesQualify method
149 * can be called for the called qualifier.
150 */
151 public boolean canDirectlyQualify(IEntityDescriptor entityDescriptor)
152 {
153 boolean selects = true;
154 for(int j=0; selects && j<mQualifiers.size(); j++)
155 selects = ((Qualifier)mQualifiers.get(j)).canDirectlyQualify(entityDescriptor);
156 return selects;
157 }
158
159 /*** This method returns true if the qualifier can uniquely select
160 * entities of the type defined by the provided entity descriptor.
161 * If that is the case then the qualifier is an identity qualifier and can
162 * never qualify more then a single entity instance of the specified type.
163 */
164 public boolean canUniquelyQualify(IEntityDescriptor entityDescriptor)
165 {
166 UniqueQualifierVisitor visitor = new UniqueQualifierVisitor(entityDescriptor, this);
167 return visitor.canUniquelyQualify();
168 }
169
170 /*** Adds an IQualifierListener to receive notifications of contents and
171 * structure changes from the Qualifier object. The CompositeQualifier
172 * overrides this method to know when to listen to the contained qualifiers.
173 */
174 public void addQualifierListener(IQualifierListener listener)
175 {
176 super.addQualifierListener(listener);
177 if(mRelayListener!=null)
178 {
179 mRelayListener = new RelayListener();
180 for(int j=0; j<this.getQualifierCount(); j++)
181 this.getQualifier(j).addQualifierListener(mRelayListener);
182 }
183 }
184
185 /*** The toString method returns an "abstract" expression of what the
186 * qualifier selects. Note that this expresion is only intended for visual
187 * aid and is not a valid SQL expresion.
188 */
189 public String toString()
190 {
191 if(mQualifiers.size()==0)
192 return "";
193 StringBuffer buf = new StringBuffer(500);
194 buf.append('(');
195 buf.append(mQualifiers.get(0));
196 for(int j=1; j<mQualifiers.size(); j++)
197 {
198 if(mUnionType==INTERSECTION)
199 buf.append(" AND ");
200 else
201 buf.append(" OR ");
202 buf.append(mQualifiers.get(j));
203 }
204 buf.append(')');
205 return buf.toString();
206 }
207
208
209
210 /*** Adds a new Qulifier to contained collection of Qualifiers. The added
211 * Qualifier will be joined as union or intersection depending of the set
212 * union type defined for the CompositeQualifier.
213 */
214 public void add(Qualifier qualifier)
215 {
216 mQualifiers.add(qualifier);
217 if(mRelayListener!=null)
218 qualifier.addQualifierListener(mRelayListener);
219 this.fireStructureChangedEvent();
220 }
221
222
223
224 /*** Access method that returns the Qualifiers union defined by one of the
225 * constants UNION or INTERSECTION.
226 */
227 public int getUnionType()
228 {
229 return mUnionType;
230 }
231
232 /*** Access method that returns the count of the contained Qualifiers.
233 */
234 public int getQualifierCount()
235 {
236 return mQualifiers.size();
237 }
238
239 /*** Access method that returns the indexed contained Qualifier.
240 * @throws java.lang.IndexOutOfBoundsException
241 */
242 public Qualifier getQualifier(int index)
243 {
244 return (Qualifier)mQualifiers.get(index);
245 }
246
247 /*** Access method that returns an Iterator object for the cotained
248 * collection of Qualifier objects.
249 */
250 public Iterator getQualifiers()
251 {
252 return mQualifiers.iterator();
253 }
254
255
256 protected static class UniqueQualifierVisitor
257 {
258 private IEntityDescriptor mEntityDescriptor;
259 private boolean mIsUnique;
260
261 private IFieldDescriptor[] identityFields;
262 private RelationQualifier[] foundFieldQualifiers;
263
264 public UniqueQualifierVisitor(IEntityDescriptor entityDescriptor, CompositeQualifier compQualifier)
265 {
266 mEntityDescriptor = entityDescriptor;
267 mIsUnique = false;
268
269
270 int fieldCount = 0;
271 for(int j=0; j<entityDescriptor.getFieldCount(); j++)
272 if(entityDescriptor.getFieldDescriptor(j).isIdentityField())
273 fieldCount++;
274
275
276 identityFields = new IFieldDescriptor[fieldCount];
277 foundFieldQualifiers = new RelationQualifier[fieldCount];
278 for(int j=0; j<entityDescriptor.getFieldCount(); j++)
279 if(entityDescriptor.getFieldDescriptor(j).isIdentityField())
280 {
281 fieldCount--;
282 identityFields[fieldCount] = entityDescriptor.getFieldDescriptor(j);
283 foundFieldQualifiers[fieldCount] = null;
284 }
285
286
287 this.visit(compQualifier);
288
289
290 if(!mIsUnique)
291 {
292 mIsUnique = true;
293
294
295
296 for(int j=0; mIsUnique && j<foundFieldQualifiers.length; j++)
297 {
298 mIsUnique = foundFieldQualifiers[j]!=null;
299
300 if(mIsUnique)
301 {
302
303 for(int k=j-1; mIsUnique && k>=0; k--)
304 mIsUnique = foundFieldQualifiers[j]!=foundFieldQualifiers[k];
305 }
306 }
307 }
308 }
309
310 protected void visit(Qualifier qual)
311 {
312 if(qual instanceof RelationQualifier)
313 {
314 if(((RelationQualifier)qual).getRelationType()!=RelationType.EQUAL)
315 return;
316
317
318 for(int j=0; j<identityFields.length; j++)
319 {
320 if(identityFields[j]==((RelationQualifier)qual).getFieldDescriptor())
321 {
322 if(foundFieldQualifiers[j]==null || !foundFieldQualifiers[j].isFieldToFieldRelation())
323 foundFieldQualifiers[j] = (RelationQualifier)qual;
324 }
325 if(((RelationQualifier)qual).isFieldToFieldRelation() && (IFieldDescriptor)((RelationQualifier)qual).getRelationValue()==identityFields[j])
326 {
327 if(foundFieldQualifiers[j]==qual)
328 foundFieldQualifiers[j] = null;
329 else if(foundFieldQualifiers[j]!=null)
330 foundFieldQualifiers[j] = (RelationQualifier)qual;
331 }
332 }
333 }
334 else if(qual instanceof CompositeQualifier)
335 {
336 if(((CompositeQualifier)qual).getUnionType()!=CompositeQualifier.INTERSECTION)
337 return;
338
339
340 for(int j=0; j<((CompositeQualifier)qual).getQualifierCount(); j++)
341 this.visit(((CompositeQualifier)qual).getQualifier(j));
342 }
343 else if(!mIsUnique && !(qual instanceof NegateQualifier))
344 mIsUnique = qual.canUniquelyQualify(mEntityDescriptor);
345 }
346
347 public boolean canUniquelyQualify()
348 {
349 return mIsUnique;
350 }
351 }
352 }