diff --git a/.gitignore b/.gitignore index 63b666d..207ce65 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ target .project .settings .classpath +.factorypath # Mobile Tools for Java (J2ME) .mtj.tmp/ diff --git a/connectors/pom.xml b/connectors/pom.xml index 12d3abf..edb1d59 100644 --- a/connectors/pom.xml +++ b/connectors/pom.xml @@ -36,6 +36,7 @@ twitter-mention-connector twitter-search-connector salesforce-upsert-contact-connector + sql-connector day-trade-get-connector day-trade-place-connector trade-insight-buy-connector diff --git a/connectors/sql-stored-connector/pom.xml b/connectors/sql-stored-connector/pom.xml new file mode 100644 index 0000000..51ffdb1 --- /dev/null +++ b/connectors/sql-stored-connector/pom.xml @@ -0,0 +1,208 @@ + + + + 4.0.0 + + + io.syndesis + connectors + 0.4-SNAPSHOT + + + sql-stored-connector + jar + Camel Sql Stored Connector + + + UTF-8 + UTF-8 + 2.20.0.fuse-000091 + + + + + + + org.apache.camel + camel-parent + ${camel.version} + import + pom + + + + + + + + + org.apache.camel + camel-sql + + + org.apache.camel + camel-sql-starter + + + + + org.apache.camel + camel-connector + + + + + org.apache.camel + apt + + + org.springframework.boot + spring-boot-configuration-processor + ${spring-boot.version} + + + + commons-dbcp + commons-dbcp + + + + + org.apache.derby + derby + + + org.postgresql + postgresql + + + + + + org.apache.logging.log4j + log4j-api + test + + + org.apache.logging.log4j + log4j-core + test + + + org.apache.logging.log4j + log4j-slf4j-impl + test + + + + + org.apache.camel + camel-test + test + + + + + install + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.6.0 + + 1.8 + 1.8 + + + + + org.apache.maven.plugins + maven-resources-plugin + 3.0.1 + + UTF-8 + + + + + + + + + + + + + jboss-ea + JBoss Early-access repository + https://repository.jboss.org/nexus/content/groups/ea/ + + true + + + false + + + + + + diff --git a/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorComponent.java b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorComponent.java new file mode 100644 index 0000000..b551a41 --- /dev/null +++ b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorComponent.java @@ -0,0 +1,31 @@ +/** + * 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 io.syndesis.connector; + +import org.apache.camel.component.connector.DefaultConnectorComponent; + +/** + * Camel SqlStoredConnector connector + */ +public class SqlStoredConnectorComponent extends DefaultConnectorComponent { + + public SqlStoredConnectorComponent() { + super("sqlStoredConnector", "io.syndesis.connector.SqlStoredConnectorComponent"); + registerExtension(SqlStoredConnectorVerifierExtension::new); +// registerExtension(SqlStoredConnectorMetaDataExtension::new); + } +} diff --git a/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorMetaDataExtension.java b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorMetaDataExtension.java new file mode 100644 index 0000000..1be1855 --- /dev/null +++ b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorMetaDataExtension.java @@ -0,0 +1,268 @@ +/** + * 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 io.syndesis.connector; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.DriverManager; +import java.sql.JDBCType; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.camel.component.extension.metadata.AbstractMetaDataExtension; +import org.apache.camel.component.extension.metadata.DefaultMetaData; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class SqlStoredConnectorMetaDataExtension extends AbstractMetaDataExtension { + + private static final Logger LOGGER = LoggerFactory.getLogger(SqlStoredConnectorMetaDataExtension.class); + + @Override + public Optional meta(Map properties) { + + MetaData metaData = null; + if (properties.containsKey("procedure")) { + StoredProcedure storedProcedure = storedProcedure(properties); + metaData = new DefaultMetaData(null, null, storedProcedure); + } else { + List list = storedProcedureList(properties); + metaData = new DefaultMetaData(null, null, list); + } + return Optional.of(metaData); + } + + private List storedProcedureList(Map parameters) { + + List storedProcedureList = new ArrayList(); + Connection connection = null; + ResultSet procedureSet = null; + try { + String driver = parameters.get("driver").toString(); + Class.forName(driver); + connection = DriverManager.getConnection( + parameters.get("url").toString(), + parameters.get("user").toString(), + parameters.get("password").toString()); + DatabaseMetaData meta = connection.getMetaData(); + String catalog = (String) parameters.getOrDefault("catalog", null); + String defaultSchema = getDefaultSchema(meta.getDatabaseProductName(), parameters); + String schemaPattern = (String) parameters.getOrDefault("schema-pattern", defaultSchema); + String procedurePattern = (String) parameters.getOrDefault("procedure-pattern", null); + + if (meta.getDatabaseProductName().equalsIgnoreCase(DatabaseProduct.POSTGRESQL.name())) { + procedureSet = meta.getFunctions(catalog, schemaPattern, procedurePattern); + } else { + procedureSet = meta.getProcedures(catalog, schemaPattern, procedurePattern); + } + while (procedureSet.next()) { + StoredProcedure storedProcedure = new StoredProcedure(); + storedProcedure.setName(procedureSet.getString("PROCEDURE_NAME")); + storedProcedure.setType(procedureSet.getString("PROCEDURE_TYPE")); + storedProcedure.setRemark(procedureSet.getString("REMARKS")); + storedProcedureList.add(storedProcedure); + } + return storedProcedureList; + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (procedureSet != null) { + try { + if (!procedureSet.isClosed()) { + procedureSet.close(); + } + } catch (SQLException e) { + LOGGER.warn(e.getMessage()); + } + } + if (connection!=null) { + try { + if (!connection.isClosed()) { + connection.close(); + } + } catch (SQLException e) { + LOGGER.warn(e.getMessage()); + } + } + } + + } + + private String getDefaultSchema(String databaseProductName, Map parameters) { + + String defaultSchema = null; + //Oracle uses the username as schema + if (databaseProductName.equalsIgnoreCase(DatabaseProduct.ORACLE.name())) { + defaultSchema = parameters.get("user").toString(); + } + return defaultSchema; + } + + private StoredProcedure storedProcedure(Map parameters) { + + Connection connection = null; + ResultSet columnSet = null; + try { + String driver = parameters.get("driver").toString(); + Class.forName(driver); + connection = DriverManager.getConnection( + parameters.get("url").toString(), + parameters.get("user").toString(), + parameters.get("password").toString()); + DatabaseMetaData meta = connection.getMetaData(); + String catalog = (String) parameters.getOrDefault("catalog", null); + String defaultSchema = getDefaultSchema(meta.getDatabaseProductName(), parameters); + String schema = (String) parameters.getOrDefault("schema", defaultSchema); + String procedureName = (String) parameters.getOrDefault("procedure", null); + + StoredProcedure storedProcedure = new StoredProcedure(); + storedProcedure.setName(procedureName); + + if (meta.getDatabaseProductName().equalsIgnoreCase(DatabaseProduct.POSTGRESQL.name())) { + columnSet = meta.getFunctionColumns(catalog, schema, procedureName, null); + } else { + columnSet = meta.getProcedureColumns(catalog, schema, procedureName, null); + } + + List columnList = new ArrayList(); + String template = procedureName + "("; + while (columnSet.next()) { + Column column = new Column(); + column.setName(columnSet.getString("COLUMN_NAME")); + column.setMode(ColumnMode.valueOf(columnSet.getInt("COLUMN_TYPE"))); + column.setJdbcType(JDBCType.valueOf(columnSet.getInt("DATA_TYPE"))); + template += " " + column.getMode().name() + " " + column.getJdbcType() + " " + column.getName() + ", "; + columnList.add(column); + } + template = template.substring(0,template.length()-2) + ")"; + storedProcedure.setTemplate(template); + storedProcedure.setColumnList(columnList); + return storedProcedure; + + } catch (Exception e) { + throw new RuntimeException(e); + } finally { + if (columnSet != null) { + try { + if (!columnSet.isClosed()) { + columnSet.close(); + } + } catch (SQLException e) { + LOGGER.warn(e.getMessage()); + } + } + if (connection!=null) { + try { + if (!connection.isClosed()) { + connection.close(); + } + } catch (SQLException e) { + LOGGER.warn(e.getMessage()); + } + } + } + } + + public class StoredProcedure { + private String name; + private String type; + private String remark; + private List columnList; + private String template; + + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public String getType() { + return type; + } + public void setType(String type) { + this.type = type; + } + public String getRemark() { + return remark; + } + public void setRemark(String remark) { + this.remark = remark; + } + public List getColumnList() { + return columnList; + } + public void setColumnList(List columnList) { + this.columnList = columnList; + } + public String getTemplate() { + return template; + } + public void setTemplate(String template) { + this.template = template; + } + } + + public class Column { + private int ordinal; + private String name; + private ColumnMode mode; + private JDBCType jdbcType; + + public int getOrdinal() { + return ordinal; + } + public void setOrdinal(int ordinal) { + this.ordinal = ordinal; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public ColumnMode getMode() { + return mode; + } + public void setMode(ColumnMode mode) { + this.mode = mode; + } + public JDBCType getJdbcType() { + return jdbcType; + } + public void setJdbcType(JDBCType jdbcType) { + this.jdbcType = jdbcType; + } + } + + public enum ColumnMode { + UNKNOWN, IN, INOUT, RESULT, OUT, RETURN; + + public static ColumnMode valueOf(int columnType) { + return ColumnMode.values()[columnType]; + } + } + + public enum DatabaseProduct { + ORACLE, POSTGRESQL; + } + +} diff --git a/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorVerifierExtension.java b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorVerifierExtension.java new file mode 100644 index 0000000..ae034fb --- /dev/null +++ b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/SqlStoredConnectorVerifierExtension.java @@ -0,0 +1,108 @@ +/** + * 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 io.syndesis.connector; + +import java.sql.Connection; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.Enumeration; +import java.util.Map; + +import org.apache.camel.component.extension.verifier.DefaultComponentVerifierExtension; +import org.apache.camel.component.extension.verifier.ResultBuilder; +import org.apache.camel.component.extension.verifier.ResultErrorBuilder; +import org.apache.camel.component.extension.verifier.ResultErrorHelper; + +public class SqlStoredConnectorVerifierExtension extends DefaultComponentVerifierExtension { + + public SqlStoredConnectorVerifierExtension() { + super("sql-stored-connector"); + } + + public SqlStoredConnectorVerifierExtension(String scheme) { + super(scheme); + } + + // ********************************* + // Parameters validation + // ********************************* + + @Override + protected Result verifyParameters(Map parameters) { + ResultBuilder builder = ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.PARAMETERS) + .error(ResultErrorHelper.requiresOption("driver", parameters)) + .error(ResultErrorHelper.requiresOption("url", parameters)) + .error(ResultErrorHelper.requiresOption("user", parameters)) + .error(ResultErrorHelper.requiresOption("password", parameters)); + + + if (builder.build().getErrors().isEmpty() && parameters.containsKey("driver")) { + try { + Class.forName(parameters.get("driver").toString()); + } catch (Exception e) { + Enumeration drivers = DriverManager.getDrivers(); + StringBuffer supportedDrivers = new StringBuffer("["); + while (drivers.hasMoreElements()) { + String driverName = drivers.nextElement().getClass().getName(); + if (supportedDrivers.length() > 1 ) { + supportedDrivers.append(", "); + } + supportedDrivers.append(driverName); + } + supportedDrivers.append("]. "); + String msgPrefix = "Unsupported Database, could not find Driver with class "; + String msgPostfix = ". Drivers on classpath are: " + supportedDrivers; + builder.error(ResultErrorBuilder.withCodeAndDescription( + VerificationError.StandardCode.UNSUPPORTED, + msgPrefix + parameters.get("driver").toString() + msgPostfix).build()).build(); + } + } + return builder.build(); + + } + + // ********************************* + // Connectivity validation + // ********************************* + + @Override + protected Result verifyConnectivity(Map parameters) { + return ResultBuilder.withStatusAndScope(Result.Status.OK, Scope.CONNECTIVITY) + .error(parameters, this::verifyCredentials) + .build(); + } + + private void verifyCredentials(ResultBuilder builder, Map parameters) { + try { + Class.forName(parameters.get("driver").toString()); + + Connection connection = DriverManager.getConnection( + parameters.get("url").toString(), + parameters.get("user").toString(), + parameters.get("password").toString()); + + if (connection == null) { + throw new SQLException("No Connection"); + } + } catch (Exception e) { + ResultErrorBuilder errorBuilder = ResultErrorBuilder.withCodeAndDescription( + VerificationError.StandardCode.AUTHENTICATION, e.getMessage()); + builder.error(errorBuilder.build()); + } + } +} diff --git a/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorAutoConfiguration.java b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorAutoConfiguration.java new file mode 100644 index 0000000..d6ab8de --- /dev/null +++ b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorAutoConfiguration.java @@ -0,0 +1,106 @@ +package io.syndesis.connector.springboot; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import javax.annotation.PostConstruct; +import javax.sql.DataSource; + +import io.syndesis.connector.SqlStoredConnectorComponent; +import org.apache.camel.CamelContext; +import org.apache.camel.util.IntrospectionSupport; +import org.apache.commons.dbcp.BasicDataSource; +import org.springframework.beans.factory.BeanCreationException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +/** + * Generated by camel-connector-maven-plugin - do not edit this file! + */ +@Generated("org.apache.camel.maven.connector.SpringBootAutoConfigurationMojo") +@Configuration +@ConditionalOnBean(type = "org.apache.camel.spring.boot.CamelAutoConfiguration") +@AutoConfigureAfter(name = "org.apache.camel.spring.boot.CamelAutoConfiguration") +@EnableConfigurationProperties(SqlStoredConnectorConnectorConfiguration.class) +public class SqlStoredConnectorConnectorAutoConfiguration { + + @Autowired + private CamelContext camelContext; + @Autowired + private SqlStoredConnectorConnectorConfiguration configuration; + + @Lazy + @Bean(name = "sql-stored-connector-component") + @ConditionalOnClass(CamelContext.class) + @ConditionalOnMissingBean(name = "sql-stored-connector-component") + public SqlStoredConnectorComponent configureSqlStoredConnectorComponent() + throws Exception { + SqlStoredConnectorComponent connector = new SqlStoredConnectorComponent(); + connector.setCamelContext(camelContext); + Map parameters = new HashMap<>(); + IntrospectionSupport.getProperties(configuration, parameters, null, + false); + IntrospectionSupport.setProperties(camelContext, + camelContext.getTypeConverter(), connector, parameters); + connector.setComponentOptions(parameters); + return connector; + } + + + @PostConstruct + public void postConstructSqlStoredConnectorComponent() { + if (camelContext != null) { + Map parameters = new HashMap<>(); + for (Map.Entry entry : configuration + .getConfigurations().entrySet()) { + parameters.clear(); + SqlStoredConnectorComponent connector = new SqlStoredConnectorComponent(); + connector.setCamelContext(camelContext); + try { + IntrospectionSupport.getProperties(entry.getValue(), + parameters, null, false); + IntrospectionSupport.setProperties(camelContext, + camelContext.getTypeConverter(), connector, + parameters); + connector.setComponentOptions(parameters); + camelContext.addComponent(entry.getKey(), connector); + } catch (Exception e) { + throw new BeanCreationException(entry.getKey(), + e.getMessage(), e); + } + } + try { + + createDataSource(configuration); + } catch (Exception e) { + throw new BeanCreationException( + e.getMessage(), e); + } + } + } + + private void createDataSource(SqlStoredConnectorConnectorConfiguration configuration) throws ClassNotFoundException { + + if (configuration.getDriver()!=null) { + BasicDataSource ds = new BasicDataSource(); + ds.setDriverClassName(configuration.getDriver()); + Class.forName(configuration.getDriver()); + configuration.setDriver(null); + ds.setUsername(configuration.getUser()); + configuration.setUser(null); + ds.setPassword(configuration.getPassword()); + configuration.setPassword(null); + ds.setUrl(configuration.getUrl()); + configuration.setUrl(null); + + configuration.setDataSource(ds); + } + } +} \ No newline at end of file diff --git a/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorConfiguration.java b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorConfiguration.java new file mode 100644 index 0000000..716111d --- /dev/null +++ b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorConfiguration.java @@ -0,0 +1,23 @@ +package io.syndesis.connector.springboot; + +import java.util.HashMap; +import java.util.Map; +import javax.annotation.Generated; +import org.springframework.boot.context.properties.ConfigurationProperties; + +@Generated("org.apache.camel.maven.connector.SpringBootAutoConfigurationMojo") +@ConfigurationProperties(prefix = "sql-stored-connector") +public class SqlStoredConnectorConnectorConfiguration + extends + SqlStoredConnectorConnectorConfigurationCommon { + + /** + * Define additional configuration definitions + */ + private Map configurations = new HashMap<>(); + + public Map getConfigurations() { + + return configurations; + } +} \ No newline at end of file diff --git a/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorConfigurationCommon.java b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorConfigurationCommon.java new file mode 100644 index 0000000..8ee2ba8 --- /dev/null +++ b/connectors/sql-stored-connector/src/main/java/io/syndesis/connector/springboot/SqlStoredConnectorConnectorConfigurationCommon.java @@ -0,0 +1,112 @@ +package io.syndesis.connector.springboot; + +import javax.annotation.Generated; +import javax.sql.DataSource; + +/** + * The sql connector allows you to work with databases using JDBC Stored + * Procedure queries. + * + * Generated by camel-package-maven-plugin - do not edit this file! + */ +@Generated("org.apache.camel.maven.connector.SpringBootAutoConfigurationMojo") +public class SqlStoredConnectorConnectorConfigurationCommon { + + /** + * Sets the DataSource to use to communicate with the database. + */ + private DataSource dataSource; + /** + * Sets the StoredProcedure template to perform + */ + private String template; + /** + * Enables or disables batch mode + */ + private boolean batch = false; + /** + * 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 = false; + /** + * Sets the user to use for the database connection + */ + private String user; + /** + * Sets the password to use for the database connection + */ + private String password; + /** + * Sets the driver class to use for the database connection + */ + private String driver; + /** + * Sets the connection url to use for the database connection + */ + private String url; + + public DataSource getDataSource() { + return dataSource; + } + + public void setDataSource(DataSource dataSource) { + this.dataSource = dataSource; + } + + public String getTemplate() { + return template; + } + + public void setTemplate(String template) { + this.template = template; + } + + public boolean isBatch() { + return batch; + } + + public void setBatch(boolean batch) { + this.batch = batch; + } + + public boolean isNoop() { + return noop; + } + + public void setNoop(boolean noop) { + this.noop = noop; + } + + public String getUser() { + return user; + } + + public void setUser(String user) { + this.user = user; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getDriver() { + return driver; + } + + public void setDriver(String driver) { + this.driver = driver; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } +} \ No newline at end of file diff --git a/connectors/sql-stored-connector/src/main/resources/META-INF/services/org/apache/camel/component/sql-stored-connector b/connectors/sql-stored-connector/src/main/resources/META-INF/services/org/apache/camel/component/sql-stored-connector new file mode 100644 index 0000000..d26e3e1 --- /dev/null +++ b/connectors/sql-stored-connector/src/main/resources/META-INF/services/org/apache/camel/component/sql-stored-connector @@ -0,0 +1 @@ +class=io.syndesis.connector.SqlStoredConnectorComponent \ No newline at end of file diff --git a/connectors/sql-stored-connector/src/main/resources/META-INF/spring.factories b/connectors/sql-stored-connector/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000..dbe4c6a --- /dev/null +++ b/connectors/sql-stored-connector/src/main/resources/META-INF/spring.factories @@ -0,0 +1,3 @@ + +org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ +io.syndesis.connector.springboot.SqlStoredConnectorConnectorAutoConfiguration diff --git a/connectors/sql-stored-connector/src/main/resources/camel-connector-schema.json b/connectors/sql-stored-connector/src/main/resources/camel-connector-schema.json new file mode 100644 index 0000000..f7d2edd --- /dev/null +++ b/connectors/sql-stored-connector/src/main/resources/camel-connector-schema.json @@ -0,0 +1,30 @@ +{ + "component": { + "kind": "component", + "baseScheme": "sql-stored", + "scheme": "sql-stored-connector", + "syntax": "sql-stored-connector:template", + "title": "SqlStoredConnector", + "description": "SQL Stored Procedure Connector to invoke a SQL Stored Procedure", + "label": "sql-stored", + "deprecated": false, + "async": false, + "producerOnly": true, + "lenientProperties": false, + "javaType": "io.syndesis.connector.SqlStoredConnectorComponent", + "groupId": "io.syndesis", + "artifactId": "sql-stored-connector", + "version": "0.4-SNAPSHOT" + }, + "componentProperties": { + "driver": { "kind": "path", "displayName": "Driver", "group": "producer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "description": "Sets the database Driver" }, + "url": { "kind": "path", "displayName": "Connection URL", "group": "producer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "description": "Sets the database URL" }, + "user": { "kind": "path", "displayName": "User", "group": "producer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "description": "Sets database user" }, + "password": { "kind": "path", "displayName": "Password", "group": "producer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": true, "description": "Sets the database password" } + }, + "properties": { + "template": { "kind": "path", "displayName": "Template", "group": "producer", "required": true, "type": "string", "javaType": "java.lang.String", "deprecated": false, "secret": false, "description": "Sets the StoredProcedure template to perform" }, + "batch": { "kind": "parameter", "displayName": "Batch", "group": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "description": "Enables or disables batch mode" }, + "noop": { "kind": "parameter", "displayName": "Noop", "group": "producer", "required": false, "type": "boolean", "javaType": "boolean", "deprecated": false, "secret": false, "defaultValue": false, "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" } + } +} diff --git a/connectors/sql-stored-connector/src/main/resources/camel-connector.json b/connectors/sql-stored-connector/src/main/resources/camel-connector.json new file mode 100644 index 0000000..6ce9997 --- /dev/null +++ b/connectors/sql-stored-connector/src/main/resources/camel-connector.json @@ -0,0 +1,21 @@ +{ + "baseScheme" : "sql-stored", + "baseGroupId" : "org.apache.camel", + "baseArtifactId" : "camel-sql", + "baseVersion" : "2.20.0-SNAPSHOT", + "baseJavaType" : "org.apache.camel.component.sql.stored.SqlStoredComponent", + "name" : "SqlStoredConnector", + "scheme" : "sql-stored-connector", + "javaType" : "io.syndesis.connector.SqlStoredConnectorComponent", + "groupId" : "io.syndesis", + "artifactId" : "sql-stored-connector", + "version" : "0.4-SNAPSHOT", + "description" : "SQL Stored Procedure Connector to invoke a SQL Stored Procedure", + "labels" : [ "sql-stored" ], + "pattern" : "To", + "inputDataType" : "*", + "outputDataType" : "none", + "componentOptions" : [ "driver", "user", "password", "url" ], + "endpointOptions" : [ "template", "batch", "noop" ], + "endpointValues" : {} +} \ No newline at end of file diff --git a/examples/pom.xml b/examples/pom.xml index 6d4c1f0..e8a6adf 100644 --- a/examples/pom.xml +++ b/examples/pom.xml @@ -37,6 +37,7 @@ http-pingcheck-example salesforce-pingcheck-example twitter-pingcheck-example + sql-stored-example diff --git a/examples/sql-stored-example/README.md b/examples/sql-stored-example/README.md new file mode 100644 index 0000000..810e7e8 --- /dev/null +++ b/examples/sql-stored-example/README.md @@ -0,0 +1,14 @@ +## Sql Stored Ping Check Example + +This example performs a ping check to a Database to check if the user credentials are valid +and that you can connect. + +### How to run + +This example can be run from the command line using: + + mvn exec:java + +### Configuring Credentials + +You can configure your own accounts in the `application.properties` file. diff --git a/examples/sql-stored-example/pom.xml b/examples/sql-stored-example/pom.xml new file mode 100644 index 0000000..bca2ec8 --- /dev/null +++ b/examples/sql-stored-example/pom.xml @@ -0,0 +1,79 @@ + + + + + + io.syndesis + examples + 0.4-SNAPSHOT + + 4.0.0 + + sql-stored-example + Syndesis Connectors :: Sql Stored Example + Validate database credentials can connect + jar + + + + + + io.syndesis + sql-stored-connector + ${project.version} + + + ch.qos.logback + logback-classic + + + + + + + org.apache.logging.log4j + log4j-api + + + org.apache.logging.log4j + log4j-core + + + org.apache.logging.log4j + log4j-slf4j-impl + + + + + + + + + org.codehaus.mojo + exec-maven-plugin + 1.5.0 + + io.syndesis.example.TwitterPingCheckMain + false + + + + + + diff --git a/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredApplication.java b/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredApplication.java new file mode 100644 index 0000000..0a12445 --- /dev/null +++ b/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredApplication.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2017 Red Hat, Inc. + * + * Licensed 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 io.syndesis.example; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +//CHECKSTYLE:OFF +@SpringBootApplication +public class SqlStoredApplication { + + /** + * A main method to start this application. + */ + public static void main(String[] args) { + SpringApplication.run(SqlStoredApplication.class, args); + try { + Thread.sleep(60000); + } catch (InterruptedException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } +} +//CHECKSTYLE:ON \ No newline at end of file diff --git a/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredPingCheck.java b/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredPingCheck.java new file mode 100644 index 0000000..e2b16fa --- /dev/null +++ b/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredPingCheck.java @@ -0,0 +1,100 @@ +/** + * Copyright (C) 2017 Red Hat, Inc. + * + * Licensed 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 io.syndesis.example; + +import java.io.FileInputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.Properties; + +import org.apache.camel.CamelContext; +import org.apache.camel.Component; +import org.apache.camel.component.extension.ComponentVerifierExtension; +import org.apache.camel.component.extension.ComponentVerifierExtension.Result; +import org.apache.camel.impl.DefaultCamelContext; + +import io.syndesis.connector.SqlStoredConnectorVerifierExtension; + +public class SqlStoredPingCheck { + + public void ping() throws Exception { + // need to create Camel + CamelContext camel = new DefaultCamelContext(); + camel.start(); + + // get the connector to use + Component sqlstored = camel.getComponent("sql-stored-connector"); + + // the connector must support ping check if its verifiable + Optional vce = sqlstored.getExtension(SqlStoredConnectorVerifierExtension.class); + if (vce.isPresent()) { + ComponentVerifierExtension verifier = vce.get(); + + Map parameters = loadParameters(); + + ComponentVerifierExtension.Result result = verifier.verify(ComponentVerifierExtension.Scope.PARAMETERS, parameters); + + System.out.println("============================================="); + System.out.println(""); + System.out.println("Parameters check result: " + result.getStatus()); + if (result.getStatus().equals(Result.Status.ERROR)) { + System.out.println(result.getErrors()); + } + System.out.println(""); + System.out.println("============================================="); + + ComponentVerifierExtension.Result result2 = verifier.verify(ComponentVerifierExtension.Scope.CONNECTIVITY, parameters); + + System.out.println("============================================="); + System.out.println(""); + System.out.println("Ping check result: " + result2.getStatus()); + if (result2.getStatus().equals(Result.Status.ERROR)) { + System.out.println(result2.getErrors()); + } + System.out.println(""); + System.out.println("============================================="); + + } else { + System.out.println("Component does not support ping check"); + } + + camel.stop(); + } + + /** + * Helper to load parameters from a .properties file + */ + private Map loadParameters() throws Exception { + Properties prop = new Properties(); + prop.load(new FileInputStream("src/main/resources/application.properties")); + + Map answer = new HashMap<>(); + Enumeration en = prop.propertyNames(); + while (en.hasMoreElements()) { + String key = (String) en.nextElement(); + if (key.startsWith("sql-stored-connector.")) { + String shortKey = key.substring(21, key.length()); + Object value = prop.getProperty(key); + answer.put(shortKey, value); + } + } + return answer; + } + + +} diff --git a/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredPingCheckMain.java b/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredPingCheckMain.java new file mode 100644 index 0000000..aab059a --- /dev/null +++ b/examples/sql-stored-example/src/main/java/io/syndesis/example/SqlStoredPingCheckMain.java @@ -0,0 +1,27 @@ +/** + * Copyright (C) 2017 Red Hat, Inc. + * + * Licensed 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 io.syndesis.example; + +public class SqlStoredPingCheckMain { + + public static void main(String[] args) throws Exception { + + SqlStoredPingCheck check = new SqlStoredPingCheck(); + check.ping(); + System.exit(0); + } + +} diff --git a/examples/sql-stored-example/src/main/java/io/syndesis/example/TimerSqlStoredRoute.java b/examples/sql-stored-example/src/main/java/io/syndesis/example/TimerSqlStoredRoute.java new file mode 100644 index 0000000..0e899ee --- /dev/null +++ b/examples/sql-stored-example/src/main/java/io/syndesis/example/TimerSqlStoredRoute.java @@ -0,0 +1,52 @@ +/** + * Copyright (C) 2017 Red Hat, Inc. + * + * Licensed 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 io.syndesis.example; + +import java.util.Properties; + +import org.apache.camel.Exchange; +import org.apache.camel.Processor; +import org.apache.camel.builder.RouteBuilder; +import org.springframework.stereotype.Component; + +@Component +public class TimerSqlStoredRoute extends RouteBuilder { + + @Override + public void configure() throws Exception { + + Properties values = new Properties(); + values.setProperty("a","1"); + values.setProperty("b","6"); + + from("timer://myTimer?period=2000") + .setBody().constant(values) + .to("sql-stored-connector:DEMO_ADD( " + + "NUMERIC ${body[a]}, " + + "NUMERIC ${body[b]}, " + + "OUT NUMERIC c)") + .process(new Processor() { + + public void process(Exchange exchange) + throws Exception { + System.out.println(exchange.getIn() + .getBody().getClass()); + System.out.println(exchange.getIn() + .getBody()); + } + }); + } +} diff --git a/examples/sql-stored-example/src/main/resources/application.properties b/examples/sql-stored-example/src/main/resources/application.properties new file mode 100644 index 0000000..6180297 --- /dev/null +++ b/examples/sql-stored-example/src/main/resources/application.properties @@ -0,0 +1,14 @@ +## name of CamelContext +camel.springboot.name=sql-stored-connector + +# Oracle database configuration to use +# sql-stored-connector.driver=oracle.jdbc.driver.OracleDriver +# sql-stored-connector.url=jdbc:oracle:thin:@:: +# sql-stored-connector.user= +# sql-stored-connector.password= + +# Postgres database configuration +# sql-stored-connector.driver=org.postgresql.Driver +# sql-stored-connector.url=jdbc:postgresql://localhost:5432/test +# sql-stored-connector.user= +# sql-stored-connector.password= diff --git a/examples/sql-stored-example/src/main/resources/log4j2.properties b/examples/sql-stored-example/src/main/resources/log4j2.properties new file mode 100644 index 0000000..f83ffbe --- /dev/null +++ b/examples/sql-stored-example/src/main/resources/log4j2.properties @@ -0,0 +1,6 @@ +appender.out.type = Console +appender.out.name = out +appender.out.layout.type = PatternLayout +appender.out.layout.pattern = %d [%-15.15t] %-5p %-30.30c{1} - %m%n +rootLogger.level = INFO +rootLogger.appenderRef.file.ref = out diff --git a/examples/sql-stored-example/src/main/resources/sql/oracle/stored_procedures.sql b/examples/sql-stored-example/src/main/resources/sql/oracle/stored_procedures.sql new file mode 100644 index 0000000..3883eab --- /dev/null +++ b/examples/sql-stored-example/src/main/resources/sql/oracle/stored_procedures.sql @@ -0,0 +1,9 @@ +create or replace PROCEDURE DEMO_ADD +( + A IN INTEGER +, B IN INTEGER +, C OUT INTEGER +) AS +BEGIN + c := a + b; +END DEMO_ADD; \ No newline at end of file diff --git a/examples/sql-stored-example/src/main/resources/sql/postgresql/stored_procedures.sql b/examples/sql-stored-example/src/main/resources/sql/postgresql/stored_procedures.sql new file mode 100644 index 0000000..cc89e64 --- /dev/null +++ b/examples/sql-stored-example/src/main/resources/sql/postgresql/stored_procedures.sql @@ -0,0 +1,25 @@ +-- FUNCTION: public.demo_add(numeric, numeric) + +-- DROP FUNCTION public.demo_add(numeric, numeric); + +CREATE OR REPLACE FUNCTION public.demo_add( + a numeric, + b numeric, + OUT c numeric) + RETURNS numeric + LANGUAGE 'plpgsql' + + COST 100 + VOLATILE + ROWS 0 +AS $BODY$ + +BEGIN + c := a + b; + return; +END; +$BODY$; + +ALTER FUNCTION public.demo_add(numeric, numeric) + OWNER TO postgres; +