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.apache.camel.bam;
018
019 import org.apache.camel.Exchange;
020 import org.apache.camel.Processor;
021 import org.apache.camel.bam.model.ActivityState;
022 import org.apache.camel.bam.model.ProcessInstance;
023 import org.apache.camel.builder.FromBuilder;
024 import org.apache.camel.builder.ProcessorFactory;
025 import org.apache.camel.impl.DefaultExchange;
026 import org.apache.camel.util.Time;
027 import org.apache.commons.logging.Log;
028 import org.apache.commons.logging.LogFactory;
029
030 import java.util.Date;
031
032 /**
033 * A temporal rule
034 *
035 * @version $Revision: $
036 */
037 public class TemporalRule {
038 private static final transient Log log = LogFactory.getLog(TemporalRule.class);
039 private TimeExpression first;
040 private TimeExpression second;
041 private long expectedMillis;
042 private long overdueMillis;
043 private Processor overdueAction;
044 private ProcessorFactory overdueProcessorFactory;
045
046 public TemporalRule(TimeExpression left, TimeExpression right) {
047 this.first = left;
048 this.second = right;
049 }
050
051 public TemporalRule expectWithin(Time builder) {
052 return expectWithin(builder.toMillis());
053 }
054
055 public TemporalRule expectWithin(long millis) {
056 expectedMillis = millis;
057 return this;
058 }
059
060 public FromBuilder errorIfOver(Time builder) {
061 return errorIfOver(builder.toMillis());
062 }
063
064 public FromBuilder errorIfOver(long millis) {
065 overdueMillis = millis;
066
067 FromBuilder builder = new FromBuilder(second.getBuilder().getProcessBuilder(), null);
068 overdueProcessorFactory = builder;
069 return builder;
070 }
071
072 public TimeExpression getFirst() {
073 return first;
074 }
075
076 public TimeExpression getSecond() {
077 return second;
078 }
079
080 public void evaluate(ProcessContext context, ActivityState activityState) {
081 ProcessInstance instance = context.getProcessInstance();
082
083 Date firstTime = first.evaluateState(instance);
084 if (firstTime == null) {
085 // ignore as first event has not accurred yet
086 return;
087 }
088
089 // TODO now we might need to set the second activity state
090 // to 'grey' to indicate it now could happen?
091 // if the second activity state is not created yet we might wanna create it
092
093 ActivityState secondState = second.getActivityState(instance);
094 if (expectedMillis > 0L) {
095 Date expected = secondState.getTimeExpected();
096 if (expected == null) {
097 expected = add(firstTime, expectedMillis);
098 secondState.setTimeExpected(expected);
099 }
100 }
101 if (overdueMillis > 0L) {
102 Date overdue = secondState.getTimeOverdue();
103 if (overdue == null) {
104 overdue = add(firstTime, overdueMillis);
105 secondState.setTimeOverdue(overdue);
106 }
107 }
108
109 Date secondTime = second.evaluateState(instance);
110 if (secondTime == null) {
111 // TODO add test that things have expired
112 }
113 else {
114
115 /*
116 if (secondTime.delta(firstTime.plus(gap)) > 0) {
117 // TODO
118 }
119 */
120 }
121 }
122
123 public void processExpired(ActivityState activityState) throws Exception {
124 if (overdueAction == null && overdueProcessorFactory != null) {
125 overdueAction = overdueProcessorFactory.createProcessor();
126 }
127 if (overdueAction != null) {
128 Date now = new Date();
129 ProcessInstance instance = activityState.getProcess();
130 ActivityState secondState = second.getActivityState(instance);
131 Date overdue = secondState.getTimeOverdue();
132 if (now.compareTo(overdue) >= 0) {
133 Exchange exchange = createExchange();
134 exchange.getIn().setBody(activityState);
135 overdueAction.process(exchange);
136 }
137 else {
138 log.warn("Process has not actually expired; the time is: " + now + " but the overdue time is: " + overdue);
139 }
140 }
141 }
142
143 protected Exchange createExchange() {
144 return new DefaultExchange(second.getBuilder().getProcessBuilder().getContext());
145 }
146
147 /**
148 * Returns the date in the future adding the given number of millis
149 *
150 * @param date
151 * @param millis
152 * @return the date in the future
153 */
154 protected Date add(Date date, long millis) {
155 return new Date(date.getTime() + millis);
156 }
157
158 /*
159 public void onActivityLifecycle(ActivityState state, ActivityRules activityRules, ActivityLifecycle lifecycle) {
160 if (first.isActivityLifecycle(activityRules, lifecycle)) {
161 // lets create the expected and error timers
162
163 // TODO we could use a single timer event; then keep incrementing its type
164 // counter to escalate & use different times each time to reduce some DB work
165 createTimer(state, expectedMillis);
166 createTimer(state, overdueMillis);
167 }
168 }
169 */
170 }