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.builder;
018
019import java.util.function.BiFunction;
020
021import org.apache.camel.AggregationStrategy;
022import org.apache.camel.Exchange;
023import org.apache.camel.Message;
024import org.apache.camel.util.ObjectHelper;
025
026public class AggregationStrategyClause<T> implements AggregationStrategy {
027    private final T parent;
028    private AggregationStrategy strategy;
029
030    public AggregationStrategyClause(T parent) {
031        this.parent = parent;
032        this.strategy = null;
033    }
034
035    @Override
036    public Exchange aggregate(Exchange oldExchange, Exchange newExchange) {
037        return ObjectHelper.notNull(strategy, "AggregationStrategy").aggregate(oldExchange, newExchange);
038    }
039
040    @Override
041    public Exchange aggregate(Exchange oldExchange, Exchange newExchange, Exchange inputExchange) {
042        return ObjectHelper.notNull(strategy, "AggregationStrategy").aggregate(oldExchange, newExchange, inputExchange);
043    }
044
045    // *******************************
046    // Exchange
047    // *******************************
048
049    /**
050     * Define an aggregation strategy which targets the exchnage.
051     */
052    public T exchange(final BiFunction<Exchange, Exchange, Exchange> function) {
053        strategy = function::apply;
054        return parent;
055    }
056
057    // *******************************
058    // Message
059    // *******************************
060
061    /**
062     * Define an aggregation strategy which targets Exchanges In Message.
063     * <blockquote>
064     * 
065     * <pre>
066     * {@code
067     * from("direct:aggregate")
068     *     .aggregate()
069     *         .message((old, new) -> {
070     *             if (old == null) {
071     *                 return new;
072     *             }
073     *
074     *             String oldBody = old.getBody(String.class);
075     *             String newBody = new.getBody(String.class);
076     *
077     *             old.setBody(oldBody + "+" + newBody);
078     *
079     *             return old;
080     *         });
081     * }
082     * </pre>
083     * 
084     * </blockquote>
085     */
086    public T message(final BiFunction<Message, Message, Message> function) {
087        return exchange((Exchange oldExchange, Exchange newExchange) -> {
088            Message oldMessage = oldExchange != null ? oldExchange.getIn() : null;
089            Message newMessage = ObjectHelper.notNull(newExchange, "NewExchange").getIn();
090            Message result = function.apply(oldMessage, newMessage);
091
092            if (oldExchange != null) {
093                oldExchange.setIn(result);
094                return oldExchange;
095            } else {
096                newExchange.setIn(result);
097                return newExchange;
098            }
099        });
100    }
101
102    // *******************************
103    // Body
104    // *******************************
105
106    /**
107     * Define an aggregation strategy which targets Exchanges In Body.
108     * <blockquote>
109     * 
110     * <pre>
111     * {@code
112     * from("direct:aggregate")
113     *     .aggregate()
114     *         .body((old, new) -> {
115     *             if (old == null) {
116     *                 return new;
117     *             }
118     *
119     *             return old.toString() + new.toString();
120     *         });
121     * }
122     * </pre>
123     * 
124     * </blockquote>
125     */
126    public T body(final BiFunction<Object, Object, Object> function) {
127        return body(Object.class, function);
128    }
129
130    /**
131     * Define an aggregation strategy which targets Exchanges In Body.
132     * <blockquote>
133     * 
134     * <pre>
135     * {@code
136     * from("direct:aggregate")
137     *     .aggregate()
138     *         .body(String.class, (old, new) -> {
139     *             if (old == null) {
140     *                 return new;
141     *             }
142     *
143     *             return old + new;
144     *         });
145     * }
146     * </pre>
147     * 
148     * </blockquote>
149     */
150    public <B> T body(final Class<B> type, final BiFunction<B, B, Object> function) {
151        return body(type, type, function);
152    }
153
154    /**
155     * Define an aggregation strategy which targets Exchanges In Body.
156     */
157    public <O, N> T body(final Class<O> oldType, final Class<N> newType, final BiFunction<O, N, Object> function) {
158        return exchange((Exchange oldExchange, Exchange newExchange) -> {
159            Message oldMessage = oldExchange != null ? oldExchange.getIn() : null;
160            Message newMessage = ObjectHelper.notNull(newExchange, "NewExchange").getIn();
161
162            Object result = function.apply(oldMessage != null ? oldMessage.getBody(oldType) : null, newMessage != null ? newMessage.getBody(newType) : null);
163
164            if (oldExchange != null) {
165                oldExchange.getIn().setBody(result);
166                return oldExchange;
167            } else {
168                newExchange.getIn().setBody(result);
169                return newExchange;
170            }
171        });
172    }
173}