KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > bridge > util > xml > query > QueryReader


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.bridge.util.xml.query;
11
12 import java.util.*;
13 import org.w3c.dom.*;
14 import org.w3c.dom.NodeList JavaDoc;
15
16 import org.mmbase.bridge.*;
17 import org.mmbase.bridge.util.Queries;
18 import org.mmbase.storage.search.*;
19 import org.mmbase.storage.search.implementation.BasicCompositeConstraint;
20 import org.mmbase.util.*;
21
22 /**
23  *
24  * @author Pierre van Rooden
25  * @version $Id: QueryReader.java,v 1.8 2006/05/17 11:30:22 michiel Exp $
26  * @since MMBase-1.8
27  **/

28 public class QueryReader {
29
30     public static final String JavaDoc XSD_SEARCHQUERY_1_0 = "searchquery.xsd";
31     public static final String JavaDoc NAMESPACE_SEARCHQUERY_1_0 = "http://www.mmbase.org/xmlns/searchquery";
32
33     /** most recent version */
34     public static final String JavaDoc NAMESPACE_SEARCHQUERY = NAMESPACE_SEARCHQUERY_1_0;
35
36     /**
37      * Register the namespace and XSD used by QueryReader
38      * This method is called by XMLEntityResolver.
39      */

40     public static void registerSystemIDs() {
41         XMLEntityResolver.registerSystemID(NAMESPACE_SEARCHQUERY_1_0 + ".xsd", XSD_SEARCHQUERY_1_0, QueryReader.class);
42     }
43
44     /**
45      * Returns whether an element has a certain attribute, either an unqualified attribute or an attribute that fits in the
46      * searchquery namespace
47      */

48     static public boolean hasAttribute(Element element, String JavaDoc localName) {
49         return element.hasAttributeNS(NAMESPACE_SEARCHQUERY,localName) || element.hasAttribute(localName);
50     }
51
52     /**
53      * Returns the value of a certain attribute, either an unqualified attribute or an attribute that fits in the
54      * searchquery namespace
55      */

56     static public String JavaDoc getAttribute(Element element, String JavaDoc localName) {
57         if (element.hasAttributeNS(NAMESPACE_SEARCHQUERY,localName)) {
58             return element.getAttributeNS(NAMESPACE_SEARCHQUERY,localName);
59         } else {
60             return element.getAttribute(localName);
61         }
62     }
63
64
65     protected static void addField(Element fieldElement, QueryDefinition queryDefinition, QueryConfigurer configurer) {
66         if (hasAttribute(fieldElement,"name")) {
67             FieldDefinition fieldDefinition = configurer.getFieldDefinition();
68             fieldDefinition.fieldName = fieldElement.getAttribute("name");
69             try {
70                 fieldDefinition.stepField = queryDefinition.query.createStepField(fieldDefinition.fieldName);
71             } catch (IllegalArgumentException JavaDoc iae) {
72                 // the field did not exist in the database.
73
// this is possible if the field is, for instance, a bytefield that is stored on disc.
74
fieldDefinition.stepField = null;
75             }
76             // custom configuration of field
77
fieldDefinition.configure(fieldElement);
78             queryDefinition.fields.add(fieldDefinition);
79             if (queryDefinition.isMultiLevel) {
80                 // have to add field for multilevel queries
81
queryDefinition.query.addField(fieldDefinition.fieldName);
82             }
83         } else {
84              throw new IllegalArgumentException JavaDoc("field tag has no 'name' attribute");
85         }
86     }
87
88     protected static Constraint getConstraint(Element constraintElement, QueryDefinition queryDefinition) {
89         if (!hasAttribute(constraintElement,"field")) {
90             throw new IllegalArgumentException JavaDoc("A constraint tag must have a 'field' attribute");
91         }
92         String JavaDoc fieldName = getAttribute(constraintElement,"field");
93         Object JavaDoc value = null;
94         if (hasAttribute(constraintElement,"value")) {
95             if (hasAttribute(constraintElement,"field2")) {
96                 throw new IllegalArgumentException JavaDoc("A constraint tag can only have one of 'value' or 'field2'");
97             }
98             value = getAttribute(constraintElement,"value");
99         } else if (hasAttribute(constraintElement,"field2")) {
100             value = queryDefinition.query.createStepField(getAttribute(constraintElement,"field2"));
101         }
102         int operator = FieldCompareConstraint.EQUAL;
103         if (hasAttribute(constraintElement,"operator")) {
104             String JavaDoc sOperator = getAttribute(constraintElement,"operator");
105             operator = Queries.getOperator(sOperator);
106         }
107         int part = -1;
108         if (hasAttribute(constraintElement,"part")) {
109             String JavaDoc sPart = getAttribute(constraintElement,"part");
110             part = Queries.getDateTimePart(sPart);
111         }
112         Object JavaDoc value2 = null;
113         if (hasAttribute(constraintElement,"value2")) {
114             if (operator != Queries.OPERATOR_BETWEEN) {
115                 throw new IllegalArgumentException JavaDoc("A constraint tag can only use 'value2' attribute with operator BETWEEN");
116             }
117             value2 = getAttribute(constraintElement,"value2");
118         }
119         if (operator == Queries.OPERATOR_BETWEEN && value2 == null) {
120             throw new IllegalArgumentException JavaDoc("Operator BETWEEN in a constraint tag requires attribute 'value2'");
121         }
122         if (operator == Queries.OPERATOR_IN && (value instanceof String JavaDoc)) {
123             value = Casting.toList(value);
124         }
125         boolean caseSensitive = false;
126         if (hasAttribute(constraintElement,"casesensitive")) {
127             caseSensitive = "true".equals(getAttribute(constraintElement,"casesensitive"));
128         }
129         return Queries.createConstraint(queryDefinition.query, fieldName, operator, value, value2, caseSensitive, part);
130     }
131
132     protected static int getDayMark(Cloud cloud, int age) {
133         // find day mark
134
NodeManager dayMarks = cloud.getNodeManager("daymarks");
135         NodeQuery query = dayMarks.createQuery();
136         StepField step = query.createStepField("daycount");
137         int currentDay = (int) (System.currentTimeMillis()/(1000*60*60*24));
138         Integer JavaDoc day = new Integer JavaDoc(currentDay - age);
139         Constraint constraint = query.createConstraint(step, FieldCompareConstraint.LESS_EQUAL, day);
140         query.setConstraint(constraint);
141         query.addSortOrder(query.createStepField("daycount"), SortOrder.ORDER_DESCENDING);
142         query.setMaxNumber(1);
143
144         org.mmbase.bridge.NodeList result = dayMarks.getList(query);
145         int daymark = -1;
146         if (result.size() > 0) {
147             daymark = result.getNode(0).getIntValue("mark");
148         }
149         return daymark;
150     }
151
152     protected static Constraint getAgeConstraint(Element constraintElement, QueryDefinition queryDefinition) {
153         // find day mark
154
int minAge = -1;
155         if (hasAttribute(constraintElement,"minage")) {
156             minAge = Integer.parseInt(getAttribute(constraintElement,"minage"));
157         }
158         int maxAge = -1;
159         if (hasAttribute(constraintElement,"maxage")) {
160             maxAge = Integer.parseInt(getAttribute(constraintElement,"maxage"));
161         }
162         if (minAge < 0 && maxAge < 0) {
163             throw new IllegalArgumentException JavaDoc("Either 'minage' or 'maxage' (or both) attributes must be present");
164         }
165         StepField stepField = null;
166         String JavaDoc fieldName = "number";
167         if (hasAttribute(constraintElement,"element")) {
168             if (hasAttribute(constraintElement,"field")) {
169                 throw new IllegalArgumentException JavaDoc("Can not specify both 'field' and 'element' attributes on ageconstraint");
170             }
171             fieldName = getAttribute(constraintElement,"element") + ".number";
172             stepField = queryDefinition.query.createStepField(fieldName);
173         } else if (hasAttribute(constraintElement,"field")) {
174             fieldName = getAttribute(constraintElement,"field");
175             stepField = queryDefinition.query.createStepField(fieldName);
176         } else {
177             if (queryDefinition.elementStep != null) {
178                 stepField = queryDefinition.query.createStepField(queryDefinition.elementStep, "number");
179             } else {
180                 throw new IllegalArgumentException JavaDoc("Don't know on what path element the ageconstraint must be applied. Use the 'element' attribute");
181             }
182         }
183
184         Constraint constraint = null;
185         // if minimal age given:
186
// you need the day marker of the day after that (hence -1 in code below inside the getDayMark), node have to have this number or lower
187
// if maximal age given:
188
// daymarker object of that age must be included, but last object of previous day not, hece the +1 outside the getDayMark
189

190         Cloud cloud = queryDefinition.query.getCloud();
191         if (maxAge != -1 && minAge > 0) {
192             int maxMarker = getDayMark(cloud, maxAge);
193             if (maxMarker > 0) {
194                 // BETWEEN constraint
195
constraint = queryDefinition.query.createConstraint(stepField, new Integer JavaDoc(maxMarker + 1), new Integer JavaDoc(getDayMark(cloud, minAge - 1)));
196             } else {
197                 constraint = queryDefinition.query.createConstraint(stepField, FieldCompareConstraint.LESS_EQUAL, new Integer JavaDoc(getDayMark(cloud, minAge - 1)));
198             }
199         } else if (maxAge != -1) { // only on max
200
int maxMarker = getDayMark(cloud, maxAge);
201             if (maxMarker > 0) {
202                 constraint = queryDefinition.query.createConstraint(stepField, FieldCompareConstraint.GREATER_EQUAL, new Integer JavaDoc(maxMarker + 1));
203             }
204         } else if (minAge > 0) {
205             constraint = queryDefinition.query.createConstraint(stepField, FieldCompareConstraint.LESS_EQUAL, new Integer JavaDoc(getDayMark(cloud, minAge - 1)));
206         }
207         return constraint;
208     }
209
210
211     protected static Integer JavaDoc getAlias(Cloud cloud, String JavaDoc name) {
212         org.mmbase.bridge.Node node = cloud.getNode(name);
213         return new Integer JavaDoc(node.getNumber());
214     }
215
216     protected static SortedSet getAliases(Cloud cloud, List JavaDoc names) {
217         SortedSet set = new TreeSet();
218         Iterator i = names.iterator();
219         while (i.hasNext()) {
220             set.add(getAlias(cloud, (String JavaDoc) i.next()));
221         }
222         return set;
223     }
224
225     protected static Constraint getAliasConstraint(Element constraintElement, QueryDefinition queryDefinition) {
226         if (!hasAttribute(constraintElement,"name")) {
227             throw new IllegalArgumentException JavaDoc("An aliasconstraint tag must have a 'name' attribute");
228         }
229         String JavaDoc elementString = getAttribute(constraintElement,"element");
230         Step step = queryDefinition.elementStep;
231         if (elementString != null || !elementString.equals("")) {
232             step = queryDefinition.query.getStep(elementString);
233         }
234         if (step == null) {
235             throw new IllegalArgumentException JavaDoc("Don't know on what path element the aliasconstraint must be applied. Use the 'element' attribute");
236         }
237         StepField stepField = queryDefinition.query.createStepField(step, "number");
238
239         String JavaDoc name = getAttribute(constraintElement,"name");
240         List JavaDoc names = Casting.toList(name);
241         return queryDefinition.query.createConstraint(stepField, getAliases(queryDefinition.query.getCloud(),names));
242     }
243
244     protected static SortedSet getOTypes(Cloud cloud, List JavaDoc names, boolean descendants) {
245         SortedSet set = new TreeSet();
246         Iterator i = names.iterator();
247         while (i.hasNext()) {
248             NodeManager nm = cloud.getNodeManager((String JavaDoc) i.next());
249             set.add(new Integer JavaDoc(nm.getNumber()));
250             if (descendants) {
251                 NodeManagerIterator j = nm.getDescendants().nodeManagerIterator();
252                 while (j.hasNext()) {
253                     set.add(new Integer JavaDoc(j.nextNodeManager().getNumber()));
254                 }
255             }
256         }
257         return set;
258     }
259
260     protected static Constraint getTypeConstraint(Element constraintElement, QueryDefinition queryDefinition) {
261         if (!hasAttribute(constraintElement,"name")) {
262             throw new IllegalArgumentException JavaDoc("A typeconstraint tag must have a 'name' attribute");
263         }
264         String JavaDoc elementString = getAttribute(constraintElement,"element");
265         Step step = queryDefinition.elementStep;
266         if (elementString != null || !elementString.equals("")) {
267             step = queryDefinition.query.getStep(elementString);
268         }
269         if (step == null) {
270             throw new IllegalArgumentException JavaDoc("Don't know on what path element the type constraint must be applied. Use the 'element' attribute");
271         }
272         StepField stepField = queryDefinition.query.createStepField(step, "otype");
273         String JavaDoc name = getAttribute(constraintElement,"name");
274         List JavaDoc names = Casting.toList(name);
275         boolean descendants = true;
276         if (hasAttribute(constraintElement,"descendants")) {
277             descendants = "true".equals(getAttribute(constraintElement,"descendants"));
278         }
279         return queryDefinition.query.createConstraint(stepField, getOTypes(queryDefinition.query.getCloud(), names, descendants));
280     }
281
282     protected static Constraint getCompositeConstraint(Element constraintElement, QueryDefinition queryDefinition) throws SearchQueryException {
283         int operator = CompositeConstraint.LOGICAL_AND;
284         if (hasAttribute(constraintElement,"operator")) {
285             String JavaDoc sOperator = getAttribute(constraintElement,"operator");
286             if (sOperator!= null && sOperator.toUpperCase().equals("OR")) {
287                 operator = CompositeConstraint.LOGICAL_OR;
288             }
289         }
290         CompositeConstraint constraint = new BasicCompositeConstraint(operator);
291         if (hasAttribute(constraintElement,"inverse")) {
292             queryDefinition.query.setInverse(constraint, "true".equals(getAttribute(constraintElement,"inverse")));
293         }
294         NodeList JavaDoc childNodes = constraintElement.getChildNodes();
295         for (int k = 0; k < childNodes.getLength(); k++) {
296             if (childNodes.item(k) instanceof Element) {
297                 Element childElement = (Element) childNodes.item(k);
298                 addConstraint(childElement, queryDefinition, constraint);
299             }
300         }
301         return constraint;
302     }
303
304     protected static void addConstraint(Element constraintElement, QueryDefinition queryDefinition, CompositeConstraint parentConstraint) throws SearchQueryException {
305         Constraint constraint = null;
306         if ("constraint".equals(constraintElement.getLocalName())) {
307             constraint = getConstraint(constraintElement, queryDefinition);
308         } else if ("ageconstraint".equals(constraintElement.getLocalName())) {
309             constraint = getAgeConstraint(constraintElement, queryDefinition);
310         } else if ("aliasconstraint".equals(constraintElement.getLocalName())) {
311             constraint = getAliasConstraint(constraintElement, queryDefinition);
312         } else if ("typeconstraint".equals(constraintElement.getLocalName())) {
313             constraint = getTypeConstraint(constraintElement, queryDefinition);
314         } else if ("compositeconstraint".equals(constraintElement.getLocalName())) {
315             constraint = getCompositeConstraint(constraintElement, queryDefinition);
316         }
317         if (constraint != null) {
318             if (hasAttribute(constraintElement,"inverse")) {
319                 queryDefinition.query.setInverse(constraint, "true".equals(getAttribute(constraintElement,"inverse")));
320             }
321             if (parentConstraint != null) {
322                 ((BasicCompositeConstraint)parentConstraint).addChild(constraint);
323             } else {
324                 Queries.addConstraint(queryDefinition.query, constraint);
325             }
326         }
327     }
328
329     protected static void addDistinct(Element distinctElement, QueryDefinition queryDefinition) {
330         boolean distinct = true;
331         if (hasAttribute(distinctElement,"value")) {
332             distinct = "true".equals(getAttribute(distinctElement,"value"));
333         }
334         queryDefinition.query.setDistinct(distinct);
335     }
336
337     protected static void addSortOrder(Element sortOrderElement, QueryDefinition queryDefinition) {
338         if (!hasAttribute(sortOrderElement,"field")) {
339             throw new IllegalArgumentException JavaDoc("A sortorder tag must have a 'field' attribute");
340         }
341         StepField stepField = queryDefinition.query.createStepField(getAttribute(sortOrderElement,"field"));
342         int order = SortOrder.ORDER_ASCENDING;
343         if (hasAttribute(sortOrderElement,"direction")) {
344             order = Queries.getSortOrder(getAttribute(sortOrderElement,"direction"));
345         }
346         boolean casesensitive = false;
347         if (hasAttribute(sortOrderElement,"casesensitive")) {
348             casesensitive = "true".equals(getAttribute(sortOrderElement,"casesensitive"));
349         }
350         queryDefinition.query.addSortOrder(stepField, order, casesensitive);
351     }
352
353     /**
354      * As {@link #parseQuery(Element, QueryConfigurer, Cloud, String)}, but with default QueryConfigurer
355      */

356     static public QueryDefinition parseQuery(Element queryElement, Cloud cloud, String JavaDoc relateFrom) throws SearchQueryException {
357         return parseQuery(queryElement, null, cloud, relateFrom);
358     }
359
360     /**
361      * Creates a Query object from an Element. The query is wrapped in a {@link QueryDefinition} and
362      * you can simply access the {@link QueryDefinition#query} member to have the actual Query.
363      *
364      * @param queryElement Any XML element which query sub-tags and attributes.
365      * @param configurer The configure which is responsible for instantiating the QueryDefinition
366      * @param cloud Cloud, needed to make Query objects.
367      * @param relateFrom (optional) name of a node manager which can be used to base the query on, as the first element of the path (can be <code>null</code>)
368      */

369
370     static public QueryDefinition parseQuery(Element queryElement, QueryConfigurer configurer, Cloud cloud, String JavaDoc relateFrom) throws SearchQueryException {
371         if (configurer == null) {
372             configurer = QueryConfigurer.getDefaultConfigurer();
373         }
374         if (hasAttribute(queryElement,"type") || hasAttribute(queryElement,"name") || hasAttribute(queryElement,"path")) {
375
376             String JavaDoc element = null;
377             String JavaDoc path = null;
378             String JavaDoc searchDirs = null;
379
380             if (hasAttribute(queryElement,"type")) {
381                 path = getAttribute(queryElement,"type");
382                 element = path;
383             } else if (hasAttribute(queryElement,"name")) {
384                 path = getAttribute(queryElement,"name");
385                 element = path;
386             } else{
387                 path = getAttribute(queryElement,"path");
388                 searchDirs = getAttribute(queryElement,"searchdirs");
389                 if (hasAttribute(queryElement,"element")) {
390                   element = getAttribute(queryElement,"element");
391                 } else {
392                     List JavaDoc builders = StringSplitter.split(path);
393                     element = (String JavaDoc)builders.get(builders.size()-1);
394                 }
395             }
396             if (relateFrom != null) {
397                 path = relateFrom + "," + path;
398             }
399
400
401             QueryDefinition queryDefinition = configurer.getQueryDefinition();
402             queryDefinition.isMultiLevel = !path.equals(element);
403
404             if (element != null) {
405                 queryDefinition.elementManager = cloud.getNodeManager(element);
406             }
407             if (queryDefinition.isMultiLevel) {
408                 queryDefinition.query = cloud.createQuery();
409                 Queries.addPath(queryDefinition.query, path, searchDirs);
410             } else {
411                 queryDefinition.query = queryDefinition.elementManager.createQuery();
412             }
413             if (element != null) {
414                 queryDefinition.elementStep = queryDefinition.query.getStep(element);
415             }
416             if (queryDefinition.fields == null) queryDefinition.fields = new ArrayList();
417
418             if (hasAttribute(queryElement, "startnodes")) {
419                 String JavaDoc startNodes = getAttribute(queryElement, "startnodes");
420                 Queries.addStartNodes(queryDefinition.query, startNodes);
421             }
422
423             // custom configurations to the query
424
queryDefinition.configure(queryElement);
425
426             NodeList JavaDoc childNodes = queryElement.getChildNodes();
427             for (int k = 0; k < childNodes.getLength(); k++) {
428                 if (childNodes.item(k) instanceof Element) {
429                     Element childElement = (Element) childNodes.item(k);
430                     if ("field".equals(childElement.getLocalName())) {
431                         addField(childElement, queryDefinition, configurer);
432                     } else if ("distinct".equals(childElement.getLocalName())) {
433                         addDistinct(childElement, queryDefinition);
434                     } else if ("sortorder".equals(childElement.getLocalName())) {
435                         addSortOrder(childElement, queryDefinition);
436                     } else {
437                         addConstraint(childElement, queryDefinition, null);
438                     }
439                 }
440             }
441             return queryDefinition;
442         } else {
443             throw new IllegalArgumentException JavaDoc("query has no 'path' or 'type' attribute");
444         }
445     }
446
447 }
448
449
450
Popular Tags