001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.bpmscript.db;
018:
019: import java.sql.Timestamp;
020: import java.util.List;
021:
022: import javax.sql.DataSource;
023:
024: import org.bpmscript.BpmScriptException;
025: import org.bpmscript.ExecutorResult;
026: import org.bpmscript.FailedResult;
027: import org.bpmscript.IMarshaler;
028: import org.bpmscript.IPagedResult;
029: import org.bpmscript.IProcess;
030: import org.bpmscript.IProcessInstance;
031: import org.bpmscript.IProcessInstanceCallback;
032: import org.bpmscript.IProcessManager;
033: import org.bpmscript.IProcessSource;
034: import org.bpmscript.IQuery;
035: import org.bpmscript.PagedResult;
036: import org.bpmscript.PausedResult;
037: import org.bpmscript.ProcessState;
038: import org.bpmscript.XStreamMarshaler;
039: import org.hibernate.Hibernate;
040: import org.hibernate.HibernateException;
041: import org.hibernate.LockMode;
042: import org.hibernate.Query;
043: import org.hibernate.Session;
044: import org.hibernate.SessionFactory;
045: import org.hibernate.Transaction;
046:
047: public class HnProcessManager implements IProcessManager {
048:
049: private final org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
050: .getLog(HibernateProcessManager.class);
051:
052: private IMarshaler marshaler = new XStreamMarshaler();
053: private SessionFactory sessionFactory = null;
054: private DataSource dataSource = null;
055:
056: public static interface HnCallback<T, E extends Throwable> {
057: T execute(Session session) throws E;
058: }
059:
060: public static interface ExceptionFactory<E extends Throwable> {
061: public E createException(String message, Throwable t);
062: }
063:
064: public static class BpmScriptExceptionFactory implements
065: ExceptionFactory<BpmScriptException> {
066:
067: public static final BpmScriptExceptionFactory DEFAULT_FACTORY = new BpmScriptExceptionFactory();
068:
069: public BpmScriptException createException(String message,
070: Throwable t) {
071: if (t instanceof BpmScriptException) {
072: return (BpmScriptException) t;
073: }
074: return new BpmScriptException(message, t);
075: }
076:
077: }
078:
079: public static class HnTemplate<T, E extends Throwable> {
080:
081: private SessionFactory sessionFactory = null;
082: private DataSource dataSource = null;
083: private ExceptionFactory<E> exceptionFactory = null;
084:
085: public HnTemplate(SessionFactory sessionFactory,
086: DataSource dataSource,
087: ExceptionFactory<E> exceptionFactory) {
088: super ();
089: this .sessionFactory = sessionFactory;
090: this .dataSource = dataSource;
091: this .exceptionFactory = exceptionFactory;
092: }
093:
094: public T execute(HnCallback<T, E> callback) throws E {
095: Session session = null;
096: Transaction tx = null;
097: try {
098: session = sessionFactory.openSession(dataSource
099: .getConnection());
100: tx = session.beginTransaction();
101: T result = callback.execute(session);
102: tx.commit();
103: return result;
104: } catch (RuntimeException e) {
105: tx.rollback();
106: throw e;
107: } catch (Exception e) {
108: tx.rollback();
109: throw exceptionFactory.createException(e.getMessage(),
110: e);
111: } finally {
112: session.close();
113: }
114: }
115: }
116:
117: public <T> HnTemplate<T, BpmScriptException> getHnTemplate() {
118: return new HnTemplate<T, BpmScriptException>(sessionFactory,
119: dataSource, BpmScriptExceptionFactory.DEFAULT_FACTORY);
120: }
121:
122: public String createProcessInstance(
123: final String parentProcessInstanceId,
124: final String processName, final String operation)
125: throws BpmScriptException {
126:
127: HnTemplate<String, BpmScriptException> hnTemplate = getHnTemplate();
128: return hnTemplate
129: .execute(new HnCallback<String, BpmScriptException>() {
130:
131: public String execute(Session session)
132: throws HibernateException,
133: BpmScriptException {
134: Query query = session
135: .createQuery("from org.bpmscript.db.DbProcess process where process.name = :processName and process.primaryProcess = true");
136: query.setString("processName", processName);
137: List list = query.list();
138: if (list.size() == 1) {
139: DbProcess process = (DbProcess) list.get(0);
140: DbProcessInstance processInstance = new DbProcessInstance();
141: processInstance
142: .setCreationDate(new Timestamp(
143: System.currentTimeMillis()));
144: processInstance.setProcess(process);
145: processInstance.setOperation(operation);
146: processInstance
147: .setProcessInstanceState(getProcessInstanceState(ProcessState.CREATED
148: .name()));
149: processInstance
150: .setParentProcessInstanceId(parentProcessInstanceId);
151: session.save(processInstance);
152: return processInstance.getId();
153: } else {
154: throw new BpmScriptException(
155: "wrong number of processes returned "
156: + list.size());
157: }
158: }
159:
160: });
161: }
162:
163: public DbProcessInstanceState getProcessInstanceState(
164: final String name) throws BpmScriptException {
165: HnTemplate<DbProcessInstanceState, BpmScriptException> hnTemplate = getHnTemplate();
166: return hnTemplate
167: .execute(new HnCallback<DbProcessInstanceState, BpmScriptException>() {
168:
169: public DbProcessInstanceState execute(
170: Session session) throws HibernateException,
171: BpmScriptException {
172: Query query = session
173: .createQuery("from org.bpmscript.db.DbProcessInstanceState processState where processState.name = :name");
174: query.setString("name", name);
175: List list = query.list();
176: if (list.size() == 1) {
177: return (DbProcessInstanceState) list.get(0);
178: } else {
179: throw new BpmScriptException(
180: "wrong number of process states returned "
181: + list.size());
182: }
183: }
184: });
185: }
186:
187: public IProcessSource getMainSource(final String processId)
188: throws BpmScriptException {
189: HnTemplate<IProcessSource, BpmScriptException> hnTemplate = getHnTemplate();
190: return hnTemplate
191: .execute(new HnCallback<IProcessSource, BpmScriptException>() {
192:
193: public IProcessSource execute(Session session)
194: throws HibernateException,
195: BpmScriptException {
196: Query query = session
197: .createQuery("from org.bpmscript.db.DbProcessSource source where source.processId = :processId and source.main = true");
198: query.setString("processId", processId);
199: List list = query.list();
200: if (list.size() == 1) {
201: return (IProcessSource) list.get(0);
202: } else {
203: throw new BpmScriptException(
204: "wrong number of process states returned "
205: + list.size());
206: }
207: }
208: });
209: }
210:
211: @SuppressWarnings("unchecked")
212: public IPagedResult<IProcessInstance> getProcessInstances(
213: final IQuery query) throws BpmScriptException {
214:
215: HnTemplate<List<IProcessInstance>, BpmScriptException> hnTemplate = getHnTemplate();
216: List<IProcessInstance> processInstances = hnTemplate
217: .execute(new HnCallback<List<IProcessInstance>, BpmScriptException>() {
218:
219: public List<IProcessInstance> execute(
220: Session session) throws HibernateException,
221: BpmScriptException {
222: Query hibernateQuery = null;
223: String filter = query.getFilter();
224: if (filter != null) {
225: hibernateQuery = session
226: .createQuery("from org.bpmscript.db.DbProcessInstance instance where instance.process.name like '%"
227: + filter.trim() + "%'");
228: } else {
229: hibernateQuery = session
230: .createQuery("from org.bpmscript.db.DbProcessInstance instance");
231: }
232: hibernateQuery.setLockMode("instance",
233: LockMode.READ);
234: if (query.getFirstResult() >= 0) {
235: hibernateQuery.setFirstResult(query
236: .getFirstResult());
237: }
238: if (query.getMaxResults() >= 0) {
239: hibernateQuery.setMaxResults(query
240: .getMaxResults() + 1);
241: }
242: List result = hibernateQuery.list();
243: return result;
244: }
245: });
246:
247: boolean more = false;
248: if (query.getMaxResults() >= 0) {
249: if (processInstances.size() > query.getMaxResults()) {
250: processInstances.remove(processInstances.size() - 1);
251: more = true;
252: }
253: }
254: addStackTrace(processInstances);
255: return new PagedResult<IProcessInstance>(processInstances,
256: more, -1);
257: }
258:
259: private void addStackTrace(List<IProcessInstance> processInstances) {
260: if (processInstances != null) {
261: for (IProcessInstance instance : processInstances) {
262: addStackTrace(instance);
263: }
264: }
265: }
266:
267: private void addStackTrace(IProcessInstance instance) {
268: DbProcessInstance dbProcessInstance = ((DbProcessInstance) instance);
269: dbProcessInstance
270: .setStackTraceElements((StackTraceElement[]) marshaler
271: .unmarshal(dbProcessInstance
272: .getSerializedStack()));
273: dbProcessInstance.setThrowable((Throwable) marshaler
274: .unmarshal(dbProcessInstance.getSerializedThrowable()));
275: }
276:
277: @SuppressWarnings("unchecked")
278: public List<IProcess> getPrimaryProcesses()
279: throws BpmScriptException {
280:
281: HnTemplate<List<IProcess>, BpmScriptException> hnTemplate = getHnTemplate();
282: return hnTemplate
283: .execute(new HnCallback<List<IProcess>, BpmScriptException>() {
284:
285: public List<IProcess> execute(Session session)
286: throws HibernateException,
287: BpmScriptException {
288: Query query = session
289: .createQuery("from org.bpmscript.db.DbProcess process where process.primaryProcess = true");
290: return query.list();
291: }
292: });
293:
294: }
295:
296: public IProcess getProcess(final String processId)
297: throws BpmScriptException {
298: HnTemplate<IProcess, BpmScriptException> hnTemplate = getHnTemplate();
299: return hnTemplate
300: .execute(new HnCallback<IProcess, BpmScriptException>() {
301:
302: public IProcess execute(Session session)
303: throws HibernateException,
304: BpmScriptException {
305: IProcess process = (IProcess) session.load(
306: DbProcess.class, processId);
307: Hibernate.initialize(process);
308: return process;
309: }
310: });
311: }
312:
313: @SuppressWarnings("unchecked")
314: public List<IProcessSource> getProcessSources(final String processId)
315: throws BpmScriptException {
316:
317: HnTemplate<List<IProcessSource>, BpmScriptException> hnTemplate = getHnTemplate();
318: return hnTemplate
319: .execute(new HnCallback<List<IProcessSource>, BpmScriptException>() {
320:
321: public List<IProcessSource> execute(Session session)
322: throws HibernateException,
323: BpmScriptException {
324: Query query = session
325: .createQuery("from org.bpmscript.db.DbProcessSource source where source.processId = :processId");
326: query.setString("processId", processId);
327: return query.list();
328: }
329: });
330:
331: }
332:
333: public void setProcessAsPrimary(final String processId)
334: throws BpmScriptException {
335: HnTemplate<Object, BpmScriptException> hnTemplate = getHnTemplate();
336: hnTemplate
337: .execute(new HnCallback<Object, BpmScriptException>() {
338:
339: public Object execute(Session session)
340: throws HibernateException,
341: BpmScriptException {
342: DbProcess process = (DbProcess) session.load(
343: DbProcess.class, processId);
344: process.setPrimaryProcess(true);
345: Query query = session
346: .createQuery("from org.bpmscript.db.DbProcess process where process.name = :processName and process.primaryProcess = true");
347: List list = query.list();
348: if (list.size() == 0) {
349: session.saveOrUpdate(process);
350: } else if (list.size() == 1) {
351: DbProcess oldPrimaryProcess = (DbProcess) list
352: .get(0);
353: oldPrimaryProcess.setPrimaryProcess(false);
354: session.saveOrUpdate(oldPrimaryProcess);
355: session.saveOrUpdate(process);
356: } else {
357: throw new BpmScriptException(
358: "wrong number of processes returned "
359: + list.size());
360: }
361: return null;
362: }
363: });
364: }
365:
366: public String createProcess(final String source, final String name,
367: final boolean pinned) throws BpmScriptException {
368: HnTemplate<String, BpmScriptException> hnTemplate = getHnTemplate();
369: return hnTemplate
370: .execute(new HnCallback<String, BpmScriptException>() {
371:
372: public String execute(Session session)
373: throws HibernateException,
374: BpmScriptException {
375: DbProcess dbProcess = new DbProcess();
376: dbProcess.setSource(source);
377: dbProcess.setName(name);
378: dbProcess.setPrimaryProcess(false);
379: dbProcess.setPinned(pinned);
380: dbProcess.setCreationDate(new Timestamp(System
381: .currentTimeMillis()));
382: session.save(dbProcess);
383: return dbProcess.getId();
384: }
385: });
386:
387: }
388:
389: public void addSourceToProcess(final String processId,
390: final String name, final String source, final boolean main)
391: throws BpmScriptException {
392: HnTemplate<Object, BpmScriptException> hnTemplate = getHnTemplate();
393: hnTemplate
394: .execute(new HnCallback<Object, BpmScriptException>() {
395:
396: public Object execute(Session session)
397: throws HibernateException,
398: BpmScriptException {
399: DbProcessSource processSource = new DbProcessSource();
400: processSource.setCreationDate(new Timestamp(
401: System.currentTimeMillis()));
402: processSource.setMain(main);
403: processSource.setProcessId(processId);
404: processSource.setSource(source);
405: processSource.setName(name);
406: processSource.setCreationDate(new Timestamp(
407: System.currentTimeMillis()));
408: session.save(processSource);
409: return null;
410: }
411: });
412: }
413:
414: public IProcessInstance getProcessInstance(
415: final String processInstanceId) throws BpmScriptException {
416:
417: HnTemplate<DbProcessInstance, BpmScriptException> hnTemplate = getHnTemplate();
418: return hnTemplate
419: .execute(new HnCallback<DbProcessInstance, BpmScriptException>() {
420:
421: public DbProcessInstance execute(Session session)
422: throws HibernateException,
423: BpmScriptException {
424: DbProcessInstance processInstance = (DbProcessInstance) session
425: .load(DbProcessInstance.class,
426: processInstanceId);
427: Hibernate.initialize(processInstance);
428: return processInstance;
429: }
430: });
431:
432: }
433:
434: public IProcessSource getProcessSource(final String processSourceId)
435: throws BpmScriptException {
436:
437: HnTemplate<IProcessSource, BpmScriptException> hnTemplate = getHnTemplate();
438: return hnTemplate
439: .execute(new HnCallback<IProcessSource, BpmScriptException>() {
440:
441: public IProcessSource execute(Session session)
442: throws HibernateException,
443: BpmScriptException {
444: IProcessSource processSource = (IProcessSource) session
445: .load(DbProcessSource.class,
446: processSourceId);
447: Hibernate.initialize(processSource);
448: return processSource;
449: }
450: });
451: }
452:
453: @SuppressWarnings("unchecked")
454: public List<IProcessInstance> getChildProcessInstances(
455: final String processInstanceId) throws BpmScriptException {
456:
457: HnTemplate<List<IProcessInstance>, BpmScriptException> hnTemplate = getHnTemplate();
458: return hnTemplate
459: .execute(new HnCallback<List<IProcessInstance>, BpmScriptException>() {
460:
461: public List<IProcessInstance> execute(
462: Session session) throws HibernateException,
463: BpmScriptException {
464: Query query = session
465: .createQuery("from org.bpmscript.db.DbProcessInstance instance where instance.parentProcessInstanceId = :parentProcessId");
466: query.setString("parentProcessId",
467: processInstanceId);
468: return query.list();
469: }
470: });
471:
472: }
473:
474: public IProcess getPrimaryProcess(final String name)
475: throws BpmScriptException {
476:
477: HnTemplate<IProcess, BpmScriptException> hnTemplate = getHnTemplate();
478: return hnTemplate
479: .execute(new HnCallback<IProcess, BpmScriptException>() {
480:
481: public IProcess execute(Session session)
482: throws HibernateException,
483: BpmScriptException {
484: Query query = session
485: .createQuery("from org.bpmscript.db.DbProcess process where process.primaryProcess = true and process.name = :name");
486: query.setString("name", name);
487: List list = query.list();
488: if (list.size() == 1) {
489: return (IProcess) list.get(0);
490: } else {
491: throw new BpmScriptException(
492: "wrong number of processes returned "
493: + list.size());
494: }
495: }
496: });
497:
498: }
499:
500: public ExecutorResult doWithProcessInstance(
501: final String processInstanceId,
502: final IProcessInstanceCallback callback) throws Throwable {
503: try {
504:
505: HnTemplate<ExecutorResult, BpmScriptException> hnTemplate = getHnTemplate();
506: return hnTemplate
507: .execute(new HnCallback<ExecutorResult, BpmScriptException>() {
508: public ExecutorResult execute(Session session)
509: throws HibernateException,
510: BpmScriptException {
511: ExecutorResult executorResult = null;
512: try {
513: // TODO: set running and created states
514: DbProcessInstance processInstance = (DbProcessInstance) session
515: .load(DbProcessInstance.class,
516: processInstanceId,
517: LockMode.UPGRADE);
518: log.debug("running "
519: + processInstanceId
520: + " "
521: + processInstance.getProcess()
522: .getName()
523: + " "
524: + processInstance
525: .getOperation());
526: executorResult = callback
527: .execute(processInstance);
528: if (executorResult.getProcessState() == ProcessState.PAUSED) {
529: PausedResult pausedResult = ((PausedResult) executorResult);
530: processInstance
531: .setProcessInstanceState(getProcessInstanceState(ProcessState.PAUSED
532: .name()));
533: processInstance
534: .setContinuation(pausedResult
535: .getContinuation());
536: processInstance
537: .setSerializedStack(marshaler
538: .marshal(pausedResult
539: .getStackTraceElements()));
540: processInstance
541: .setSerializedThrowable(null);
542: session.update(processInstance);
543: } else if (executorResult
544: .getProcessState() == ProcessState.COMPLETED) {
545: processInstance
546: .setProcessInstanceState(getProcessInstanceState(ProcessState.COMPLETED
547: .name()));
548: processInstance
549: .setContinuation(null);
550: processInstance
551: .setSerializedStack(null);
552: processInstance
553: .setSerializedThrowable(null);
554: session.update(processInstance);
555: } else if (executorResult
556: .getProcessState() == ProcessState.FAILED) {
557: FailedResult failedResult = ((FailedResult) executorResult);
558: Throwable throwable = failedResult
559: .getThrowable();
560: processInstance
561: .setProcessInstanceState(getProcessInstanceState(ProcessState.FAILED
562: .name()));
563: processInstance
564: .setSerializedStack(marshaler
565: .marshal(failedResult
566: .getStackTraceElements()));
567: processInstance
568: .setSerializedThrowable(marshaler
569: .marshal(throwable));
570: session.update(processInstance);
571: throw throwable;
572: } else {
573: session.update(processInstance);
574: }
575: log.debug("finished running "
576: + processInstanceId
577: + " "
578: + processInstance.getProcess()
579: .getName()
580: + " "
581: + processInstance
582: .getOperation());
583: } catch (Throwable t) {
584: throw new RuntimeException(t);
585: }
586: return executorResult;
587: }
588: });
589:
590: } catch (RuntimeException e) {
591: if (e.getCause() != null) {
592: throw e.getCause();
593: } else {
594: throw e;
595: }
596: }
597: }
598:
599: public void setDataSource(DataSource dataSource) {
600: this .dataSource = dataSource;
601: }
602:
603: public void setSessionFactory(SessionFactory sessionFactory) {
604: this .sessionFactory = sessionFactory;
605: }
606:
607: public List<IProcess> getProcessVersions(String name)
608: throws BpmScriptException {
609: // TODO Auto-generated method stub
610: return null;
611: }
612: }
|