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