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 }