1 10 package org.mmbase.cache; 11 12 import java.util.Iterator ; 13 import java.util.List ; 14 import java.util.Set ; 15 16 import org.mmbase.core.event.*; 17 import org.mmbase.module.core.*; 18 import org.mmbase.storage.search.*; 19 import org.mmbase.storage.search.implementation.database.BasicSqlHandler; 20 import org.mmbase.util.logging.Logger; 21 import org.mmbase.util.logging.Logging; 22 23 24 31 public class BetterStrategy extends ReleaseStrategy { 32 33 private static final BasicSqlHandler sqlHandler = new BasicSqlHandler(); 35 private static final Logger log = Logging.getLoggerInstance(BetterStrategy.class); 36 37 public String getName() { 39 return "Better Release Strategy"; 40 } 41 42 47 public String getDescription() { 48 return "This strategy performs all kinds of checks to test if the node or relation event actually matches the query. " + 49 "For node events the type is checked, as well as some other things. For relation events the type is checked as well as " + 50 "the source and destination. Then there are some other things like: 'new node events should not flush queries with " + 51 "more than one step, because they have no relation yet'. It also checks if a certain change in a node actually can affect the " + 52 "outcome of a query."; 53 } 54 55 protected boolean doEvaluate(RelationEvent event, SearchQuery query, List cachedResult) { 56 return shouldRelease(event, query); 57 } 58 59 66 protected final boolean doEvaluate(NodeEvent event, SearchQuery query, List cachedResult) { 67 if (log.isDebugEnabled()) { 68 log.debug(event.toString()); 69 } 70 return shouldRelease(event, query); 71 } 72 73 79 private boolean shouldRelease(NodeEvent event, SearchQuery query) { 80 switch (event.getType()) { 81 case Event.TYPE_NEW: 82 if (query.getSteps().size() > 1) { 85 logResult("no flush: 'new node' event in multistep query", query, event); 86 return false; } 88 if(! checkSteps(event, query)) { 89 logResult("no flush: the query has nodes set and this event's node is not one of them, or this step has no steps of corresponding type", query, event); 90 return false; 91 } 92 break; 93 94 case Event.TYPE_DELETE: 95 if(! checkSteps(event, query)) { 96 logResult("no flush: the query has nodes set and this event's node is not one of them, or this step has no steps of corresponding type", query, event); 97 return false; 98 } 99 break; 100 101 case Event.TYPE_CHANGE: 102 if(! checkSteps(event, query)) { 103 logResult("no flush: the query has nodes set and this event's node is not one of them, or this step has no steps of corresponding type", query, event); 104 return false; 105 } 106 if(! checkChangedFieldsMatch(event, query)) { 109 logResult("no flush: the fields that have changed are not used in the query", query, event); 110 return false; 111 } 112 113 if(checkAggregationCount(event, query)) { 116 logResult("query is aggregating and fields are of type count, changed fields do not affect the query result", query, event); 117 return false; 118 } 119 120 121 } 122 logResult("flush: no reason not to", query, event); 123 return true; 124 } 125 126 133 private boolean shouldRelease(RelationEvent event, SearchQuery query) { 134 135 139 140 if (query.getSteps().size() == 1 ){ 142 logResult("no flush: query has one step and event is relation event", query, event); 143 return false ; } 145 146 if (! checkPathMatches(event, query)){ 149 logResult("no flush: either source, destination or role does not match to the query", query, event); 150 return false; 151 } 152 153 154 switch (event.getType()) { 155 case Event.TYPE_NEW: 156 log.debug(">> relation event type new"); 157 160 161 break; 162 163 case Event.TYPE_DELETE: 164 log.debug(">> relation event type delete"); 165 168 169 break; 170 171 case Event.TYPE_CHANGE: 172 log.debug(">> relation event type changed"); 173 176 177 if(! checkChangedFieldsMatch(event.getNodeEvent(), query)) { 180 logResult("no flush: the changed relation fields do not match the fields or constraints of the query", query, event); 181 return false; 182 } 183 184 break; 185 186 } 187 logResult("flush: no reason not to", query, event); 188 return true; 189 } 190 191 197 private boolean checkAggregationCount(NodeEvent event, SearchQuery query) { 198 log.debug("method: checkAggregationCount()"); 199 if(!query.isAggregating()){ 200 return false; 201 } 202 for(Iterator i = query.getFields().iterator(); i.hasNext(); ){ 204 StepField field = (StepField) i.next(); 205 if(event.getChangedFields().contains(field.getFieldName()) ){ 206 if( ! (field instanceof AggregatedField)) { 207 return false; 208 } 209 if( ! (((AggregatedField)field).getAggregationType() == AggregatedField.AGGREGATION_TYPE_COUNT) ){ 210 return false; 211 } 212 } 213 } 214 Constraint constraint = query.getConstraint(); 216 if(constraint == null){ 217 return true; 218 } 219 MMObjectBuilder eventBuilder = MMBase.getMMBase().getBuilder(event.getBuilderName()); 220 for (Iterator i = event.getChangedFields().iterator(); i.hasNext();) { 221 String fieldName = (String ) i.next(); 222 if(getConstraintsForField(fieldName, eventBuilder, constraint, query).size() > 0){ 223 return false; 224 } 225 } 226 return true; 228 } 229 230 235 private boolean checkPathMatches(RelationEvent event, SearchQuery query){ 236 if (log.isDebugEnabled()) { 240 log.debug("method: checkPathMatches()"); 241 log.debug(event.toString()); 242 log.debug("query: " + query.toString()); 243 } 244 MMBase mmb = MMBase.getMMBase(); 245 String eventSourceType = event.getRelationSourceType(); 246 String eventDestType = event.getRelationDestinationType(); 247 MMObjectBuilder eventSource = mmb.getBuilder(eventSourceType); 248 MMObjectBuilder eventDest = mmb.getBuilder(eventDestType); 249 250 251 Iterator i = query.getSteps().iterator(); 252 Step prevStep = (Step) i.next(); 253 String stepDest = prevStep.getTableName(); 254 while (i.hasNext()) { 255 String stepSource = stepDest; 256 RelationStep step = (RelationStep) i.next(); 257 Step nextStep = (Step) i.next(); 258 stepDest = nextStep.getTableName(); 259 boolean matchesProper = 260 (eventSourceType.equals(stepSource) || eventSource.isExtensionOf(mmb.getBuilder(stepSource))) && 261 (eventDestType.equals(stepDest) || eventDest.isExtensionOf(mmb.getBuilder(stepDest))); 262 boolean matches = matchesProper || 263 ( (eventDestType.equals(stepSource) || eventDest.isExtensionOf(mmb.getBuilder(stepSource))) && 265 (eventSourceType.equals(stepDest) || eventSource.isExtensionOf(mmb.getBuilder(stepDest))) 266 ); 267 268 Integer role = step.getRole(); 269 if (matches && 270 (role == null || role.intValue() == event.getRole())) { 271 return true; 272 } 273 } 274 return false; 275 } 276 277 278 279 280 281 282 289 private boolean checkChangedFieldsMatch(NodeEvent event, SearchQuery query){ 290 if (log.isDebugEnabled()) { 291 log.debug("method: checkChangedFieldsMatch(). changed fields: " + event.getChangedFields().size()); 292 } 293 boolean constraintsFound = false; 294 boolean fieldsFound = false; 295 boolean sortordersFound = false; 296 String eventBuilderName = event.getBuilderName(); 297 MMBase mmb = MMBase.getMMBase(); 298 MMObjectBuilder eventBuilder = mmb.getBuilder(eventBuilderName); 299 search: 300 for (Iterator i = event.getChangedFields().iterator(); i.hasNext();) { 301 String fieldName = (String ) i.next(); 302 303 List constraintsForFieldList = getConstraintsForField(fieldName, eventBuilder, query.getConstraint(), query); 305 if(constraintsForFieldList.size() > 0) { 306 constraintsFound = true; 307 if (log.isDebugEnabled()) { 308 log.debug("matching constraint found: " + constraintsForFieldList.size()); 309 } 310 break search; 311 } 312 313 for (Iterator fieldIterator = query.getFields().iterator(); fieldIterator.hasNext();) { 315 StepField field = (StepField) fieldIterator.next(); 316 if (field.getFieldName().equals(fieldName) 317 && (field.getStep().getTableName().equals(eventBuilderName) || 318 eventBuilder.isExtensionOf(mmb.getBuilder(field.getStep().getTableName()))) 319 ) { 320 fieldsFound = true; 321 if(log.isDebugEnabled()) { 322 log.debug("matching field found: " + field.getStep().getTableName() + "." + field.getFieldName()); 323 } 324 break search; 325 } 326 } 327 328 List sortordersForFieldList = getSortordersForField(fieldName, eventBuilder, query.getSortOrders(), query); 330 if(sortordersForFieldList.size() > 0) { 331 sortordersFound = true; 332 if (log.isDebugEnabled()) { 333 log.debug("matching sortorders found: " + sortordersForFieldList.size()); 334 } 335 break search; 336 } 337 } 338 if(log.isDebugEnabled()){ 339 String logMsg =""; 340 if (!sortordersFound) logMsg = logMsg + " no matching sortorders found"; 341 if (!fieldsFound) logMsg = "no matching fields found, "; 342 if (!constraintsFound) logMsg = logMsg + " no matching constraints found"; 343 log.debug(logMsg); 344 } 345 return sortordersFound || fieldsFound || constraintsFound; 347 } 348 349 361 private boolean checkSteps(NodeEvent event, SearchQuery query){ 362 MMBase mmb = MMBase.getMMBase(); 364 String eventTable = event.getBuilderName(); 365 MMObjectBuilder eventBuilder = mmb.getBuilder(eventTable); 366 Iterator i = query.getSteps().iterator(); 367 while (i.hasNext()) { 368 Step step = (Step) i.next(); 369 String table = step.getTableName(); 370 if (! (table.equals(eventTable) || 371 eventBuilder.isExtensionOf(mmb.getBuilder(table)))) continue; 372 Set nodes = step.getNodes(); 373 if (nodes == null || nodes.size() == 0 || nodes.contains(new Integer (event.getNodeNumber()))) { 374 return true; 375 } 376 } 377 return false; 378 } 379 380 private void logResult(String comment, SearchQuery query, Event event){ 381 if(log.isDebugEnabled()){ 382 String role=""; 383 if (event instanceof RelationEvent) { 385 RelationEvent revent = (RelationEvent) event; 387 MMObjectNode relDef = MMBase.getMMBase().getBuilder("reldef").getNode(revent.getRole()); 388 role = " role: " + relDef.getStringValue("sname") + "/" + relDef.getStringValue("dname"); 389 if (revent.getRelationSourceType().equals("object") 391 || revent.getRelationDestinationType().equals("object")) 392 return; 393 } 394 try { 395 log.debug("\n******** \n**" + comment + "\n**" + event.toString() + role + "\n**" + sqlHandler.toSql(query, sqlHandler) + "\n******"); 396 } catch (SearchQueryException e) { 397 log.warn(e); 398 } 399 } 400 } 401 } 402 | Popular Tags |