0001: /*
0002: * $Id: Controller.java 1296 2007-08-09 13:25:14Z hengels $
0003: * (c) Copyright 2004 con:cern development team.
0004: *
0005: * This file is part of con:cern (http://concern.sf.net).
0006: *
0007: * con:cern is free software; you can redistribute it and/or modify
0008: * it under the terms of the GNU Lesser General Public License
0009: * as published by the Free Software Foundation; either version 2.1
0010: * of the License, or (at your option) any later version.
0011: *
0012: * Please see COPYING for the complete licence.
0013: */
0014: /* $Id $ */
0015: package org.concern.controller;
0016:
0017: import org.hibernate.Filter;
0018: import org.hibernate.HibernateException;
0019: import org.hibernate.LockMode;
0020: import org.hibernate.Query;
0021: import org.hibernate.SessionFactory;
0022: import org.hibernate.Session;
0023: import org.concern.*;
0024: import org.concern.Loader;
0025: import org.concern.Log;
0026: import org.concern.model.Process;
0027: import org.apache.commons.logging.LogFactory;
0028:
0029: import javax.transaction.*;
0030: import java.util.*;
0031:
0032: /**
0033: * @author hengels
0034: * @version $Revision: 1296 $
0035: * @noinspection ALL
0036: */
0037: // NOTE: @noinspection ALL is to prevent IntelliJ IDEA from displaying
0038: // (many!) warnings if you happen to be in a project with 1.5 syntax
0039: // enabled.
0040: public class Controller implements org.concern.Controller {
0041: private static org.apache.commons.logging.Log LOG = LogFactory
0042: .getLog(Controller.class);
0043: private static final NodeNameComparator NODE_NAME_COMPARATOR = new NodeNameComparator();
0044:
0045: private String processName;
0046: private Process processDescription;
0047: private ResourceLocator resourceLocator;
0048: private Configuration configuration;
0049: private Loader loader;
0050: private long timerInterval = 10000;
0051: protected Map environment = new HashMap();
0052:
0053: protected Map<String, Actor> actorsByName = new HashMap<String, Actor>();
0054: protected Map<String, Activity> activitiesByName = new HashMap();
0055: protected Map<String, Listener> listenersByName = new HashMap();
0056: protected Map<String, Event> eventsByName = new HashMap<String, Event>();
0057: protected Map<String, Condition> conditionsByName = new HashMap<String, Condition>();
0058: private List<Actor> actors = Collections.EMPTY_LIST;
0059: private List<Activity> activities = Collections.EMPTY_LIST;
0060: private List<Listener> listeners = Collections.EMPTY_LIST;
0061: private List<Event> events = Collections.EMPTY_LIST;
0062: private List<Condition> conditions = Collections.EMPTY_LIST;
0063:
0064: Sessions sessions = new DefaultSessions();
0065:
0066: protected SessionFactory sessionFactory;
0067: protected TransactionManager transactionManager = new NoTransactionManager(
0068: sessions);
0069: private Transactions transactions = new Transactions(
0070: transactionManager);
0071: private java.util.Timer timer;
0072: private TimeoutTask timeoutTask;
0073:
0074: public Controller() {
0075: }
0076:
0077: public Controller(String processName) {
0078: this .processName = processName;
0079: }
0080:
0081: public String getProcessName() {
0082: return processName;
0083: }
0084:
0085: public void setProcessName(String processName) {
0086: this .processName = processName;
0087: }
0088:
0089: public Process getProcess() {
0090: return processDescription;
0091: }
0092:
0093: public void setProcessDescription(Process processDescription) {
0094: this .processDescription = processDescription;
0095: if (processName == null)
0096: processName = processDescription.getName();
0097: }
0098:
0099: public void setConfiguration(Configuration configuration) {
0100: this .configuration = configuration;
0101: }
0102:
0103: public long getTimerInterval() {
0104: return timerInterval;
0105: }
0106:
0107: public void setTimerInterval(long timerInterval) {
0108: this .timerInterval = timerInterval;
0109: if (timer == null)
0110: return;
0111:
0112: if (timeoutTask != null)
0113: timeoutTask.cancel();
0114: timeoutTask = new TimeoutTask();
0115: timer.schedule(timeoutTask, getTimerInterval(),
0116: getTimerInterval());
0117: }
0118:
0119: public Map getEnvironment() {
0120: return environment;
0121: }
0122:
0123: public void setEnvironment(Map environment) {
0124: this .environment = environment;
0125: }
0126:
0127: public ResourceLocator getResourceLocator() {
0128: return resourceLocator;
0129: }
0130:
0131: public void setResourceLocator(ResourceLocator resourceLocator) {
0132: resourceLocator.setController(this );
0133: this .resourceLocator = resourceLocator;
0134: }
0135:
0136: public List<Actor> getActors() {
0137: return actors;
0138: }
0139:
0140: public void setActors(List<Actor> actors) {
0141: this .actors = actors;
0142: Collections.sort(this .actors, NODE_NAME_COMPARATOR);
0143: actorsByName.clear();
0144: for (Iterator<Actor> iterator = actors.iterator(); iterator
0145: .hasNext();) {
0146: Actor actor = iterator.next();
0147: actor.setController(this );
0148: actorsByName.put(actor.getName(), actor);
0149: }
0150: }
0151:
0152: public List<Activity> getActivities() {
0153: return activities;
0154: }
0155:
0156: public void setActivities(List<Activity> activities) {
0157: this .activities = activities;
0158: Collections.sort(this .activities, NODE_NAME_COMPARATOR);
0159: activitiesByName.clear();
0160: for (Iterator<Activity> iterator = activities.iterator(); iterator
0161: .hasNext();) {
0162: Activity activity = iterator.next();
0163: activity.setController(this );
0164: activitiesByName.put(activity.getName(), activity);
0165: }
0166: }
0167:
0168: public List<Listener> getListeners() {
0169: return listeners;
0170: }
0171:
0172: public void setListeners(List<Listener> listeners) {
0173: this .listeners = listeners;
0174: Collections.sort(this .listeners, NODE_NAME_COMPARATOR);
0175: listenersByName.clear();
0176: for (Iterator<Listener> iterator = listeners.iterator(); iterator
0177: .hasNext();) {
0178: Listener listener = iterator.next();
0179: listener.setController(this );
0180: listenersByName.put(listener.getName(), listener);
0181: }
0182: }
0183:
0184: public List<Event> getEvents() {
0185: return events;
0186: }
0187:
0188: public void setEvents(List<Event> events) {
0189: this .events = events;
0190: Collections.sort(this .events, NODE_NAME_COMPARATOR);
0191: eventsByName.clear();
0192: for (Iterator<Event> iterator = events.iterator(); iterator
0193: .hasNext();) {
0194: Event event = iterator.next();
0195: event.setController(this );
0196: eventsByName.put(event.getName(), event);
0197: }
0198: }
0199:
0200: public List<Condition> getConditions() {
0201: return conditions;
0202: }
0203:
0204: public void setConditions(List<Condition> conditions) {
0205: this .conditions = conditions;
0206: Collections.sort(this .conditions, NODE_NAME_COMPARATOR);
0207: conditionsByName.clear();
0208: for (Iterator<Condition> iterator = conditions.iterator(); iterator
0209: .hasNext();) {
0210: Condition condition = iterator.next();
0211: condition.setController(this );
0212: conditionsByName.put(condition.getName(), condition);
0213: }
0214: }
0215:
0216: public Condition getCondition(String name) {
0217: return conditionsByName.get(name);
0218: }
0219:
0220: void timeout() {
0221: Set list = Collections.EMPTY_SET;
0222: try {
0223: transactions.begin();
0224: Query query = sessions.getSession().getNamedQuery(
0225: "subject.byTimeout");
0226: query.setLong("now", System.currentTimeMillis());
0227: sessions.getSession().enableFilter("process").setParameter(
0228: "process", processName);
0229: list = new HashSet(query.list());
0230: } catch (HibernateException e) {
0231: LOG.error("timeout", e);
0232: } finally {
0233: try {
0234: transactions.commit();
0235: } catch (ControllerException t) {
0236: t.printStackTrace();
0237: throw t;
0238: }
0239: }
0240: for (Iterator iterator = list.iterator(); iterator.hasNext();) {
0241: Subject subject = (Subject) iterator.next();
0242: while (process(subject))
0243: ;
0244: }
0245: }
0246:
0247: public Integer createSubject(String userValue)
0248: throws SubjectCreationException, ControllerException {
0249: Subject subject = new Subject(userValue);
0250: subject.setProcess(processName);
0251: try {
0252: transactions.beginRequired();
0253: Map map = loader.formatSubjectLines(loader.load(subject
0254: .getUserValue()));
0255: for (Iterator iterator = map.entrySet().iterator(); iterator
0256: .hasNext();) {
0257: Map.Entry entry = (Map.Entry) iterator.next();
0258: subject.getSubjectLines().add(
0259: new SubjectLine((String) entry.getKey(),
0260: (String) entry.getValue()));
0261: }
0262: subject.setOriginator(loader.getOriginator(loader
0263: .load(subject.getUserValue())));
0264: Logs.logCreated(subject);
0265: sessions.getSession().save(subject);
0266: LOG.debug("CREATE " + userValue);
0267: return subject.getId();
0268: } catch (HibernateException e) {
0269: transactions.setRollbackOnly();
0270: LOG.error(userValue, e);
0271: throw new SubjectCreationException(e.getMessage());
0272: } catch (SubjectNotFoundException e) {
0273: LOG.error(userValue, e);
0274: throw new ControllerException(e.getMessage());
0275: } catch (RuntimeException e) {
0276: LOG.error(userValue, e);
0277: throw new ControllerException(e.getMessage());
0278: } finally {
0279: try {
0280: transactions.endRequired();
0281: } catch (ControllerException t) {
0282: t.printStackTrace();
0283: throw t;
0284: }
0285: }
0286: }
0287:
0288: public boolean isKnownSubject(String userValue)
0289: throws ControllerException {
0290: try {
0291: transactions.beginRequired();
0292: return findSubject(userValue, null) != null;
0293: } catch (HibernateException e) {
0294: LOG.error(userValue, e);
0295: throw new ControllerException(e.getMessage());
0296: } catch (RuntimeException e) {
0297: LOG.error(userValue, e);
0298: throw new ControllerException(e.getMessage());
0299: } finally {
0300: try {
0301: transactions.endRequired();
0302: } catch (ControllerException t) {
0303: t.printStackTrace();
0304: throw t;
0305: }
0306: }
0307: }
0308:
0309: public void lockSubject(String userValue)
0310: throws UnknownSubjectException, ControllerException {
0311: try {
0312: transactions.beginRequired();
0313: getSubject(userValue, LockMode.UPGRADE);
0314: } catch (HibernateException e) {
0315: LOG.error(userValue, e);
0316: throw new ControllerException(e.getMessage());
0317: } catch (RuntimeException e) {
0318: LOG.error(userValue, e);
0319: throw new ControllerException(e.getMessage());
0320: } finally {
0321: try {
0322: transactions.endRequired();
0323: } catch (ControllerException t) {
0324: t.printStackTrace();
0325: throw t;
0326: }
0327: }
0328: }
0329:
0330: public void destroySubject(String userValue)
0331: throws UnknownSubjectException, ControllerException {
0332: try {
0333: transactions.beginRequired();
0334: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0335: subject.setState(STATE_DESTROYED);
0336: subject.getEnlistments().add(
0337: new Enlistment("DESTROY", System
0338: .currentTimeMillis()));
0339: } catch (HibernateException e) {
0340: LOG.error(userValue, e);
0341: throw new ControllerException(e.getMessage());
0342: } finally {
0343: try {
0344: transactions.endRequired();
0345: } catch (ControllerException t) {
0346: t.printStackTrace();
0347: throw t;
0348: }
0349: }
0350: }
0351:
0352: public void reviveSubject(String userValue)
0353: throws UnknownSubjectException, ControllerException {
0354: try {
0355: transactions.beginRequired();
0356: Query query = sessions.getSession().getNamedQuery(
0357: "archive.byUserValue");
0358: query.setString("userValue", userValue);
0359: ArchiveSubject archiveSubject = (ArchiveSubject) query
0360: .uniqueResult();
0361:
0362: Subject subject = new Subject();
0363: subject.setProcess(archiveSubject.getProcess());
0364: subject.setUserValue(archiveSubject.getUserValue());
0365: subject.setOriginator(archiveSubject.getOriginator());
0366: subject.setCreated(archiveSubject.getCreated());
0367:
0368: Set subjectLines = subject.getSubjectLines();
0369: for (Iterator iterator = archiveSubject.getSubjectLines()
0370: .iterator(); iterator.hasNext();) {
0371: ArchiveSubjectLine archiveSubjectLine = (ArchiveSubjectLine) iterator
0372: .next();
0373: SubjectLine subjectLine = new SubjectLine();
0374: subjectLine.setLanguage(archiveSubjectLine
0375: .getLanguage());
0376: subjectLine.setLine(archiveSubjectLine.getLine());
0377: subjectLines.add(subjectLine);
0378: }
0379:
0380: List logs = subject.getLogs();
0381: for (Iterator iterator = archiveSubject.getLogs()
0382: .iterator(); iterator.hasNext();) {
0383: ArchiveLog archiveLog = (ArchiveLog) iterator.next();
0384: org.concern.controller.Log log = new org.concern.controller.Log();
0385: log.setActivity(archiveLog.getActivity());
0386: log.setSuccess(archiveLog.isSuccess());
0387: log.setMessage(archiveLog.getMessage());
0388: log.setDetails(archiveLog.getDetails());
0389: log.setTimestamp(archiveLog.getTimestamp());
0390: log
0391: .setAnnotations(archiveLog.getAnnotations() != null ? new HashMap(
0392: archiveLog.getAnnotations())
0393: : null);
0394: log.setSubject(subject);
0395: logs.add(log);
0396: }
0397: Logs.logRevived(subject);
0398: sessions.getSession().save(subject);
0399: sessions.getSession().delete(archiveSubject);
0400: } catch (HibernateException e) {
0401: LOG.error(userValue, e);
0402: throw new ControllerException(e.getMessage());
0403: } catch (RuntimeException e) {
0404: LOG.error(userValue, e);
0405: throw new ControllerException(e.getMessage());
0406: } finally {
0407: try {
0408: transactions.endRequired();
0409: } catch (ControllerException t) {
0410: t.printStackTrace();
0411: throw t;
0412: }
0413: }
0414: }
0415:
0416: public void suspendSubject(String userValue)
0417: throws UnknownSubjectException, ControllerException {
0418: try {
0419: transactions.beginRequired();
0420: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0421: subject.setState(STATE_SUSPENDED);
0422: Logs.logSuspended(subject);
0423: } catch (HibernateException e) {
0424: LOG.error(userValue, e);
0425: throw new ControllerException(e.getMessage());
0426: } catch (RuntimeException e) {
0427: LOG.error(userValue, e);
0428: throw new ControllerException(e.getMessage());
0429: } finally {
0430: try {
0431: transactions.endRequired();
0432: } catch (ControllerException t) {
0433: t.printStackTrace();
0434: throw t;
0435: }
0436: }
0437: }
0438:
0439: public void resumeSubject(String userValue)
0440: throws UnknownSubjectException, ControllerException {
0441: try {
0442: transactions.beginRequired();
0443: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0444: subject.setState(STATE_RUNNING);
0445: Logs.logResumed(subject);
0446: } catch (HibernateException e) {
0447: LOG.error(userValue, e);
0448: throw new ControllerException(e.getMessage());
0449: } finally {
0450: try {
0451: transactions.endRequired();
0452: } catch (ControllerException t) {
0453: t.printStackTrace();
0454: throw t;
0455: }
0456: }
0457: }
0458:
0459: public void announceSubject(String userValue)
0460: throws UnknownSubjectException, ControllerException {
0461: if (userValue == null)
0462: throw new IllegalArgumentException("null not allowed");
0463:
0464: scheduleAnnouncement(userValue, 0);
0465: }
0466:
0467: public void scheduleAnnouncement(String userValue, long duration)
0468: throws UnknownSubjectException, ControllerException {
0469: try {
0470: transactions.beginRequired();
0471: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0472: long when = System.currentTimeMillis() + duration * 1000;
0473: subject.getEnlistments().add(
0474: new Enlistment("EVALUATE", when));
0475: fine("ANNOUNCED", "CHANGE", userValue);
0476: } catch (HibernateException e) {
0477: LOG.error(userValue, e);
0478: throw new ControllerException(e.getMessage());
0479: } catch (RuntimeException e) {
0480: LOG.error(userValue, e);
0481: throw new ControllerException(e.getMessage());
0482: } finally {
0483: try {
0484: transactions.endRequired();
0485: } catch (ControllerException t) {
0486: t.printStackTrace();
0487: throw t;
0488: }
0489: }
0490: }
0491:
0492: public void log(org.concern.Log log)
0493: throws UnknownSubjectException, ControllerException {
0494: try {
0495: transactions.beginRequired();
0496: Subject subject = getSubject(log.getUserValue(),
0497: LockMode.UPGRADE);
0498: Logs.log(subject, log);
0499: fine("LOG", "-", log.getUserValue());
0500: } catch (UnknownSubjectException e) {
0501: throw e;
0502: } catch (RuntimeException e) {
0503: LOG.error(log, e);
0504: throw new ControllerException(e.getMessage());
0505: } finally {
0506: try {
0507: transactions.endRequired();
0508: } catch (ControllerException t) {
0509: t.printStackTrace();
0510: throw t;
0511: }
0512: }
0513: }
0514:
0515: // TODO: select from archive if state is STATE_DESTROYED
0516: public List<String> getSubjects(int state)
0517: throws ControllerException {
0518: List<String> list = new ArrayList<String>();
0519: try {
0520: transactions.beginRequired();
0521: Query query = sessions.getSession().getNamedQuery(
0522: "subject.all");
0523: query.setInteger("state", state);
0524: Filter filter = sessions.getSession().enableFilter(
0525: "process");
0526: filter.setParameter("process", processName);
0527:
0528: List subjects = query.list();
0529: for (Iterator iterator = subjects.iterator(); iterator
0530: .hasNext();) {
0531: Subject subject = (Subject) iterator.next();
0532: list.add(subject.getUserValue());
0533: }
0534: return list;
0535: } catch (HibernateException e) {
0536: LOG.error(state, e);
0537: throw new ControllerException(e.getMessage());
0538: } finally {
0539: try {
0540: transactions.endRequired();
0541: } catch (ControllerException t) {
0542: t.printStackTrace();
0543: throw t;
0544: }
0545: }
0546: }
0547:
0548: protected Subject getSubject(String userValue, LockMode lockMode)
0549: throws HibernateException, UnknownSubjectException {
0550: Subject subject = findSubject(userValue, lockMode);
0551: if (subject == null)
0552: throw new UnknownSubjectException(userValue);
0553: return subject;
0554: }
0555:
0556: protected Subject findSubject(String userValue, LockMode lockMode)
0557: throws HibernateException {
0558: Query query = sessions.getSession().getNamedQuery(
0559: "subject.byUserValue");
0560: query.setString("userValue", userValue);
0561: if (lockMode != null) {
0562: query.setLockMode("subject", lockMode);
0563: }
0564: sessions.getSession().enableFilter("process").setParameter(
0565: "process", processName);
0566: return (Subject) query.uniqueResult();
0567: }
0568:
0569: public List<String> getEnlistments(String userValue)
0570: throws UnknownSubjectException, ControllerException {
0571: List<String> list = new ArrayList<String>();
0572: try {
0573: transactions.beginRequired();
0574: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0575: for (Iterator iterator = subject.getEnlistments()
0576: .iterator(); iterator.hasNext();) {
0577: Enlistment enlistment = (Enlistment) iterator.next();
0578: String activityName = enlistment.getActivity();
0579: Activity activity = (Activity) activitiesByName
0580: .get(activityName);
0581: if (activity instanceof AsynchronousActivity)
0582: list.add(activityName);
0583: }
0584: return list;
0585: } catch (HibernateException e) {
0586: LOG.error(userValue, e);
0587: throw new ControllerException(e.getMessage());
0588: } catch (RuntimeException e) {
0589: LOG.error(userValue, e);
0590: throw new ControllerException(e.getMessage());
0591: } finally {
0592: try {
0593: transactions.endRequired();
0594: } catch (ControllerException t) {
0595: t.printStackTrace();
0596: throw t;
0597: }
0598: }
0599: }
0600:
0601: public List<String> getTasks(String userValue)
0602: throws UnknownSubjectException, ControllerException {
0603: List enlistments = getEnlistments(userValue);
0604: for (Iterator iterator = enlistments.iterator(); iterator
0605: .hasNext();) {
0606: String activityName = (String) iterator.next();
0607: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0608: .get(activityName);
0609: if (activity == null)
0610: continue;
0611: if (activity.isOptional())
0612: iterator.remove();
0613: }
0614: return enlistments;
0615: }
0616:
0617: public List<String> getOptions(String userValue)
0618: throws UnknownSubjectException, ControllerException {
0619: List enlistments = getEnlistments(userValue);
0620: for (Iterator iterator = enlistments.iterator(); iterator
0621: .hasNext();) {
0622: String activityName = (String) iterator.next();
0623: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0624: .get(activityName);
0625: if (activity == null)
0626: continue;
0627: if (!activity.isOptional())
0628: iterator.remove();
0629: }
0630: return enlistments;
0631: }
0632:
0633: public List<String> getSubjects(String activity)
0634: throws ControllerException {
0635: List list = new ArrayList();
0636: try {
0637: transactions.beginRequired();
0638: Query query = sessions.getSession().getNamedQuery(
0639: "subject.byEnlistment");
0640: query.setString("activity", activity);
0641: query.setLong("now", System.currentTimeMillis());
0642: sessions.getSession().enableFilter("process").setParameter(
0643: "process", processName);
0644: return query.list();
0645: } catch (HibernateException e) {
0646: LOG.error(activity, e);
0647: throw new ControllerException(e.getMessage());
0648: } catch (RuntimeException e) {
0649: LOG.error(activity, e);
0650: throw new ControllerException(e.getMessage());
0651: } finally {
0652: try {
0653: transactions.endRequired();
0654: } catch (ControllerException t) {
0655: t.printStackTrace();
0656: throw t;
0657: }
0658: }
0659: }
0660:
0661: public List<Log> getLog(String userValue)
0662: throws UnknownSubjectException, ControllerException {
0663: List<Log> list = new ArrayList<Log>();
0664: try {
0665: transactions.beginRequired();
0666: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0667: for (Iterator iterator = subject.getLogs().iterator(); iterator
0668: .hasNext();) {
0669: org.concern.controller.Log log = (org.concern.controller.Log) iterator
0670: .next();
0671: list.add(new org.concern.Log(userValue, log
0672: .getActivity(), log.isSuccess(), log
0673: .getMessage(), log.getDetails(), log
0674: .getAnnotations(), log.getTimestamp()));
0675: }
0676: return list;
0677: } catch (HibernateException e) {
0678: LOG.error(userValue, e);
0679: throw new ControllerException(e.getMessage());
0680: } catch (RuntimeException e) {
0681: LOG.error(userValue, e);
0682: throw new ControllerException(e.getMessage());
0683: } finally {
0684: try {
0685: transactions.endRequired();
0686: } catch (ControllerException t) {
0687: t.printStackTrace();
0688: throw t;
0689: }
0690: }
0691: }
0692:
0693: public List<Log> getArchive(String userValue)
0694: throws UnknownSubjectException, ControllerException {
0695: List<Log> list = new ArrayList<Log>();
0696: try {
0697: transactions.beginRequired();
0698: Query query = sessions.getSession().getNamedQuery(
0699: "archive.byUserValue");
0700: query.setString("userValue", userValue);
0701: ArchiveSubject archiveSubject = (ArchiveSubject) query
0702: .uniqueResult();
0703: if (archiveSubject == null)
0704: throw new UnknownSubjectException(userValue);
0705: for (Iterator iterator = archiveSubject.getLogs()
0706: .iterator(); iterator.hasNext();) {
0707: ArchiveLog log = (ArchiveLog) iterator.next();
0708: list.add(new org.concern.Log(userValue, log
0709: .getActivity(), log.isSuccess(), log
0710: .getMessage(), log.getDetails(), log
0711: .getAnnotations(), log.getTimestamp()));
0712: }
0713: return list;
0714: } catch (HibernateException e) {
0715: LOG.error(userValue, e);
0716: throw new ControllerException(e.getMessage());
0717: } catch (RuntimeException e) {
0718: LOG.error(userValue, e);
0719: throw new ControllerException(e.getMessage());
0720: } finally {
0721: try {
0722: transactions.endRequired();
0723: } catch (ControllerException t) {
0724: t.printStackTrace();
0725: throw t;
0726: }
0727: }
0728: }
0729:
0730: public boolean notify(String userValue, String eventName)
0731: throws UnknownSubjectException, ControllerException {
0732: return notify(userValue, eventName, null);
0733: }
0734:
0735: public boolean notify(String userValue, String eventName,
0736: Map<String, String> logAnnotations)
0737: throws UnknownSubjectException, ControllerException {
0738: boolean complete = false;
0739: try {
0740: transactions.beginRequired();
0741: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0742: Event event = eventsByName.get(eventName);
0743: if (event == null)
0744: throw new ControllerException(eventName + " is unknown");
0745:
0746: Interpreter interpreter = new Interpreter(
0747: evaluations(loader.load(subject.getUserValue())));
0748: if (interpreter.eval(event.getPostcondition())) {
0749: try {
0750: event.occured(loader.load(subject.getUserValue()));
0751: } catch (RuntimeException e) {
0752: throw new ElementRuntimeException(e);
0753: }
0754:
0755: Logs.logSuccess(subject, eventName, logAnnotations);
0756: fine("ACCPETED", eventName, userValue);
0757: complete = true;
0758: } else {
0759: fine("NOT ACCPETED", eventName, userValue);
0760: Logs.logFailure(subject, eventName, "NOT ACCPETED");
0761: complete = false;
0762: }
0763: } catch (SubjectNotFoundException e) {
0764: LOG.error(new Object[] { userValue, eventName }, e);
0765: throw new ControllerException(userValue);
0766: } catch (ActivityExecutionException e) {
0767: LOG.error(new Object[] { userValue, eventName }, e);
0768: throw new ControllerException(e.getMessage());
0769: } catch (ElementRuntimeException e) {
0770: LOG.error(new Object[] { userValue, eventName }, e);
0771: throw new ControllerException(e.getMessage());
0772: } catch (RuntimeException e) {
0773: LOG.error(new Object[] { userValue, eventName }, e);
0774: throw new ControllerException(e.getMessage());
0775: } finally {
0776: try {
0777: transactions.endRequired();
0778: } catch (ControllerException t) {
0779: t.printStackTrace();
0780: throw t;
0781: }
0782: }
0783: return complete;
0784: }
0785:
0786: public boolean complete(String userValue, String activityName)
0787: throws UnknownSubjectException, ControllerException {
0788: return complete(userValue, activityName, null);
0789: }
0790:
0791: public boolean complete(String userValue, String activityName,
0792: Map<String, String> logAnnotations)
0793: throws UnknownSubjectException, ControllerException {
0794: boolean complete = false;
0795: try {
0796: transactions.beginRequired();
0797: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0798: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0799: .get(activityName);
0800: if (activity == null)
0801: throw new ControllerException(activityName
0802: + " is unknown");
0803:
0804: Interpreter interpreter = new Interpreter(
0805: evaluations(loader.load(subject.getUserValue())));
0806: if (interpreter.eval(activity.getPostcondition())) {
0807: Enlistment timeoutEnlistment = subject
0808: .getTimeoutEnlistment(activityName);
0809: if (timeoutEnlistment != null) {
0810: complete = true;
0811: try {
0812: activity.delist(loader.load(subject
0813: .getUserValue()));
0814: } catch (RuntimeException e) {
0815: throw new ElementRuntimeException(e);
0816: }
0817:
0818: subject.getEnlistments().remove(timeoutEnlistment);
0819: Logs.logSuccess(subject, activityName,
0820: logAnnotations);
0821: fine("COMPLETED", activityName, userValue);
0822: unassign(timeoutEnlistment, loader.load(subject
0823: .getUserValue()));
0824: } else
0825: throw new ControllerException(userValue
0826: + " is not enlisted for " + activityName);
0827: } else {
0828: Logs.logFailure(subject, activityName, "NOT COMPLETE");
0829: fine("NOT COMPLETED", activityName, userValue);
0830: }
0831: } catch (SubjectNotFoundException e) {
0832: LOG.error(new Object[] { userValue, activityName }, e);
0833: throw new ControllerException(userValue);
0834: } catch (ActivityExecutionException e) {
0835: LOG.error(new Object[] { userValue, activityName }, e);
0836: throw new ControllerException(e.getMessage());
0837: } catch (ElementRuntimeException e) {
0838: LOG.error(new Object[] { userValue, activityName }, e);
0839: throw new ControllerException(e.getMessage());
0840: } catch (RuntimeException e) {
0841: LOG.error(new Object[] { userValue, activityName }, e);
0842: throw new ControllerException(e.getMessage());
0843: } finally {
0844: try {
0845: transactions.endRequired();
0846: } catch (ControllerException t) {
0847: t.printStackTrace();
0848: throw t;
0849: }
0850: }
0851: return complete;
0852: }
0853:
0854: public boolean isForwardPossible(String userValue,
0855: String activityName) throws UnknownSubjectException,
0856: ControllerException {
0857: try {
0858: transactions.beginRequired();
0859: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0860: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0861: .get(activityName);
0862: if (activity == null)
0863: throw new ControllerException(activityName
0864: + " is unknown");
0865:
0866: Enlistment timeoutEnlistment = subject
0867: .getTimeoutEnlistment(activityName);
0868: return isForwardPossible(timeoutEnlistment, loader
0869: .load(subject.getUserValue()));
0870: } catch (SubjectNotFoundException e) {
0871: LOG.error(new Object[] { userValue, activityName }, e);
0872: throw new ControllerException(userValue);
0873: } catch (RuntimeException e) {
0874: LOG.error(new Object[] { userValue, activityName }, e);
0875: throw new ControllerException(e.getMessage());
0876: } finally {
0877: try {
0878: transactions.endRequired();
0879: } catch (ControllerException t) {
0880: t.printStackTrace();
0881: throw t;
0882: }
0883: }
0884: }
0885:
0886: public void forward(String userValue, String activityName)
0887: throws UnknownSubjectException, ControllerException {
0888: forward(userValue, activityName, null);
0889: }
0890:
0891: public void forward(String userValue, String activityName,
0892: Map<String, String> logAnnotations)
0893: throws UnknownSubjectException, ControllerException {
0894: try {
0895: transactions.beginRequired();
0896: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0897: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0898: .get(activityName);
0899: if (activity == null)
0900: throw new ControllerException(activityName
0901: + " is unknown");
0902:
0903: Enlistment timeoutEnlistment = subject
0904: .getTimeoutEnlistment(activityName);
0905: timeoutEnlistment
0906: .setTrials(timeoutEnlistment.getTrials() + 1);
0907: timeoutEnlistment.setTimeout(System.currentTimeMillis()
0908: + activity.getTimeout() * 1000);
0909: Logs.logForwarded(subject, activityName, logAnnotations);
0910: fine("FORWARDED", activityName, userValue);
0911: Object userSubject = loader.load(subject.getUserValue());
0912: reassign(timeoutEnlistment, subject, userSubject);
0913: adjustTimeout(timeoutEnlistment, userSubject);
0914: } catch (SubjectNotFoundException e) {
0915: LOG.error(new Object[] { userValue, activityName }, e);
0916: throw new ControllerException(userValue);
0917: } catch (ElementRuntimeException e) {
0918: LOG.error(new Object[] { userValue, activityName }, e);
0919: throw new ControllerException(e.getMessage());
0920: } catch (RuntimeException e) {
0921: LOG.error(new Object[] { userValue, activityName }, e);
0922: throw new ControllerException(e.getMessage());
0923: } finally {
0924: try {
0925: transactions.endRequired();
0926: } catch (ControllerException t) {
0927: t.printStackTrace();
0928: throw t;
0929: }
0930: }
0931: }
0932:
0933: public boolean isBackwardPossible(String userValue,
0934: String activityName) throws UnknownSubjectException,
0935: ControllerException {
0936: try {
0937: transactions.beginRequired();
0938: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0939: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0940: .get(activityName);
0941: if (activity == null)
0942: throw new ControllerException(activityName
0943: + " is unknown");
0944:
0945: Enlistment timeoutEnlistment = subject
0946: .getTimeoutEnlistment(activityName);
0947: return isBackwardPossible(timeoutEnlistment);
0948: } catch (RuntimeException e) {
0949: LOG.error(new Object[] { userValue, activityName }, e);
0950: throw new ControllerException(e.getMessage());
0951: } finally {
0952: try {
0953: transactions.endRequired();
0954: } catch (ControllerException t) {
0955: t.printStackTrace();
0956: throw t;
0957: }
0958: }
0959: }
0960:
0961: public void backward(String userValue, String activityName)
0962: throws UnknownSubjectException, ControllerException {
0963: forward(userValue, activityName, null);
0964: }
0965:
0966: public void backward(String userValue, String activityName,
0967: Map<String, String> logAnnotations)
0968: throws UnknownSubjectException, ControllerException {
0969: try {
0970: transactions.beginRequired();
0971: Subject subject = getSubject(userValue, LockMode.UPGRADE);
0972: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
0973: .get(activityName);
0974: if (activity == null)
0975: throw new ControllerException(activityName
0976: + " is unknown");
0977:
0978: Enlistment timeoutEnlistment = subject
0979: .getTimeoutEnlistment(activityName);
0980: timeoutEnlistment.setTrials(Math.max(0, timeoutEnlistment
0981: .getTrials() - 1));
0982: timeoutEnlistment.setTimeout(System.currentTimeMillis()
0983: + activity.getTimeout() * 1000);
0984: Logs.logBackwarded(subject, activityName, logAnnotations);
0985: fine("BACKWARDED", activityName, userValue);
0986: Object userSubject = loader.load(subject.getUserValue());
0987: reassign(timeoutEnlistment, subject, userSubject);
0988: adjustTimeout(timeoutEnlistment, userSubject);
0989: } catch (SubjectNotFoundException e) {
0990: LOG.error(new Object[] { userValue, activityName }, e);
0991: throw new ControllerException(userValue);
0992: } catch (ElementRuntimeException e) {
0993: LOG.error(new Object[] { userValue, activityName }, e);
0994: throw new ControllerException(e.getMessage());
0995: } catch (RuntimeException e) {
0996: LOG.error(new Object[] { userValue, activityName }, e);
0997: throw new ControllerException(e.getMessage());
0998: } finally {
0999: try {
1000: transactions.endRequired();
1001: } catch (ControllerException t) {
1002: t.printStackTrace();
1003: throw t;
1004: }
1005: }
1006: }
1007:
1008: public void reset(String userValue, String activityName)
1009: throws UnknownSubjectException, ControllerException {
1010: try {
1011: transactions.beginRequired();
1012: Subject subject = getSubject(userValue, LockMode.UPGRADE);
1013: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1014: .get(activityName);
1015: if (activity == null)
1016: throw new ControllerException(activityName
1017: + " is unknown");
1018:
1019: Enlistment timeoutEnlistment = subject
1020: .getTimeoutEnlistment(activityName);
1021: timeoutEnlistment.setTrials(0);
1022: timeoutEnlistment.setTimeout(System.currentTimeMillis()
1023: + activity.getTimeout() * 1000);
1024: Logs.logReset(subject, activityName);
1025: fine("RESET", activityName, userValue);
1026: Object userSubject = loader.load(subject.getUserValue());
1027: reassign(timeoutEnlistment, subject, userSubject);
1028: adjustTimeout(timeoutEnlistment, userSubject);
1029: } catch (SubjectNotFoundException e) {
1030: LOG.error(new Object[] { userValue, activityName }, e);
1031: throw new ControllerException(userValue);
1032: } catch (ElementRuntimeException e) {
1033: LOG.error(new Object[] { userValue, activityName }, e);
1034: throw new ControllerException(e.getMessage());
1035: } catch (RuntimeException e) {
1036: LOG.error(new Object[] { userValue, activityName }, e);
1037: throw new ControllerException(e.getMessage());
1038: } finally {
1039: try {
1040: transactions.endRequired();
1041: } catch (ControllerException t) {
1042: t.printStackTrace();
1043: throw t;
1044: }
1045: }
1046: }
1047:
1048: public Boolean matchCondition(String userValue, String conditionName)
1049: throws UnknownSubjectException, ControllerException {
1050: boolean match = false;
1051: try {
1052: transactions.beginRequired();
1053: Condition condition = conditionsByName.get(conditionName);
1054: if (condition != null) {
1055: try {
1056: match = condition.eval(loader.load(userValue));
1057: } catch (RuntimeException e) {
1058: throw new ElementRuntimeException(e);
1059: }
1060: return Boolean.valueOf(match);
1061: }
1062: throw new ControllerException(conditionName + " is unknown");
1063: } catch (SubjectNotFoundException e) {
1064: LOG.error(new Object[] { userValue, conditionName }, e);
1065: throw new ControllerException(userValue);
1066: } catch (ElementRuntimeException e) {
1067: LOG.error(new Object[] { userValue, conditionName }, e);
1068: throw new ControllerException(userValue);
1069: } catch (ConditionEvaluationException e) {
1070: return null;
1071: } finally {
1072: try {
1073: transactions.endRequired();
1074: } catch (ControllerException t) {
1075: t.printStackTrace();
1076: throw t;
1077: }
1078: }
1079: }
1080:
1081: public boolean matchPrecondition(String userValue,
1082: String activityName) throws UnknownSubjectException,
1083: ControllerException {
1084: boolean match = false;
1085: try {
1086: transactions.beginRequired();
1087:
1088: Interpreter interpreter = new Interpreter(
1089: evaluations(loader.load(userValue)));
1090:
1091: Activity activity = (Activity) activitiesByName
1092: .get(activityName);
1093: if (activity != null) {
1094: match = interpreter.eval(activity.getPrecondition());
1095: return match;
1096: }
1097:
1098: Listener listener = (Listener) listenersByName
1099: .get(activityName);
1100: if (listener != null) {
1101: match = interpreter.eval(listener.getPrecondition());
1102: return match;
1103: }
1104: throw new ControllerException(activityName + " is unknown");
1105: } catch (SubjectNotFoundException e) {
1106: LOG.error(new Object[] { userValue, activityName }, e);
1107: throw new ControllerException(userValue);
1108: } catch (ElementRuntimeException e) {
1109: LOG.error(new Object[] { userValue, activityName }, e);
1110: throw new ControllerException(userValue);
1111: } finally {
1112: try {
1113: transactions.endRequired();
1114: } catch (ControllerException t) {
1115: t.printStackTrace();
1116: throw t;
1117: }
1118: }
1119: }
1120:
1121: public boolean matchPostcondition(String userValue,
1122: String activityName) throws UnknownSubjectException,
1123: ControllerException {
1124: boolean match = false;
1125: try {
1126: transactions.beginRequired();
1127: Activity activity = (Activity) activitiesByName
1128: .get(activityName);
1129: if (activity == null)
1130: throw new ControllerException(activityName
1131: + " is unknown");
1132:
1133: Interpreter interpreter = new Interpreter(
1134: evaluations(loader.load(userValue)));
1135: match = interpreter.eval(activity.getPostcondition());
1136: return match;
1137: } catch (SubjectNotFoundException e) {
1138: LOG.error(new Object[] { userValue, activityName }, e);
1139: throw new ControllerException(userValue);
1140: } catch (ElementRuntimeException e) {
1141: LOG.error(new Object[] { userValue, activityName }, e);
1142: throw new ControllerException(userValue);
1143: } finally {
1144: try {
1145: transactions.endRequired();
1146: } catch (ControllerException t) {
1147: t.printStackTrace();
1148: throw t;
1149: }
1150: }
1151: }
1152:
1153: public void process(String userValue)
1154: throws UnknownSubjectException, ControllerException {
1155: Subject subject;
1156: try {
1157: transactions.beginNever();
1158: subject = getSubject(userValue, LockMode.UPGRADE);
1159: subject.getEnlistments().add(
1160: new Enlistment("EVALUATE", System
1161: .currentTimeMillis()));
1162: } catch (HibernateException e) {
1163: LOG.error(userValue, e);
1164: throw new ControllerException(e.getMessage());
1165: } finally {
1166: try {
1167: transactions.endNever();
1168: } catch (ControllerException t) {
1169: t.printStackTrace();
1170: throw t;
1171: }
1172: }
1173:
1174: while (process(subject))
1175: ;
1176: }
1177:
1178: private boolean process(Subject subject) throws ControllerException {
1179: boolean followup = false;
1180: try {
1181: transactions.begin();
1182: sessions.getSession().lock(subject, LockMode.UPGRADE);
1183:
1184: LOG.debug("subject.getEnlistments() = "
1185: + subject.getEnlistments());
1186: Enlistment enlistment = (Enlistment) subject
1187: .getEnlistments().iterator().next();
1188: LOG.debug("enlistment = " + enlistment);
1189: String command = enlistment.getCommand();
1190: String activityName = enlistment.getActivity();
1191:
1192: if (subject.getState() == STATE_DESTROYED
1193: || "DESTROY".equals(command)) {
1194: destroy(subject);
1195: return false;
1196: }
1197:
1198: if (enlistment.getTimeout() > System.currentTimeMillis())
1199: return false;
1200:
1201: if ("RETRY".equals(command)) {
1202: SynchronousActivity activity = (SynchronousActivity) activitiesByName
1203: .get(activityName);
1204: if (activity != null)
1205: execute(subject, (SynchronousActivity) activity,
1206: enlistment);
1207:
1208: Listener listener = (Listener) listenersByName
1209: .get(activityName);
1210: if (listener != null)
1211: notify(subject, listener, enlistment);
1212: } else if ("EXECUTE".equals(command)) {
1213: SynchronousActivity activity = (SynchronousActivity) activitiesByName
1214: .get(activityName);
1215: execute(subject, (SynchronousActivity) activity,
1216: enlistment);
1217: } else if ("NOTIFY".equals(command)) {
1218: Listener listener = (Listener) listenersByName
1219: .get(activityName);
1220: notify(subject, listener, enlistment);
1221: } else if ("ESCALATE".equals(command)) {
1222: SynchronousActivity activity = (SynchronousActivity) activitiesByName
1223: .get(activityName);
1224: if (activity != null)
1225: escalate(subject, activity, enlistment);
1226:
1227: Listener listener = (Listener) listenersByName
1228: .get(activityName);
1229: if (listener != null)
1230: escalate(subject, listener, enlistment);
1231: } else if ("ENLIST".equals(command)) {
1232: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1233: .get(activityName);
1234: enlist(subject, activity, enlistment);
1235: } else if ("LIST".equals(command)) {
1236: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1237: .get(activityName);
1238: list(subject, activity, enlistment);
1239: } else if ("DELIST".equals(command)) {
1240: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1241: .get(activityName);
1242: delist(subject, activity, enlistment);
1243: } else if ("TIMEOUT".equals(command)) {
1244: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1245: .get(activityName);
1246: escalate(subject, activity, enlistment);
1247: } else if ("EVALUATE".equals(command))
1248: evaluate(subject, enlistment);
1249: LOG.debug("subject.getEnlistments() = "
1250: + subject.getEnlistments());
1251:
1252: if (subject.getEnlistments().isEmpty())
1253: stall(subject);
1254: else
1255: followup = subject.getState() == Controller.STATE_RUNNING
1256: && ((Enlistment) subject.getEnlistments()
1257: .first()).getTimeout() < System
1258: .currentTimeMillis();
1259:
1260: LOG.debug("followup = " + followup);
1261: return followup;
1262: } catch (HibernateException e) {
1263: LOG.error(subject, e);
1264: throw new ControllerException(e.getMessage());
1265: } finally {
1266: transactions.commit();
1267: }
1268: }
1269:
1270: private void evaluate(Subject subject, Enlistment enlistment) {
1271: try {
1272: fine("EVALUATE", "SUBJECT", subject.getUserValue());
1273: Object object = loader.load(subject.getUserValue());
1274: long now = System.currentTimeMillis();
1275: SortedSet enlistments = subject.getEnlistments();
1276: enlistments.remove(enlistment);
1277:
1278: Map<String, Enlistment> activityEnlistments = new HashMap<String, Enlistment>();
1279: Map<String, Enlistment> retryEnlistments = new HashMap<String, Enlistment>();
1280: for (Iterator iterator = enlistments.iterator(); iterator
1281: .hasNext();) {
1282: Enlistment current = (Enlistment) iterator.next();
1283: if ("TIMEOUT".equals(current.getCommand()))
1284: activityEnlistments.put(current.getActivity(),
1285: current);
1286: else if ("RETRY".equals(current.getCommand()))
1287: retryEnlistments
1288: .put(current.getActivity(), current);
1289: else if (!"ESCALATE".equals(current.getCommand()))
1290: iterator.remove();
1291: }
1292:
1293: Map<String, Boolean> evaluations = evaluations(object);
1294: Interpreter interpreter = new Interpreter(evaluations);
1295:
1296: for (Iterator iterator = activities.iterator(); iterator
1297: .hasNext();) {
1298: Activity activity = (Activity) iterator.next();
1299: String name = activity.getName();
1300: boolean match = interpreter.eval(activity
1301: .getPrecondition());
1302: match = !activity.isReentrant() ? match
1303: && !interpreter.eval(activity
1304: .getPostcondition()) : match;
1305: System.out.println(name + " = " + match);
1306:
1307: if (activity instanceof SynchronousActivity) {
1308: boolean enlisted = retryEnlistments
1309: .containsKey(name);
1310: System.out.println("enlisted = " + enlisted);
1311: if (match && !enlisted)
1312: enlistments.add(new Enlistment("EXECUTE", name,
1313: now));
1314: else if (!match && enlisted)
1315: enlistments.remove(retryEnlistments.get(name));
1316: }
1317:
1318: if (activity instanceof AsynchronousActivity) {
1319: boolean enlisted = activityEnlistments
1320: .containsKey(name);
1321: System.out.println("enlisted = " + enlisted);
1322: if (match && !enlisted)
1323: enlistments.add(new Enlistment("ENLIST", name,
1324: now));
1325: else if (match && enlisted)
1326: enlistments.add(new Enlistment("LIST", name,
1327: now));
1328: else if (!match && enlisted)
1329: enlistments.add(new Enlistment("DELIST", name,
1330: now));
1331: }
1332: }
1333:
1334: for (Iterator iterator = listeners.iterator(); iterator
1335: .hasNext();) {
1336: Listener listener = (Listener) iterator.next();
1337: String precondition = listener.getPrecondition();
1338: boolean match = interpreter.eval(precondition);
1339:
1340: if (match)
1341: enlistments.add(new Enlistment("NOTIFY", listener
1342: .getName(), now));
1343: }
1344:
1345: long nextTransition = Long.MAX_VALUE;
1346: for (Iterator iterator = conditions.iterator(); iterator
1347: .hasNext();) {
1348: Condition condition = (Condition) iterator.next();
1349: if (condition instanceof TemporalCondition) {
1350: TemporalCondition temporalCondition = (TemporalCondition) condition;
1351: long transition = temporalCondition
1352: .getAnticipatedTransition(loader
1353: .load(subject.getUserValue()));
1354: if (transition >= now)
1355: nextTransition = Math.min(nextTransition,
1356: transition);
1357: }
1358: }
1359: if (nextTransition != Long.MAX_VALUE)
1360: enlistments.add(new Enlistment("EVALUATE",
1361: nextTransition));
1362:
1363: doCommitAndBegin(subject);
1364: } catch (SubjectNotFoundException e) {
1365: suspend(subject, "LOAD", e);
1366: } catch (ElementRuntimeException e) {
1367: suspend(subject, "EVALUATE", e.getCause());
1368: }
1369: }
1370:
1371: private void destroy(Subject subject) {
1372: try {
1373: Logs.logDestroyed(subject);
1374: fine("DESTROY", "SUBJECT", subject.getUserValue());
1375: archive(subject);
1376: sessions.getSession().delete(subject);
1377:
1378: // TODO: check if this could be transactions.commit() and transactions.begin() also
1379: transactionManager.commit();
1380: transactionManager.begin();
1381: } catch (Exception e) {
1382: throw new ControllerException(e);
1383: }
1384: }
1385:
1386: private void stall(Subject subject) {
1387: try {
1388: Logs.logStalled(subject, diagnostics(loader.load(subject
1389: .getUserValue())));
1390: } catch (LoaderException e) {
1391: throw new ControllerException(e);
1392: } catch (SubjectNotFoundException e) {
1393: Logs.logFailure(subject, "LOAD", e.getMessage());
1394: subject.setState(STATE_SUSPENDED);
1395: }
1396: }
1397:
1398: /**
1399: * may finish the transaction in progress and create a new one
1400: */
1401: private void execute(Subject subject, SynchronousActivity activity,
1402: Enlistment enlistment) {
1403: try {
1404: Interpreter interpreter = new Interpreter(
1405: evaluations(loader.load(subject.getUserValue())));
1406: if (interpreter.eval(activity.getPrecondition())) {
1407: try {
1408: fine("EXECUTE", activity.getName(), subject
1409: .getUserValue());
1410: activity.execute(loader
1411: .load(subject.getUserValue()));
1412: } catch (ActivityExecutionException e) {
1413: doRollbackAndBegin(subject);
1414: failure(subject, activity, enlistment, e
1415: .getMessage());
1416: doCommitAndBegin(subject);
1417: return;
1418: } catch (RuntimeException e) {
1419: throw new ElementRuntimeException(e);
1420: }
1421:
1422: interpreter = new Interpreter(evaluations(loader
1423: .load(subject.getUserValue())));
1424: if (interpreter.eval(activity.getPostcondition())) {
1425: success(subject, activity, enlistment);
1426: doCommitAndBegin(subject);
1427: } else {
1428: doRollbackAndBegin(subject);
1429: failure(subject, activity, enlistment,
1430: "postcondition - "
1431: + diagnostics(loader.load(subject
1432: .getUserValue())));
1433: doCommitAndBegin(subject);
1434: }
1435: } else
1436: subject.getEnlistments().remove(enlistment);
1437: } catch (SubjectNotFoundException e) {
1438: suspend(subject, "LOAD", e);
1439: } catch (ElementRuntimeException e) {
1440: suspend(subject, activity.getName(), e.getCause());
1441: }
1442: }
1443:
1444: private void success(Subject subject, SynchronousActivity activity,
1445: Enlistment enlistment) {
1446: subject.getEnlistments().remove(enlistment);
1447: subject.getEnlistments().add(new Enlistment("EVALUATE", 0));
1448: Logs.logSuccess(subject, activity.getName(), null);
1449: }
1450:
1451: private void failure(Subject subject, SynchronousActivity activity,
1452: Enlistment enlistment, String details) {
1453: String name = activity.getName();
1454: try {
1455: Logs.logFailure(subject, name, details);
1456: subject.getEnlistments().remove(enlistment);
1457: if (enlistment.getTrials() < activity.getTrials() - 1) {
1458: Enlistment retryEnlistment = new Enlistment("RETRY",
1459: activity.getName(), System.currentTimeMillis()
1460: + activity.getRetryDelay() * 1000);
1461: retryEnlistment.setTrials(enlistment.getTrials() + 1);
1462: subject.getEnlistments().add(retryEnlistment);
1463: } else
1464: subject.getEnlistments().add(
1465: new Enlistment("ESCALATE", activity.getName(),
1466: 0));
1467:
1468: doCommitAndBegin(subject);
1469: } catch (Exception e) {
1470: LOG.error(subject, e);
1471: throw new ControllerException(e.getMessage());
1472: }
1473: }
1474:
1475: private void escalate(Subject subject, Activity activity,
1476: Enlistment enlistment) {
1477: try {
1478: fine("ESCALATE", activity.getName(), subject.getUserValue());
1479: try {
1480: activity.escalate(loader.load(subject.getUserValue()));
1481: } catch (RuntimeException e) {
1482: throw new ElementRuntimeException(e);
1483: }
1484: subject.getEnlistments().remove(enlistment);
1485: subject.getEnlistments().add(new Enlistment("EVALUATE", 0));
1486: Logs.logEscalation(subject, activity.getName());
1487: } catch (ActivityExecutionException e) {
1488: doRollbackAndBegin(subject);
1489: Logs
1490: .logFailure(subject, activity.getName(), e
1491: .getMessage());
1492: doCommitAndBegin(subject);
1493: } catch (SubjectNotFoundException e) {
1494: suspend(subject, "LOAD", e);
1495: } catch (ElementRuntimeException e) {
1496: suspend(subject, activity.getName(), e.getCause());
1497: }
1498: }
1499:
1500: private void enlist(Subject subject, AsynchronousActivity activity,
1501: Enlistment enlistment) {
1502: try {
1503: fine("ENLIST", activity.getName(), subject.getUserValue());
1504: Object userSubject = loader.load(subject.getUserValue());
1505: try {
1506: activity.enlist(userSubject);
1507: } catch (RuntimeException e) {
1508: throw new ElementRuntimeException(e);
1509: }
1510: subject.getEnlistments().remove(enlistment);
1511: long timeout = System.currentTimeMillis()
1512: + activity.getTimeout() * 1000;
1513: if (activity.isOptional() || activity.getTimeout() == -1)
1514: timeout = Long.MAX_VALUE;
1515: Enlistment newEnlistment = new Enlistment("TIMEOUT",
1516: activity.getName(), timeout);
1517: subject.getEnlistments().add(newEnlistment);
1518: if (activity.getActor() != null)
1519: assign(newEnlistment, subject, userSubject);
1520:
1521: doCommitAndBegin(subject);
1522: } catch (ActivityExecutionException e) {
1523: doRollbackAndBegin(subject);
1524: Logs
1525: .logFailure(subject, activity.getName(), e
1526: .getMessage());
1527: doCommitAndBegin(subject);
1528: } catch (SubjectNotFoundException e) {
1529: suspend(subject, "LOAD", e);
1530: } catch (ElementRuntimeException e) {
1531: suspend(subject, activity.getName(), e.getCause());
1532: }
1533: }
1534:
1535: private void list(Subject subject, AsynchronousActivity activity,
1536: Enlistment enlistment) {
1537: try {
1538: fine("LIST", activity.getName(), subject.getUserValue());
1539: Object userSubject = loader.load(subject.getUserValue());
1540: subject.getEnlistments().remove(enlistment);
1541:
1542: Enlistment timeoutEnlistment = subject
1543: .getTimeoutEnlistment(activity.getName());
1544: if (activity.getActor() != null)
1545: reassign(timeoutEnlistment, subject, userSubject);
1546:
1547: doCommitAndBegin(subject);
1548: } catch (SubjectNotFoundException e) {
1549: suspend(subject, "LOAD", e);
1550: } catch (ElementRuntimeException e) {
1551: suspend(subject, activity.getName(), e.getCause());
1552: }
1553: }
1554:
1555: private void delist(Subject subject, AsynchronousActivity activity,
1556: Enlistment enlistment) {
1557: try {
1558: fine("DELIST", activity.getName(), subject.getUserValue());
1559: try {
1560: activity.delist(loader.load(subject.getUserValue()));
1561: } catch (RuntimeException e) {
1562: throw new ElementRuntimeException(e);
1563: }
1564: subject.getEnlistments().remove(enlistment);
1565: Enlistment timeoutEnlistment = subject
1566: .getTimeoutEnlistment(activity.getName());
1567: subject.getEnlistments().remove(timeoutEnlistment);
1568: if (activity.getActor() != null)
1569: unassign(timeoutEnlistment, loader.load(subject
1570: .getUserValue()));
1571: } catch (ActivityExecutionException e) {
1572: doRollbackAndBegin(subject);
1573: Logs
1574: .logFailure(subject, activity.getName(), e
1575: .getMessage());
1576: doCommitAndBegin(subject);
1577: } catch (SubjectNotFoundException e) {
1578: suspend(subject, "LOAD", e);
1579: } catch (ElementRuntimeException e) {
1580: suspend(subject, activity.getName(), e.getCause());
1581: }
1582: }
1583:
1584: private void assign(Enlistment enlistment, Subject subject,
1585: Object userSubject) throws ElementRuntimeException {
1586: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1587: .get(enlistment.getActivity());
1588: String actorName = activity.getActor();
1589: Actor actor = actorsByName.get(actorName);
1590: if (actor != null) {
1591: Set assignees = actor.getAssignees(userSubject, enlistment
1592: .getTrials());
1593: for (Iterator iterator = assignees.iterator(); iterator
1594: .hasNext();) {
1595: String id = (String) iterator.next();
1596: Assignment assignment = new Assignment();
1597: assignment.setAssignee(id);
1598: enlistment.getAssignments().add(assignment);
1599: try {
1600: activity.assign(userSubject, id, enlistment
1601: .getTrials());
1602: } catch (RuntimeException e) {
1603: throw new ElementRuntimeException(e);
1604: }
1605: }
1606: }
1607: }
1608:
1609: private void reassign(Enlistment enlistment, Subject subject,
1610: Object userSubject) throws ElementRuntimeException {
1611: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1612: .get(enlistment.getActivity());
1613: String actorName = activity.getActor();
1614: Actor actor = actorsByName.get(actorName);
1615: if (actor != null) {
1616: Set assignees = actor.getAssignees(userSubject, enlistment
1617: .getTrials());
1618: for (Iterator iterator = enlistment.getAssignments()
1619: .iterator(); iterator.hasNext();) {
1620: Assignment assignment = (Assignment) iterator.next();
1621:
1622: if (!assignees.contains(assignment.getAssignee())) {
1623: iterator.remove();
1624: try {
1625: activity.unassign(userSubject, assignment
1626: .getAssignee(), enlistment.getTrials());
1627: } catch (RuntimeException e) {
1628: throw new ElementRuntimeException(e);
1629: }
1630: }
1631: }
1632: for (Iterator iterator = assignees.iterator(); iterator
1633: .hasNext();) {
1634: String id = (String) iterator.next();
1635: Assignment assignment = new Assignment();
1636: assignment.setAssignee(id);
1637: if (!enlistment.getAssignments().contains(assignment)) {
1638: enlistment.getAssignments().add(assignment);
1639: try {
1640: activity.assign(userSubject, assignment
1641: .getAssignee(), enlistment.getTrials());
1642: } catch (RuntimeException e) {
1643: throw new ElementRuntimeException(e);
1644: }
1645: }
1646: }
1647: }
1648: }
1649:
1650: private void unassign(Enlistment enlistment, Object userSubject)
1651: throws ElementRuntimeException {
1652: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1653: .get(enlistment.getActivity());
1654: String actorName = activity.getActor();
1655: if (actorName != null) {
1656: for (Iterator iterator = enlistment.getAssignments()
1657: .iterator(); iterator.hasNext();) {
1658: Assignment assignment = (Assignment) iterator.next();
1659: iterator.remove();
1660: try {
1661: activity.unassign(userSubject, assignment
1662: .getAssignee(), enlistment.getTrials());
1663: } catch (RuntimeException e) {
1664: throw new ElementRuntimeException(e);
1665: }
1666: }
1667: }
1668: }
1669:
1670: private void adjustTimeout(Enlistment enlistment, Object userSubject) {
1671: AsynchronousActivity activity = (AsynchronousActivity) activitiesByName
1672: .get(enlistment.getActivity());
1673: String actorName = activity.getActor();
1674: Actor actor = actorsByName.get(actorName);
1675: if (actor != null && !activity.isOptional()) {
1676: long timeout = actor.getTimeout(userSubject, enlistment
1677: .getTrials());
1678: if (timeout != -1)
1679: enlistment.setTimeout(System.currentTimeMillis()
1680: + timeout * 1000);
1681: }
1682: }
1683:
1684: private boolean isForwardPossible(Enlistment enlistment,
1685: Object userSubject) {
1686: Activity activity = (Activity) activitiesByName.get(enlistment
1687: .getActivity());
1688: String actorName = activity.getActor();
1689: Actor actor = actorsByName.get(actorName);
1690: if (actor != null) {
1691: Set assignees = actor.getAssignees(userSubject, enlistment
1692: .getTrials() + 1);
1693: if (assignees.size() > 0) {
1694: return true;
1695: }
1696: }
1697: return false;
1698: }
1699:
1700: private boolean isBackwardPossible(Enlistment enlistment) {
1701: return enlistment.getTrials() > 0;
1702: }
1703:
1704: private void notify(Subject subject, Listener listener,
1705: Enlistment enlistment) {
1706: try {
1707: Interpreter interpreter = new Interpreter(
1708: evaluations(loader.load(subject.getUserValue())));
1709: if (interpreter.eval(listener.getPrecondition())) {
1710: try {
1711: fine("NOTIFY", listener.getName(), subject
1712: .getUserValue());
1713: listener
1714: .notify(loader.load(subject.getUserValue()));
1715: success(subject, listener, enlistment);
1716: doCommitAndBegin(subject);
1717: } catch (ActivityExecutionException e) {
1718: doRollbackAndBegin(subject);
1719: failure(subject, listener, enlistment, e
1720: .getMessage());
1721: doCommitAndBegin(subject);
1722: } catch (RuntimeException e) {
1723: throw new ElementRuntimeException(e);
1724: }
1725: } else
1726: subject.getEnlistments().remove(enlistment);
1727: } catch (SubjectNotFoundException e) {
1728: suspend(subject, "LOAD", e);
1729: } catch (ElementRuntimeException e) {
1730: suspend(subject, listener.getName(), e.getCause());
1731: }
1732: }
1733:
1734: private void suspend(Subject subject, String message,
1735: Throwable throwable) {
1736: try {
1737: doRollbackAndBegin(subject);
1738: Logs.logFailure(subject, message, throwable.getMessage());
1739: subject.setState(STATE_SUSPENDED);
1740: Logs.logSuspended(subject);
1741: doCommitAndBegin(subject);
1742: } catch (Exception e) {
1743: throw new ControllerException(e);
1744: }
1745: }
1746:
1747: private void success(Subject subject, Listener listener,
1748: Enlistment enlistment) {
1749: subject.getEnlistments().remove(enlistment);
1750: Logs.logSuccess(subject, listener.getName(), null);
1751: }
1752:
1753: private void failure(Subject subject, Listener activity,
1754: Enlistment enlistment, String details) {
1755: String name = activity.getName();
1756: Logs.logFailure(subject, name, details);
1757: subject.getEnlistments().remove(enlistment);
1758: if (enlistment.getTrials() < activity.getTrials() - 1) {
1759: Enlistment retryEnlistment = new Enlistment("RETRY",
1760: activity.getName(), System.currentTimeMillis()
1761: + activity.getRetryDelay() * 1000);
1762: retryEnlistment.setTrials(enlistment.getTrials() + 1);
1763: subject.getEnlistments().add(retryEnlistment);
1764: } else
1765: subject.getEnlistments().add(
1766: new Enlistment("ESCALATE", activity.getName(), 0));
1767:
1768: doCommitAndBegin(subject);
1769: }
1770:
1771: private void escalate(Subject subject, Listener listener,
1772: Enlistment enlistment) {
1773: try {
1774: fine("ESCALATE", listener.getName(), subject.getUserValue());
1775: try {
1776: listener.escalate(loader.load(subject.getUserValue()));
1777: } catch (RuntimeException e) {
1778: throw new ElementRuntimeException(e);
1779: }
1780: subject.getEnlistments().remove(enlistment);
1781: subject.getEnlistments().add(new Enlistment("EVALUATE", 0));
1782: Logs.logEscalation(subject, listener.getName());
1783: } catch (ActivityExecutionException e) {
1784: doRollbackAndBegin(subject);
1785: Logs.logFailure(subject, ((Activity) listener).getName(), e
1786: .getMessage());
1787: doCommitAndBegin(subject);
1788: } catch (SubjectNotFoundException e) {
1789: suspend(subject, "LOAD", e);
1790: } catch (ElementRuntimeException e) {
1791: suspend(subject, listener.getName(), e.getCause());
1792: }
1793: }
1794:
1795: private void archive(Subject subject) {
1796: try {
1797: Query query = sessions.getSession().getNamedQuery(
1798: "archive.byUserValue");
1799: query.setString("userValue", subject.getUserValue());
1800: ArchiveSubject archiveSubject = (ArchiveSubject) query
1801: .uniqueResult();
1802: if (archiveSubject == null) {
1803: archiveSubject = new ArchiveSubject();
1804: archiveSubject.setProcess(subject.getProcess());
1805: archiveSubject.setUserValue(subject.getUserValue());
1806: archiveSubject.setOriginator(subject.getOriginator());
1807: archiveSubject.setCreated(subject.getCreated());
1808:
1809: Set archiveSubjectLines = archiveSubject
1810: .getSubjectLines();
1811: for (Iterator iterator = subject.getSubjectLines()
1812: .iterator(); iterator.hasNext();) {
1813: SubjectLine subjectLine = (SubjectLine) iterator
1814: .next();
1815: ArchiveSubjectLine archiveSubjectLine = new ArchiveSubjectLine();
1816: archiveSubjectLine.setLanguage(subjectLine
1817: .getLanguage());
1818: archiveSubjectLine.setLine(subjectLine.getLine());
1819: archiveSubjectLines.add(archiveSubjectLine);
1820: }
1821: sessions.getSession().save(archiveSubject);
1822: }
1823:
1824: List archiveLogs = archiveSubject.getLogs();
1825: for (Iterator iterator = subject.getLogs().iterator(); iterator
1826: .hasNext();) {
1827: org.concern.controller.Log log = (org.concern.controller.Log) iterator
1828: .next();
1829: ArchiveLog archiveLog = new ArchiveLog();
1830: archiveLog.setActivity(log.getActivity());
1831: archiveLog.setSuccess(log.isSuccess());
1832: archiveLog.setMessage(log.getMessage());
1833: archiveLog.setDetails(log.getDetails());
1834: archiveLog.setTimestamp(log.getTimestamp());
1835: archiveLog
1836: .setAnnotations(log.getAnnotations() != null ? new HashMap(
1837: log.getAnnotations())
1838: : null);
1839: archiveLog.setSubject(archiveSubject);
1840: archiveLogs.add(archiveLog);
1841: }
1842: } catch (HibernateException e) {
1843: LOG.error(subject, e);
1844: throw new ControllerException(e.getMessage());
1845: }
1846: }
1847:
1848: private Map<String, Boolean> evaluations(Object object)
1849: throws ElementRuntimeException {
1850: try {
1851: Map<String, Boolean> evaluations = new HashMap<String, Boolean>();
1852: for (Iterator iterator = conditions.iterator(); iterator
1853: .hasNext();) {
1854: Condition condition = (Condition) iterator.next();
1855: try {
1856: evaluations.put(condition.getName(), Boolean
1857: .valueOf(condition.eval(object)));
1858: } catch (ConditionEvaluationException e) {
1859: evaluations.put(condition.getName(), null);
1860: }
1861: }
1862: LOG.trace("STATE " + evaluations);
1863:
1864: return evaluations;
1865: } catch (RuntimeException e) {
1866: throw new ElementRuntimeException(e);
1867: }
1868: }
1869:
1870: private String diagnostics(Object subject) {
1871: StringBuffer buffer = new StringBuffer();
1872: for (Iterator iterator = conditions.iterator(); iterator
1873: .hasNext();) {
1874: Condition condition = (Condition) iterator.next();
1875: buffer.append(condition.getName());
1876: buffer.append(": ");
1877: try {
1878: buffer.append(condition.eval(subject));
1879: } catch (ConditionEvaluationException e) {
1880: buffer.append("?");
1881: }
1882: if (iterator.hasNext())
1883: buffer.append(", ");
1884: }
1885: return buffer.toString();
1886: }
1887:
1888: private void fine(String what, String name, String userValue) {
1889: if (LOG.isDebugEnabled())
1890: LOG.debug(what + " " + name + " ON " + userValue);
1891: }
1892:
1893: public void setLoader(Loader loader) {
1894: this .loader = loader;
1895: }
1896:
1897: public Loader getLoader() {
1898: return loader;
1899: }
1900:
1901: public void setSessionFactory(SessionFactory sessionFactory) {
1902: this .sessionFactory = sessionFactory;
1903: this .sessions.setSessionFactory(sessionFactory);
1904: }
1905:
1906: public void setTransactionManager(
1907: TransactionManager transactionManager) {
1908: this .transactionManager = transactionManager;
1909: this .transactions.setTransactionManager(transactionManager);
1910: this .sessions = new JTASessions();
1911: this .sessions.setSessionFactory(sessionFactory);
1912: this .sessions.setTransactionManager(transactionManager);
1913: }
1914:
1915: public TransactionManager getTransactionManager() {
1916: return transactionManager;
1917: }
1918:
1919: public void start() {
1920: if (timer != null)
1921: throw new IllegalStateException("already started");
1922: timer = new java.util.Timer(true);
1923: timeoutTask = new TimeoutTask();
1924: timer.schedule(timeoutTask, getTimerInterval(),
1925: getTimerInterval());
1926: }
1927:
1928: public void stop() {
1929: if (timer != null) {
1930: timer.cancel();
1931: timer = null;
1932: }
1933: if (sessionFactory != null) {
1934: try {
1935: sessionFactory.close();
1936: sessionFactory = null;
1937: } catch (HibernateException e) {
1938: LOG.error(getProcessName(), e);
1939: throw new ControllerException(e.getMessage());
1940: }
1941: }
1942: }
1943:
1944: public void reload() {
1945: if (configuration == null)
1946: throw new ControllerException(
1947: "No reference to Configuration");
1948:
1949: try {
1950: stop();
1951: configuration.initializeController(this );
1952: start();
1953: } catch (Exception e) {
1954: LOG.error(getProcessName(), e);
1955: throw new ControllerException(e.getMessage());
1956: }
1957: }
1958:
1959: private void doCommitAndBegin(Subject subject)
1960: throws ControllerException {
1961: try {
1962: // TODO: check if this could be transactions.commit() and transactions.begin() also
1963: transactionManager.commit();
1964: transactionManager.begin();
1965: sessions.getSession().lock(subject, LockMode.UPGRADE);
1966: } catch (Exception e) {
1967: throw new ControllerException(e);
1968: }
1969: }
1970:
1971: /**
1972: * Hibernate does not handle the situation where you reassociate an
1973: * entity to a session after a rollback and that entity contains a
1974: * collection that was modified during the rolled back transaction. Some
1975: * consider this a bug in Hibernate, but whatever the case, we need to
1976: * handle this carefully, thus the need for this method.
1977: *
1978: * @param subject
1979: */
1980: private void doRollbackAndBegin(Subject subject)
1981: throws ControllerException {
1982: try {
1983: // TODO: check if this could be transactions.commit() and transactions.begin() also
1984: final Session session = sessions.getSession();
1985: transactionManager.rollback();
1986:
1987: transactionManager.begin();
1988: sessions.getSession().refresh(subject, LockMode.UPGRADE);
1989: } catch (Exception e) {
1990: throw new ControllerException(e);
1991: }
1992: }
1993:
1994: private class TimeoutTask extends TimerTask {
1995: public void run() {
1996: if (System.currentTimeMillis() - scheduledExecutionTime() >= getTimerInterval())
1997: return;
1998:
1999: try {
2000: timeout();
2001: } catch (Throwable e) {
2002: LOG.error(getProcessName(), e);
2003: }
2004: }
2005: }
2006:
2007: public boolean equals(Object o) {
2008: if (this == o)
2009: return true;
2010: if (o == null || getClass() != o.getClass())
2011: return false;
2012:
2013: final Controller that = (Controller) o;
2014:
2015: if (!processName.equals(that.processName))
2016: return false;
2017:
2018: return true;
2019: }
2020:
2021: public int hashCode() {
2022: return processName.hashCode();
2023: }
2024:
2025: private static class NodeNameComparator implements Comparator<Node> {
2026: public int compare(Node n1, Node n2) {
2027: return n1.getName().compareTo(n2.getName());
2028: }
2029: }
2030:
2031: static class ElementRuntimeException extends Exception {
2032: public ElementRuntimeException() {
2033: }
2034:
2035: public ElementRuntimeException(String message) {
2036: super (message);
2037: }
2038:
2039: public ElementRuntimeException(String message, Throwable cause) {
2040: super (message, cause);
2041: }
2042:
2043: public ElementRuntimeException(Throwable cause) {
2044: super(cause);
2045: }
2046: }
2047: }
|