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) */