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.processor;
018
019import org.apache.camel.AsyncCallback;
020import org.apache.camel.AsyncProcessor;
021import org.apache.camel.CamelContext;
022import org.apache.camel.CamelContextAware;
023import org.apache.camel.Exchange;
024import org.apache.camel.impl.DefaultClaimCheckRepository;
025import org.apache.camel.processor.aggregate.AggregationStrategy;
026import org.apache.camel.spi.ClaimCheckRepository;
027import org.apache.camel.spi.IdAware;
028import org.apache.camel.support.ServiceSupport;
029import org.apache.camel.util.AsyncProcessorHelper;
030import org.apache.camel.util.ExchangeHelper;
031import org.apache.camel.util.ObjectHelper;
032import org.apache.camel.util.ServiceHelper;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036/**
037 * ClaimCheck EIP implementation.
038 * <p/>
039 * The current Claim Check EIP implementation in Camel is only intended for temporary memory repository. Likewise
040 * the repository is not shared among {@link Exchange}s, but a private instance is created per {@link Exchange}.
041 * This guards against concurrent and thread-safe issues. For off-memory persistent storage of data, then use
042 * any of the many Camel components that support persistent storage, and do not use this Claim Check EIP implementation.
043 */
044public class ClaimCheckProcessor extends ServiceSupport implements AsyncProcessor, IdAware, CamelContextAware {
045
046    private static final Logger LOG = LoggerFactory.getLogger(ClaimCheckProcessor.class);
047    private CamelContext camelContext;
048    private String id;
049    private String operation;
050    private AggregationStrategy aggregationStrategy;
051    private String key;
052    private String filter;
053
054    @Override
055    public CamelContext getCamelContext() {
056        return camelContext;
057    }
058
059    @Override
060    public void setCamelContext(CamelContext camelContext) {
061        this.camelContext = camelContext;
062    }
063
064    @Override
065    public String getId() {
066        return id;
067    }
068
069    @Override
070    public void setId(String id) {
071        this.id = id;
072    }
073
074    public String getOperation() {
075        return operation;
076    }
077
078    public void setOperation(String operation) {
079        this.operation = operation;
080    }
081
082    public AggregationStrategy getAggregationStrategy() {
083        return aggregationStrategy;
084    }
085
086    public void setAggregationStrategy(AggregationStrategy aggregationStrategy) {
087        this.aggregationStrategy = aggregationStrategy;
088    }
089
090    public String getKey() {
091        return key;
092    }
093
094    public void setKey(String key) {
095        this.key = key;
096    }
097
098    public String getFilter() {
099        return filter;
100    }
101
102    public void setFilter(String filter) {
103        this.filter = filter;
104    }
105
106    public void process(Exchange exchange) throws Exception {
107        AsyncProcessorHelper.process(this, exchange);
108    }
109
110    @Override
111    public boolean process(Exchange exchange, AsyncCallback callback) {
112        // the repository is scoped per exchange
113        ClaimCheckRepository repo = exchange.getProperty(Exchange.CLAIM_CHECK_REPOSITORY, ClaimCheckRepository.class);
114        if (repo == null) {
115            repo = new DefaultClaimCheckRepository();
116            exchange.setProperty(Exchange.CLAIM_CHECK_REPOSITORY, repo);
117        }
118
119        try {
120            if ("Set".equals(operation)) {
121                // copy exchange, and do not share the unit of work
122                Exchange copy = ExchangeHelper.createCorrelatedCopy(exchange, false);
123                boolean addedNew = repo.add(key, copy);
124                if (addedNew) {
125                    LOG.debug("Add: {} -> {}", key, copy);
126                } else {
127                    LOG.debug("Override: {} -> {}", key, copy);
128                }
129            } else if ("Get".equals(operation)) {
130                Exchange copy = repo.get(key);
131                LOG.debug("Get: {} -> {}", key, exchange);
132                if (copy != null) {
133                    Exchange result = aggregationStrategy.aggregate(exchange, copy);
134                    if (result != null) {
135                        ExchangeHelper.copyResultsPreservePattern(exchange, result);
136                    }
137                }
138            } else if ("GetAndRemove".equals(operation)) {
139                Exchange copy = repo.getAndRemove(key);
140                LOG.debug("GetAndRemove: {} -> {}", key, exchange);
141                if (copy != null) {
142                    // prepare the exchanges for aggregation
143                    ExchangeHelper.prepareAggregation(exchange, copy);
144                    Exchange result = aggregationStrategy.aggregate(exchange, copy);
145                    if (result != null) {
146                        ExchangeHelper.copyResultsPreservePattern(exchange, result);
147                    }
148                }
149            } else if ("Push".equals(operation)) {
150                // copy exchange, and do not share the unit of work
151                Exchange copy = ExchangeHelper.createCorrelatedCopy(exchange, false);
152                LOG.debug("Push: {} -> {}", key, copy);
153                repo.push(copy);
154            } else if ("Pop".equals(operation)) {
155                Exchange copy = repo.pop();
156                LOG.debug("Pop: {} -> {}", key, exchange);
157                if (copy != null) {
158                    // prepare the exchanges for aggregation
159                    ExchangeHelper.prepareAggregation(exchange, copy);
160                    Exchange result = aggregationStrategy.aggregate(exchange, copy);
161                    if (result != null) {
162                        ExchangeHelper.copyResultsPreservePattern(exchange, result);
163                    }
164                }
165            }
166        } catch (Throwable e) {
167            exchange.setException(e);
168        }
169
170        callback.done(true);
171        return true;
172    }
173
174    @Override
175    protected void doStart() throws Exception {
176        ObjectHelper.notNull(operation, "operation", this);
177
178        if (aggregationStrategy == null) {
179            aggregationStrategy = createAggregationStrategy();
180        }
181        if (aggregationStrategy instanceof CamelContextAware) {
182            ((CamelContextAware) aggregationStrategy).setCamelContext(camelContext);
183        }
184
185        ServiceHelper.startServices(aggregationStrategy);
186    }
187
188    @Override
189    protected void doStop() throws Exception {
190        ServiceHelper.stopServices(aggregationStrategy);
191    }
192
193    @Override
194    public String toString() {
195        return "ClaimCheck[" + operation + "]";
196    }
197
198    protected AggregationStrategy createAggregationStrategy() {
199        ClaimCheckAggregationStrategy answer = new ClaimCheckAggregationStrategy();
200        answer.setFilter(filter);
201        return answer;
202    }
203}