1 5 package com.opensymphony.workflow.spi.hibernate; 6 7 import com.opensymphony.module.propertyset.PropertySet; 8 import com.opensymphony.module.propertyset.PropertySetManager; 9 import com.opensymphony.module.propertyset.hibernate.DefaultHibernateConfigurationProvider; 10 11 import com.opensymphony.util.TextUtils; 12 13 import com.opensymphony.workflow.StoreException; 14 import com.opensymphony.workflow.query.*; 15 import com.opensymphony.workflow.spi.Step; 16 import com.opensymphony.workflow.spi.WorkflowEntry; 17 import com.opensymphony.workflow.spi.WorkflowStore; 18 19 import net.sf.hibernate.Criteria; 20 import net.sf.hibernate.Hibernate; 21 import net.sf.hibernate.HibernateException; 22 import net.sf.hibernate.Session; 23 import net.sf.hibernate.SessionFactory; 24 import net.sf.hibernate.Transaction; 25 import net.sf.hibernate.expression.Criterion; 26 import net.sf.hibernate.expression.Expression; 27 28 import org.apache.commons.logging.Log; 29 import org.apache.commons.logging.LogFactory; 30 31 import java.util.*; 32 33 34 44 public class HibernateWorkflowStore implements WorkflowStore { 45 47 private static final Log log = LogFactory.getLog(HibernateWorkflowStore.class); 48 49 51 Session session; 52 SessionFactory sessionFactory; 53 54 56 public HibernateWorkflowStore() { 57 } 58 59 public HibernateWorkflowStore(SessionFactory sessionFactory) throws StoreException { 60 this.sessionFactory = sessionFactory; 61 62 try { 63 this.session = sessionFactory.openSession(); 64 } catch (HibernateException he) { 65 log.error("constructor", he); 66 throw new StoreException("constructor", he); 67 } 68 } 69 70 72 public void setEntryState(long entryId, int state) throws StoreException { 73 try { 74 HibernateWorkflowEntry entry = (HibernateWorkflowEntry) session.find("FROM entry IN CLASS " + HibernateWorkflowEntry.class.getName() + " WHERE entry.id = ?", new Long (entryId), Hibernate.LONG).get(0); 75 entry.setState(state); 76 session.save(entry); 77 } catch (HibernateException e) { 78 log.error("An exception occured", e); 79 80 return; 81 } 82 } 83 84 public PropertySet getPropertySet(long entryId) { 85 HashMap args = new HashMap(); 86 args.put("entityName", "OSWorkflowEntry"); 87 args.put("entityId", new Long (entryId)); 88 89 DefaultHibernateConfigurationProvider configurationProvider = new DefaultHibernateConfigurationProvider(); 90 configurationProvider.setSessionFactory(sessionFactory); 91 92 args.put("configurationProvider", configurationProvider); 93 94 return PropertySetManager.getInstance("hibernate", args); 95 } 96 97 public Step createCurrentStep(long entryId, int stepId, String owner, Date startDate, Date dueDate, String status, long[] previousIds) throws StoreException { 98 HibernateCurrentStep step = new HibernateCurrentStep(); 99 HibernateWorkflowEntry entry; 100 101 Transaction tx; 102 103 try { 104 tx = session.beginTransaction(); 105 entry = (HibernateWorkflowEntry) session.find("FROM entry in CLASS " + HibernateWorkflowEntry.class.getName() + " WHERE entry.id = ?", new Long (entryId), Hibernate.LONG).get(0); 106 } catch (HibernateException he) { 107 log.error("Looking for workflow entry " + entryId, he); 108 throw new StoreException("Looking for workflow entry " + entryId, he); 109 } 110 111 step.setEntry(entry); 112 step.setStepId(stepId); 113 step.setOwner(owner); 114 step.setStartDate(startDate); 115 step.setDueDate(dueDate); 116 step.setStatus(status); 117 118 List stepIdList = new ArrayList(previousIds.length); 119 120 for (int i = 0; i < previousIds.length; i++) { 121 long previousId = previousIds[i]; 122 stepIdList.add(new Long (previousId)); 123 } 124 125 if (!stepIdList.isEmpty()) { 126 String stepIds = TextUtils.join(", ", stepIdList); 127 128 try { 129 step.setPreviousSteps(session.find("FROM step in CLASS " + HibernateCurrentStep.class.getName() + " WHERE step.id IN (" + stepIds + ")")); 130 } catch (HibernateException he) { 131 log.error("Looking for step in " + stepIds, he); 132 throw new StoreException("Looking for step in " + stepIds, he); 133 } 134 } else { 135 step.setPreviousSteps(Collections.EMPTY_LIST); 136 } 137 138 if (entry.getCurrentSteps() == null) { 139 ArrayList cSteps = new ArrayList(1); 140 cSteps.add(step); 141 entry.setCurrentSteps(cSteps); 142 } else { 143 entry.getCurrentSteps().add(step); 144 } 145 146 try { 147 session.save(entry); 148 tx.commit(); 149 150 return step; 152 } catch (HibernateException he) { 153 log.error("Saving new workflow entry", he); 154 throw new StoreException("Saving new workflow entry", he); 155 } 156 } 157 158 public WorkflowEntry createEntry(String workflowName) throws StoreException { 159 HibernateWorkflowEntry entry = new HibernateWorkflowEntry(); 160 entry.setState(WorkflowEntry.CREATED); 161 entry.setWorkflowName(workflowName); 162 163 Transaction tx; 164 165 try { 166 tx = session.beginTransaction(); 167 session.save(entry); 168 tx.commit(); 169 } catch (HibernateException he) { 170 log.error("Saving new workflow entry", he); 171 throw new StoreException("Saving new workflow entry", he); 172 } 173 174 return entry; 175 } 176 177 public List findCurrentSteps(long entryId) throws StoreException { 178 HibernateWorkflowEntry entry; 179 180 try { 181 entry = (HibernateWorkflowEntry) session.find("FROM entry in CLASS " + HibernateWorkflowEntry.class.getName() + " WHERE entry.id = ?", new Long (entryId), Hibernate.LONG).get(0); 182 } catch (HibernateException he) { 183 log.error("Looking for entryId " + entryId, he); 184 throw new StoreException("Looking for entryId " + entryId, he); 185 } 186 187 try { 188 return session.find("FROM step IN CLASS " + HibernateCurrentStep.class.getName() + " WHERE step.entry = ?", entry, Hibernate.entity(entry.getClass())); 189 } catch (HibernateException he) { 190 log.error("Looking for step id" + entry, he); 191 throw new StoreException("Looking for step id" + entry, he); 192 } 193 } 194 195 public WorkflowEntry findEntry(long entryId) throws StoreException { 196 try { 197 List result = session.find("FROM entry IN CLASS " + HibernateWorkflowEntry.class.getName() + " WHERE entry.id = ?", new Long (entryId), Hibernate.LONG); 198 199 return (WorkflowEntry) result.get(0); 200 } catch (HibernateException he) { 201 log.error("Looking for entry " + entryId, he); 202 throw new StoreException("Loooking for entry " + entryId, he); 203 } 204 } 205 206 public List findHistorySteps(long entryId) throws StoreException { 207 HibernateWorkflowEntry entry; 208 209 try { 210 entry = (HibernateWorkflowEntry) session.find("FROM entry in CLASS " + HibernateWorkflowEntry.class.getName() + " WHERE entry.id = ?", new Long (entryId), Hibernate.LONG).get(0); 211 } catch (HibernateException he) { 212 log.error("Finding entry " + entryId, he); 213 throw new StoreException("Finding entry " + entryId, he); 214 } 215 216 try { 217 return session.find("FROM step IN CLASS " + HibernateHistoryStep.class.getName() + " WHERE step.entry = ?", entry, Hibernate.entity(entry.getClass())); 218 } catch (HibernateException he) { 219 log.error("Looking for step with entry " + entry, he); 220 throw new StoreException("Looking for step with entry " + entry, he); 221 } 222 } 223 224 public void init(Map props) throws StoreException { 225 try { 226 sessionFactory = (SessionFactory) props.get("sessionFactory"); 228 session = sessionFactory.openSession(); 229 230 } catch (HibernateException he) { 232 log.error("Setting sessionFactory", he); 233 throw new StoreException("Setting sessionFactory", he); 234 } 235 } 236 237 public Step markFinished(Step step, int actionId, Date finishDate, String status, String caller) throws StoreException { 238 HibernateCurrentStep currentStep = (HibernateCurrentStep) step; 239 240 currentStep.setActionId(actionId); 241 currentStep.setFinishDate(finishDate); 242 currentStep.setStatus(status); 243 currentStep.setCaller(caller); 244 245 try { 246 Transaction tx = session.beginTransaction(); 247 session.save(currentStep); 248 tx.commit(); 249 250 return currentStep; 251 } catch (HibernateException he) { 252 log.error("Saving current step with action " + actionId, he); 253 throw new StoreException("Saving current step with action " + actionId, he); 254 } 255 } 256 257 public void moveToHistory(Step step) throws StoreException { 258 HibernateWorkflowEntry entry; 259 260 Transaction tx; 261 262 try { 263 tx = session.beginTransaction(); 264 entry = (HibernateWorkflowEntry) session.find("FROM entry IN CLASS " + HibernateWorkflowEntry.class.getName() + " WHERE entry.id = ?", new Long (step.getEntryId()), Hibernate.LONG).get(0); 265 } catch (HibernateException he) { 266 log.error("Looking for workflow entry " + step.getEntryId(), he); 267 throw new StoreException("Looking for workflow entry " + step.getEntryId(), he); 268 } 269 270 HibernateHistoryStep hStep = new HibernateHistoryStep((HibernateStep) step); 271 272 entry.getCurrentSteps().remove(step); 273 274 if (entry.getHistorySteps() == null) { 275 ArrayList hSteps = new ArrayList(1); 276 hSteps.add(hStep); 277 entry.setHistorySteps(hSteps); 278 } else { 279 entry.getHistorySteps().add(hStep); 280 } 281 282 try { 283 session.save(hStep); 284 session.save(entry); 285 tx.commit(); 286 287 } catch (HibernateException he) { 290 log.error("Saving workflow entry " + entry.getId(), he); 291 throw new StoreException("Saving workflow entry " + entry.getId(), he); 292 } 293 } 294 295 public List query(WorkflowExpressionQuery query) throws StoreException { 296 com.opensymphony.workflow.query.Expression expression = query.getExpression(); 297 298 Criterion expr; 299 300 Class entityClass = getQueryClass(expression, null); 301 302 if (expression.isNested()) { 303 expr = buildNested((NestedExpression) expression); 304 } else { 305 expr = queryComparison((FieldExpression) expression); 306 } 307 308 Criteria criteria = session.createCriteria(entityClass); 310 criteria.add(expr); 311 312 try { 313 Set results = new HashSet(); 314 315 Iterator iter = criteria.list().iterator(); 316 317 while (iter.hasNext()) { 318 Object next = iter.next(); 319 Object item; 320 321 if (next instanceof HibernateStep) { 322 HibernateStep step = (HibernateStep) next; 323 item = new Long (step.getEntryId()); 324 } else { 325 WorkflowEntry entry = (WorkflowEntry) next; 326 item = new Long (entry.getId()); 327 } 328 329 results.add(item); 330 } 331 332 return new ArrayList(results); 333 } catch (HibernateException e) { 334 throw new StoreException("Error executing query " + expression, e); 335 } 336 } 337 338 public List query(WorkflowQuery query) throws StoreException { 339 Class entityClass; 340 341 int qtype = query.getType(); 342 343 if (qtype == 0) { 345 if (query.getLeft() != null) { 346 qtype = query.getLeft().getType(); 347 } 348 } 349 350 if (qtype == WorkflowQuery.CURRENT) { 351 entityClass = HibernateCurrentStep.class; 352 } else { 353 entityClass = HibernateHistoryStep.class; 354 } 355 356 Criteria criteria = session.createCriteria(entityClass); 357 Criterion expression = buildExpression(query); 358 criteria.add(expression); 359 360 try { 362 Set results = new HashSet(); 363 Iterator iter = criteria.list().iterator(); 364 365 while (iter.hasNext()) { 366 HibernateStep step = (HibernateStep) iter.next(); 367 results.add(new Long (step.getEntryId())); 368 } 369 370 return new ArrayList(results); 371 } catch (HibernateException e) { 372 throw new StoreException("Error executing query " + expression, e); 373 } 374 } 375 376 379 private Criterion getExpression(WorkflowQuery query) { 380 int operator = query.getOperator(); 381 382 switch (operator) { 383 case WorkflowQuery.EQUALS: 384 return Expression.eq(getFieldName(query.getField()), query.getValue()); 385 386 case WorkflowQuery.NOT_EQUALS: 387 return Expression.not(Expression.like(getFieldName(query.getField()), query.getValue())); 388 389 case WorkflowQuery.GT: 390 return Expression.gt(getFieldName(query.getField()), query.getValue()); 391 392 case WorkflowQuery.LT: 393 return Expression.lt(getFieldName(query.getField()), query.getValue()); 394 395 default: 396 return Expression.eq(getFieldName(query.getField()), query.getValue()); 397 } 398 } 399 400 406 private String getFieldName(int field) { 407 switch (field) { 408 case FieldExpression.ACTION: return "actionId"; 410 411 case FieldExpression.CALLER: 412 return "caller"; 413 414 case FieldExpression.FINISH_DATE: 415 return "finishDate"; 416 417 case FieldExpression.OWNER: 418 return "owner"; 419 420 case FieldExpression.START_DATE: 421 return "startDate"; 422 423 case FieldExpression.STEP: return "stepId"; 425 426 case FieldExpression.STATUS: 427 return "status"; 428 429 case FieldExpression.STATE: 430 return "state"; 431 432 case FieldExpression.NAME: 433 return "workflowName"; 434 435 default: 436 return "1"; 437 } 438 } 439 440 private Class getQueryClass(com.opensymphony.workflow.query.Expression expr, Collection classesCache) throws StoreException { 441 if (classesCache == null) { 442 classesCache = new HashSet(); 443 } 444 445 if (expr instanceof FieldExpression) { 446 FieldExpression fieldExpression = (FieldExpression) expr; 447 448 switch (fieldExpression.getContext()) { 449 case FieldExpression.CURRENT_STEPS: 450 classesCache.add(HibernateCurrentStep.class); 451 452 break; 453 454 case FieldExpression.HISTORY_STEPS: 455 classesCache.add(HibernateHistoryStep.class); 456 457 break; 458 459 case FieldExpression.ENTRY: 460 classesCache.add(HibernateWorkflowEntry.class); 461 462 break; 463 464 default: 465 throw new StoreException("Query for unsupported context " + fieldExpression.getContext()); 466 } 467 } else { 468 NestedExpression nestedExpression = (NestedExpression) expr; 469 470 for (int i = 0; i < nestedExpression.getExpressionCount(); i++) { 471 com.opensymphony.workflow.query.Expression expression = nestedExpression.getExpression(i); 472 473 if (expression.isNested()) { 474 classesCache.add(getQueryClass(nestedExpression.getExpression(i), classesCache)); 475 } else { 476 classesCache.add(getQueryClass(expression, classesCache)); 477 } 478 } 479 } 480 481 if (classesCache.size() > 1) { 482 throw new StoreException("Store does not support nested queries of different types (types found:" + classesCache + ")"); 483 } 484 485 return (Class ) classesCache.iterator().next(); 486 } 487 488 491 private Criterion buildExpression(WorkflowQuery query) throws StoreException { 492 if (query.getLeft() == null) { 493 if (query.getRight() == null) { 494 return getExpression(query); } else { 496 throw new StoreException("Invalid WorkflowQuery object. QueryLeft is null but QueryRight is not."); 497 } 498 } else { 499 if (query.getRight() == null) { 500 throw new StoreException("Invalid WorkflowQuery object. QueryLeft is not null but QueryRight is."); 501 } 502 503 int operator = query.getOperator(); 504 WorkflowQuery left = query.getLeft(); 505 WorkflowQuery right = query.getRight(); 506 507 switch (operator) { 508 case WorkflowQuery.AND: 509 return Expression.and(buildExpression(left), buildExpression(right)); 510 511 case WorkflowQuery.OR: 512 return Expression.or(buildExpression(left), buildExpression(right)); 513 514 case WorkflowQuery.XOR: 515 throw new StoreException("XOR Operator in Queries not supported by " + this.getClass().getName()); 516 517 default: 518 throw new StoreException("Operator '" + operator + "' is not supported by " + this.getClass().getName()); 519 } 520 } 521 } 522 523 private Criterion buildNested(NestedExpression nestedExpression) throws StoreException { 524 Criterion full = null; 525 526 for (int i = 0; i < nestedExpression.getExpressionCount(); i++) { 527 Criterion expr; 528 com.opensymphony.workflow.query.Expression expression = nestedExpression.getExpression(i); 529 530 if (expression.isNested()) { 531 expr = buildNested((NestedExpression) nestedExpression.getExpression(i)); 532 } else { 533 FieldExpression sub = (FieldExpression) nestedExpression.getExpression(i); 534 expr = queryComparison(sub); 535 536 if (sub.isNegate()) { 537 expr = Expression.not(expr); 538 } 539 } 540 541 if (full == null) { 542 full = expr; 543 } else { 544 switch (nestedExpression.getExpressionOperator()) { 545 case NestedExpression.AND: 546 full = Expression.and(full, expr); 547 548 break; 549 550 case NestedExpression.OR: 551 full = Expression.or(full, expr); 552 } 553 } 554 } 555 556 return full; 557 } 558 559 private Criterion queryComparison(FieldExpression expression) { 560 int operator = expression.getOperator(); 561 562 switch (operator) { 563 case FieldExpression.EQUALS: 564 return Expression.eq(getFieldName(expression.getField()), expression.getValue()); 565 566 case FieldExpression.NOT_EQUALS: 567 return Expression.not(Expression.like(getFieldName(expression.getField()), expression.getValue())); 568 569 case FieldExpression.GT: 570 return Expression.gt(getFieldName(expression.getField()), expression.getValue()); 571 572 case FieldExpression.LT: 573 return Expression.lt(getFieldName(expression.getField()), expression.getValue()); 574 575 default: 576 return Expression.eq(getFieldName(expression.getField()), expression.getValue()); 577 } 578 } 579 } 580 | Popular Tags |