├── README.md
├── .mvn
├── jvm.config
├── wrapper
│ ├── maven-wrapper.jar
│ └── maven-wrapper.properties
└── maven.config
├── spring-cloud-starter-stream-sink-gpfdist
├── src
│ ├── main
│ │ ├── resources
│ │ │ └── META-INF
│ │ │ │ ├── spring.provides
│ │ │ │ └── spring-configuration-metadata-whitelist.properties
│ │ └── java
│ │ │ └── org
│ │ │ └── springframework
│ │ │ └── cloud
│ │ │ └── stream
│ │ │ └── app
│ │ │ └── gpfdist
│ │ │ └── sink
│ │ │ ├── support
│ │ │ ├── Format.java
│ │ │ ├── Mode.java
│ │ │ ├── GreenplumLoad.java
│ │ │ ├── LoadService.java
│ │ │ ├── NetworkUtils.java
│ │ │ ├── SegmentRejectType.java
│ │ │ ├── DefaultGreenplumLoad.java
│ │ │ ├── RuntimeContext.java
│ │ │ ├── ReadableTable.java
│ │ │ ├── DefaultLoadService.java
│ │ │ ├── LoadFactoryBean.java
│ │ │ ├── LoadConfiguration.java
│ │ │ ├── GreenplumDataSourceFactoryBean.java
│ │ │ ├── AbstractExternalTable.java
│ │ │ ├── ControlFile.java
│ │ │ ├── JdbcCommands.java
│ │ │ ├── LoadConfigurationFactoryBean.java
│ │ │ ├── ControlFileFactoryBean.java
│ │ │ ├── ReadableTableFactoryBean.java
│ │ │ └── SqlUtils.java
│ │ │ ├── GpfdistSinkApplication.java
│ │ │ ├── GpfdistCodec.java
│ │ │ ├── HostInfoDiscoveryProperties.java
│ │ │ ├── AbstractGpfdistMessageHandler.java
│ │ │ ├── GpfdistServer.java
│ │ │ ├── GpfdistSinkConfiguration.java
│ │ │ ├── GpfdistMessageHandler.java
│ │ │ └── GpfdistSinkProperties.java
│ └── test
│ │ ├── resources
│ │ ├── test.yml
│ │ └── LoadConfigurationFactoryBeanTests1.xml
│ │ └── java
│ │ └── org
│ │ └── springframework
│ │ └── cloud
│ │ └── stream
│ │ └── app
│ │ └── gpfdist
│ │ └── sink
│ │ ├── support
│ │ ├── LoadConfigurationFactoryBeanTests.java
│ │ ├── ControlFileTests.java
│ │ └── LoadConfigurationIT.java
│ │ ├── TestListenAddress.java
│ │ ├── AbstractDbTests.java
│ │ ├── TestUtils.java
│ │ ├── GpfdistSinkPropertiesTests.java
│ │ ├── AbstractLoadTests.java
│ │ ├── HostInfoDiscoveryPropertiesTests.java
│ │ └── LoadIT.java
├── pom.xml
└── README.adoc
├── README.adoc
├── .gitignore
├── CODE_OF_CONDUCT.adoc
├── pom.xml
├── mvnw.cmd
├── gpfdist-app-dependencies
└── pom.xml
├── mvnw
└── LICENSE
/README.md:
--------------------------------------------------------------------------------
1 | # gpfdist is no longer actively maintained by VMware, Inc.
2 |
3 |
--------------------------------------------------------------------------------
/.mvn/jvm.config:
--------------------------------------------------------------------------------
1 | -Xmx1024m -XX:CICompilerCount=1 -XX:TieredStopAtLevel=1 -Djava.security.egd=file:/dev/./urandom
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spring-attic/gpfdist/main/.mvn/wrapper/maven-wrapper.jar
--------------------------------------------------------------------------------
/.mvn/maven.config:
--------------------------------------------------------------------------------
1 | -DaltSnapshotDeploymentRepository=repo.spring.io::default::https://repo.spring.io/libs-snapshot-local -P spring
2 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/resources/META-INF/spring.provides:
--------------------------------------------------------------------------------
1 | provides: spring-cloud-starter-stream-sink-gpfdist
--------------------------------------------------------------------------------
/.mvn/wrapper/maven-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionUrl=https://repo1.maven.org/maven2/org/apache/maven/apache-maven/3.3.3/apache-maven-3.3.3-bin.zip
--------------------------------------------------------------------------------
/README.adoc:
--------------------------------------------------------------------------------
1 | # Gpfdist Sink
2 |
3 | To learn more about this application and the supported properties, please review the following link.
4 |
5 | include::spring-cloud-starter-stream-sink-gpfdist/README.adoc[]
6 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/resources/META-INF/spring-configuration-metadata-whitelist.properties:
--------------------------------------------------------------------------------
1 | configuration-properties.classes=org.springframework.cloud.stream.app.gpfdist.sink.GpfdistSinkProperties, \
2 | org.springframework.cloud.stream.app.gpfdist.sink.HostInfoDiscoveryProperties
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | apps/
2 | /application.yml
3 | /application.properties
4 | asciidoctor.css
5 | *~
6 | .#*
7 | *#
8 | target/
9 | build/
10 | bin/
11 | _site/
12 | .classpath
13 | .project
14 | .settings
15 | .springBeans
16 | .DS_Store
17 | *.sw*
18 | *.iml
19 | *.ipr
20 | *.iws
21 | .idea/
22 | .factorypath
23 | spring-xd-samples/*/xd
24 | dump.rdb
25 | coverage-error.log
26 | .apt_generated
27 | aws.credentials.properties
28 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/Format.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | public enum Format {
19 |
20 | TEXT, CSV
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/Mode.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | public enum Mode {
20 |
21 | INSERT, UPDATE
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/resources/test.yml:
--------------------------------------------------------------------------------
1 | VERSION: 1.0.0.1
2 | DATABASE: gpadmin
3 | USER: gpadmin
4 | HOST: mdw.example.org
5 | PORT: 5432
6 | GPLOAD:
7 | INPUT:
8 | - SOURCE:
9 | PORT: 8100
10 | FILE: [ /home/gpadmin/test/data/* ]
11 | - COLUMNS:
12 | - "id":
13 | - "name":
14 | - FORMAT: text
15 | - DELIMITER: ','
16 | - ENCODING: 'UTF8'
17 | - NULL_AS: ''
18 | - ERROR_LIMIT: 100000
19 | - ERROR_TABLE: test_err
20 | OUTPUT:
21 | - TABLE: test
22 | - MODE: UPDATE
23 | - MATCH_COLUMNS:
24 | - col11
25 | - col12
26 | - UPDATE_COLUMNS:
27 | - col21
28 | - col22
29 | - UPDATE_CONDITION: 'condition'
30 | SQL:
31 | - BEFORE: "select 1 as before"
32 | - BEFORE: "select 2 as before"
33 | - AFTER: "select 1 as after"
34 | - AFTER: "select 2 as after"
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/GreenplumLoad.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | public interface GreenplumLoad {
19 |
20 | public void load();
21 |
22 | public void load(RuntimeContext context);
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/resources/LoadConfigurationFactoryBeanTests1.xml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/LoadService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | public interface LoadService {
19 |
20 | public void load(LoadConfiguration loadConfiguration);
21 |
22 | public void load(LoadConfiguration loadConfiguration, RuntimeContext context);
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/NetworkUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | /**
19 | * Various network utilities.
20 | *
21 | * @author Janne Valkealahti
22 | *
23 | */
24 | public class NetworkUtils {
25 |
26 | public static String getGPFDistUri(String address, int port) {
27 | return "gpfdist://" + address + ":" + port + "/data";
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/SegmentRejectType.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | /**
19 | * Enumeration of a possible values in a clause section
20 | * `SEGMENT REJECT LIMIT count [ROWS | PERCENT]`
21 | *
22 | * @author Janne Valkealahti
23 | */
24 | public enum SegmentRejectType {
25 |
26 | /** Rows reject type */
27 | ROWS,
28 |
29 | /** Percent reject type */
30 | PERCENT
31 | }
32 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/GpfdistSinkApplication.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.springframework.boot.SpringApplication;
20 | import org.springframework.boot.autoconfigure.SpringBootApplication;
21 | import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
22 |
23 | /**
24 | * Spring Boot app running gpfdist sink application.
25 | *
26 | * @author Janne Valkealahti
27 | */
28 | @SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
29 | public class GpfdistSinkApplication {
30 | // explicitly exclude DataSourceAutoConfiguration as it is
31 | // interfering too much with data source config for gpdb.
32 |
33 | public static void main(String[] args) throws InterruptedException {
34 | SpringApplication.run(GpfdistSinkApplication.class, args);
35 | }
36 |
37 | }
38 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/GpfdistCodec.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import reactor.fn.Consumer;
20 | import reactor.fn.Function;
21 | import reactor.io.buffer.Buffer;
22 | import reactor.io.codec.Codec;
23 |
24 | import java.nio.ByteBuffer;
25 | import java.nio.charset.Charset;
26 |
27 | /**
28 | * Gpfdist related reactor {@link Codec}.
29 | *
30 | * @author Janne Valkealahti
31 | */
32 | public class GpfdistCodec extends Codec {
33 |
34 | final byte[] h1 = Character.toString('D').getBytes(Charset.forName("UTF-8"));
35 |
36 | @SuppressWarnings("resource")
37 | @Override
38 | public Buffer apply(Buffer t) {
39 | byte[] h2 = ByteBuffer.allocate(4).putInt(t.flip().remaining()).array();
40 | return new Buffer().append(h1).append(h2).append(t).flip();
41 | }
42 |
43 | @Override
44 | public Function decoder(Consumer next) {
45 | return null;
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/support/LoadConfigurationFactoryBeanTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.junit.Test;
20 | import org.springframework.context.support.ClassPathXmlApplicationContext;
21 |
22 | import static org.hamcrest.Matchers.is;
23 | import static org.junit.Assert.assertThat;
24 |
25 | /**
26 | * Tests for {@link LoadConfigurationFactoryBean}.
27 | *
28 | * @author Janne Valkealahti
29 | */
30 | public class LoadConfigurationFactoryBeanTests {
31 |
32 | @Test
33 | public void testListValuesToColumns() {
34 | ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(
35 | "LoadConfigurationFactoryBeanTests1.xml");
36 | LoadConfigurationFactoryBean factoryBean = context.getBean("&greenplumLoadConfiguration",
37 | LoadConfigurationFactoryBean.class);
38 | assertThat(factoryBean.getUpdateColumns().size(), is(2));
39 | assertThat(factoryBean.getMatchColumns().size(), is(2));
40 | context.close();
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/DefaultGreenplumLoad.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | import org.apache.commons.logging.Log;
19 | import org.apache.commons.logging.LogFactory;
20 | import org.springframework.util.Assert;
21 |
22 | public class DefaultGreenplumLoad implements GreenplumLoad {
23 |
24 | private final static Log log = LogFactory.getLog(DefaultGreenplumLoad.class);
25 |
26 | private final LoadService loadService;
27 |
28 | private final LoadConfiguration loadConfiguration;
29 |
30 | public DefaultGreenplumLoad(LoadConfiguration loadConfiguration, LoadService loadService) {
31 | this.loadConfiguration = loadConfiguration;
32 | this.loadService = loadService;
33 | Assert.notNull(loadConfiguration, "Load configuration must be set");
34 | Assert.notNull(loadService, "Load service must be set");
35 | }
36 |
37 | @Override
38 | public void load() {
39 | load(null);
40 | }
41 |
42 | @Override
43 | public void load(RuntimeContext context) {
44 | log.debug("Doing greenplum load");
45 | loadService.load(loadConfiguration, context);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/RuntimeContext.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | import java.util.ArrayList;
19 | import java.util.List;
20 |
21 | /**
22 | * Runtime context for load operations.
23 | *
24 | * @author Janne Valkealahti
25 | */
26 | public class RuntimeContext {
27 |
28 | private final List locations;
29 |
30 | /**
31 | * Instantiates a new runtime context.
32 | */
33 | public RuntimeContext() {
34 | this.locations = new ArrayList<>();
35 | }
36 |
37 | /**
38 | * Instantiates a new runtime context.
39 | *
40 | * @param location the location
41 | */
42 | public RuntimeContext(String location) {
43 | this.locations = new ArrayList<>();
44 | addLocation(location);
45 | }
46 |
47 | /**
48 | * Gets the locations.
49 | *
50 | * @return the locations
51 | */
52 | public List getLocations() {
53 | return locations;
54 | }
55 |
56 | /**
57 | * Sets the locations.
58 | *
59 | * @param locations the new locations
60 | */
61 | public void setLocations(List locations) {
62 | this.locations.clear();
63 | this.locations.addAll(locations);
64 | }
65 |
66 | /**
67 | * Adds the location.
68 | *
69 | * @param location the location
70 | */
71 | public void addLocation(String location) {
72 | this.locations.add(location);
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/TestListenAddress.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.junit.Test;
20 | import reactor.Environment;
21 | import reactor.fn.Function;
22 | import reactor.io.buffer.Buffer;
23 | import reactor.io.net.NetStreams;
24 | import reactor.io.net.Spec.HttpServerSpec;
25 | import reactor.io.net.http.HttpServer;
26 |
27 | import java.net.InetSocketAddress;
28 |
29 | import static org.hamcrest.Matchers.not;
30 | import static org.hamcrest.Matchers.notNullValue;
31 | import static org.junit.Assert.assertThat;
32 |
33 | public class TestListenAddress {
34 |
35 | @Test
36 | public void testBindZero() throws Exception {
37 | Environment.initializeIfEmpty().assignErrorJournal();
38 |
39 | HttpServer httpServer = NetStreams
40 | .httpServer(new Function, HttpServerSpec>() {
41 |
42 | @Override
43 | public HttpServerSpec apply(HttpServerSpec server) {
44 | return server
45 | .codec(new GpfdistCodec())
46 | .listen(0);
47 | }
48 | });
49 | httpServer.start().awaitSuccess();
50 | InetSocketAddress address = httpServer.getListenAddress();
51 | assertThat(address, notNullValue());
52 | assertThat(address.getPort(), not(0));
53 | httpServer.shutdown();
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/ReadableTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
17 |
18 | /**
19 | * Settings for readable external table.
20 | *
21 | * @author Janne Valkealahti
22 | */
23 | public class ReadableTable extends AbstractExternalTable {
24 |
25 | // [LOG ERRORS]
26 | private boolean logErrors;
27 |
28 | // SEGMENT REJECT LIMIT count
29 | private Integer segmentRejectLimit;
30 |
31 | // [ROWS | PERCENT]
32 | private SegmentRejectType segmentRejectType;
33 |
34 | // FORMAT 'TEXT|CVS' [( [HEADER]
35 | private boolean formatHeader;
36 |
37 | public boolean isFormatHeader() {
38 | return formatHeader;
39 | }
40 |
41 | public void setFormatHeader(boolean formatHeader) {
42 | this.formatHeader = formatHeader;
43 | }
44 |
45 | public boolean isLogErrors() {
46 | return logErrors;
47 | }
48 |
49 | public void setLogErrors(boolean logErrors) {
50 | this.logErrors = logErrors;
51 | }
52 |
53 | public Integer getSegmentRejectLimit() {
54 | return segmentRejectLimit;
55 | }
56 |
57 | public void setSegmentRejectLimit(Integer segmentRejectLimit) {
58 | this.segmentRejectLimit = segmentRejectLimit;
59 | }
60 |
61 | public SegmentRejectType getSegmentRejectType() {
62 | return segmentRejectType;
63 | }
64 |
65 | public void setSegmentRejectType(SegmentRejectType segmentRejectType) {
66 | this.segmentRejectType = segmentRejectType;
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/AbstractDbTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink;
17 |
18 | import org.apache.commons.dbcp.BasicDataSource;
19 | import org.junit.After;
20 | import org.junit.Before;
21 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
22 | import org.springframework.context.annotation.Bean;
23 | import org.springframework.context.annotation.Configuration;
24 | import org.springframework.jdbc.core.JdbcTemplate;
25 |
26 | public abstract class AbstractDbTests {
27 |
28 | protected AnnotationConfigApplicationContext context;
29 |
30 | @Before
31 | public void setup() {
32 | context = buildContext();
33 | }
34 |
35 | @After
36 | public void clean() {
37 | if (context != null) {
38 | context.close();
39 | }
40 | }
41 |
42 | protected AnnotationConfigApplicationContext buildContext() {
43 | return null;
44 | }
45 |
46 | @Configuration
47 | protected static class TestDatasourceConfig {
48 |
49 | @Bean
50 | public JdbcTemplate jdbcTemplate() {
51 | return new JdbcTemplate(dataSource());
52 | }
53 |
54 | @Bean
55 | public BasicDataSource dataSource() {
56 | BasicDataSource dataSource = new BasicDataSource();
57 | dataSource.setDriverClassName("org.postgresql.Driver");
58 | dataSource.setUrl("jdbc:postgresql://mdw/gpadmin");
59 | dataSource.setUsername("gpadmin");
60 | dataSource.setPassword("gpadmin");
61 | return dataSource;
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/DefaultLoadService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.springframework.jdbc.core.JdbcTemplate;
20 | import org.springframework.util.Assert;
21 |
22 | import java.util.UUID;
23 |
24 | public class DefaultLoadService implements LoadService {
25 |
26 | private final JdbcTemplate jdbcTemplate;
27 |
28 | public DefaultLoadService(JdbcTemplate jdbcTemplate) {
29 | this.jdbcTemplate = jdbcTemplate;
30 | Assert.notNull(jdbcTemplate, "JdbcTemplate must be set");
31 | }
32 |
33 | @Override
34 | public void load(LoadConfiguration loadConfiguration) {
35 | load(loadConfiguration, null);
36 | }
37 |
38 | @Override
39 | public void load(LoadConfiguration loadConfiguration, RuntimeContext context) {
40 | String prefix = UUID.randomUUID().toString().replaceAll("-", "_");
41 |
42 | // setup jdbc operations
43 | JdbcCommands operations = new JdbcCommands(jdbcTemplate);
44 |
45 | String sqlCreateTable = SqlUtils.createExternalReadableTable(loadConfiguration, prefix,
46 | context != null ? context.getLocations() : null);
47 | String sqlDropTable = SqlUtils.dropExternalReadableTable(loadConfiguration, prefix);
48 | String sqlInsert = SqlUtils.load(loadConfiguration, prefix);
49 |
50 | operations.setPrepareSql(sqlCreateTable);
51 | operations.setCleanSql(sqlDropTable);
52 | operations.setRunSql(sqlInsert);
53 |
54 | operations.setBeforeSqls(loadConfiguration.getSqlBefore());
55 | operations.setAfterSqls(loadConfiguration.getSqlAfter());
56 |
57 | if (!operations.execute() && operations.getLastException() != null) {
58 | throw operations.getLastException();
59 | }
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.adoc:
--------------------------------------------------------------------------------
1 | = Contributor Code of Conduct
2 |
3 | As contributors and maintainers of this project, and in the interest of fostering an open
4 | and welcoming community, we pledge to respect all people who contribute through reporting
5 | issues, posting feature requests, updating documentation, submitting pull requests or
6 | patches, and other activities.
7 |
8 | We are committed to making participation in this project a harassment-free experience for
9 | everyone, regardless of level of experience, gender, gender identity and expression,
10 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age,
11 | religion, or nationality.
12 |
13 | Examples of unacceptable behavior by participants include:
14 |
15 | * The use of sexualized language or imagery
16 | * Personal attacks
17 | * Trolling or insulting/derogatory comments
18 | * Public or private harassment
19 | * Publishing other's private information, such as physical or electronic addresses,
20 | without explicit permission
21 | * Other unethical or unprofessional conduct
22 |
23 | Project maintainers have the right and responsibility to remove, edit, or reject comments,
24 | commits, code, wiki edits, issues, and other contributions that are not aligned to this
25 | Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors
26 | that they deem inappropriate, threatening, offensive, or harmful.
27 |
28 | By adopting this Code of Conduct, project maintainers commit themselves to fairly and
29 | consistently applying these principles to every aspect of managing this project. Project
30 | maintainers who do not follow or enforce the Code of Conduct may be permanently removed
31 | from the project team.
32 |
33 | This Code of Conduct applies both within project spaces and in public spaces when an
34 | individual is representing the project or its community.
35 |
36 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by
37 | contacting a project maintainer at spring-code-of-conduct@pivotal.io . All complaints will
38 | be reviewed and investigated and will result in a response that is deemed necessary and
39 | appropriate to the circumstances. Maintainers are obligated to maintain confidentiality
40 | with regard to the reporter of an incident.
41 |
42 | This Code of Conduct is adapted from the
43 | https://contributor-covenant.org[Contributor Covenant], version 1.3.0, available at
44 | https://contributor-covenant.org/version/1/3/0/[contributor-covenant.org/version/1/3/0/]
45 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/LoadFactoryBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.springframework.beans.factory.DisposableBean;
20 | import org.springframework.beans.factory.FactoryBean;
21 | import org.springframework.beans.factory.InitializingBean;
22 | import org.springframework.jdbc.core.JdbcTemplate;
23 | import org.springframework.util.Assert;
24 |
25 | import javax.sql.DataSource;
26 | import java.io.IOException;
27 |
28 | /**
29 | * FactoryBean for easy creation and configuration of {@link GreenplumLoad}
30 | * instances.
31 | *
32 | * @author Janne Valkealahti
33 | *
34 | */
35 | public class LoadFactoryBean implements FactoryBean, InitializingBean, DisposableBean {
36 |
37 | private DataSource dataSource;
38 |
39 | private LoadConfiguration loadConfiguration;
40 |
41 | private JdbcTemplate jdbcTemplate;
42 |
43 | @Override
44 | public GreenplumLoad getObject() throws Exception {
45 | return new DefaultGreenplumLoad(loadConfiguration, new DefaultLoadService(jdbcTemplate));
46 | }
47 |
48 | @Override
49 | public Class getObjectType() {
50 | return GreenplumLoad.class;
51 | }
52 |
53 | @Override
54 | public boolean isSingleton() {
55 | return true;
56 | }
57 |
58 | @Override
59 | public void afterPropertiesSet() throws IOException {
60 | Assert.notNull(dataSource, "DataSource must not be null.");
61 | Assert.notNull(loadConfiguration, "Load configuration must not be null.");
62 | jdbcTemplate = new JdbcTemplate(dataSource);
63 | }
64 |
65 | @Override
66 | public void destroy() {
67 | }
68 |
69 | public void setDataSource(DataSource dataSource) {
70 | this.dataSource = dataSource;
71 | }
72 |
73 | public void setLoadConfiguration(LoadConfiguration LoadConfiguration) {
74 | this.loadConfiguration = LoadConfiguration;
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/HostInfoDiscoveryProperties.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink;
17 |
18 | import org.springframework.boot.context.properties.ConfigurationProperties;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * Shared boot configuration properties for "spring.net.hostdiscovery".
24 | *
25 | * @author Janne Valkealahti
26 | * @author Sabby Anandan
27 | *
28 | */
29 | @ConfigurationProperties(value = "spring.net.hostdiscovery")
30 | public class HostInfoDiscoveryProperties {
31 |
32 | /**
33 | * Used to match ip address from a network using a cidr notation
34 | */
35 | private String matchIpv4;
36 |
37 | /**
38 | * The new match interface regex pattern. Default value is is empty
39 | */
40 | private String matchInterface;
41 |
42 | /**
43 | * The new preferred interface list
44 | */
45 | private List preferInterface;
46 |
47 | /**
48 | * The new point to point flag. Default value is FALSE
49 | */
50 | private boolean pointToPoint = false;
51 |
52 | /**
53 | * The new loopback flag. Default value is FALSE
54 | */
55 | private boolean loopback = false;
56 |
57 | public String getMatchIpv4() {
58 | return matchIpv4;
59 | }
60 |
61 | public void setMatchIpv4(String matchIpv4) {
62 | this.matchIpv4 = matchIpv4;
63 | }
64 |
65 | public String getMatchInterface() {
66 | return matchInterface;
67 | }
68 |
69 | public void setMatchInterface(String matchInterface) {
70 | this.matchInterface = matchInterface;
71 | }
72 |
73 | public List getPreferInterface() {
74 | return preferInterface;
75 | }
76 |
77 | public void setPreferInterface(List preferInterface) {
78 | this.preferInterface = preferInterface;
79 | }
80 |
81 | public boolean isPointToPoint() {
82 | return pointToPoint;
83 | }
84 |
85 | public void setPointToPoint(boolean pointToPoint) {
86 | this.pointToPoint = pointToPoint;
87 | }
88 |
89 | public boolean isLoopback() {
90 | return loopback;
91 | }
92 |
93 | public void setLoopback(boolean loopback) {
94 | this.loopback = loopback;
95 | }
96 | }
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | gpfdist-app-starters-build
5 | 2.0.0.BUILD-SNAPSHOT
6 | pom
7 |
8 |
9 | org.springframework.cloud.stream.app
10 | app-starters-build
11 | 2.1.6.BUILD-SNAPSHOT
12 |
13 |
14 |
15 |
16 | true
17 |
18 |
19 |
20 | spring-cloud-starter-stream-sink-gpfdist
21 | gpfdist-app-dependencies
22 |
23 |
24 |
25 |
26 |
27 | org.springframework.cloud.stream.app
28 | gpfdist-app-dependencies
29 | 2.0.0.BUILD-SNAPSHOT
30 | pom
31 | import
32 |
33 |
34 |
35 |
36 |
37 | spring
38 |
39 |
40 | spring-snapshots
41 | Spring Snapshots
42 | https://repo.spring.io/libs-snapshot-local
43 |
44 | true
45 |
46 |
47 |
48 | spring-milestones
49 | Spring Milestones
50 | https://repo.spring.io/libs-milestone-local
51 |
52 | false
53 |
54 |
55 |
56 | spring-releases
57 | Spring Releases
58 | https://repo.spring.io/release
59 |
60 | false
61 |
62 |
63 |
64 | spring-libs-release
65 | Spring Libs Release
66 | https://repo.spring.io/libs-release
67 |
68 | false
69 |
70 |
71 |
72 |
73 | false
74 |
75 | spring-milestone-release
76 | Spring Milestone Release
77 | https://repo.spring.io/libs-milestone
78 |
79 |
80 |
81 |
82 | spring-snapshots
83 | Spring Snapshots
84 | https://repo.spring.io/libs-snapshot-local
85 |
86 | true
87 |
88 |
89 |
90 | spring-milestones
91 | Spring Milestones
92 | https://repo.spring.io/libs-milestone-local
93 |
94 | false
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/support/ControlFileTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.junit.After;
20 | import org.junit.Test;
21 | import org.springframework.cloud.stream.app.gpfdist.sink.support.ControlFile.OutputMode;
22 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
23 | import org.springframework.context.annotation.Bean;
24 | import org.springframework.core.io.ClassPathResource;
25 |
26 | import static org.hamcrest.Matchers.*;
27 | import static org.junit.Assert.assertThat;
28 |
29 | public class ControlFileTests {
30 |
31 | private AnnotationConfigApplicationContext context;
32 |
33 | @Test
34 | public void testLoadFromFactory() {
35 | context = new AnnotationConfigApplicationContext();
36 | context.register(Config1.class);
37 | context.refresh();
38 |
39 | ControlFile cf = context.getBean(ControlFile.class);
40 | assertThat(cf.getGploadOutputTable(), is("test"));
41 | assertThat(cf.getGploadInputDelimiter(), is(','));
42 | assertThat(cf.getDatabase(), is("gpadmin"));
43 | assertThat(cf.getUser(), is("gpadmin"));
44 | assertThat(cf.getHost(), is("mdw.example.org"));
45 | assertThat(cf.getPort(), is(5432));
46 | assertThat(cf.getPassword(), nullValue());
47 |
48 | assertThat(cf.getGploadOutputMode(), is(OutputMode.UPDATE));
49 |
50 | assertThat(cf.getGploadOutputMatchColumns(), notNullValue());
51 | assertThat(cf.getGploadOutputMatchColumns().size(), is(2));
52 | assertThat(cf.getGploadOutputMatchColumns().get(0), is("col11"));
53 | assertThat(cf.getGploadOutputMatchColumns().get(1), is("col12"));
54 |
55 | assertThat(cf.getGploadOutputUpdateColumns(), notNullValue());
56 | assertThat(cf.getGploadOutputUpdateColumns().size(), is(2));
57 | assertThat(cf.getGploadOutputUpdateColumns().get(0), is("col21"));
58 | assertThat(cf.getGploadOutputUpdateColumns().get(1), is("col22"));
59 | assertThat(cf.getGploadOutputUpdateCondition(), is("condition"));
60 |
61 | assertThat(cf.getGploadSqlBefore().get(0), is("select 1 as before"));
62 | assertThat(cf.getGploadSqlBefore().get(1), is("select 2 as before"));
63 | assertThat(cf.getGploadSqlAfter().get(0), is("select 1 as after"));
64 | assertThat(cf.getGploadSqlAfter().get(1), is("select 2 as after"));
65 | }
66 |
67 | static class Config1 {
68 |
69 | @Bean
70 | public ControlFileFactoryBean controlFile() {
71 | ControlFileFactoryBean f = new ControlFileFactoryBean();
72 | f.setControlFileResource(new ClassPathResource("test.yml"));
73 | return f;
74 | }
75 |
76 | }
77 |
78 | @After
79 | public void clean() {
80 | context.close();
81 | context = null;
82 | }
83 |
84 | }
85 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/TestUtils.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.springframework.util.ReflectionUtils;
20 |
21 | import java.lang.reflect.Field;
22 | import java.lang.reflect.Method;
23 |
24 | /**
25 | * Utils for tests.
26 | *
27 | * @author Janne Valkealahti
28 | *
29 | */
30 | public class TestUtils {
31 |
32 | @SuppressWarnings("unchecked")
33 | public static T readField(String name, Object target) throws Exception {
34 | Field field = null;
35 | Class> clazz = target.getClass();
36 | do {
37 | try {
38 | field = clazz.getDeclaredField(name);
39 | } catch (Exception ex) {
40 | }
41 |
42 | clazz = clazz.getSuperclass();
43 | } while (field == null && !clazz.equals(Object.class));
44 |
45 | if (field == null)
46 | throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of "
47 | + target.getClass());
48 | field.setAccessible(true);
49 | return (T) field.get(target);
50 | }
51 |
52 | @SuppressWarnings("unchecked")
53 | public static T callMethod(String name, Object target) throws Exception {
54 | Class> clazz = target.getClass();
55 | Method method = ReflectionUtils.findMethod(clazz, name);
56 |
57 | if (method == null)
58 | throw new IllegalArgumentException("Cannot find method '" + method + "' in the class hierarchy of "
59 | + target.getClass());
60 | method.setAccessible(true);
61 | return (T) ReflectionUtils.invokeMethod(method, target);
62 | }
63 |
64 | public static void setField(String name, Object target, Object value) throws Exception {
65 | Field field = null;
66 | Class> clazz = target.getClass();
67 | do {
68 | try {
69 | field = clazz.getDeclaredField(name);
70 | } catch (Exception ex) {
71 | }
72 |
73 | clazz = clazz.getSuperclass();
74 | } while (field == null && !clazz.equals(Object.class));
75 |
76 | if (field == null)
77 | throw new IllegalArgumentException("Cannot find field '" + name + "' in the class hierarchy of "
78 | + target.getClass());
79 | field.setAccessible(true);
80 | field.set(target, value);
81 | }
82 |
83 | @SuppressWarnings("unchecked")
84 | public static T callMethod(String name, Object target, Object[] args, Class>[] argsTypes) throws Exception {
85 | Class> clazz = target.getClass();
86 | Method method = ReflectionUtils.findMethod(clazz, name, argsTypes);
87 |
88 | if (method == null)
89 | throw new IllegalArgumentException("Cannot find method '" + method + "' in the class hierarchy of "
90 | + target.getClass());
91 | method.setAccessible(true);
92 | return (T) ReflectionUtils.invokeMethod(method, target, args);
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/LoadConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import java.util.List;
20 |
21 | public class LoadConfiguration {
22 |
23 | private String table;
24 |
25 | private String columns;
26 |
27 | private ReadableTable externalTable;
28 |
29 | private Mode mode;
30 |
31 | private List matchColumns;
32 |
33 | private List updateColumns;
34 |
35 | private String updateCondition;
36 |
37 | private List sqlBefore;
38 |
39 | private List sqlAfter;
40 |
41 | public LoadConfiguration() {
42 | super();
43 | }
44 |
45 | public LoadConfiguration(String table, String columns, ReadableTable externalTable, Mode mode,
46 | List matchColumns, List updateColumns, String updateCondition) {
47 | this.table = table;
48 | this.columns = columns;
49 | this.externalTable = externalTable;
50 | this.mode = mode;
51 | this.matchColumns = matchColumns;
52 | this.updateColumns = updateColumns;
53 | this.updateCondition = updateCondition;
54 | }
55 |
56 | public String getTable() {
57 | return table;
58 | }
59 |
60 | public void setTable(String table) {
61 | this.table = table;
62 | }
63 |
64 | public String getColumns() {
65 | return columns;
66 | }
67 |
68 | public void setColumns(String columns) {
69 | this.columns = columns;
70 | }
71 |
72 | public ReadableTable getExternalTable() {
73 | return externalTable;
74 | }
75 |
76 | public void setExternalTable(ReadableTable externalTable) {
77 | this.externalTable = externalTable;
78 | }
79 |
80 | public Mode getMode() {
81 | return mode;
82 | }
83 |
84 | public void setMode(Mode mode) {
85 | this.mode = mode;
86 | }
87 |
88 | public List getMatchColumns() {
89 | return matchColumns;
90 | }
91 |
92 | public void setMatchColumns(List matchColumns) {
93 | this.matchColumns = matchColumns;
94 | }
95 |
96 | public List getUpdateColumns() {
97 | return updateColumns;
98 | }
99 |
100 | public void setUpdateColumns(List updateColumns) {
101 | this.updateColumns = updateColumns;
102 | }
103 |
104 | public String getUpdateCondition() {
105 | return updateCondition;
106 | }
107 |
108 | public void setUpdateCondition(String updateCondition) {
109 | this.updateCondition = updateCondition;
110 | }
111 |
112 | public List getSqlBefore() {
113 | return sqlBefore;
114 | }
115 |
116 | public void setSqlBefore(List sqlBefore) {
117 | this.sqlBefore = sqlBefore;
118 | }
119 |
120 | public List getSqlAfter() {
121 | return sqlAfter;
122 | }
123 |
124 | public void setSqlAfter(List sqlAfter) {
125 | this.sqlAfter = sqlAfter;
126 | }
127 |
128 | }
129 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/GpfdistSinkPropertiesTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink;
17 |
18 | import static org.hamcrest.CoreMatchers.notNullValue;
19 | import static org.hamcrest.Matchers.is;
20 | import static org.junit.Assert.assertThat;
21 |
22 | import org.junit.Test;
23 |
24 | import org.springframework.boot.SpringApplication;
25 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
26 | import org.springframework.cloud.stream.app.gpfdist.sink.support.SegmentRejectType;
27 | import org.springframework.context.ConfigurableApplicationContext;
28 | import org.springframework.context.annotation.Configuration;
29 |
30 | public class GpfdistSinkPropertiesTests {
31 |
32 | @Test
33 | public void testErrorTable1() {
34 | SpringApplication app = new SpringApplication(TestConfiguration.class);
35 | app.setWebEnvironment(false);
36 | ConfigurableApplicationContext context = app
37 | .run(new String[] { "--gpfdist.logErrors=true",
38 | "--gpfdist.segmentRejectLimit=1",
39 | "--gpfdist.segmentRejectType=ROWS" });
40 |
41 | GpfdistSinkProperties properties = context.getBean(GpfdistSinkProperties.class);
42 | assertThat(properties, notNullValue());
43 | assertThat(properties.isLogErrors(), is(true));
44 | assertThat(properties.getSegmentRejectLimit(), is("1"));
45 | assertThat(properties.getSegmentRejectType(), is(SegmentRejectType.ROWS));
46 | context.close();
47 | }
48 |
49 | @Test
50 | public void testErrorTable2() {
51 | SpringApplication app = new SpringApplication(TestConfiguration.class);
52 | app.setWebEnvironment(false);
53 | ConfigurableApplicationContext context = app
54 | .run(new String[] { "--gpfdist.logErrors=true",
55 | "--gpfdist.segmentRejectLimit=1",
56 | "--gpfdist.segmentRejectType=percent" });
57 |
58 | GpfdistSinkProperties properties = context.getBean(GpfdistSinkProperties.class);
59 | assertThat(properties, notNullValue());
60 | assertThat(properties.isLogErrors(), is(true));
61 | assertThat(properties.getSegmentRejectLimit(), is("1"));
62 | assertThat(properties.getSegmentRejectType(), is(SegmentRejectType.PERCENT));
63 | context.close();
64 | }
65 |
66 | @Test
67 | public void testNullString() {
68 | SpringApplication app = new SpringApplication(TestConfiguration.class);
69 | app.setWebEnvironment(false);
70 | ConfigurableApplicationContext context = app
71 | .run(new String[] { "--gpfdist.nullString=mynullstring" });
72 |
73 | GpfdistSinkProperties properties = context.getBean(GpfdistSinkProperties.class);
74 | assertThat(properties, notNullValue());
75 | assertThat(properties.getNullString(), is("mynullstring"));
76 | context.close();
77 | }
78 |
79 | @Configuration
80 | @EnableConfigurationProperties({ GpfdistSinkProperties.class })
81 | protected static class TestConfiguration {
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/GreenplumDataSourceFactoryBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.apache.commons.dbcp.BasicDataSource;
20 | import org.springframework.beans.factory.config.AbstractFactoryBean;
21 | import org.springframework.util.StringUtils;
22 |
23 | import javax.sql.DataSource;
24 |
25 | /**
26 | * Factory bean for configuring a {@link DataSource}. Needed to use
27 | * both command-line props and a control file.
28 | *
29 | * @author Janne Valkealahti
30 | */
31 | public class GreenplumDataSourceFactoryBean extends AbstractFactoryBean {
32 |
33 | private ControlFile controlFile;
34 |
35 | private String dbHost = "localhost";
36 |
37 | private String dbName = "gpadmin";
38 |
39 | private String dbUser = "gpadmin";
40 |
41 | private String dbPassword = "gpadmin";
42 |
43 | private int dbPort = 5432;
44 |
45 | @Override
46 | public Class getObjectType() {
47 | return DataSource.class;
48 | }
49 |
50 | @Override
51 | protected BasicDataSource createInstance() throws Exception {
52 | BasicDataSource ds = new BasicDataSource();
53 | ds.setDriverClassName("org.postgresql.Driver");
54 | if (StringUtils.hasText(dbUser)) {
55 | ds.setUsername(dbUser);
56 | }
57 | if (StringUtils.hasText(dbPassword)) {
58 | ds.setPassword(dbPassword);
59 | }
60 | ds.setUrl("jdbc:postgresql://" + dbHost + ":" + dbPort + "/" + dbName);
61 | return ds;
62 | }
63 |
64 | @Override
65 | public void afterPropertiesSet() throws Exception {
66 | if (controlFile != null) {
67 | if (StringUtils.hasText(controlFile.getHost())) {
68 | dbHost = controlFile.getHost();
69 | }
70 | if (StringUtils.hasText(controlFile.getDatabase())) {
71 | dbName = controlFile.getDatabase();
72 | }
73 | if (StringUtils.hasText(controlFile.getUser())) {
74 | dbUser = controlFile.getUser();
75 | }
76 | if (StringUtils.hasText(controlFile.getPassword())) {
77 | dbPassword = controlFile.getPassword();
78 | }
79 | if (controlFile.getPort() != null) {
80 | dbPort = controlFile.getPort();
81 | }
82 | }
83 | super.afterPropertiesSet();
84 | }
85 |
86 | @Override
87 | protected void destroyInstance(BasicDataSource instance) throws Exception {
88 | instance.close();
89 | }
90 |
91 | public void setControlFile(ControlFile controlFile) {
92 | this.controlFile = controlFile;
93 | }
94 |
95 | public void setDbHost(String dbHost) {
96 | this.dbHost = dbHost;
97 | }
98 |
99 |
100 | public void setDbName(String dbName) {
101 | this.dbName = dbName;
102 | }
103 |
104 |
105 | public void setDbUser(String dbUser) {
106 | this.dbUser = dbUser;
107 | }
108 |
109 |
110 | public void setDbPassword(String dbPassword) {
111 | this.dbPassword = dbPassword;
112 | }
113 |
114 |
115 | public void setDbPort(int dbPort) {
116 | this.dbPort = dbPort;
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 |
5 |
6 | org.springframework.cloud.stream.app
7 | gpfdist-app-starters-build
8 | 2.0.0.BUILD-SNAPSHOT
9 |
10 |
11 | spring-cloud-starter-stream-sink-gpfdist
12 | 2.0.0.BUILD-SNAPSHOT
13 |
14 |
15 |
16 |
17 | org.springframework.cloud.stream.app
18 | gpfdist-app-dependencies
19 | 2.0.0.BUILD-SNAPSHOT
20 | pom
21 | import
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 | io.projectreactor
30 | reactor-core
31 |
32 |
33 | io.projectreactor
34 | reactor-net
35 |
36 |
37 | com.codahale.metrics
38 | metrics-core
39 |
40 |
41 | commons-dbcp
42 | commons-dbcp
43 |
44 |
45 | org.springframework
46 | spring-jdbc
47 |
48 |
49 | io.netty
50 | netty-all
51 |
52 |
53 | org.postgresql
54 | postgresql
55 |
56 |
57 | org.springframework.data
58 | spring-data-hadoop-util
59 |
60 |
61 | org.springframework.cloud.stream.app
62 | app-starters-test-support
63 |
64 |
65 |
66 |
67 |
68 |
69 | maven-failsafe-plugin
70 |
71 | ${skipITs}
72 |
73 |
74 |
75 | package
76 |
77 | integration-test
78 | verify
79 |
80 |
81 |
82 |
83 |
84 | org.springframework.cloud
85 | spring-cloud-app-starter-doc-maven-plugin
86 |
87 |
88 | org.springframework.cloud.stream.app.plugin
89 | spring-cloud-stream-app-maven-plugin
90 |
91 | ${session.executionRootDirectory}/apps
92 | ${project.version}
93 |
94 | scs-bom
95 | org.springframework.cloud.stream.app
96 | gpfdist-app-dependencies
97 | ${project.version}
98 |
99 |
100 |
101 | true
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/AbstractLoadTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.apache.commons.dbcp.BasicDataSource;
20 | import org.junit.After;
21 | import org.junit.Before;
22 | import org.reactivestreams.Processor;
23 | import org.springframework.cloud.stream.app.gpfdist.sink.support.*;
24 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
25 | import org.springframework.context.annotation.Bean;
26 | import org.springframework.data.hadoop.util.net.DefaultHostInfoDiscovery;
27 | import org.springframework.jdbc.core.JdbcTemplate;
28 | import reactor.Environment;
29 | import reactor.core.processor.RingBufferProcessor;
30 | import reactor.io.buffer.Buffer;
31 |
32 | import java.util.Arrays;
33 | import java.util.List;
34 |
35 | /**
36 | * Base integration support for using local protocol listener.
37 | *
38 | * @author Janne Valkealahti
39 | *
40 | */
41 | public abstract class AbstractLoadTests {
42 |
43 | protected AnnotationConfigApplicationContext context;
44 |
45 | protected Processor processor;
46 |
47 | private GpfdistServer server;
48 |
49 | static class CommonConfig {
50 |
51 | @Bean
52 | public LoadFactoryBean greenplumLoad(LoadConfiguration loadConfiguration) {
53 | LoadFactoryBean factory = new LoadFactoryBean();
54 | factory.setLoadConfiguration(loadConfiguration);
55 | factory.setDataSource(dataSource());
56 | return factory;
57 | }
58 |
59 | @Bean
60 | public ReadableTableFactoryBean greenplumReadableTable() {
61 | ReadableTableFactoryBean factory = new ReadableTableFactoryBean();
62 | DefaultHostInfoDiscovery discovery = new DefaultHostInfoDiscovery();
63 | factory.setLocations(Arrays.asList(NetworkUtils.getGPFDistUri(discovery.getHostInfo().getAddress(), 8080)));
64 | factory.setFormat(Format.TEXT);
65 | return factory;
66 | }
67 |
68 | @Bean
69 | public JdbcTemplate jdbcTemplate() {
70 | return new JdbcTemplate(dataSource());
71 | }
72 |
73 | @Bean
74 | public BasicDataSource dataSource() {
75 | BasicDataSource dataSource = new BasicDataSource();
76 | dataSource.setDriverClassName("org.postgresql.Driver");
77 | dataSource.setUrl("jdbc:postgresql://mdw/gpadmin");
78 | dataSource.setUsername("gpadmin");
79 | dataSource.setPassword("gpadmin");
80 | return dataSource;
81 | }
82 |
83 | }
84 |
85 | protected void broadcastData(List data) {
86 | for (String d : data) {
87 | processor.onNext(Buffer.wrap(d));
88 | }
89 | }
90 |
91 | @Before
92 | public void setup() throws Exception {
93 | Environment.initializeIfEmpty().assignErrorJournal();
94 | processor = RingBufferProcessor.create(false);
95 | server = new GpfdistServer(processor, 8080, 1, 1, 1, 10);
96 | server.start();
97 | context = new AnnotationConfigApplicationContext();
98 | }
99 |
100 | @After
101 | public void clean() throws Exception {
102 | server.stop();
103 | context.close();
104 | context = null;
105 | server = null;
106 | }
107 |
108 | }
109 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/HostInfoDiscoveryPropertiesTests.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.springframework.cloud.stream.app.gpfdist.sink;
17 |
18 | import org.junit.Test;
19 | import org.springframework.boot.SpringApplication;
20 | import org.springframework.boot.context.properties.EnableConfigurationProperties;
21 | import org.springframework.context.ConfigurableApplicationContext;
22 | import org.springframework.context.annotation.Configuration;
23 |
24 | import static org.hamcrest.CoreMatchers.notNullValue;
25 | import static org.hamcrest.Matchers.containsInAnyOrder;
26 | import static org.hamcrest.Matchers.is;
27 | import static org.junit.Assert.assertThat;
28 |
29 | public class HostInfoDiscoveryPropertiesTests {
30 |
31 | @Test
32 | public void testAllSet() {
33 | SpringApplication app = new SpringApplication(TestConfiguration.class);
34 | app.setWebEnvironment(false);
35 | ConfigurableApplicationContext context = app
36 | .run(new String[] { "--spring.net.hostdiscovery.pointToPoint=true",
37 | "--spring.net.hostdiscovery.loopback=true",
38 | "--spring.net.hostdiscovery.preferInterface=lxcbr",
39 | "--spring.net.hostdiscovery.matchIpv4=192.168.0.0/24",
40 | "--spring.net.hostdiscovery.matchInterface=eth0" });
41 |
42 | HostInfoDiscoveryProperties properties = context.getBean(HostInfoDiscoveryProperties.class);
43 | assertThat(properties, notNullValue());
44 | assertThat(properties.isPointToPoint(), is(true));
45 | assertThat(properties.isLoopback(), is(true));
46 | assertThat(properties.getPreferInterface(), notNullValue());
47 | assertThat(properties.getPreferInterface().size(), is(1));
48 | assertThat(properties.getMatchIpv4(), is("192.168.0.0/24"));
49 | assertThat(properties.getMatchInterface(), is("eth0"));
50 | context.close();
51 | }
52 |
53 | @Test
54 | public void testPreferOne() {
55 | SpringApplication app = new SpringApplication(TestConfiguration.class);
56 | app.setWebEnvironment(false);
57 | ConfigurableApplicationContext context = app
58 | .run(new String[] { "--spring.net.hostdiscovery.preferInterface=lxcbr" });
59 |
60 | HostInfoDiscoveryProperties properties = context.getBean(HostInfoDiscoveryProperties.class);
61 | assertThat(properties, notNullValue());
62 | assertThat(properties.getPreferInterface(), notNullValue());
63 | assertThat(properties.getPreferInterface().size(), is(1));
64 | context.close();
65 | }
66 |
67 | @Test
68 | public void testPreferTwo() {
69 | SpringApplication app = new SpringApplication(TestConfiguration.class);
70 | app.setWebEnvironment(false);
71 | ConfigurableApplicationContext context = app
72 | .run(new String[] { "--spring.net.hostdiscovery.preferInterface=lxcbr,foo" });
73 |
74 | HostInfoDiscoveryProperties properties = context.getBean(HostInfoDiscoveryProperties.class);
75 | assertThat(properties, notNullValue());
76 | assertThat(properties.getPreferInterface(), notNullValue());
77 | assertThat(properties.getPreferInterface().size(), is(2));
78 | assertThat(properties.getPreferInterface(), containsInAnyOrder("lxcbr", "foo"));
79 | context.close();
80 | }
81 |
82 | @Configuration
83 | @EnableConfigurationProperties({ HostInfoDiscoveryProperties.class })
84 | protected static class TestConfiguration {
85 | }
86 | }
87 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/AbstractExternalTable.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import java.util.ArrayList;
20 | import java.util.Arrays;
21 | import java.util.List;
22 |
23 | /**
24 | * Base settings for all external tables;
25 | *
26 | * @author Janne Valkealahti
27 | * @author Gary Russell
28 | */
29 | public abstract class AbstractExternalTable {
30 |
31 | // LOCATION
32 | private List locations;
33 |
34 | // FORMAT 'TEXT'|'CVS'
35 | private Format format;
36 |
37 | // [DELIMITER [AS] 'delimiter' | 'OFF']
38 | private Character delimiter;
39 |
40 | // [NULL [AS] 'null string']
41 | private String nullString;
42 |
43 | // [ESCAPE [AS] 'escape' | 'OFF']
44 | private Character escape;
45 |
46 | // [QUOTE [AS] 'quote']
47 | private Character formatQuote;
48 |
49 | // [FORCE NOT NULL column [, ...]]
50 | private String[] formatForceQuote;
51 |
52 | // [ ENCODING 'encoding' ]
53 | private String encoding;
54 |
55 | private String like;
56 |
57 | private String columns;
58 |
59 | public List getLocations() {
60 | return locations;
61 | }
62 |
63 | public void setLocations(List locations) {
64 | this.locations = new ArrayList(locations);
65 | }
66 |
67 | public void setTextFormat() {
68 | this.format = Format.TEXT;
69 | }
70 |
71 | public void setTextFormat(Character delimiter, String nullString, Character escape) {
72 | this.format = Format.TEXT;
73 | this.delimiter = delimiter;
74 | this.nullString = nullString;
75 | this.escape = escape;
76 | }
77 |
78 | public void setCsvFormat() {
79 | this.format = Format.CSV;
80 | }
81 |
82 | public void setCsvFormat(Character quote, Character delimiter, String nullString, String[] forceQuote,
83 | Character escape) {
84 | this.format = Format.CSV;
85 | this.formatQuote = quote;
86 | this.delimiter = delimiter;
87 | this.nullString = nullString;
88 | this.escape = escape;
89 | this.formatForceQuote = Arrays.copyOf(forceQuote, forceQuote.length);
90 | }
91 |
92 | public Format getFormat() {
93 | return format;
94 | }
95 |
96 | public Character getDelimiter() {
97 | return delimiter;
98 | }
99 |
100 | public void setDelimiter(Character delimiter) {
101 | this.delimiter = delimiter;
102 | }
103 |
104 | public String getNullString() {
105 | return nullString;
106 | }
107 |
108 | public void setNullString(String nullString) {
109 | this.nullString = nullString;
110 | }
111 |
112 | public Character getEscape() {
113 | return escape;
114 | }
115 |
116 | public void setEscape(Character escape) {
117 | this.escape = escape;
118 | }
119 |
120 | public Character getQuote() {
121 | return formatQuote;
122 | }
123 |
124 | public void setQuote(Character quote) {
125 | this.formatQuote = quote;
126 | }
127 |
128 | public String[] getForceQuote() {
129 | return formatForceQuote;
130 | }
131 |
132 | public void setForceQuote(String[] forceQuote) {
133 | this.formatForceQuote = Arrays.copyOf(forceQuote, forceQuote.length);
134 | }
135 |
136 | public String getEncoding() {
137 | return encoding;
138 | }
139 |
140 | public void setEncoding(String encoding) {
141 | this.encoding = encoding;
142 | }
143 |
144 | public String getLike() {
145 | return like;
146 | }
147 |
148 | public void setLike(String like) {
149 | this.like = like;
150 | }
151 |
152 | public String getColumns() {
153 | return columns;
154 | }
155 |
156 | public void setColumns(String columns) {
157 | this.columns = columns;
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/ControlFile.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import java.util.ArrayList;
20 | import java.util.List;
21 |
22 | public class ControlFile {
23 |
24 | private Character gploadInputDelimiter;
25 |
26 | private String gploadOutputTable;
27 |
28 | private List gploadOutputMatchColumns;
29 |
30 | private List gploadOutputUpdateColumns;
31 |
32 | private String gploadOutputUpdateCondition;
33 |
34 | private OutputMode gploadOutputMode;
35 |
36 | private String database;
37 |
38 | private String user;
39 |
40 | private String password;
41 |
42 | private String host;
43 |
44 | private Integer port;
45 |
46 | private final List gploadSqlBefore = new ArrayList();
47 |
48 | private final List gploadSqlAfter = new ArrayList();
49 |
50 | public Character getGploadInputDelimiter() {
51 | return gploadInputDelimiter;
52 | }
53 |
54 | public void setGploadInputDelimiter(Character gploadInputDelimiter) {
55 | this.gploadInputDelimiter = gploadInputDelimiter;
56 | }
57 |
58 | public String getGploadOutputTable() {
59 | return gploadOutputTable;
60 | }
61 |
62 | public void setGploadOutputTable(String gploadOutputTable) {
63 | this.gploadOutputTable = gploadOutputTable;
64 | }
65 |
66 | public List getGploadOutputMatchColumns() {
67 | return gploadOutputMatchColumns;
68 | }
69 |
70 | public void setGploadOutputMatchColumns(List gploadOutputMatchColumns) {
71 | this.gploadOutputMatchColumns = gploadOutputMatchColumns;
72 | }
73 |
74 | public List getGploadOutputUpdateColumns() {
75 | return gploadOutputUpdateColumns;
76 | }
77 |
78 | public void setGploadOutputUpdateColumns(List gploadOutputUpdateColumns) {
79 | this.gploadOutputUpdateColumns = gploadOutputUpdateColumns;
80 | }
81 |
82 | public String getGploadOutputUpdateCondition() {
83 | return gploadOutputUpdateCondition;
84 | }
85 |
86 | public void setGploadOutputUpdateCondition(String gploadOutputUpdateCondition) {
87 | this.gploadOutputUpdateCondition = gploadOutputUpdateCondition;
88 | }
89 |
90 | public OutputMode getGploadOutputMode() {
91 | return gploadOutputMode;
92 | }
93 |
94 | public void setGploadOutputMode(OutputMode gploadOutputMode) {
95 | this.gploadOutputMode = gploadOutputMode;
96 | }
97 |
98 | public String getDatabase() {
99 | return database;
100 | }
101 |
102 | public void setDatabase(String database) {
103 | this.database = database;
104 | }
105 |
106 | public String getUser() {
107 | return user;
108 | }
109 |
110 | public void setUser(String user) {
111 | this.user = user;
112 | }
113 |
114 | public String getPassword() {
115 | return password;
116 | }
117 |
118 | public void setPassword(String password) {
119 | this.password = password;
120 | }
121 |
122 | public String getHost() {
123 | return host;
124 | }
125 |
126 | public void setHost(String host) {
127 | this.host = host;
128 | }
129 |
130 | public Integer getPort() {
131 | return port;
132 | }
133 |
134 | public void setPort(Integer port) {
135 | this.port = port;
136 | }
137 |
138 | public List getGploadSqlBefore() {
139 | return gploadSqlBefore;
140 | }
141 |
142 | public void addGploadSqlBefore(String gploadSqlBefore) {
143 | this.gploadSqlBefore.add(gploadSqlBefore);
144 | }
145 |
146 | public List getGploadSqlAfter() {
147 | return gploadSqlAfter;
148 | }
149 |
150 | public void addGploadSqlAfter(String gploadSqlAfter) {
151 | this.gploadSqlAfter.add(gploadSqlAfter);
152 | }
153 |
154 | public enum OutputMode {
155 | INSERT, UPDATE, MERGE
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/AbstractGpfdistMessageHandler.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.apache.commons.logging.Log;
20 | import org.apache.commons.logging.LogFactory;
21 | import org.springframework.context.SmartLifecycle;
22 | import org.springframework.integration.handler.AbstractMessageHandler;
23 | import org.springframework.messaging.Message;
24 | import org.springframework.messaging.MessageHandlingException;
25 |
26 | import java.util.concurrent.locks.ReentrantLock;
27 |
28 | /**
29 | * Base implementation of Spring Integration {@code MessageHandler} handling {@code Message}.
30 | *
31 | * @author Janne Valkealahti
32 | */
33 | public abstract class AbstractGpfdistMessageHandler extends AbstractMessageHandler implements SmartLifecycle {
34 |
35 | private static final Log logger = LogFactory.getLog(AbstractGpfdistMessageHandler.class);
36 |
37 | private volatile boolean autoStartup = true;
38 |
39 | private volatile int phase = 0;
40 |
41 | private volatile boolean running;
42 |
43 | private final ReentrantLock lifecycleLock = new ReentrantLock();
44 |
45 | @Override
46 | public final boolean isAutoStartup() {
47 | return this.autoStartup;
48 | }
49 |
50 | @Override
51 | public final int getPhase() {
52 | return this.phase;
53 | }
54 |
55 | @Override
56 | public final boolean isRunning() {
57 | this.lifecycleLock.lock();
58 | try {
59 | return this.running;
60 | }
61 | finally {
62 | this.lifecycleLock.unlock();
63 | }
64 | }
65 |
66 | @Override
67 | public final void start() {
68 | this.lifecycleLock.lock();
69 | try {
70 | if (!this.running) {
71 | this.doStart();
72 | this.running = true;
73 | if (logger.isInfoEnabled()) {
74 | logger.info("started " + this);
75 | }
76 | else {
77 | if (logger.isDebugEnabled()) {
78 | logger.debug("already started " + this);
79 | }
80 | }
81 | }
82 | }
83 | finally {
84 | this.lifecycleLock.unlock();
85 | }
86 | }
87 |
88 | @Override
89 | public final void stop() {
90 | this.lifecycleLock.lock();
91 | try {
92 | if (this.running) {
93 | this.doStop();
94 | this.running = false;
95 | if (logger.isInfoEnabled()) {
96 | logger.info("stopped " + this);
97 | }
98 | }
99 | else {
100 | if (logger.isDebugEnabled()) {
101 | logger.debug("already stopped " + this);
102 | }
103 | }
104 | }
105 | finally {
106 | this.lifecycleLock.unlock();
107 | }
108 | }
109 |
110 | @Override
111 | public final void stop(Runnable callback) {
112 | this.lifecycleLock.lock();
113 | try {
114 | this.stop();
115 | callback.run();
116 | }
117 | finally {
118 | this.lifecycleLock.unlock();
119 | }
120 | }
121 |
122 | @Override
123 | protected final void handleMessageInternal(Message> message) throws Exception {
124 | try {
125 | doWrite(message);
126 | }
127 | catch (Exception e) {
128 | throw new MessageHandlingException(message,
129 | "failed to write Message payload to GPDB/HAWQ", e);
130 | }
131 | }
132 |
133 | /**
134 | * Sets the auto startup.
135 | *
136 | * @param autoStartup the new auto startup
137 | * @see SmartLifecycle
138 | */
139 | public void setAutoStartup(boolean autoStartup) {
140 | this.autoStartup = autoStartup;
141 | }
142 |
143 | /**
144 | * Sets the phase.
145 | *
146 | * @param phase the new phase
147 | * @see SmartLifecycle
148 | */
149 | public void setPhase(int phase) {
150 | this.phase = phase;
151 | }
152 |
153 | /**
154 | * Subclasses may override this method with the start behaviour. This method will be invoked while holding the
155 | * {@link #lifecycleLock}.
156 | */
157 | protected void doStart() {
158 | };
159 |
160 | /**
161 | * Subclasses may override this method with the stop behaviour. This method will be invoked while holding the
162 | * {@link #lifecycleLock}.
163 | */
164 | protected void doStop() {
165 | };
166 |
167 | /**
168 | * Subclasses need to implement this method to handle {@link Message} in its writer.
169 | *
170 | * @param message the message to write
171 | */
172 | protected abstract void doWrite(Message> message) throws Exception;
173 |
174 | }
175 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/JdbcCommands.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.apache.commons.logging.Log;
20 | import org.apache.commons.logging.LogFactory;
21 | import org.springframework.dao.DataAccessException;
22 | import org.springframework.jdbc.core.JdbcTemplate;
23 | import org.springframework.util.StringUtils;
24 |
25 | import java.util.List;
26 |
27 | /**
28 | * Utility class helping to execute jdbc operations within a load session.
29 | * Provides a way to prepare, run and clean a main load command. Additionally
30 | * it can use a list of before and after commands which are execute before and after
31 | * of a main command. Clean command is executed last even if some of the other
32 | * commands fail.
33 | *
34 | * @author Janne Valkealahti
35 | *
36 | */
37 | public class JdbcCommands {
38 |
39 | private static final Log log = LogFactory.getLog(JdbcCommands.class);
40 |
41 | private JdbcTemplate jdbcTemplate;
42 |
43 | private List beforeSqls;
44 |
45 | private List afterSqls;
46 |
47 | private String prepareSql;
48 |
49 | private String runSql;
50 |
51 | private String cleanSql;
52 |
53 | private DataAccessException lastException;
54 |
55 | public JdbcCommands(JdbcTemplate jdbcTemplate) {
56 | this.jdbcTemplate = jdbcTemplate;
57 | }
58 |
59 | public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
60 | this.jdbcTemplate = jdbcTemplate;
61 | }
62 |
63 | public void setPrepareSql(String sql) {
64 | this.prepareSql = sql;
65 | }
66 |
67 | public void setRunSql(String sql) {
68 | this.runSql = sql;
69 | }
70 |
71 | public void setCleanSql(String sql) {
72 | this.cleanSql = sql;
73 | }
74 |
75 | public void setBeforeSqls(List beforeSqls) {
76 | this.beforeSqls = beforeSqls;
77 | }
78 |
79 | public void setAfterSqls(List afterSqls) {
80 | this.afterSqls = afterSqls;
81 | }
82 |
83 | public boolean execute() {
84 | boolean succeed = true;
85 |
86 | try {
87 | succeed = prepare();
88 | if (succeed) {
89 | succeed = before();
90 | }
91 | if (succeed) {
92 | succeed = run();
93 | }
94 | if (succeed) {
95 | succeed = after();
96 | }
97 | }
98 | catch (Exception e) {
99 | }
100 | finally {
101 | try {
102 | clean();
103 | }
104 | catch (Exception e2) {
105 | }
106 | }
107 | return succeed;
108 | }
109 |
110 | public DataAccessException getLastException() {
111 | return lastException;
112 | }
113 |
114 | private boolean prepare() {
115 | try {
116 | if (log.isDebugEnabled()) {
117 | log.debug("Executing prepare: " + prepareSql);
118 | }
119 | jdbcTemplate.execute(prepareSql);
120 | }
121 | catch (DataAccessException e) {
122 | log.error("Error during prepare sql", e);
123 | lastException = e;
124 | return false;
125 | }
126 | return true;
127 | }
128 |
129 | private boolean run() {
130 | try {
131 | if (log.isDebugEnabled()) {
132 | log.debug("Executing run: " + runSql);
133 | }
134 | jdbcTemplate.execute(runSql);
135 | }
136 | catch (DataAccessException e) {
137 | log.error("Error during run sql", e);
138 | lastException = e;
139 | return false;
140 | }
141 | return true;
142 | }
143 |
144 | private boolean clean() {
145 | try {
146 | if (log.isDebugEnabled()) {
147 | log.debug("Executing clean: " + cleanSql);
148 | }
149 | jdbcTemplate.execute(cleanSql);
150 | }
151 | catch (DataAccessException e) {
152 | log.error("Error during clean sql", e);
153 | lastException = e;
154 | return false;
155 | }
156 | return true;
157 | }
158 |
159 | private boolean before() {
160 | if (beforeSqls != null) {
161 | for (String sql : beforeSqls) {
162 | if (!StringUtils.hasText(sql)) {
163 | continue;
164 | }
165 | if (log.isDebugEnabled()) {
166 | log.debug("Executing before: " + sql);
167 | }
168 | try {
169 | jdbcTemplate.execute(sql);
170 | }
171 | catch (DataAccessException e) {
172 | lastException = e;
173 | return false;
174 | }
175 | }
176 | }
177 | return true;
178 | }
179 |
180 | private boolean after() {
181 | if (afterSqls != null) {
182 | for (String sql : afterSqls) {
183 | if (!StringUtils.hasText(sql)) {
184 | continue;
185 | }
186 | if (log.isDebugEnabled()) {
187 | log.debug("Executing after: " + sql);
188 | }
189 | try {
190 | jdbcTemplate.execute(sql);
191 | }
192 | catch (DataAccessException e) {
193 | lastException = e;
194 | return false;
195 | }
196 | }
197 | }
198 | return true;
199 | }
200 |
201 | }
202 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/support/LoadConfigurationFactoryBean.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink.support;
18 |
19 | import org.springframework.beans.factory.FactoryBean;
20 | import org.springframework.beans.factory.InitializingBean;
21 | import org.springframework.cloud.stream.app.gpfdist.sink.support.ControlFile.OutputMode;
22 | import org.springframework.util.StringUtils;
23 |
24 | import java.util.Arrays;
25 | import java.util.List;
26 |
27 | /**
28 | * {@link FactoryBean} creating instances of a {@link LoadConfiguration}.
29 | *
30 | * @author Janne Valkealahti
31 | */
32 | public class LoadConfigurationFactoryBean implements FactoryBean, InitializingBean {
33 |
34 | private ControlFile controlFile;
35 |
36 | private String table;
37 |
38 | private String columns;
39 |
40 | private ReadableTable externalTable;
41 |
42 | private Mode mode = Mode.INSERT;
43 |
44 | private List matchColumns;
45 |
46 | private List updateColumns;
47 |
48 | private String updateCondition;
49 |
50 | private List sqlBefore;
51 |
52 | private List sqlAfter;
53 |
54 | @Override
55 | public void afterPropertiesSet() throws Exception {
56 | if (controlFile != null) {
57 | if (controlFile.getGploadOutputMode() != null) {
58 | if (controlFile.getGploadOutputMode() == OutputMode.INSERT) {
59 | mode = Mode.INSERT;
60 | }
61 | else if (controlFile.getGploadOutputMode() == OutputMode.UPDATE) {
62 | mode = Mode.UPDATE;
63 | }
64 | }
65 | if (StringUtils.hasText(controlFile.getGploadOutputTable())) {
66 | table = controlFile.getGploadOutputTable();
67 | }
68 | if (controlFile.getGploadOutputMatchColumns() != null) {
69 | matchColumns = controlFile.getGploadOutputMatchColumns();
70 | }
71 | if (controlFile.getGploadOutputUpdateColumns() != null) {
72 | updateColumns = controlFile.getGploadOutputUpdateColumns();
73 | }
74 | if (StringUtils.hasText(controlFile.getGploadOutputUpdateCondition())) {
75 | updateCondition = controlFile.getGploadOutputUpdateCondition();
76 | }
77 | if (!controlFile.getGploadSqlBefore().isEmpty()) {
78 | sqlBefore = controlFile.getGploadSqlBefore();
79 | }
80 | if (!controlFile.getGploadSqlAfter().isEmpty()) {
81 | sqlAfter = controlFile.getGploadSqlAfter();
82 | }
83 | }
84 | }
85 |
86 | @Override
87 | public LoadConfiguration getObject() throws Exception {
88 | LoadConfiguration loadConfiguration = new LoadConfiguration(table, columns, externalTable, mode, matchColumns,
89 | updateColumns, updateCondition);
90 | loadConfiguration.setSqlBefore(sqlBefore);
91 | loadConfiguration.setSqlAfter(sqlAfter);
92 | return loadConfiguration;
93 | }
94 |
95 | @Override
96 | public Class getObjectType() {
97 | return LoadConfiguration.class;
98 | }
99 |
100 | @Override
101 | public boolean isSingleton() {
102 | return false;
103 | }
104 |
105 | public void setControlFile(ControlFile controlFile) {
106 | this.controlFile = controlFile;
107 | }
108 |
109 | public String getTable() {
110 | return table;
111 | }
112 |
113 | public void setTable(String table) {
114 | this.table = table;
115 | }
116 |
117 | public String getColumns() {
118 | return columns;
119 | }
120 |
121 | public void setColumns(String columns) {
122 | this.columns = columns;
123 | }
124 |
125 | public ReadableTable getExternalTable() {
126 | return externalTable;
127 | }
128 |
129 | public void setExternalTable(ReadableTable externalTable) {
130 | this.externalTable = externalTable;
131 | }
132 |
133 | public Mode getMode() {
134 | return mode;
135 | }
136 |
137 | public void setMode(Mode mode) {
138 | this.mode = mode;
139 | }
140 |
141 | public List getMatchColumns() {
142 | return matchColumns;
143 | }
144 |
145 | public void setMatchColumns(String[] matchColumns) {
146 | this.matchColumns = Arrays.asList(matchColumns);
147 | }
148 |
149 | public List getUpdateColumns() {
150 | return updateColumns;
151 | }
152 |
153 | public void setUpdateColumns(String[] updateColumns) {
154 | this.updateColumns = Arrays.asList(updateColumns);
155 | }
156 |
157 | public String getUpdateCondition() {
158 | return updateCondition;
159 | }
160 |
161 | public void setUpdateCondition(String updateCondition) {
162 | this.updateCondition = updateCondition;
163 | }
164 |
165 | public List getSqlBefore() {
166 | return sqlBefore;
167 | }
168 |
169 | public void setSqlBefore(List sqlBefore) {
170 | this.sqlBefore = sqlBefore;
171 | }
172 |
173 | public List getSqlAfter() {
174 | return sqlAfter;
175 | }
176 |
177 | public void setSqlAfter(List sqlAfter) {
178 | this.sqlAfter = sqlAfter;
179 | }
180 |
181 | }
182 |
--------------------------------------------------------------------------------
/mvnw.cmd:
--------------------------------------------------------------------------------
1 | @REM ----------------------------------------------------------------------------
2 | @REM Licensed to the Apache Software Foundation (ASF) under one
3 | @REM or more contributor license agreements. See the NOTICE file
4 | @REM distributed with this work for additional information
5 | @REM regarding copyright ownership. The ASF licenses this file
6 | @REM to you under the Apache License, Version 2.0 (the
7 | @REM "License"); you may not use this file except in compliance
8 | @REM with the License. You may obtain a copy of the License at
9 | @REM
10 | @REM https://www.apache.org/licenses/LICENSE-2.0
11 | @REM
12 | @REM Unless required by applicable law or agreed to in writing,
13 | @REM software distributed under the License is distributed on an
14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 | @REM KIND, either express or implied. See the License for the
16 | @REM specific language governing permissions and limitations
17 | @REM under the License.
18 | @REM ----------------------------------------------------------------------------
19 |
20 | @REM ----------------------------------------------------------------------------
21 | @REM Maven2 Start Up Batch script
22 | @REM
23 | @REM Required ENV vars:
24 | @REM JAVA_HOME - location of a JDK home dir
25 | @REM
26 | @REM Optional ENV vars
27 | @REM M2_HOME - location of maven2's installed home dir
28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands
29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending
30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven
31 | @REM e.g. to debug Maven itself, use
32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000
33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files
34 | @REM ----------------------------------------------------------------------------
35 |
36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on'
37 | @echo off
38 | @REM enable echoing my setting MAVEN_BATCH_ECHO to 'on'
39 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO%
40 |
41 | @REM set %HOME% to equivalent of $HOME
42 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%")
43 |
44 | @REM Execute a user defined script before this one
45 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre
46 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending
47 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat"
48 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd"
49 | :skipRcPre
50 |
51 | @setlocal
52 |
53 | set ERROR_CODE=0
54 |
55 | @REM To isolate internal variables from possible post scripts, we use another setlocal
56 | @setlocal
57 |
58 | @REM ==== START VALIDATION ====
59 | if not "%JAVA_HOME%" == "" goto OkJHome
60 |
61 | echo.
62 | echo Error: JAVA_HOME not found in your environment. >&2
63 | echo Please set the JAVA_HOME variable in your environment to match the >&2
64 | echo location of your Java installation. >&2
65 | echo.
66 | goto error
67 |
68 | :OkJHome
69 | if exist "%JAVA_HOME%\bin\java.exe" goto init
70 |
71 | echo.
72 | echo Error: JAVA_HOME is set to an invalid directory. >&2
73 | echo JAVA_HOME = "%JAVA_HOME%" >&2
74 | echo Please set the JAVA_HOME variable in your environment to match the >&2
75 | echo location of your Java installation. >&2
76 | echo.
77 | goto error
78 |
79 | @REM ==== END VALIDATION ====
80 |
81 | :init
82 |
83 | set MAVEN_CMD_LINE_ARGS=%*
84 |
85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn".
86 | @REM Fallback to current working directory if not found.
87 |
88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR%
89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir
90 |
91 | set EXEC_DIR=%CD%
92 | set WDIR=%EXEC_DIR%
93 | :findBaseDir
94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound
95 | cd ..
96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound
97 | set WDIR=%CD%
98 | goto findBaseDir
99 |
100 | :baseDirFound
101 | set MAVEN_PROJECTBASEDIR=%WDIR%
102 | cd "%EXEC_DIR%"
103 | goto endDetectBaseDir
104 |
105 | :baseDirNotFound
106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR%
107 | cd "%EXEC_DIR%"
108 |
109 | :endDetectBaseDir
110 |
111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig
112 |
113 | @setlocal EnableExtensions EnableDelayedExpansion
114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a
115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS%
116 |
117 | :endReadAdditionalConfig
118 |
119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe"
120 |
121 | set WRAPPER_JAR="".\.mvn\wrapper\maven-wrapper.jar""
122 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain
123 |
124 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CMD_LINE_ARGS%
125 | if ERRORLEVEL 1 goto error
126 | goto end
127 |
128 | :error
129 | set ERROR_CODE=1
130 |
131 | :end
132 | @endlocal & set ERROR_CODE=%ERROR_CODE%
133 |
134 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost
135 | @REM check for post script, once with legacy .bat ending and once with .cmd ending
136 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat"
137 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd"
138 | :skipRcPost
139 |
140 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on'
141 | if "%MAVEN_BATCH_PAUSE%" == "on" pause
142 |
143 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE%
144 |
145 | exit /B %ERROR_CODE%
146 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/main/java/org/springframework/cloud/stream/app/gpfdist/sink/GpfdistServer.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.apache.commons.logging.Log;
20 | import org.apache.commons.logging.LogFactory;
21 | import org.reactivestreams.Processor;
22 | import org.reactivestreams.Publisher;
23 | import reactor.core.processor.RingBufferWorkProcessor;
24 | import reactor.fn.BiFunction;
25 | import reactor.fn.Function;
26 | import reactor.io.buffer.Buffer;
27 | import reactor.io.net.NetStreams;
28 | import reactor.io.net.ReactorChannelHandler;
29 | import reactor.io.net.Spec.HttpServerSpec;
30 | import reactor.io.net.http.HttpChannel;
31 | import reactor.io.net.http.HttpServer;
32 | import reactor.rx.Stream;
33 | import reactor.rx.Streams;
34 |
35 | import java.util.concurrent.TimeUnit;
36 |
37 | /**
38 | * Server implementation around reactor and netty providing endpoint
39 | * where data can be sent using a gpfdist protocol.
40 | *
41 | * @author Janne Valkealahti
42 | */
43 | public class GpfdistServer {
44 |
45 | private final static Log log = LogFactory.getLog(GpfdistServer.class);
46 |
47 | private final Processor processor;
48 | private final int port;
49 | private final int flushCount;
50 | private final int flushTime;
51 | private final int batchTimeout;
52 | private final int batchCount;
53 | private HttpServer server;
54 | private int localPort = -1;
55 |
56 | /**
57 | * Instantiates a new gpfdist server.
58 | *
59 | * @param processor the processor
60 | * @param port the port
61 | * @param flushCount the flush count
62 | * @param flushTime the flush time
63 | * @param batchTimeout the batch timeout
64 | * @param batchCount the batch count
65 | */
66 | public GpfdistServer(Processor processor, int port, int flushCount, int flushTime,
67 | int batchTimeout, int batchCount) {
68 | this.processor = processor;
69 | this.port = port;
70 | this.flushCount = flushCount;
71 | this.flushTime = flushTime;
72 | this.batchTimeout = batchTimeout;
73 | this.batchCount = batchCount;
74 | }
75 |
76 | /**
77 | * Start a server.
78 | *
79 | * @return the http server
80 | * @throws Exception the exception
81 | */
82 | public synchronized HttpServer start() throws Exception {
83 | if (server == null) {
84 | server = createProtocolListener();
85 | }
86 | return server;
87 | }
88 |
89 | /**
90 | * Stop a server.
91 | *
92 | * @throws Exception the exception
93 | */
94 | public synchronized void stop() throws Exception {
95 | if (server != null) {
96 | server.shutdown().awaitSuccess();
97 | }
98 | server = null;
99 | }
100 |
101 | /**
102 | * Gets the local port.
103 | *
104 | * @return the local port
105 | */
106 | public int getLocalPort() {
107 | return localPort;
108 | }
109 |
110 | private HttpServer createProtocolListener()
111 | throws Exception {
112 |
113 | final Stream stream = Streams
114 | .wrap(processor)
115 | .window(flushCount, flushTime, TimeUnit.SECONDS)
116 | .flatMap(new Function, Publisher>() {
117 |
118 | @Override
119 | public Publisher apply(Stream t) {
120 |
121 | return t.reduce(new Buffer(), new BiFunction() {
122 |
123 | @Override
124 | public Buffer apply(Buffer prev, Buffer next) {
125 | return prev.append(next);
126 | }
127 | });
128 | }
129 | })
130 | .process(RingBufferWorkProcessor.create("gpfdist-sink-worker", 8192, false));
131 |
132 | HttpServer httpServer = NetStreams
133 | .httpServer(new Function, HttpServerSpec>() {
134 |
135 | @Override
136 | public HttpServerSpec apply(HttpServerSpec server) {
137 | return server
138 | .codec(new GpfdistCodec())
139 | .listen(port);
140 | }
141 | });
142 |
143 | httpServer.get("/data", new ReactorChannelHandler>() {
144 |
145 | @Override
146 | public Publisher apply(HttpChannel request) {
147 | request.responseHeaders().removeTransferEncodingChunked();
148 | request.addResponseHeader("Content-type", "text/plain");
149 | request.addResponseHeader("Expires", "0");
150 | request.addResponseHeader("X-GPFDIST-VERSION", "Spring Dataflow");
151 | request.addResponseHeader("X-GP-PROTO", "1");
152 | request.addResponseHeader("Cache-Control", "no-cache");
153 | request.addResponseHeader("Connection", "close");
154 |
155 | return request.writeWith(stream
156 | .take(batchCount)
157 | .timeout(batchTimeout, TimeUnit.SECONDS, Streams.empty())
158 | .concatWith(Streams.just(Buffer.wrap(new byte[0]))))
159 | .capacity(1l);
160 | }
161 | });
162 |
163 | httpServer.start().awaitSuccess();
164 | log.info("Server running using address=[" + httpServer.getListenAddress() + "]");
165 | localPort = httpServer.getListenAddress().getPort();
166 | return httpServer;
167 | }
168 | }
169 |
--------------------------------------------------------------------------------
/gpfdist-app-dependencies/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 4.0.0
4 | org.springframework.cloud.stream.app
5 | gpfdist-app-dependencies
6 | 2.0.0.BUILD-SNAPSHOT
7 | pom
8 | gpfdist-app-dependencies
9 | Spring Cloud Stream Gpfdist App Dependencies
10 |
11 |
12 | spring-cloud-dependencies-parent
13 | org.springframework.cloud
14 | 2.0.0.BUILD-SNAPSHOT
15 |
16 |
17 |
18 |
19 | 2.0.8.RELEASE
20 | 3.0.2
21 | 4.0.27.Final
22 | 9.4-1201-jdbc41
23 | 1.4
24 | 4.3.5.RELEASE
25 | 2.4.0.RELEASE
26 |
27 |
28 |
29 |
30 |
31 | org.springframework.cloud.stream.app
32 | spring-cloud-starter-stream-sink-gpfdist
33 | 2.0.0.BUILD-SNAPSHOT
34 |
35 |
36 | io.projectreactor
37 | reactor-core
38 | ${reactor.version}
39 |
40 |
41 | io.projectreactor
42 | reactor-net
43 | ${reactor.version}
44 |
45 |
46 | com.codahale.metrics
47 | metrics-core
48 | ${codahale.version}
49 |
50 |
51 | commons-dbcp
52 | commons-dbcp
53 | ${commons-dbcp.version}
54 |
55 |
56 | org.springframework
57 | spring-jdbc
58 | ${spring-jdbc.version}
59 |
60 |
61 | io.netty
62 | netty-all
63 | ${netty.version}
64 | runtime
65 |
66 |
67 | org.postgresql
68 | postgresql
69 | ${postgresql.version}
70 | runtime
71 |
72 |
73 | org.springframework.data
74 | spring-data-hadoop-util
75 | ${spring-data-hadoop.version}
76 |
77 |
78 | org.apache.hadoop
79 | *
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 | spring
88 |
89 |
90 | spring-snapshots
91 | Spring Snapshots
92 | https://repo.spring.io/libs-snapshot-local
93 |
94 | true
95 |
96 |
97 |
98 | spring-milestones
99 | Spring Milestones
100 | https://repo.spring.io/libs-milestone-local
101 |
102 | false
103 |
104 |
105 |
106 | spring-releases
107 | Spring Releases
108 | https://repo.spring.io/release
109 |
110 | false
111 |
112 |
113 |
114 | spring-libs-release
115 | Spring Libs Release
116 | https://repo.spring.io/libs-release
117 |
118 | false
119 |
120 |
121 |
122 |
123 | false
124 |
125 | spring-milestone-release
126 | Spring Milestone Release
127 | https://repo.spring.io/libs-milestone
128 |
129 |
130 |
131 |
132 | spring-snapshots
133 | Spring Snapshots
134 | https://repo.spring.io/libs-snapshot-local
135 |
136 | true
137 |
138 |
139 |
140 | spring-milestones
141 | Spring Milestones
142 | https://repo.spring.io/libs-milestone-local
143 |
144 | false
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
--------------------------------------------------------------------------------
/spring-cloud-starter-stream-sink-gpfdist/src/test/java/org/springframework/cloud/stream/app/gpfdist/sink/LoadIT.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2016 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * https://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | package org.springframework.cloud.stream.app.gpfdist.sink;
18 |
19 | import org.junit.Test;
20 | import org.springframework.cloud.stream.app.gpfdist.sink.support.GreenplumLoad;
21 | import org.springframework.cloud.stream.app.gpfdist.sink.support.LoadConfigurationFactoryBean;
22 | import org.springframework.cloud.stream.app.gpfdist.sink.support.Mode;
23 | import org.springframework.cloud.stream.app.gpfdist.sink.support.ReadableTable;
24 | import org.springframework.context.annotation.Bean;
25 | import org.springframework.jdbc.core.JdbcTemplate;
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 | import java.util.Map;
30 |
31 | import static org.hamcrest.Matchers.*;
32 | import static org.junit.Assert.assertThat;
33 |
34 | public class LoadIT extends AbstractLoadTests {
35 |
36 | @Test
37 | public void testInsert() {
38 | context.register(Config1.class, CommonConfig.class);
39 | context.refresh();
40 | JdbcTemplate template = context.getBean(JdbcTemplate.class);
41 | String drop = "DROP TABLE IF EXISTS AbstractLoadTests;";
42 | String create = "CREATE TABLE AbstractLoadTests (data text);";
43 | template.execute(drop);
44 | template.execute(create);
45 |
46 | List data = new ArrayList();
47 | for (int i = 0; i < 10; i++) {
48 | data.add("DATA" + i + "\n");
49 | }
50 |
51 | broadcastData(data);
52 |
53 | GreenplumLoad greenplumLoad = context.getBean(GreenplumLoad.class);
54 | greenplumLoad.load();
55 |
56 | List