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     */
017    package org.apache.camel.builder.sql;
018    
019    import java.util.Collections;
020    import java.util.HashMap;
021    import java.util.List;
022    import java.util.Map;
023    import java.util.Set;
024    
025    import org.apache.camel.Exchange;
026    import org.apache.camel.Expression;
027    import org.apache.camel.Message;
028    import org.apache.camel.Predicate;
029    import org.apache.camel.RuntimeExpressionException;
030    import org.apache.camel.util.ObjectHelper;
031    
032    import org.josql.Query;
033    import org.josql.QueryExecutionException;
034    import org.josql.QueryParseException;
035    
036    /**
037     * A builder of SQL {@link org.apache.camel.Expression} and
038     * {@link org.apache.camel.Predicate} implementations
039     * 
040     * @version $Revision: 941994 $
041     */
042    public class SqlBuilder implements Expression, Predicate {
043    
044        private Query query;
045        private Map<String, Object> variables = new HashMap<String, Object>();
046    
047        public SqlBuilder(Query query) {
048            this.query = query;
049        }
050    
051        public <T> T evaluate(Exchange exchange, Class<T> type) {
052            Object result = evaluateQuery(exchange);
053            return exchange.getContext().getTypeConverter().convertTo(type, result);
054        }
055    
056        public boolean matches(Exchange exchange) {
057            List list = evaluateQuery(exchange);
058            return matches(exchange, list);
059        }
060    
061        public void assertMatches(String text, Exchange exchange) throws AssertionError {
062            List list = evaluateQuery(exchange);
063            if (!matches(exchange, list)) {
064                throw new AssertionError(this + " failed on " + exchange + " as found " + list);
065            }
066        }
067    
068        // Builder API
069        // -----------------------------------------------------------------------
070    
071        /**
072         * Creates a new builder for the given SQL query string
073         * 
074         * @param sql the SQL query to perform
075         * @return a new builder
076         * @throws QueryParseException if there is an issue with the SQL
077         */
078        public static SqlBuilder sql(String sql) throws QueryParseException {
079            Query q = new Query();
080            q.parse(sql);
081            return new SqlBuilder(q);
082        }
083    
084        /**
085         * Adds the variable value to be used by the SQL query
086         */
087        public SqlBuilder variable(String name, Object value) {
088            getVariables().put(name, value);
089            return this;
090        }
091    
092        // Properties
093        // -----------------------------------------------------------------------
094        public Map<String, Object> getVariables() {
095            return variables;
096        }
097    
098        public void setVariables(Map<String, Object> properties) {
099            this.variables = properties;
100        }
101    
102        // Implementation methods
103        // -----------------------------------------------------------------------
104        protected boolean matches(Exchange exchange, List list) {
105            return ObjectHelper.matches(list);
106        }
107    
108        protected List evaluateQuery(Exchange exchange) {
109            configureQuery(exchange);
110            Message in = exchange.getIn();
111            List list = in.getBody(List.class);
112            if (list == null) {
113                list = Collections.singletonList(in.getBody());
114            }
115            try {
116                return query.execute(list).getResults();
117            } catch (QueryExecutionException e) {
118                throw new RuntimeExpressionException(e);
119            }
120        }
121    
122        protected void configureQuery(Exchange exchange) {
123            // lets pass in the headers as variables that the SQL can use
124            addVariables(exchange.getProperties());
125            addVariables(exchange.getIn().getHeaders());
126            addVariables(getVariables());
127    
128            query.setVariable("exchange", exchange);
129            query.setVariable("in", exchange.getIn());
130            query.setVariable("out", exchange.getOut());
131        }
132    
133        protected void addVariables(Map<String, Object> map) {
134            Set<Map.Entry<String, Object>> propertyEntries = map.entrySet();
135            for (Map.Entry<String, Object> entry : propertyEntries) {
136                query.setVariable(entry.getKey(), entry.getValue());
137            }
138        }
139    }