Skip to content

Commit 0a5e80f

Browse files
authored
Merge pull request #91 from linny0608/racAndSchemaSupport
Add RAC Support for Sink, Add Built in Schema for JMS Message for Source, Add Correlation id for SourceRecord
2 parents cc46342 + 0e7127f commit 0a5e80f

20 files changed

+2214
-381
lines changed

connectors/README.md

Lines changed: 213 additions & 16 deletions
Large diffs are not rendered by default.

connectors/pom.xml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
<groupId>com.oracle.database.messaging</groupId>
88
<artifactId>txeventq-connector</artifactId>
9-
<version>23.4.0.24.06</version>
9+
<version>23.8.0.25.06</version>
1010

1111
<packaging>jar</packaging>
1212

@@ -47,11 +47,11 @@
4747
<maven.compiler.source>${java.version}</maven.compiler.source>
4848
<java.version>11</java.version>
4949
<logback.version>1.4.14</logback.version>
50-
<oracle-db-messaging.version>23.2.0.0</oracle-db-messaging.version>
51-
<oracle-jdbc.version>23.2.0.0</oracle-jdbc.version>
52-
<oracle.database.security.version>21.9.0.0</oracle.database.security.version>
50+
<oracle-db-messaging.version>23.7.0.0</oracle-db-messaging.version>
51+
<oracle-jdbc.version>23.8.0.25.04</oracle-jdbc.version>
52+
<oracle.database.security.version>21.17.0.0</oracle.database.security.version>
5353
<jms.version>2.0.1</jms.version>
54-
<kafka.version>3.6.1</kafka.version>
54+
<kafka.version>4.0.0</kafka.version>
5555
</properties>
5656

5757
<dependencies>
@@ -77,7 +77,7 @@
7777
<dependency>
7878
<groupId>com.oracle.database.security</groupId>
7979
<artifactId>oraclepki</artifactId>
80-
<version>${oracle.database.security.version}</version>
80+
<version>23.8.0.25.04</version>
8181
</dependency>
8282
<dependency>
8383
<groupId>com.oracle.database.security</groupId>
@@ -111,25 +111,25 @@
111111
<extension>
112112
<groupId>kr.motd.maven</groupId>
113113
<artifactId>os-maven-plugin</artifactId>
114-
<version>1.6.2</version>
114+
<version>1.7.1</version>
115115
</extension>
116116
</extensions>
117117
<pluginManagement>
118118
<plugins>
119119
<plugin>
120120
<groupId>org.apache.maven.plugins</groupId>
121121
<artifactId>maven-jar-plugin</artifactId>
122-
<version>3.2.2</version>
122+
<version>3.4.2</version>
123123
</plugin>
124124
<plugin>
125125
<groupId>org.apache.maven.plugins</groupId>
126126
<artifactId>maven-dependency-plugin</artifactId>
127-
<version>3.3.0</version>
127+
<version>3.8.1</version>
128128
</plugin>
129129
<plugin>
130130
<groupId>org.apache.maven.plugins</groupId>
131131
<artifactId>maven-assembly-plugin</artifactId>
132-
<version>3.4.2</version>
132+
<version>3.7.1</version>
133133
</plugin>
134134
</plugins>
135135
</pluginManagement>
@@ -179,7 +179,7 @@
179179
<plugin>
180180
<groupId>org.apache.maven.plugins</groupId>
181181
<artifactId>maven-javadoc-plugin</artifactId>
182-
<version>3.3.2</version>
182+
<version>3.11.2</version>
183183
<configuration>
184184
<bottom>
185185
<![CDATA[Copyright © 2023, Oracle and/or its affiliates. All rights reserved.]]>
@@ -189,8 +189,8 @@
189189
</plugin>
190190
<plugin>
191191
<artifactId>maven-surefire-plugin</artifactId>
192-
<version>2.22.0</version>
192+
<version>3.5.2</version>
193193
</plugin>
194194
</plugins>
195195
</build>
196-
</project>
196+
</project>
Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
/*
2+
** Kafka Connect for TxEventQ.
3+
**
4+
** Copyright (c) 2024, 2025 Oracle and/or its affiliates.
5+
** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl.
6+
*/
7+
8+
/*
9+
* Licensed to the Apache Software Foundation (ASF) under one or more
10+
* contributor license agreements. See the NOTICE file distributed with
11+
* this work for additional information regarding copyright ownership.
12+
* The ASF licenses this file to You under the Apache License, Version 2.0
13+
* (the "License"); you may not use this file except in compliance with
14+
* the License. You may obtain a copy of the License at
15+
*
16+
* http://www.apache.org/licenses/LICENSE-2.0
17+
*
18+
* Unless required by applicable law or agreed to in writing, software
19+
* distributed under the License is distributed on an "AS IS" BASIS,
20+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21+
* See the License for the specific language governing permissions and
22+
* limitations under the License.
23+
*/
24+
25+
import java.util.Properties;
26+
import java.util.List;
27+
import java.util.UUID;
28+
import java.util.Iterator;
29+
import java.time.Duration;
30+
import org.apache.kafka.clients.consumer.KafkaConsumer;
31+
import org.apache.kafka.clients.consumer.ConsumerRecords;
32+
import org.apache.kafka.clients.consumer.ConsumerRecord;
33+
import org.json.JSONObject;
34+
import java.util.Base64;
35+
import java.nio.charset.StandardCharsets;
36+
37+
/*
38+
* Pass in the name of the Kafka topic to consume from for the first argument.
39+
* Pass in the number of messages to consume from the Kafka topic for the second argument.
40+
*/
41+
public class ConsumerOfJmsSchema {
42+
public static void main(String[] args) {
43+
44+
String kafkaTopic = args[0];
45+
int numOfMsgToConsume = Integer.valueOf(args[1]);
46+
final int BLOCK_TIMEOUT_MS = 3000;
47+
Properties props = new Properties();
48+
props.put("bootstrap.servers", "localhost:9092");
49+
props.put("group.id" , UUID.randomUUID().toString());
50+
props.put("auto.offset.reset","earliest");
51+
52+
props.put("key.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
53+
props.put("value.deserializer", "org.apache.kafka.common.serialization.StringDeserializer");
54+
KafkaConsumer<String , String> consumer = new KafkaConsumer<String, String>(props);
55+
56+
consumer.subscribe(List.of(kafkaTopic));
57+
int msgCounter = 0;
58+
59+
while(msgCounter < numOfMsgToConsume)
60+
{
61+
ConsumerRecords <String, String> records = consumer.poll(Duration.ofMillis(BLOCK_TIMEOUT_MS));
62+
System.out.println("");
63+
64+
for (ConsumerRecord<String, String> record : records)
65+
{
66+
msgCounter++;
67+
JSONObject jsonObject = new JSONObject(record.value());
68+
69+
System.out.println("********Gets list of JSON keys for the schema.********");
70+
71+
Iterator<?> keys = jsonObject.keys();
72+
while (keys.hasNext()) {
73+
String key = (String)keys.next();
74+
System.out.println("JSON Keys:" + key);
75+
}
76+
77+
System.out.println("");
78+
79+
String messageId = jsonObject.getString("messageId");
80+
System.out.println("messageId = " + messageId);
81+
82+
String messageType = jsonObject.getString("messageType");
83+
System.out.println("messageType = " + messageType);
84+
85+
if (!jsonObject.get("correlationId").equals(null)) {
86+
String correlationId = jsonObject.getString("correlationId");
87+
System.out.println("correlationId = " + correlationId);
88+
}
89+
90+
// Gets the payloadBytes property and decodes the message.
91+
if (!jsonObject.get("payloadBytes").equals(null)) {
92+
String payloadBytes = jsonObject.get("payloadBytes").toString();
93+
System.out.println("Undecoded payloadBytes: " + payloadBytes);
94+
System.out.println("Decoded payloadBytes: " + decodeKafkaMessage(payloadBytes));
95+
}
96+
97+
// Gets the payloadText message.
98+
if (!jsonObject.get("payloadText").equals(null)) {
99+
String payloadText = jsonObject.get("payloadText").toString();
100+
System.out.println("payloadText: " + payloadText);
101+
}
102+
103+
/**
104+
* Gets the payloadMap message that is a Map of keys/values.
105+
* If access to different property values are required follow the example
106+
* below for the properties schema.
107+
*/
108+
if (!jsonObject.get("payloadMap").equals(null)) {
109+
JSONObject payloadMapJsonObject = jsonObject.getJSONObject("payloadMap");
110+
System.out.println("payloadMap: " + payloadMapJsonObject);
111+
}
112+
113+
System.out.println("");
114+
115+
/*********************************************************/
116+
/* Gets the different values from the properties schema. */
117+
/*********************************************************/
118+
119+
JSONObject propertiesJsonObject = jsonObject.getJSONObject("properties");
120+
System.out.println("********Gets the different values from the properties schema.********");
121+
122+
// Since the propertyType for JMSXRcvTimestamp property is a long use the getLong to get the value.
123+
JSONObject jmsXrcvTimestamp = propertiesJsonObject.getJSONObject("JMSXRcvTimestamp");
124+
long jmsXrcvTimestampVal = jmsXrcvTimestamp.getLong("long");
125+
System.out.println("JMSXRcvTimestamp: " + jmsXrcvTimestampVal);
126+
127+
// Since the propertyType for JMSXDeliveryCount property is a integer use the getInt to get the value.
128+
JSONObject jmsXdeliveryCount = propertiesJsonObject.getJSONObject("JMSXDeliveryCount");
129+
int jmsXdeliveryCountVal = jmsXdeliveryCount.getInt("integer");
130+
System.out.println("JMSXDeliveryCount: " + jmsXdeliveryCountVal);
131+
132+
// Since the propertyType for JMSXState property is a integer use the getInt to get the value.
133+
JSONObject jmsXstate = propertiesJsonObject.getJSONObject("JMSXState");
134+
int jmsXstateVal = jmsXstate.getInt("integer");
135+
System.out.println("JMSXState: " + jmsXstateVal);
136+
137+
System.out.println("");
138+
139+
/*********************************************************/
140+
/* Gets the different values from the destination schema. */
141+
/*********************************************************/
142+
143+
JSONObject destinationJsonObject = jsonObject.getJSONObject("destination");
144+
System.out.println("********Gets the different values from the Destination schema.********");
145+
String destinationType = destinationJsonObject.getString("type");
146+
System.out.println("type= " + destinationType);
147+
148+
String destinationName = destinationJsonObject.getString("name");
149+
System.out.println("name= " + destinationName);
150+
151+
if (destinationType.equals("topic") || destinationType.equals("queue")) {
152+
String destinationOwner = destinationJsonObject.getString("owner");
153+
System.out.println("owner= " + destinationOwner);
154+
155+
String destinationCompleteName = destinationJsonObject.getString("completeName");
156+
System.out.println("completeName= " + destinationCompleteName);
157+
158+
String destinationCompleteTableName = destinationJsonObject.getString("completeTableName");
159+
System.out.println("completeTableName= " + destinationCompleteTableName);
160+
161+
}
162+
163+
System.out.println("");
164+
}
165+
}
166+
}
167+
168+
// This method is used to decode the JMS Bytes message stored in the payloadBytes schema property.
169+
public static String decodeKafkaMessage(String encodedMessage) {
170+
// Decode the Base64 encoded string
171+
byte[] decodedBytes = Base64.getDecoder().decode(encodedMessage);
172+
173+
// Convert the byte array to a String (assuming UTF-8 encoding)
174+
return new String(decodedBytes, StandardCharsets.UTF_8);
175+
}
176+
}

connectors/src/main/java/oracle/jdbc/txeventq/kafka/connect/common/utils/Constants.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,24 @@ private Constants() {
7474
// Database not open
7575
public static final int ORA_01109 = 1109;
7676

77+
// Closed statement
78+
public static final int ORA_17009 = 17009;
79+
80+
// Got minus one from a read call
81+
public static final int ORA_17800 = 17800;
82+
83+
// Timeout occurred while waiting for lock to flush object string data object string
84+
public static final int ORA_62187 = 62187;
85+
86+
// Invalid credential or not authorized; logon denied
87+
public static final int ORA_01017 = 1017;
88+
89+
// Interrupted IO error.: Socket read interrupted
90+
public static final int ORA_18730 = 18730;
91+
92+
// Database connection closed by peer
93+
public static final int ORA_03113 = 3113;
94+
95+
// Cannot connect to database. Instance ...
96+
public static final int ORA_12521 = 12521;
7797
}

0 commit comments

Comments
 (0)