CAMEL-4725: Batch support and other options for Producer.

Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/df5944fa
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/df5944fa
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/df5944fa

Branch: refs/heads/master
Commit: df5944fad4e3100e054f1dda09c60ebc80274e15
Parents: f511606
Author: Sami Nurminen <snurm...@gmail.com>
Authored: Tue Jan 12 23:12:18 2016 +0200
Committer: Claus Ibsen <davscl...@apache.org>
Committed: Thu Jan 14 16:34:09 2016 +0000

----------------------------------------------------------------------
 .../BatchCallableStatementCreatorFactory.java   | 100 +++
 .../sql/stored/CallableStatementWrapper.java    | 128 +++
 .../stored/CallableStatementWrapperFactory.java | 101 +++
 .../sql/stored/SqlStoredComponent.java          |  28 +-
 .../sql/stored/SqlStoredConstants.java          |  30 +
 .../component/sql/stored/SqlStoredEndpoint.java | 128 +--
 .../component/sql/stored/SqlStoredProducer.java |  95 ++-
 .../component/sql/stored/StamentWrapper.java    |  42 +
 .../sql/stored/TemplateStoredProcedure.java     |  83 ++
 .../sql/stored/WrapperExecuteCallback.java      |  26 +
 .../sql/stored/template/TemplateParser.java     |  45 +
 .../template/TemplateStoredProcedure.java       |  74 --
 .../TemplateStoredProcedureFactory.java         |  76 --
 .../sql/stored/template/ast/InputParameter.java |  52 +-
 .../sql/stored/template/ast/ParseHelper.java    |  51 +-
 .../sql/stored/template/ast/Template.java       |  17 +-
 .../sql/stored/template/ast/ValueExtractor.java |  29 +
 .../template/generated/ParseException.java      | 315 ++++---
 .../stored/template/generated/SSPTParser.java   | 542 ++++++------
 .../template/generated/SSPTParserConstants.java |  56 +-
 .../generated/SSPTParserTokenManager.java       | 695 +++++++--------
 .../template/generated/SimpleCharStream.java    | 854 +++++++++----------
 .../sql/stored/template/generated/Token.java    | 228 +++--
 .../template/generated/TokenMgrError.java       | 241 +++---
 .../sql/stored/template/grammar/sspt.jj         |  37 +-
 .../stored/CallableStatementWrapperTest.java    |  99 +++
 .../camel/component/sql/stored/ParserTest.java  |  39 +-
 .../component/sql/stored/ProducerBatchTest.java |  95 +++
 .../component/sql/stored/ProducerTest.java      |   7 +-
 .../ProducerUseMessageBodyForTemplateTest.java  |  85 ++
 .../sql/stored/SqlStoredDataSourceTest.java     |  80 ++
 .../component/sql/stored/TemplateCacheTest.java |  59 ++
 .../sql/stored/TemplateStoredProcedureTest.java |  79 --
 .../sql/stored/TestStoredProcedure.java         |  19 +-
 .../test/resources/sql/storedProcedureTest.sql  |  12 +-
 35 files changed, 2786 insertions(+), 1861 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
new file mode 100644
index 0000000..cda2bd4
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/BatchCallableStatementCreatorFactory.java
@@ -0,0 +1,100 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+import java.sql.CallableStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.apache.camel.component.sql.stored.template.ast.Template;
+import org.springframework.jdbc.core.CallableStatementCreator;
+import org.springframework.jdbc.core.CallableStatementCreatorFactory;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.core.StatementCreatorUtils;
+
+
+public class BatchCallableStatementCreatorFactory {
+
+    final CallableStatementCreatorFactory callableStatementCreatorFactory;
+
+    final List<SqlParameter> sqlParameterList;
+
+    final Template template;
+
+
+    public BatchCallableStatementCreatorFactory(Template template) {
+        this.template = template;
+        this.sqlParameterList = createParams();
+        this.callableStatementCreatorFactory = new 
CallableStatementCreatorFactory(formatSql(), createParams());
+    }
+
+    public void addParameter(CallableStatement callableStatement, Map 
batchRow) throws SQLException {
+        int i = 1;
+        for (SqlParameter parameter : getSqlParameterList()) {
+            StatementCreatorUtils.setParameterValue(callableStatement, i, 
parameter, batchRow.get(parameter.getName()));
+            i++;
+        }
+    }
+
+    private String formatSql() {
+        return "{call " + this.template.getProcedureName() + "(" + 
repeatParameter(this.template.getParameterList()
+                .size()) + ")}";
+    }
+
+    private String repeatParameter(int size) {
+        StringBuilder ret = new StringBuilder();
+        for (int i = 0; i < size; i++) {
+            ret.append('?');
+            if (i + 1 < size) {
+                ret.append(',');
+            }
+        }
+        return ret.toString();
+    }
+
+    private List<SqlParameter> createParams() {
+        List<SqlParameter> params = new ArrayList<>();
+
+        for (Object parameter : template.getParameterList()) {
+            if (parameter instanceof InputParameter) {
+                InputParameter inputParameter = (InputParameter) parameter;
+                params.add(new SqlParameter(inputParameter.getName(), 
inputParameter.getSqlType()));
+
+            } else {
+                throw new UnsupportedOperationException("Only IN parameters 
supported by batch!");
+            }
+        }
+
+
+        return params;
+    }
+
+    public CallableStatementCreator newCallableStatementCreator(Map params) {
+        return 
this.callableStatementCreatorFactory.newCallableStatementCreator(params);
+    }
+
+    public List<SqlParameter> getSqlParameterList() {
+        return sqlParameterList;
+    }
+
+    public Template getTemplate() {
+        return template;
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
new file mode 100644
index 0000000..824f21d
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapper.java
@@ -0,0 +1,128 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.core.CallableStatementCallback;
+import org.springframework.jdbc.core.CallableStatementCreator;
+
+public class CallableStatementWrapper implements StamentWrapper {
+
+    final CallableStatementWrapperFactory factory;
+
+    final String template;
+
+    Map result;
+
+    List<Map> batchItems;
+
+    Integer updateCount;
+
+    BatchCallableStatementCreatorFactory batchFactory;
+
+    public CallableStatementWrapper(String template, 
CallableStatementWrapperFactory wrapperFactory) {
+        this.factory = wrapperFactory;
+        this.template = template;
+    }
+
+    @Override
+    public void call(final WrapperExecuteCallback cb) throws Exception {
+        cb.execute(this);
+    }
+
+
+    @Override
+    public int[] executeBatch() throws SQLException {
+
+        if (this.batchItems == null) {
+            throw new IllegalArgumentException("Batch must have at least one 
item");
+        }
+
+        final Iterator<Map> params = batchItems.iterator();
+
+
+        return factory.getJdbcTemplate().execute(new 
CallableStatementCreator() {
+            @Override
+            public CallableStatement createCallableStatement(Connection 
connection) throws SQLException {
+                return 
batchFactory.newCallableStatementCreator(params.next()).createCallableStatement(connection);
+
+            }
+        }, new CallableStatementCallback<int[]>() {
+            @Override
+            public int[] doInCallableStatement(CallableStatement 
callableStatement) throws SQLException, DataAccessException {
+                //add first item to batch
+                callableStatement.addBatch();
+
+                while (params.hasNext()) {
+                    batchFactory.addParameter(callableStatement, 
params.next());
+                    callableStatement.addBatch();
+                }
+                return callableStatement.executeBatch();
+            }
+        });
+    }
+
+
+    @Override
+    public Integer getUpdateCount() throws SQLException {
+        return this.updateCount;
+    }
+
+
+    @Override
+    public Object executeStatement() throws SQLException {
+        return this.result;
+    }
+
+    @Override
+    public void populateStatement(Object value, Exchange exchange) throws 
SQLException {
+        this.result = 
this.factory.getTemplateStoredProcedure(this.template).execute(exchange, value);
+        //Spring sets #update-result-1
+        this.updateCount = (Integer) this.result.get("#update-count-1");
+    }
+
+    @Override
+    public void addBatch(Object value, Exchange exchange) {
+
+        if (this.batchFactory == null) {
+            this.batchFactory = factory.getTemplateForBatch(template);
+        }
+
+        Map<String, Object> batchValues = new HashMap<>();
+        //only IN-parameters supported by template
+        for (Object param : 
this.batchFactory.getTemplate().getParameterList()) {
+            InputParameter inputParameter = (InputParameter) param;
+            Object paramValue = 
inputParameter.getValueExtractor().eval(exchange, value);
+            batchValues.put(inputParameter.getName(), paramValue);
+        }
+        if (this.batchItems == null) {
+            this.batchItems = new ArrayList<>();
+        }
+        batchItems.add(batchValues);
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapperFactory.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapperFactory.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapperFactory.java
new file mode 100644
index 0000000..503fdb3
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/CallableStatementWrapperFactory.java
@@ -0,0 +1,101 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+import java.sql.SQLException;
+
+import org.apache.camel.component.sql.stored.template.TemplateParser;
+import org.apache.camel.support.ServiceSupport;
+import org.apache.camel.util.LRUCache;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+/**
+ * Statefull class that cached template functions.
+ */
+public class CallableStatementWrapperFactory extends ServiceSupport {
+
+    public static final int TEMPLATE_CACHE_DEFAULT_SIZE = 200;
+
+    public static final int BATCH_TEMPLATE_CACHE_DEFAULT_SIZE = 200;
+
+    final JdbcTemplate jdbcTemplate;
+
+    final TemplateParser templateParser;
+
+    private final LRUCache<String, TemplateStoredProcedure> templateCache = 
new LRUCache<>(TEMPLATE_CACHE_DEFAULT_SIZE);
+
+    private final LRUCache<String, BatchCallableStatementCreatorFactory> 
batchTemplateCache = new LRUCache<>(BATCH_TEMPLATE_CACHE_DEFAULT_SIZE);
+
+    public CallableStatementWrapperFactory(JdbcTemplate jdbcTemplate, 
TemplateParser
+            templateParser) {
+        this.jdbcTemplate = jdbcTemplate;
+        this.templateParser = templateParser;
+    }
+
+    public StamentWrapper create(String sql) throws SQLException {
+        return new CallableStatementWrapper(sql, this);
+    }
+
+    public BatchCallableStatementCreatorFactory getTemplateForBatch(String 
sql) {
+        BatchCallableStatementCreatorFactory template = 
this.batchTemplateCache.get(sql);
+        if (template != null) {
+            return template;
+        }
+
+        template = new 
BatchCallableStatementCreatorFactory(templateParser.parseTemplate(sql));
+        this.batchTemplateCache.put(sql, template);
+
+        return template;
+    }
+
+    public TemplateStoredProcedure getTemplateStoredProcedure(String sql) {
+        TemplateStoredProcedure templateStoredProcedure = 
this.templateCache.get(sql);
+        if (templateStoredProcedure != null) {
+            return templateStoredProcedure;
+        }
+
+        templateStoredProcedure = new TemplateStoredProcedure(jdbcTemplate, 
templateParser.parseTemplate(sql));
+
+        this.templateCache.put(sql, templateStoredProcedure);
+
+        return templateStoredProcedure;
+    }
+
+    public JdbcTemplate getJdbcTemplate() {
+        return jdbcTemplate;
+    }
+
+    @Override
+    protected void doStart() throws Exception {
+    }
+
+    @Override
+    protected void doStop() throws Exception {
+        try {
+            // clear cache when we are stopping
+            templateCache.clear();
+        } catch (Exception ex) {
+            //noop
+        }
+        try {
+            // clear cache when we are stopping
+            batchTemplateCache.clear();
+        } catch (Exception ex) {
+            //noop
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
index 3391450..5444b18 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredComponent.java
@@ -21,19 +21,24 @@ import javax.sql.DataSource;
 
 import org.apache.camel.CamelContext;
 import org.apache.camel.Endpoint;
-import 
org.apache.camel.component.sql.stored.template.TemplateStoredProcedureFactory;
 import org.apache.camel.impl.UriEndpointComponent;
-import org.apache.camel.util.CamelContextHelper;
 import org.springframework.jdbc.core.JdbcTemplate;
 
 public class SqlStoredComponent extends UriEndpointComponent {
-
     private DataSource dataSource;
 
     public SqlStoredComponent() {
         super(SqlStoredEndpoint.class);
     }
 
+    public SqlStoredComponent(Class<? extends Endpoint> endpointClass) {
+        super(endpointClass);
+    }
+
+    public SqlStoredComponent(CamelContext context) {
+        super(context, SqlStoredEndpoint.class);
+    }
+
     public SqlStoredComponent(CamelContext context, Class<? extends Endpoint> 
endpointClass) {
         super(context, endpointClass);
     }
@@ -47,10 +52,6 @@ public class SqlStoredComponent extends UriEndpointComponent 
{
         if (ds != null) {
             target = ds;
         }
-        String dataSourceRef = getAndRemoveParameter(parameters, 
"dataSourceRef", String.class);
-        if (target == null && dataSourceRef != null) {
-            target = CamelContextHelper.mandatoryLookup(getCamelContext(), 
dataSourceRef, DataSource.class);
-        }
         if (target == null) {
             // fallback and use component
             target = dataSource;
@@ -59,14 +60,12 @@ public class SqlStoredComponent extends 
UriEndpointComponent {
             throw new IllegalArgumentException("DataSource must be 
configured");
         }
 
-        JdbcTemplate template = new JdbcTemplate(target);
-        TemplateStoredProcedureFactory factory = new 
TemplateStoredProcedureFactory(template);
+        JdbcTemplate jdbcTemplate = new JdbcTemplate(target);
+        String template = remaining;
 
-        SqlStoredEndpoint answer = new SqlStoredEndpoint(uri, this);
-        answer.setJdbcTemplate(template);
-        answer.setTemplate(remaining);
-        answer.setTemplateStoredProcedureFactory(factory);
-        return answer;
+        SqlStoredEndpoint endpoint = new SqlStoredEndpoint(uri, this, 
jdbcTemplate);
+        endpoint.setTemplate(template);
+        return endpoint;
     }
 
     public DataSource getDataSource() {
@@ -79,5 +78,4 @@ public class SqlStoredComponent extends UriEndpointComponent {
     public void setDataSource(DataSource dataSource) {
         this.dataSource = dataSource;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
new file mode 100644
index 0000000..801d4ea
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredConstants.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+public final class SqlStoredConstants {
+
+    public static final String SQL_STORED_TEMPLATE = "CamelSqlStoredTemplate";
+
+    public static final String SQL_STORED_PARAMETERS = 
"CamelSqlStoredParameters";
+
+    public static final String SQL_STORED_UPDATE_COUNT = 
"CamelSqlStoredUpdateCount";
+
+    private SqlStoredConstants() {
+        // Utility class
+    }
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
index e65fa8b..7897c74 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredEndpoint.java
@@ -16,96 +16,128 @@
  */
 package org.apache.camel.component.sql.stored;
 
-import org.apache.camel.Component;
-import org.apache.camel.Consumer;
-import org.apache.camel.Processor;
+import javax.sql.DataSource;
+
 import org.apache.camel.Producer;
-import 
org.apache.camel.component.sql.stored.template.TemplateStoredProcedureFactory;
-import org.apache.camel.impl.DefaultEndpoint;
+import org.apache.camel.component.sql.stored.template.TemplateParser;
+import org.apache.camel.impl.DefaultPollingEndpoint;
 import org.apache.camel.spi.Metadata;
 import org.apache.camel.spi.UriEndpoint;
+import org.apache.camel.spi.UriParam;
 import org.apache.camel.spi.UriPath;
-import org.apache.camel.util.ObjectHelper;
-import org.apache.camel.util.ServiceHelper;
 import org.apache.camel.util.UnsafeUriCharactersEncoder;
 import org.springframework.jdbc.core.JdbcTemplate;
 
 @UriEndpoint(scheme = "sql-stored", title = "SQL StoredProcedure", syntax = 
"sql-stored:template", producerOnly = true, label = "database,sql")
-public class SqlStoredEndpoint extends DefaultEndpoint {
+public class SqlStoredEndpoint extends DefaultPollingEndpoint {
 
+    private final CallableStatementWrapperFactory wrapperFactory;
     private JdbcTemplate jdbcTemplate;
-    private TemplateStoredProcedureFactory templateStoredProcedureFactory;
 
-    @UriPath @Metadata(required = "true")
-    private String template;
+    @UriParam(description = "Sets the DataSource to use to communicate with 
the database.")
+    private DataSource dataSource;
 
-    public SqlStoredEndpoint(String endpointUri, Component component) {
-        super(endpointUri, component);
+    @UriPath(description = "Sets the StoredProcedure template to perform")
+    @Metadata(required = "true")
+    private String template;
+    @UriParam(label = "producer", description = "Enables or disables batch 
mode")
+    private boolean batch;
+    @UriParam(label = "producer", description = "Whether to use the message 
body as the template and then headers for parameters. If this option is enabled 
then the template in the uri is not used.")
+    private boolean useMessageBodyForTemplate;
+    @UriParam(label = "producer", description = "If set, will ignore the 
results of the template and use the existing IN message as the OUT message for 
the continuation of processing")
+    private boolean noop;
+    @UriParam(description = "Store the template result in a header instead of 
the message body. By default, outputHeader == null and the template result is 
stored"
+            + " in the message body, any existing content in the message body 
is discarded. If outputHeader is set, the value is used as the name of the 
header"
+            + " to store the template result and the original message body is 
preserved.")
+    private String outputHeader;
+
+    public SqlStoredEndpoint(String uri, SqlStoredComponent component, 
JdbcTemplate jdbcTemplate) {
+        super(uri, component);
+        setJdbcTemplate(jdbcTemplate);
+        wrapperFactory = new CallableStatementWrapperFactory(jdbcTemplate, new 
TemplateParser());
     }
 
-    @Override
     public Producer createProducer() throws Exception {
-        ObjectHelper.notNull(template, "template");
-        ObjectHelper.notNull(templateStoredProcedureFactory, 
"templateStoredProcedureFactory");
-
-        return new SqlStoredProducer(this, template, 
templateStoredProcedureFactory);
+        SqlStoredProducer result = new SqlStoredProducer(this);
+        return result;
     }
 
+
     @Override
-    public Consumer createConsumer(Processor processor) throws Exception {
-        throw new UnsupportedOperationException("This component does not 
support consumer");
+    protected String createEndpointUri() {
+        // Make sure it's properly encoded
+        return "sql-stored:" + 
UnsafeUriCharactersEncoder.encode(this.template);
     }
 
     @Override
-    public boolean isSingleton() {
-        return true;
+    protected void doStop() throws Exception {
+        super.doStop();
+        this.wrapperFactory.shutdown();
+
     }
 
-    @Override
-    protected String createEndpointUri() {
-        return "sql-stored:" + UnsafeUriCharactersEncoder.encode(template);
+    public JdbcTemplate getJdbcTemplate() {
+        return jdbcTemplate;
     }
 
-    @Override
-    protected void doStart() throws Exception {
-        ServiceHelper.startService(templateStoredProcedureFactory);
+    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
+        this.jdbcTemplate = jdbcTemplate;
     }
 
-    @Override
-    protected void doStop() throws Exception {
-        ServiceHelper.stopService(templateStoredProcedureFactory);
+    public boolean isBatch() {
+        return batch;
+    }
+
+    public void setBatch(boolean batch) {
+        this.batch = batch;
+    }
+
+    public boolean isUseMessageBodyForTemplate() {
+        return useMessageBodyForTemplate;
+    }
+
+    public void setUseMessageBodyForTemplate(boolean 
useMessageBodyForTemplate) {
+        this.useMessageBodyForTemplate = useMessageBodyForTemplate;
+    }
+
+    public boolean isNoop() {
+        return noop;
+    }
+
+    public void setNoop(boolean noop) {
+        this.noop = noop;
+    }
+
+    public String getOutputHeader() {
+        return outputHeader;
+    }
+
+    public void setOutputHeader(String outputHeader) {
+        this.outputHeader = outputHeader;
     }
 
     public String getTemplate() {
         return template;
     }
 
-    /**
-     * The stored procedure template to perform
-     */
     public void setTemplate(String template) {
         this.template = template;
     }
 
-    public TemplateStoredProcedureFactory getTemplateStoredProcedureFactory() {
-        return templateStoredProcedureFactory;
+    public DataSource getDataSource() {
+        return dataSource;
     }
 
-    /**
-     * To use a custom instance of TemplateStoredProcedureFactory
-     */
-    public void 
setTemplateStoredProcedureFactory(TemplateStoredProcedureFactory 
templateStoredProcedureFactory) {
-        this.templateStoredProcedureFactory = templateStoredProcedureFactory;
+    public void setDataSource(DataSource dataSource) {
+        this.dataSource = dataSource;
     }
 
-    public JdbcTemplate getJdbcTemplate() {
-        return jdbcTemplate;
+    @Override
+    public boolean isSingleton() {
+        return false;
     }
 
-    /**
-     * to use a custom instance of JdbcTemplate
-     */
-    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
-        this.jdbcTemplate = jdbcTemplate;
+    public CallableStatementWrapperFactory getWrapperFactory() {
+        return wrapperFactory;
     }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
index 4a7ccc4..eff61b1 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/SqlStoredProducer.java
@@ -16,24 +16,101 @@
  */
 package org.apache.camel.component.sql.stored;
 
-import org.apache.camel.Endpoint;
+import java.sql.SQLException;
+import java.util.Iterator;
+
 import org.apache.camel.Exchange;
-import org.apache.camel.component.sql.stored.template.TemplateStoredProcedure;
-import 
org.apache.camel.component.sql.stored.template.TemplateStoredProcedureFactory;
 import org.apache.camel.impl.DefaultProducer;
+import org.springframework.dao.DataAccessException;
 
 public class SqlStoredProducer extends DefaultProducer {
+    private CallableStatementWrapperFactory callableStatementWrapperFactory;
 
-    private TemplateStoredProcedure defaultTemplateStoredProcedure;
-
-    public SqlStoredProducer(Endpoint endpoint, String template, 
TemplateStoredProcedureFactory templateStoredProcedureFactory) {
+    public SqlStoredProducer(SqlStoredEndpoint endpoint) {
         super(endpoint);
-        this.defaultTemplateStoredProcedure = 
templateStoredProcedureFactory.createFromString(template);
     }
 
     @Override
-    public void process(Exchange exchange) throws Exception {
-        defaultTemplateStoredProcedure.execute(exchange);
+    public SqlStoredEndpoint getEndpoint() {
+        return (SqlStoredEndpoint) super.getEndpoint();
+    }
+
+    public void process(final Exchange exchange) throws Exception {
+        StamentWrapper stamentWrapper = createStatement(exchange);
+        stamentWrapper.call(new WrapperExecuteCallback() {
+            @Override
+            public void execute(StamentWrapper ps) throws SQLException, 
DataAccessException {
+                // transfer incoming message body data to prepared statement 
parameters, if necessary
+                if (getEndpoint().isBatch()) {
+                    Iterator<?> iterator;
+                    if (getEndpoint().isUseMessageBodyForTemplate()) {
+                        iterator = 
exchange.getIn().getHeader(SqlStoredConstants.SQL_STORED_PARAMETERS, 
Iterator.class);
+                    } else {
+                        iterator = exchange.getIn().getBody(Iterator.class);
+                    }
+
+                    if (iterator == null) {
+                        throw new IllegalStateException("batch=true but 
Iterator cannot be found from body or header");
+                    }
+                    while (iterator.hasNext()) {
+                        Object value = iterator.next();
+                        ps.addBatch(value, exchange);
+                    }
+                } else {
+                    Object value;
+                    if (getEndpoint().isUseMessageBodyForTemplate()) {
+                        value = 
exchange.getIn().getHeader(SqlStoredConstants.SQL_STORED_PARAMETERS);
+                    } else {
+                        value = exchange.getIn().getBody();
+                    }
+                    ps.populateStatement(value, exchange);
+                }
+
+                // call the prepared statement and populate the outgoing 
message
+                if (getEndpoint().isBatch()) {
+                    int[] updateCounts = ps.executeBatch();
+                    int total = 0;
+                    for (int count : updateCounts) {
+                        total += count;
+                    }
+                    
exchange.getIn().setHeader(SqlStoredConstants.SQL_STORED_UPDATE_COUNT, total);
+                } else {
+                    Object result = ps.executeStatement();
+                    // preserve headers first, so we can override the 
SQL_ROW_COUNT and SQL_UPDATE_COUNT headers
+                    // if statement returns them
+                    
exchange.getOut().getHeaders().putAll(exchange.getIn().getHeaders());
+
+                    if (result != null) {
+                        if (getEndpoint().isNoop()) {
+                            
exchange.getOut().setBody(exchange.getIn().getBody());
+                        } else if (getEndpoint().getOutputHeader() != null) {
+                            
exchange.getOut().setBody(exchange.getIn().getBody());
+                            
exchange.getOut().setHeader(getEndpoint().getOutputHeader(), result);
+                        } else {
+                            exchange.getOut().setBody(result);
+                        }
+                    }
+                    // for noop=true we still want to enrich with the headers
+
+                    if (ps.getUpdateCount() != null) {
+                        
exchange.getOut().setHeader(SqlStoredConstants.SQL_STORED_UPDATE_COUNT, 
ps.getUpdateCount());
+                    }
+                }
+            }
+        });
+    }
+
+    private StamentWrapper createStatement(Exchange exchange) throws 
SQLException {
+        final String sql;
+        if (getEndpoint().isUseMessageBodyForTemplate()) {
+            sql = exchange.getIn().getBody(String.class);
+        } else {
+            String templateHeader = 
exchange.getIn().getHeader(SqlStoredConstants.SQL_STORED_TEMPLATE, 
String.class);
+            sql = templateHeader != null ? templateHeader : 
getEndpoint().getTemplate();
+        }
+
+        return getEndpoint().getWrapperFactory().create(sql);
     }
 
+
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/StamentWrapper.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/StamentWrapper.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/StamentWrapper.java
new file mode 100644
index 0000000..1b92b28
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/StamentWrapper.java
@@ -0,0 +1,42 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+import java.sql.SQLException;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.sql.SqlProducer;
+
+/**
+ * Wrapper that simplifies operations on  {@link java.sql.CallableStatement}
+ * in {@link SqlStoredProducer}.
+ * Wrappers are statefull objects and must not be reused.
+ */
+public interface StamentWrapper {
+
+    void call(WrapperExecuteCallback cb) throws Exception;
+
+    int[] executeBatch() throws SQLException;
+
+    Integer getUpdateCount() throws SQLException;
+
+    Object executeStatement() throws SQLException;
+
+    void populateStatement(Object value, Exchange exchange) throws 
SQLException;
+
+    void addBatch(Object value, Exchange exchange);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
new file mode 100644
index 0000000..c7a1df5
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/TemplateStoredProcedure.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.camel.Exchange;
+import org.apache.camel.component.sql.stored.template.ast.InputParameter;
+import org.apache.camel.component.sql.stored.template.ast.OutParameter;
+import org.apache.camel.component.sql.stored.template.ast.Template;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.SqlOutParameter;
+import org.springframework.jdbc.core.SqlParameter;
+import org.springframework.jdbc.object.StoredProcedure;
+
+public class TemplateStoredProcedure extends StoredProcedure {
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(TemplateStoredProcedure.class);
+
+    private final Template template;
+
+    private List<InputParameter> inputParameterList = new ArrayList<>();
+
+    public TemplateStoredProcedure(JdbcTemplate jdbcTemplate, Template 
template) {
+        this.template = template;
+        setDataSource(jdbcTemplate.getDataSource());
+
+        setSql(template.getProcedureName());
+
+        for (Object parameter : template.getParameterList()) {
+            if (parameter instanceof InputParameter) {
+                InputParameter inputParameter = (InputParameter) parameter;
+                declareParameter(new SqlParameter(inputParameter.getName(), 
inputParameter.getSqlType()));
+                inputParameterList.add(inputParameter);
+
+            } else if (parameter instanceof OutParameter) {
+                OutParameter outParameter = (OutParameter) parameter;
+                declareParameter(new 
SqlOutParameter(outParameter.getOutHeader(), outParameter.getSqlType()));
+                setFunction(false);
+            }
+        }
+
+        LOG.debug("Compiling stored procedure: {}", 
template.getProcedureName());
+        compile();
+    }
+
+    public Map execute(Exchange exchange, Object rowData) {
+        Map<String, Object> params = new HashMap<>();
+
+        for (InputParameter inputParameter : inputParameterList) {
+            params.put(inputParameter.getName(), 
inputParameter.getValueExtractor().eval(exchange, rowData));
+        }
+
+        LOG.debug("Invoking stored procedure: {}", 
template.getProcedureName());
+        Map<String, Object> ret = super.execute(params);
+
+        return ret;
+    }
+
+    public Template getTemplate() {
+        return template;
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/WrapperExecuteCallback.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/WrapperExecuteCallback.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/WrapperExecuteCallback.java
new file mode 100644
index 0000000..fedd926
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/WrapperExecuteCallback.java
@@ -0,0 +1,26 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored;
+
+import java.sql.SQLException;
+
+import org.springframework.dao.DataAccessException;
+
+public interface WrapperExecuteCallback {
+
+    void execute(StamentWrapper stamentWrapper) throws SQLException, 
DataAccessException;
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
new file mode 100644
index 0000000..321fa09
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateParser.java
@@ -0,0 +1,45 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored.template;
+
+import java.io.StringReader;
+
+import 
org.apache.camel.component.sql.stored.template.ast.ParseRuntimeException;
+import org.apache.camel.component.sql.stored.template.ast.Template;
+import org.apache.camel.component.sql.stored.template.generated.ParseException;
+import org.apache.camel.component.sql.stored.template.generated.SSPTParser;
+
+public class TemplateParser {
+
+    public Template parseTemplate(String template) {
+        try {
+            SSPTParser parser = new SSPTParser(new StringReader(template));
+            Template ret = validate(parser.parse());
+
+            return ret;
+
+        } catch (ParseException parseException) {
+            throw new ParseRuntimeException(parseException);
+        }
+    }
+
+    private Template validate(Template input) {
+        return input;
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedure.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedure.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedure.java
deleted file mode 100644
index 180c1b2..0000000
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedure.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.sql.stored.template;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.camel.Exchange;
-import org.apache.camel.component.sql.stored.template.ast.InputParameter;
-import org.apache.camel.component.sql.stored.template.ast.OutParameter;
-import org.apache.camel.component.sql.stored.template.ast.Template;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.jdbc.core.JdbcTemplate;
-import org.springframework.jdbc.core.SqlOutParameter;
-import org.springframework.jdbc.core.SqlParameter;
-import org.springframework.jdbc.object.StoredProcedure;
-
-public class TemplateStoredProcedure extends StoredProcedure {
-
-    private static final Logger LOG = 
LoggerFactory.getLogger(TemplateStoredProcedure.class);
-    private final Template template;
-
-    public TemplateStoredProcedure(JdbcTemplate jdbcTemplate, Template 
template) {
-        this.template = template;
-        setDataSource(jdbcTemplate.getDataSource());
-
-        setSql(template.getProcedureName());
-
-        for (InputParameter inputParameter : template.getInputParameterList()) 
{
-            declareParameter(new SqlParameter(inputParameter.getName(), 
inputParameter.getSqlType()));
-        }
-
-        for (OutParameter outParameter : template.getOutParameterList()) {
-            declareParameter(new SqlOutParameter(outParameter.getName(), 
outParameter.getSqlType()));
-            setFunction(false);
-        }
-
-        LOG.debug("Compiling stored procedure: {}", 
template.getProcedureName());
-        compile();
-    }
-
-    public void execute(Exchange exchange) {
-
-        Map<String, Object> params = new HashMap<>();
-
-        for (InputParameter inputParameter : template.getInputParameterList()) 
{
-            params.put(inputParameter.getName(), 
inputParameter.getValueExpression().evaluate(exchange, 
inputParameter.getJavaType()));
-        }
-
-        LOG.debug("Invoking stored procedure: {}", 
template.getProcedureName());
-        Map<String, Object> ret = super.execute(params);
-
-        for (OutParameter out : template.getOutParameterList()) {
-            exchange.getOut().setHeader(out.getOutHeader(), 
ret.get(out.getName()));
-        }
-
-    }
-
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedureFactory.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedureFactory.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedureFactory.java
deleted file mode 100644
index f096dc8..0000000
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/TemplateStoredProcedureFactory.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.component.sql.stored.template;
-
-import java.io.StringReader;
-
-import 
org.apache.camel.component.sql.stored.template.ast.ParseRuntimeException;
-import org.apache.camel.component.sql.stored.template.ast.Template;
-import org.apache.camel.component.sql.stored.template.generated.ParseException;
-import org.apache.camel.component.sql.stored.template.generated.SSPTParser;
-import org.apache.camel.support.ServiceSupport;
-import org.apache.camel.util.LRUCache;
-import org.springframework.jdbc.core.JdbcTemplate;
-
-public class TemplateStoredProcedureFactory extends ServiceSupport {
-
-    public static final int TEMPLATE_CACHE_DEFAULT_SIZE = 200;
-    private final JdbcTemplate jdbcTemplate;
-    private final LRUCache<String, TemplateStoredProcedure> templateCache = 
new LRUCache<String, TemplateStoredProcedure>(TEMPLATE_CACHE_DEFAULT_SIZE);
-
-    public TemplateStoredProcedureFactory(JdbcTemplate jdbcTemplate) {
-        this.jdbcTemplate = jdbcTemplate;
-    }
-
-    public TemplateStoredProcedure createFromString(String string) {
-        TemplateStoredProcedure fromCache = templateCache.get(string);
-
-        if (fromCache != null) {
-            return fromCache;
-        }
-
-        Template sptpRootNode = parseTemplate(string);
-        TemplateStoredProcedure ret = new 
TemplateStoredProcedure(jdbcTemplate, sptpRootNode);
-
-        templateCache.put(string, ret);
-
-        return ret;
-    }
-
-    public Template parseTemplate(String template) {
-        try {
-            SSPTParser parser = new SSPTParser(new StringReader(template));
-            return validate(parser.parse());
-        } catch (ParseException parseException) {
-            throw new ParseRuntimeException(parseException);
-        }
-    }
-
-    private Template validate(Template input) {
-        return input;
-    }
-
-    @Override
-    protected void doStart() throws Exception {
-    }
-
-    @Override
-    protected void doStop() throws Exception {
-        // clear cache when we are stopping
-        templateCache.clear();
-    }
-}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
index 68927a2..deb4d52 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/InputParameter.java
@@ -16,27 +16,63 @@
  */
 package org.apache.camel.component.sql.stored.template.ast;
 
+import java.util.Map;
+
+import org.apache.camel.Exchange;
 import org.apache.camel.Expression;
 import org.apache.camel.builder.ExpressionBuilder;
+import 
org.apache.camel.component.sql.stored.template.generated.SSPTParserConstants;
+import org.apache.camel.component.sql.stored.template.generated.Token;
 
 public class InputParameter {
 
     private final String name;
     private final int sqlType;
-    private final Expression valueExpression;
     private final Class javaType;
+    private ValueExtractor valueExtractor;
 
-    public InputParameter(String name, int sqlType, String valueSrcAsStr, 
Class javaType) {
+    public InputParameter(String name, int sqlType, Token valueSrcToken, Class 
javaType) {
         this.name = name;
         this.sqlType = sqlType;
         this.javaType = javaType;
-        this.valueExpression = parseValueExpression(valueSrcAsStr);
+        parseValueExpression(valueSrcToken);
     }
 
-    private Expression parseValueExpression(String str) {
-        return ExpressionBuilder.simpleExpression(str);
+    private void parseValueExpression(Token valueSrcToken) {
+        if (SSPTParserConstants.SIMPLE_EXP_TOKEN == valueSrcToken.kind) {
+            final Expression exp = 
ExpressionBuilder.simpleExpression(valueSrcToken.toString());
+            this.valueExtractor = new ValueExtractor() {
+
+                @Override
+                public Object eval(Exchange exchange, Object container) {
+                    return exp.evaluate(exchange, javaType);
+                }
+            };
+        } else if (SSPTParserConstants.PARAMETER_POS_TOKEN == 
valueSrcToken.kind) {
+
+            //remove leading :#
+            final String mapKey = valueSrcToken.toString().substring(2);
+            this.valueExtractor = new ValueExtractor() {
+                @Override
+                public Object eval(Exchange exchange, Object container) {
+                    return ((Map) container).get(mapKey);
+                }
+            };
+        }
     }
 
+    /*public Object getParameterValueFromContainer(Exchange exchange, Object 
container) {
+        if (this.valueExpression != null) {
+            return valueExpression.evaluate(exchange, this.getJavaType());
+        } else {
+            return getValueFromMap((Map<String, Object>) container);
+        }
+    }*/
+
+    /*private Object getValueFromMap(Map<String, Object> container) {
+        return container.get(mapKey);
+    }*/
+
     public String getName() {
         return name;
     }
@@ -45,12 +81,12 @@ public class InputParameter {
         return sqlType;
     }
 
-    public Expression getValueExpression() {
-        return valueExpression;
-    }
 
     public Class getJavaType() {
         return javaType;
     }
 
+    public ValueExtractor getValueExtractor() {
+        return valueExtractor;
+    }
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ParseHelper.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ParseHelper.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ParseHelper.java
index dd926ef..8a2d9b5 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ParseHelper.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ParseHelper.java
@@ -17,14 +17,31 @@
 package org.apache.camel.component.sql.stored.template.ast;
 
 import java.lang.reflect.Field;
-import java.math.BigInteger;
+import java.math.BigDecimal;
 import java.sql.Date;
 import java.sql.Types;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.springframework.util.ReflectionUtils;
 
 public final class ParseHelper {
 
+    static final Map<Integer, Class> SQL_TYPE_TO_JAVA_CLASS = new HashMap<>();
+
+    //somekind of mapping here 
https://docs.oracle.com/cd/E19501-01/819-3659/gcmaz/
+    //TODO: test with each SQL_TYPE_TO_JAVA_CLASS that JAVA conversion works!
+    static {
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.INTEGER, Integer.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.VARCHAR, String.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.BIGINT, Long.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.CHAR, String.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.DECIMAL, BigDecimal.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.BOOLEAN, Boolean.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.DATE, Date.class);
+        SQL_TYPE_TO_JAVA_CLASS.put(Types.TIMESTAMP, Date.class);
+    }
+
     private ParseHelper() {
     }
 
@@ -41,36 +58,10 @@ public final class ParseHelper {
     }
 
     public static Class sqlTypeToJavaType(int sqlType, String sqlTypeStr) {
-        //TODO: as rest of types.
-        //TODO: add test for each type.
-        Class ret;
-        switch (sqlType) {
-        case Types.INTEGER:
-            ret = Integer.class;
-            break;
-        case Types.VARCHAR:
-            ret = String.class;
-            break;
-        case Types.BIGINT:
-            ret = BigInteger.class;
-            break;
-        case Types.CHAR:
-            ret = String.class;
-            break;
-        case Types.BOOLEAN:
-            ret = Boolean.class;
-            break;
-        case Types.DATE:
-            ret = Date.class;
-            break;
-        case Types.TIMESTAMP:
-            ret = Date.class;
-            break;
-        default:
+        Class javaType = SQL_TYPE_TO_JAVA_CLASS.get(sqlType);
+        if (javaType == null) {
             throw new ParseRuntimeException("Unable to map SQL type " + 
sqlTypeStr + " to Java type");
         }
-
-        return ret;
+        return javaType;
     }
-
 }

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/Template.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/Template.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/Template.java
index 935609c..290abde 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/Template.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/Template.java
@@ -24,16 +24,11 @@ import java.util.List;
  */
 public class Template {
 
+    private final List<Object> parameterList = new ArrayList<>();
     private String procedureName;
-    private final List<InputParameter> inputParameterList = new ArrayList<>();
-    private final List<OutParameter> outParameterList = new ArrayList<>();
 
     public void addParameter(Object parameter) {
-        if (parameter instanceof OutParameter) {
-            outParameterList.add((OutParameter) parameter);
-        } else {
-            inputParameterList.add((InputParameter) parameter);
-        }
+        parameterList.add(parameter);
     }
 
     public String getProcedureName() {
@@ -44,12 +39,8 @@ public class Template {
         this.procedureName = procedureName;
     }
 
-    public List<InputParameter> getInputParameterList() {
-        return inputParameterList;
-    }
-
-    public List<OutParameter> getOutParameterList() {
-        return outParameterList;
+    public List<Object> getParameterList() {
+        return parameterList;
     }
 }
 

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ValueExtractor.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ValueExtractor.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ValueExtractor.java
new file mode 100644
index 0000000..228c758
--- /dev/null
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/ast/ValueExtractor.java
@@ -0,0 +1,29 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.sql.stored.template.ast;
+
+import org.apache.camel.Exchange;
+
+/**
+ * ValueExtractotr extracts value from Exchange and Container object.
+ * Usually each input parameter has one extractor which extracts
+ * parameter value from input "map" to be sent into db.
+ */
+public interface ValueExtractor {
+
+    Object eval(Exchange exchange, Object container);
+}

http://git-wip-us.apache.org/repos/asf/camel/blob/df5944fa/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
----------------------------------------------------------------------
diff --git 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
index 30e4737..b3829dd 100644
--- 
a/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
+++ 
b/components/camel-sql/src/main/java/org/apache/camel/component/sql/stored/template/generated/ParseException.java
@@ -13,175 +13,168 @@ package 
org.apache.camel.component.sql.stored.template.generated;
  */
 public class ParseException extends Exception {
 
-  /**
-   * The version identifier for this Serializable class.
-   * Increment only if the <i>serialized</i> form of the
-   * class changes.
-   */
-  private static final long serialVersionUID = 1L;
+    /**
+     * The version identifier for this Serializable class.
+     * Increment only if the <i>serialized</i> form of the
+     * class changes.
+     */
+    private static final long serialVersionUID = 1L;
+    /**
+     * This is the last token that has been consumed successfully.  If
+     * this object has been created due to a parse error, the token
+     * followng this token will (therefore) be the first error token.
+     */
+    public Token currentToken;
+    /**
+     * Each entry in this array is an array of integers.  Each array
+     * of integers represents a sequence of tokens (by their ordinal
+     * values) that is expected at this point of the parse.
+     */
+    public int[][] expectedTokenSequences;
+    /**
+     * This is a reference to the "tokenImage" array of the generated
+     * parser within which the parse error occurred.  This array is
+     * defined in the generated ...Constants interface.
+     */
+    public String[] tokenImage;
+    /**
+     * The end of line string for this machine.
+     */
+    protected String eol = System.getProperty("line.separator", "\n");
 
-  /**
-   * This constructor is used by the method "generateParseException"
-   * in the generated parser.  Calling this constructor generates
-   * a new object of this type with the fields "currentToken",
-   * "expectedTokenSequences", and "tokenImage" set.
-   */
-  public ParseException(Token currentTokenVal,
-                        int[][] expectedTokenSequencesVal,
-                        String[] tokenImageVal
-                       )
-  {
-    super(initialise(currentTokenVal, expectedTokenSequencesVal, 
tokenImageVal));
-    currentToken = currentTokenVal;
-    expectedTokenSequences = expectedTokenSequencesVal;
-    tokenImage = tokenImageVal;
-  }
-
-  /**
-   * The following constructors are for use by you for whatever
-   * purpose you can think of.  Constructing the exception in this
-   * manner makes the exception behave in the normal way - i.e., as
-   * documented in the class "Throwable".  The fields "errorToken",
-   * "expectedTokenSequences", and "tokenImage" do not contain
-   * relevant information.  The JavaCC generated code does not use
-   * these constructors.
-   */
-
-  public ParseException() {
-    super();
-  }
-
-  /** Constructor with message. */
-  public ParseException(String message) {
-    super(message);
-  }
-
-
-  /**
-   * This is the last token that has been consumed successfully.  If
-   * this object has been created due to a parse error, the token
-   * followng this token will (therefore) be the first error token.
-   */
-  public Token currentToken;
-
-  /**
-   * Each entry in this array is an array of integers.  Each array
-   * of integers represents a sequence of tokens (by their ordinal
-   * values) that is expected at this point of the parse.
-   */
-  public int[][] expectedTokenSequences;
+    /**
+     * This constructor is used by the method "generateParseException"
+     * in the generated parser.  Calling this constructor generates
+     * a new object of this type with the fields "currentToken",
+     * "expectedTokenSequences", and "tokenImage" set.
+     */
+    public ParseException(Token currentTokenVal,
+                          int[][] expectedTokenSequencesVal,
+                          String[] tokenImageVal
+    ) {
+        super(initialise(currentTokenVal, expectedTokenSequencesVal, 
tokenImageVal));
+        currentToken = currentTokenVal;
+        expectedTokenSequences = expectedTokenSequencesVal;
+        tokenImage = tokenImageVal;
+    }
 
-  /**
-   * This is a reference to the "tokenImage" array of the generated
-   * parser within which the parse error occurred.  This array is
-   * defined in the generated ...Constants interface.
-   */
-  public String[] tokenImage;
+    /**
+     * The following constructors are for use by you for whatever
+     * purpose you can think of.  Constructing the exception in this
+     * manner makes the exception behave in the normal way - i.e., as
+     * documented in the class "Throwable".  The fields "errorToken",
+     * "expectedTokenSequences", and "tokenImage" do not contain
+     * relevant information.  The JavaCC generated code does not use
+     * these constructors.
+     */
 
-  /**
-   * It uses "currentToken" and "expectedTokenSequences" to generate a parse
-   * error message and returns it.  If this object has been created
-   * due to a parse error, and you do not catch it (it gets thrown
-   * from the parser) the correct error message
-   * gets displayed.
-   */
-  private static String initialise(Token currentToken,
-                           int[][] expectedTokenSequences,
-                           String[] tokenImage) {
-    String eol = System.getProperty("line.separator", "\n");
-    StringBuffer expected = new StringBuffer();
-    int maxSize = 0;
-    for (int i = 0; i < expectedTokenSequences.length; i++) {
-      if (maxSize < expectedTokenSequences[i].length) {
-        maxSize = expectedTokenSequences[i].length;
-      }
-      for (int j = 0; j < expectedTokenSequences[i].length; j++) {
-        expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
-      }
-      if (expectedTokenSequences[i][expectedTokenSequences[i].length - 1] != 
0) {
-        expected.append("...");
-      }
-      expected.append(eol).append("    ");
+    public ParseException() {
+        super();
     }
-    String retval = "Encountered \"";
-    Token tok = currentToken.next;
-    for (int i = 0; i < maxSize; i++) {
-      if (i != 0) retval += " ";
-      if (tok.kind == 0) {
-        retval += tokenImage[0];
-        break;
-      }
-      retval += " " + tokenImage[tok.kind];
-      retval += " \"";
-      retval += add_escapes(tok.image);
-      retval += " \"";
-      tok = tok.next;
-    }
-    retval += "\" at line " + currentToken.next.beginLine + ", column " + 
currentToken.next.beginColumn;
-    retval += "." + eol;
-    if (expectedTokenSequences.length == 1) {
-      retval += "Was expecting:" + eol + "    ";
-    } else {
-      retval += "Was expecting one of:" + eol + "    ";
+
+    /** Constructor with message. */
+    public ParseException(String message) {
+        super(message);
     }
-    retval += expected.toString();
-    return retval;
-  }
 
-  /**
-   * The end of line string for this machine.
-   */
-  protected String eol = System.getProperty("line.separator", "\n");
+    /**
+     * It uses "currentToken" and "expectedTokenSequences" to generate a parse
+     * error message and returns it.  If this object has been created
+     * due to a parse error, and you do not catch it (it gets thrown
+     * from the parser) the correct error message
+     * gets displayed.
+     */
+    private static String initialise(Token currentToken,
+                                     int[][] expectedTokenSequences,
+                                     String[] tokenImage) {
+        String eol = System.getProperty("line.separator", "\n");
+        StringBuffer expected = new StringBuffer();
+        int maxSize = 0;
+        for (int i = 0; i < expectedTokenSequences.length; i++) {
+            if (maxSize < expectedTokenSequences[i].length) {
+                maxSize = expectedTokenSequences[i].length;
+            }
+            for (int j = 0; j < expectedTokenSequences[i].length; j++) {
+                
expected.append(tokenImage[expectedTokenSequences[i][j]]).append(' ');
+            }
+            if (expectedTokenSequences[i][expectedTokenSequences[i].length - 
1] != 0) {
+                expected.append("...");
+            }
+            expected.append(eol).append("    ");
+        }
+        String retval = "Encountered \"";
+        Token tok = currentToken.next;
+        for (int i = 0; i < maxSize; i++) {
+            if (i != 0) retval += " ";
+            if (tok.kind == 0) {
+                retval += tokenImage[0];
+                break;
+            }
+            retval += " " + tokenImage[tok.kind];
+            retval += " \"";
+            retval += add_escapes(tok.image);
+            retval += " \"";
+            tok = tok.next;
+        }
+        retval += "\" at line " + currentToken.next.beginLine + ", column " + 
currentToken.next.beginColumn;
+        retval += "." + eol;
+        if (expectedTokenSequences.length == 1) {
+            retval += "Was expecting:" + eol + "    ";
+        } else {
+            retval += "Was expecting one of:" + eol + "    ";
+        }
+        retval += expected.toString();
+        return retval;
+    }
 
-  /**
-   * Used to convert raw characters to their escaped version
-   * when these raw version cannot be used as part of an ASCII
-   * string literal.
-   */
-  static String add_escapes(String str) {
-      StringBuffer retval = new StringBuffer();
-      char ch;
-      for (int i = 0; i < str.length(); i++) {
-        switch (str.charAt(i))
-        {
-           case 0 :
-              continue;
-           case '\b':
-              retval.append("\\b");
-              continue;
-           case '\t':
-              retval.append("\\t");
-              continue;
-           case '\n':
-              retval.append("\\n");
-              continue;
-           case '\f':
-              retval.append("\\f");
-              continue;
-           case '\r':
-              retval.append("\\r");
-              continue;
-           case '\"':
-              retval.append("\\\"");
-              continue;
-           case '\'':
-              retval.append("\\\'");
-              continue;
-           case '\\':
-              retval.append("\\\\");
-              continue;
-           default:
-              if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
-                 String s = "0000" + Integer.toString(ch, 16);
-                 retval.append("\\u" + s.substring(s.length() - 4, 
s.length()));
-              } else {
-                 retval.append(ch);
-              }
-              continue;
+    /**
+     * Used to convert raw characters to their escaped version
+     * when these raw version cannot be used as part of an ASCII
+     * string literal.
+     */
+    static String add_escapes(String str) {
+        StringBuffer retval = new StringBuffer();
+        char ch;
+        for (int i = 0; i < str.length(); i++) {
+            switch (str.charAt(i)) {
+                case 0:
+                    continue;
+                case '\b':
+                    retval.append("\\b");
+                    continue;
+                case '\t':
+                    retval.append("\\t");
+                    continue;
+                case '\n':
+                    retval.append("\\n");
+                    continue;
+                case '\f':
+                    retval.append("\\f");
+                    continue;
+                case '\r':
+                    retval.append("\\r");
+                    continue;
+                case '\"':
+                    retval.append("\\\"");
+                    continue;
+                case '\'':
+                    retval.append("\\\'");
+                    continue;
+                case '\\':
+                    retval.append("\\\\");
+                    continue;
+                default:
+                    if ((ch = str.charAt(i)) < 0x20 || ch > 0x7e) {
+                        String s = "0000" + Integer.toString(ch, 16);
+                        retval.append("\\u" + s.substring(s.length() - 4, 
s.length()));
+                    } else {
+                        retval.append(ch);
+                    }
+                    continue;
+            }
         }
-      }
-      return retval.toString();
-   }
+        return retval.toString();
+    }
 
 }
 /* JavaCC - OriginalChecksum=5189b93605d5a3d3833ed059f46e94c9 (do not edit 
this line) */

Reply via email to