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.model; 018 019import java.util.function.Supplier; 020 021import javax.xml.bind.annotation.XmlAccessType; 022import javax.xml.bind.annotation.XmlAccessorType; 023import javax.xml.bind.annotation.XmlAttribute; 024import javax.xml.bind.annotation.XmlRootElement; 025import javax.xml.bind.annotation.XmlTransient; 026 027import org.apache.camel.Expression; 028import org.apache.camel.model.language.ExpressionDefinition; 029import org.apache.camel.spi.IdempotentRepository; 030import org.apache.camel.spi.Metadata; 031 032/** 033 * Filters out duplicate messages 034 */ 035@Metadata(label = "eip,routing") 036@XmlRootElement(name = "idempotentConsumer") 037@XmlAccessorType(XmlAccessType.FIELD) 038public class IdempotentConsumerDefinition extends OutputExpressionNode { 039 040 @XmlAttribute(required = true) 041 private String messageIdRepositoryRef; 042 @XmlAttribute 043 @Metadata(defaultValue = "true") 044 private String eager; 045 @XmlAttribute 046 private String completionEager; 047 @XmlAttribute 048 @Metadata(defaultValue = "true") 049 private String skipDuplicate; 050 @XmlAttribute 051 @Metadata(defaultValue = "true") 052 private String removeOnFailure; 053 @XmlTransient 054 private IdempotentRepository idempotentRepository; 055 056 public IdempotentConsumerDefinition() { 057 } 058 059 public IdempotentConsumerDefinition(Expression messageIdExpression, IdempotentRepository idempotentRepository) { 060 super(messageIdExpression); 061 this.idempotentRepository = idempotentRepository; 062 } 063 064 @Override 065 public String toString() { 066 return "IdempotentConsumer[" + getExpression() + " -> " + getOutputs() + "]"; 067 } 068 069 @Override 070 public String getShortName() { 071 return "idempotentConsumer"; 072 } 073 074 @Override 075 public String getLabel() { 076 return "idempotentConsumer[" + getExpression() + "]"; 077 } 078 079 // Fluent API 080 // ------------------------------------------------------------------------- 081 082 /** 083 * Sets the reference name of the message id repository 084 * 085 * @param messageIdRepositoryRef the reference name of message id repository 086 * @return builder 087 */ 088 public IdempotentConsumerDefinition messageIdRepositoryRef(String messageIdRepositoryRef) { 089 setMessageIdRepositoryRef(messageIdRepositoryRef); 090 return this; 091 } 092 093 /** 094 * Sets the message id repository for the idempotent consumer 095 * 096 * @param idempotentRepository the repository instance of idempotent 097 * @return builder 098 */ 099 public IdempotentConsumerDefinition messageIdRepository(IdempotentRepository idempotentRepository) { 100 setMessageIdRepository(idempotentRepository); 101 return this; 102 } 103 104 /** 105 * Sets the message id repository for the idempotent consumer 106 * 107 * @param idempotentRepository the repository instance of idempotent 108 * @return builder 109 */ 110 public IdempotentConsumerDefinition messageIdRepository(Supplier<IdempotentRepository> idempotentRepository) { 111 setMessageIdRepository(idempotentRepository.get()); 112 return this; 113 } 114 115 /** 116 * Sets whether to eagerly add the key to the idempotent repository or wait 117 * until the exchange is complete. Eager is default enabled. 118 * 119 * @param eager <tt>true</tt> to add the key before processing, 120 * <tt>false</tt> to wait until the exchange is complete. 121 * @return builder 122 */ 123 public IdempotentConsumerDefinition eager(boolean eager) { 124 setEager(Boolean.toString(eager)); 125 return this; 126 } 127 128 /** 129 * Sets whether to complete the idempotent consumer eager or when the 130 * exchange is done. 131 * <p/> 132 * If this option is <tt>true</tt> to complete eager, then the idempotent 133 * consumer will trigger its completion when the exchange reached the end of 134 * the block of the idempotent consumer pattern. So if the exchange is 135 * continued routed after the block ends, then whatever happens there does 136 * not affect the state. 137 * <p/> 138 * If this option is <tt>false</tt> (default) to <b>not</b> complete eager, 139 * then the idempotent consumer will complete when the exchange is done 140 * being routed. So if the exchange is continued routed after the block 141 * ends, then whatever happens there <b>also</b> affect the state. For 142 * example if the exchange failed due to an exception, then the state of the 143 * idempotent consumer will be a rollback. 144 * 145 * @param completionEager whether to complete eager or complete when the 146 * exchange is done 147 * @return builder 148 */ 149 public IdempotentConsumerDefinition completionEager(boolean completionEager) { 150 setCompletionEager(Boolean.toString(completionEager)); 151 return this; 152 } 153 154 /** 155 * Sets whether to remove or keep the key on failure. 156 * <p/> 157 * The default behavior is to remove the key on failure. 158 * 159 * @param removeOnFailure <tt>true</tt> to remove the key, <tt>false</tt> to 160 * keep the key if the exchange fails. 161 * @return builder 162 */ 163 public IdempotentConsumerDefinition removeOnFailure(boolean removeOnFailure) { 164 setRemoveOnFailure(Boolean.toString(removeOnFailure)); 165 return this; 166 } 167 168 /** 169 * Sets whether to skip duplicates or not. 170 * <p/> 171 * The default behavior is to skip duplicates. 172 * <p/> 173 * A duplicate message would have the Exchange property 174 * {@link org.apache.camel.Exchange#DUPLICATE_MESSAGE} set to a 175 * {@link Boolean#TRUE} value. A none duplicate message will not have this 176 * property set. 177 * 178 * @param skipDuplicate <tt>true</tt> to skip duplicates, <tt>false</tt> to 179 * allow duplicates. 180 * @return builder 181 */ 182 public IdempotentConsumerDefinition skipDuplicate(boolean skipDuplicate) { 183 setSkipDuplicate(Boolean.toString(skipDuplicate)); 184 return this; 185 } 186 187 /** 188 * Expression used to calculate the correlation key to use for duplicate 189 * check. The Exchange which has the same correlation key is regarded as a 190 * duplicate and will be rejected. 191 */ 192 @Override 193 public void setExpression(ExpressionDefinition expression) { 194 // override to include javadoc what the expression is used for 195 super.setExpression(expression); 196 } 197 198 public String getMessageIdRepositoryRef() { 199 return messageIdRepositoryRef; 200 } 201 202 public void setMessageIdRepositoryRef(String messageIdRepositoryRef) { 203 this.messageIdRepositoryRef = messageIdRepositoryRef; 204 } 205 206 public IdempotentRepository getMessageIdRepository() { 207 return idempotentRepository; 208 } 209 210 public void setMessageIdRepository(IdempotentRepository idempotentRepository) { 211 this.idempotentRepository = idempotentRepository; 212 } 213 214 public String getEager() { 215 return eager; 216 } 217 218 public void setEager(String eager) { 219 this.eager = eager; 220 } 221 222 public String getSkipDuplicate() { 223 return skipDuplicate; 224 } 225 226 public void setSkipDuplicate(String skipDuplicate) { 227 this.skipDuplicate = skipDuplicate; 228 } 229 230 public String getRemoveOnFailure() { 231 return removeOnFailure; 232 } 233 234 public void setRemoveOnFailure(String removeOnFailure) { 235 this.removeOnFailure = removeOnFailure; 236 } 237 238 public String getCompletionEager() { 239 return completionEager; 240 } 241 242 public void setCompletionEager(String completionEager) { 243 this.completionEager = completionEager; 244 } 245 246}