| 1 10 package org.mmbase.bridge.util.xml.query; 11 12 import java.util.*; 13 import org.w3c.dom.*; 14 import org.w3c.dom.NodeList ; 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 28 public class QueryReader { 29 30 public static final String XSD_SEARCHQUERY_1_0 = "searchquery.xsd"; 31 public static final String NAMESPACE_SEARCHQUERY_1_0 = "http://www.mmbase.org/xmlns/searchquery"; 32 33 34 public static final String NAMESPACE_SEARCHQUERY = NAMESPACE_SEARCHQUERY_1_0; 35 36 40 public static void registerSystemIDs() { 41 XMLEntityResolver.registerSystemID(NAMESPACE_SEARCHQUERY_1_0 + ".xsd", XSD_SEARCHQUERY_1_0, QueryReader.class); 42 } 43 44 48 static public boolean hasAttribute(Element element, String localName) { 49 return element.hasAttributeNS(NAMESPACE_SEARCHQUERY,localName) || element.hasAttribute(localName); 50 } 51 52 56 static public String getAttribute(Element element, String 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 iae) { 72 fieldDefinition.stepField = null; 75 } 76 fieldDefinition.configure(fieldElement); 78 queryDefinition.fields.add(fieldDefinition); 79 if (queryDefinition.isMultiLevel) { 80 queryDefinition.query.addField(fieldDefinition.fieldName); 82 } 83 } else { 84 throw new IllegalArgumentException ("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 ("A constraint tag must have a 'field' attribute"); 91 } 92 String fieldName = getAttribute(constraintElement,"field"); 93 Object value = null; 94 if (hasAttribute(constraintElement,"value")) { 95 if (hasAttribute(constraintElement,"field2")) { 96 throw new IllegalArgumentException ("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 sOperator = getAttribute(constraintElement,"operator"); 105 operator = Queries.getOperator(sOperator); 106 } 107 int part = -1; 108 if (hasAttribute(constraintElement,"part")) { 109 String sPart = getAttribute(constraintElement,"part"); 110 part = Queries.getDateTimePart(sPart); 111 } 112 Object value2 = null; 113 if (hasAttribute(constraintElement,"value2")) { 114 if (operator != Queries.OPERATOR_BETWEEN) { 115 throw new IllegalArgumentException ("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 ("Operator BETWEEN in a constraint tag requires attribute 'value2'"); 121 } 122 if (operator == Queries.OPERATOR_IN && (value instanceof String )) { 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 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 day = new Integer (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 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 ("Either 'minage' or 'maxage' (or both) attributes must be present"); 164 } 165 StepField stepField = null; 166 String fieldName = "number"; 167 if (hasAttribute(constraintElement,"element")) { 168 if (hasAttribute(constraintElement,"field")) { 169 throw new IllegalArgumentException ("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 ("Don't know on what path element the ageconstraint must be applied. Use the 'element' attribute"); 181 } 182 } 183 184 Constraint constraint = null; 185 190 Cloud cloud = queryDefinition.query.getCloud(); 191 if (maxAge != -1 && minAge > 0) { 192 int maxMarker = getDayMark(cloud, maxAge); 193 if (maxMarker > 0) { 194 constraint = queryDefinition.query.createConstraint(stepField, new Integer (maxMarker + 1), new Integer (getDayMark(cloud, minAge - 1))); 196 } else { 197 constraint = queryDefinition.query.createConstraint(stepField, FieldCompareConstraint.LESS_EQUAL, new Integer (getDayMark(cloud, minAge - 1))); 198 } 199 } else if (maxAge != -1) { int maxMarker = getDayMark(cloud, maxAge); 201 if (maxMarker > 0) { 202 constraint = queryDefinition.query.createConstraint(stepField, FieldCompareConstraint.GREATER_EQUAL, new Integer (maxMarker + 1)); 203 } 204 } else if (minAge > 0) { 205 constraint = queryDefinition.query.createConstraint(stepField, FieldCompareConstraint.LESS_EQUAL, new Integer (getDayMark(cloud, minAge - 1))); 206 } 207 return constraint; 208 } 209 210 211 protected static Integer getAlias(Cloud cloud, String name) { 212 org.mmbase.bridge.Node node = cloud.getNode(name); 213 return new Integer (node.getNumber()); 214 } 215 216 protected static SortedSet getAliases(Cloud cloud, List names) { 217 SortedSet set = new TreeSet(); 218 Iterator i = names.iterator(); 219 while (i.hasNext()) { 220 set.add(getAlias(cloud, (String ) 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 ("An aliasconstraint tag must have a 'name' attribute"); 228 } 229 String 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 ("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 name = getAttribute(constraintElement,"name"); 240 List 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 names, boolean descendants) { 245 SortedSet set = new TreeSet(); 246 Iterator i = names.iterator(); 247 while (i.hasNext()) { 248 NodeManager nm = cloud.getNodeManager((String ) i.next()); 249 set.add(new Integer (nm.getNumber())); 250 if (descendants) { 251 NodeManagerIterator j = nm.getDescendants().nodeManagerIterator(); 252 while (j.hasNext()) { 253 set.add(new Integer (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 ("A typeconstraint tag must have a 'name' attribute"); 263 } 264 String 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 ("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 name = getAttribute(constraintElement,"name"); 274 List 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 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 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 ("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 356 static public QueryDefinition parseQuery(Element queryElement, Cloud cloud, String relateFrom) throws SearchQueryException { 357 return parseQuery(queryElement, null, cloud, relateFrom); 358 } 359 360 369 370 static public QueryDefinition parseQuery(Element queryElement, QueryConfigurer configurer, Cloud cloud, String 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 element = null; 377 String path = null; 378 String 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 builders = StringSplitter.split(path); 393 element = (String )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 startNodes = getAttribute(queryElement, "startnodes"); 420 Queries.addStartNodes(queryDefinition.query, startNodes); 421 } 422 423 queryDefinition.configure(queryElement); 425 426 NodeList 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 ("query has no 'path' or 'type' attribute"); 444 } 445 } 446 447 } 448 449 450 | Popular Tags |