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 */ 017package org.apache.camel.component.mock; 018 019import java.util.Date; 020import java.util.Locale; 021import java.util.concurrent.TimeUnit; 022 023import org.apache.camel.Exchange; 024import org.apache.camel.Expression; 025import org.apache.camel.builder.BinaryPredicateSupport; 026import org.apache.camel.util.Time; 027import org.slf4j.Logger; 028import org.slf4j.LoggerFactory; 029 030/** 031 * Represents time based clauses for setting expectations on the mocks. 032 * Such as time constrains for the received messages. 033 * 034 * @version 035 */ 036public class TimeClause extends BinaryPredicateSupport { 037 038 private static final Logger LOG = LoggerFactory.getLogger(TimeClause.class); 039 040 private Time timeFrom; 041 private Time timeTo; 042 private boolean beforeNext; 043 private String was; 044 045 public TimeClause(Expression left, Expression right) { 046 // previous, next 047 super(left, right); 048 } 049 050 // TimeUnit DSL 051 // ------------------------------------------------------------------------- 052 053 public class TimeClassUnit { 054 055 private final TimeClause clause; 056 private int from; 057 private int to; 058 059 public TimeClassUnit(TimeClause clause, int to) { 060 this(clause, -1, to); 061 } 062 063 public TimeClassUnit(TimeClause clause, int from, int to) { 064 this.clause = clause; 065 this.from = from; 066 this.to = to; 067 } 068 069 public TimeClause millis() { 070 period(TimeUnit.MILLISECONDS); 071 return clause; 072 } 073 074 public TimeClause seconds() { 075 period(TimeUnit.SECONDS); 076 return clause; 077 } 078 079 public TimeClause minutes() { 080 period(TimeUnit.MINUTES); 081 return clause; 082 } 083 084 private void period(TimeUnit unit) { 085 if (from > 0) { 086 timeFrom = new Time(from, unit); 087 } 088 timeTo = new Time(to, unit); 089 } 090 } 091 092 // DSL 093 // ------------------------------------------------------------------------- 094 095 public TimeClassUnit noLaterThan(int period) { 096 TimeClassUnit unit = new TimeClassUnit(this, period); 097 return unit; 098 } 099 100 public TimeClassUnit between(int from, int to) { 101 TimeClassUnit unit = new TimeClassUnit(this, from, to); 102 return unit; 103 } 104 105 public void beforeNext() { 106 this.beforeNext = true; 107 } 108 109 public void afterPrevious() { 110 this.beforeNext = false; 111 } 112 113 // Implementation 114 // ------------------------------------------------------------------------- 115 116 protected boolean matches(Exchange exchange, Object leftValue, Object rightValue) { 117 was = null; 118 boolean answer = true; 119 120 if (timeTo == null) { 121 throw new IllegalArgumentException("The time period has not been set. Ensure to include the time unit as well."); 122 } 123 124 Date currentDate = exchange.getProperty(Exchange.RECEIVED_TIMESTAMP, Date.class); 125 126 // the other date is either the previous or the next 127 Date otherDate; 128 if (beforeNext) { 129 // grab the previous value (left) 130 if (leftValue != null) { 131 otherDate = (Date) leftValue; 132 } else { 133 // we hit a boundary so grab the other 134 otherDate = (Date) rightValue; 135 } 136 } else { 137 // grab the next value (right) 138 if (rightValue != null) { 139 otherDate = (Date) rightValue; 140 } else { 141 // we hit a boundary so grab the other 142 otherDate = (Date) leftValue; 143 } 144 } 145 146 // if we could not grab the value, we hit a boundary (ie. either 0 message or last message) 147 if (otherDate == null) { 148 return true; 149 } 150 151 // compute if we were within the allowed time range 152 Time current = new Time(currentDate.getTime(), TimeUnit.MILLISECONDS); 153 Time other = new Time(otherDate.getTime(), TimeUnit.MILLISECONDS); 154 // must absolute delta as when we hit the boundaries the delta would negative 155 long delta = Math.abs(other.toMillis() - current.toMillis()); 156 was = "delta: " + delta + " millis"; 157 158 if (timeFrom != null) { 159 long from = timeFrom.toMillis(); 160 answer = delta >= from; 161 } 162 if (answer) { 163 long to = timeTo.toMillis(); 164 answer = delta <= to; 165 } 166 167 if (LOG.isDebugEnabled()) { 168 LOG.debug("Evaluated time clause [{}] with current: {}, other: {} -> {}", new Object[]{toString(), currentDate, otherDate, answer}); 169 } 170 171 return answer; 172 } 173 174 @Override 175 protected String getOperationText() { 176 return beforeNext ? "before next" : "after previous"; 177 } 178 179 @Override 180 public String toString() { 181 if (timeFrom == null) { 182 return "no later than " + timeTo + " " + getOperationText() + " (" + was + ")"; 183 } else { 184 return "between " + timeFrom.getNumber() + "-" + timeTo.getNumber() + " " + timeTo.getTimeUnit().toString().toLowerCase(Locale.ENGLISH) 185 + " " + getOperationText() + " (" + was + ")"; 186 } 187 } 188}