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(javaType = "java.lang.Boolean", defaultValue = "true")
044    private String eager;
045    @XmlAttribute
046    private String completionEager;
047    @XmlAttribute
048    @Metadata(javaType = "java.lang.Boolean", defaultValue = "true")
049    private String skipDuplicate;
050    @XmlAttribute
051    @Metadata(javaType = "java.lang.Boolean", 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}