Skip to content

Commit a929316

Browse files
committed
Refactoring and fixing issues
1 parent 57be4c9 commit a929316

27 files changed

+225
-150
lines changed

src/main/java/io/cdap/plugin/jms/common/SchemaValidationUtils.java

+58-25
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import io.cdap.plugin.jms.source.JMSStreamingSourceConfig;
2323

2424
import java.util.Arrays;
25+
import java.util.List;
2526
import java.util.stream.Collectors;
2627

2728
/**
@@ -60,20 +61,25 @@ public class SchemaValidationUtils {
6061
WRONG_BODY_DATA_TYPE_FOR_HEADER_ACTION = "The \"header\" field must be of Record data type.",
6162

6263
NOT_SUPPORTED_FIELDS_IN_HEADER_RECORD_ERROR = "Not supported fields set in the header record!",
63-
NOT_SUPPORTED_FIELDS_IN_HEADER_RECORD_ACTION = "The field \"header\" support only the fields " +
64+
NOT_SUPPORTED_FIELDS_IN_HEADER_RECORD_ACTION = "The field \"header\" support only fields: " +
6465
JMSMessageHeader.describe(),
6566

6667
WRONG_PROPERTIES_DATA_TYPE_ERROR = "The field \"properties\" has a not supported data type set!",
6768
WRONG_PROPERTIES_DATA_TYPE_ACTION = "The field \"properties\" is mandatory to be of String or Record data type.",
6869

6970
NOT_SUPPORTED_ROOT_FIELDS_IN_MESSAGE_ERROR = "Not supported root fields in the schema!",
7071
NOT_SUPPORTED_ROOT_FIELDS_IN_MESSAGE_ACTION = "JMS \"Message\" message type supports only \"header\" and " +
71-
"\"properties\" as root fields.";
72+
"\"properties\" as root fields.",
73+
74+
HEADER_AND_PROPERTIES_MISSING_IN_MESSAGE_ERROR = "Fields \"Header\" and \"Properties\" are missing!",
75+
HEADER_AND_PROPERTIES_MISSING_IN_MESSAGE_ACTION = "When JMS \"Message\" message type is selected, it is " +
76+
"mandatory that either \"Header\" or \"Properties\" root fields to be present in schema. " +
77+
"Set at least one of \"Keep Message Header\" or \"Keep Message Properties\" to true.";
7278

7379
/**
7480
* Throws an error if schema is null.
7581
*
76-
* @param schema the user defined schema
82+
* @param schema the user defined schema
7783
* @param collector the failure collector
7884
*/
7985
public static void validateIfSchemaIsNull(Schema schema, FailureCollector collector) {
@@ -85,7 +91,7 @@ public static void validateIfSchemaIsNull(Schema schema, FailureCollector collec
8591
/**
8692
* Throws an error if the input schema contains any other root fields except of "header", "properties", and "body".
8793
*
88-
* @param schema the user defined schema
94+
* @param schema the user defined schema
8995
* @param collector the failure collector
9096
*/
9197
public static void validateIfAnyNotSupportedRootFieldExists(Schema schema, FailureCollector collector) {
@@ -104,7 +110,7 @@ public static void validateIfAnyNotSupportedRootFieldExists(Schema schema, Failu
104110
* Throws an error if the input schema does not contain the root field "body". JMS "Message" type is the only message
105111
* type allowed to have the schema without the root field "body".
106112
*
107-
* @param schema the user defined schema
113+
* @param schema the user defined schema
108114
* @param collector the failure collector
109115
*/
110116
public static void validateIfBodyNotInSchema(Schema schema, FailureCollector collector) {
@@ -123,7 +129,7 @@ public static void validateIfBodyNotInSchema(Schema schema, FailureCollector col
123129
/**
124130
* Throws an error if the root field "body" is not of type "string" when JMS "TextMessage" is selected.
125131
*
126-
* @param schema the user defined schema
132+
* @param schema the user defined schema
127133
* @param collector the failure collector
128134
*/
129135
public static void validateTextMessageSchema(Schema schema, FailureCollector collector) {
@@ -138,15 +144,15 @@ public static void validateTextMessageSchema(Schema schema, FailureCollector col
138144
/**
139145
* Throws an error if the root field "body" is not of type "string" or "record" when JMS "MapMessage" is selected.
140146
*
141-
* @param schema the user defined schema
147+
* @param schema the user defined schema
142148
* @param collector the failure collector
143149
*/
144150
public static void validateMapMessageSchema(Schema schema, FailureCollector collector) {
145151
Schema.Type type = schema.getField(JMSMessageParts.BODY).getSchema().getType();
146152
boolean isTypeString = type.equals(Schema.Type.STRING);
147153
boolean isTypeRecord = type.equals(Schema.Type.RECORD);
148154

149-
if (!isTypeString || !isTypeRecord) {
155+
if (!isTypeString && !isTypeRecord) {
150156
tell(collector, WRONG_BODY_DATA_TYPE_IN_MAP_MESSAGE_ERROR, WRONG_BODY_DATA_TYPE_IN_MAP_MESSAGE_ACTION);
151157
}
152158
}
@@ -155,25 +161,35 @@ public static void validateMapMessageSchema(Schema schema, FailureCollector coll
155161
* Throws an error if the input schema contains any other root fields except of "header", and "properties" when JMS
156162
* "Message" type is selected.
157163
*
158-
* @param schema the user defined schema
164+
* @param schema the user defined schema
159165
* @param collector the failure collector
160166
*/
161167
public static void validateMessageSchema(Schema schema, FailureCollector collector) {
162-
boolean areNonSupportedRootFieldsPresent = schema
163-
.getFields()
164-
.stream()
165-
.map(field -> field.getName())
166-
.anyMatch(f -> !Arrays.asList(JMSMessageParts.HEADER, JMSMessageParts.PROPERTIES).contains(f));
168+
List<String> fieldNames = schema.getFields().stream().map(field -> field.getName()).collect(Collectors.toList());
169+
170+
boolean areNonSupportedRootFieldsPresent = false;
171+
for (String fieldName: fieldNames) {
172+
if (Arrays.asList(JMSMessageParts.PROPERTIES, JMSMessageParts.HEADER).contains(fieldName)) {
173+
areNonSupportedRootFieldsPresent = true;
174+
break;
175+
}
176+
}
167177

168178
if (areNonSupportedRootFieldsPresent) {
169179
tell(collector, NOT_SUPPORTED_ROOT_FIELDS_IN_MESSAGE_ERROR, NOT_SUPPORTED_ROOT_FIELDS_IN_MESSAGE_ACTION);
170180
}
181+
182+
boolean areHeaderAndPropertiesMissing = !fieldNames.contains(JMSMessageParts.HEADER) &&
183+
!fieldNames.contains(JMSMessageParts.PROPERTIES);
184+
if (areHeaderAndPropertiesMissing) {
185+
tell(collector, HEADER_AND_PROPERTIES_MISSING_IN_MESSAGE_ERROR, HEADER_AND_PROPERTIES_MISSING_IN_MESSAGE_ACTION);
186+
}
171187
}
172188

173189
/**
174190
* Throws an error if the root field "body" is not of type "array of bytes" when JMS "ObjectMessage" is selected.
175191
*
176-
* @param schema the user defined schema
192+
* @param schema the user defined schema
177193
* @param collector the failure collector
178194
*/
179195
public static void validateObjectMessageSchema(Schema schema, FailureCollector collector) {
@@ -205,15 +221,15 @@ public static void validateObjectMessageSchema(Schema schema, FailureCollector c
205221
/**
206222
* Throws an error if the root field "body" is not of type "string" or "record" when JMS "BytesMessage" is selected.
207223
*
208-
* @param schema the user defined schema
224+
* @param schema the user defined schema
209225
* @param collector the failure collector
210226
*/
211227
public static void validateBytesMessageSchema(Schema schema, FailureCollector collector) {
212228
Schema.Type type = schema.getField(JMSMessageParts.BODY).getSchema().getType();
213229
boolean isTypeString = type.equals(Schema.Type.STRING);
214230
boolean isTypeRecord = type.equals(Schema.Type.RECORD);
215231

216-
if (!isTypeString || !isTypeRecord) {
232+
if (!isTypeString && !isTypeRecord) {
217233
tell(collector, WRONG_BODY_DATA_TYPE_IN_BYTES_MESSAGE_ERROR, WRONG_BODY_DATA_TYPE_IN_BYTES_MESSAGE_ACTION);
218234
}
219235
}
@@ -223,10 +239,15 @@ public static void validateBytesMessageSchema(Schema schema, FailureCollector co
223239
* contains other fields except of "messageId", "messageTimestamp", "correlationId", "replyTo", "destination",
224240
* "deliveryNode", "redelivered", "type", "expiration", and "priority".
225241
*
226-
* @param schema the user defined schema
242+
* @param schema the user defined schema
227243
* @param collector the failure collector
228244
*/
229245
public static void validateHeaderSchema(Schema schema, FailureCollector collector) {
246+
247+
if (!isFieldPresent(schema, JMSMessageParts.HEADER)) {
248+
return;
249+
}
250+
230251
boolean isTypeRecord = schema
231252
.getField(JMSMessageParts.HEADER)
232253
.getSchema()
@@ -238,6 +259,8 @@ public static void validateHeaderSchema(Schema schema, FailureCollector collecto
238259
}
239260

240261
boolean areNonSupportedHeaderFieldsPresent = schema
262+
.getField(JMSMessageParts.HEADER)
263+
.getSchema()
241264
.getFields()
242265
.stream()
243266
.map(field -> field.getName())
@@ -251,40 +274,50 @@ public static void validateHeaderSchema(Schema schema, FailureCollector collecto
251274
/**
252275
* Throws an error if the root field "properties" is not of type "string" or "record".
253276
*
254-
* @param schema the user defined schema
277+
* @param schema the user defined schema
255278
* @param collector the failure collector
256279
*/
257280
public static void validatePropertiesSchema(Schema schema, FailureCollector collector) {
281+
282+
if (!isFieldPresent(schema, JMSMessageParts.PROPERTIES)) {
283+
return;
284+
}
285+
258286
Schema.Type type = schema.getField(JMSMessageParts.PROPERTIES).getSchema().getType();
259287
boolean isTypeString = type.equals(Schema.Type.STRING);
260288
boolean isTypeRecord = type.equals(Schema.Type.RECORD);
261289

262-
if (!isTypeString || !isTypeRecord) {
290+
if (!isTypeString && !isTypeRecord) {
263291
tell(collector, WRONG_PROPERTIES_DATA_TYPE_ERROR, WRONG_PROPERTIES_DATA_TYPE_ACTION);
264292
}
265293
}
266294

267295
/**
268296
* Throws an error and also add the error in the failure collector if one is provided.
269297
*
270-
* @param collector the failure collector
271-
* @param errorMessage the error message
298+
* @param collector the failure collector
299+
* @param errorMessage the error message
272300
* @param correctiveAction the action that the user should perform to resolve the error
273301
*/
274-
private static void tell(FailureCollector collector, String errorMessage, String correctiveAction) {
302+
public static void tell(FailureCollector collector, String errorMessage, String correctiveAction) {
275303
String errorNature = "Error during schema validation";
276304

277305
if (collector != null) {
278306
collector.addFailure(errorNature + ": " + errorMessage, correctiveAction)
279307
.withConfigProperty(JMSStreamingSourceConfig.NAME_SCHEMA);
308+
} else {
309+
throw new RuntimeException(concatenate(errorNature + ": " + errorMessage, correctiveAction));
280310
}
311+
}
281312

282-
throw new RuntimeException(concatenate(errorNature + ": " + errorMessage, correctiveAction));
313+
private static boolean isFieldPresent(Schema schema, String fieldName) {
314+
return schema.getField(fieldName) != null;
283315
}
284316

285317
/**
286318
* Concatenates two strings with a space in between
287-
* @param left the left string
319+
*
320+
* @param left the left string
288321
* @param right the right string
289322
* @return the concatenated string
290323
*/

src/main/java/io/cdap/plugin/jms/sink/converters/RecordToBytesMessageConverter.java

+34-13
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,8 @@
1717
package io.cdap.plugin.jms.sink.converters;
1818

1919
import io.cdap.cdap.api.data.format.StructuredRecord;
20-
import io.cdap.cdap.format.StructuredRecordStringConverter;
20+
import io.cdap.cdap.api.data.schema.Schema;
2121

22-
import java.io.IOException;
23-
import java.nio.charset.StandardCharsets;
2422
import javax.jms.BytesMessage;
2523
import javax.jms.JMSException;
2624

@@ -31,24 +29,47 @@ public class RecordToBytesMessageConverter {
3129

3230
/**
3331
* Converts an incoming {@link StructuredRecord} to a JMS {@link BytesMessage}
32+
*
3433
* @param bytesMessage the jms message to be populated with data
35-
* @param record the incoming record
34+
* @param record the incoming record
3635
* @return a JMS bytes message
3736
*/
38-
public static BytesMessage convertStructuredRecordToBytesMessage(BytesMessage bytesMessage, StructuredRecord record) {
39-
byte[] body = null;
40-
37+
public static BytesMessage toBytesMessage(BytesMessage bytesMessage, StructuredRecord record) {
4138
try {
42-
body = StructuredRecordStringConverter.toJsonString(record).getBytes(StandardCharsets.UTF_8);
43-
} catch (IOException e) {
44-
throw new RuntimeException("Failed to convert record to json!", e);
45-
}
39+
for (Schema.Field field : record.getSchema().getFields()) {
40+
String fieldName = field.getName();
41+
Object value = record.get(fieldName);
4642

47-
try {
48-
bytesMessage.writeBytes(body);
43+
switch (field.getSchema().getType()) {
44+
case INT:
45+
bytesMessage.writeInt(cast(value, Integer.class));
46+
break;
47+
case LONG:
48+
bytesMessage.writeLong(cast(value, Long.class));
49+
break;
50+
case DOUBLE:
51+
bytesMessage.writeDouble(cast(value, Double.class));
52+
break;
53+
case FLOAT:
54+
bytesMessage.writeFloat(cast(value, Float.class));
55+
break;
56+
case BOOLEAN:
57+
bytesMessage.writeBoolean(cast(value, Boolean.class));
58+
break;
59+
case BYTES:
60+
bytesMessage.writeBytes(cast(value, byte[].class));
61+
break;
62+
default:
63+
bytesMessage.writeUTF(cast(value, String.class));
64+
}
65+
}
4966
} catch (JMSException e) {
5067
throw new RuntimeException(String.format("%s: %s", e.getErrorCode(), e.getMessage()));
5168
}
5269
return bytesMessage;
5370
}
71+
72+
public static <T> T cast(Object o, Class<T> clazz) {
73+
return o != null ? clazz.cast(o) : null;
74+
}
5475
}

src/main/java/io/cdap/plugin/jms/sink/converters/RecordToMapMessageConverter.java

+1-10
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class RecordToMapMessageConverter {
3434
* @param record the incoming record
3535
* @return a JMS map message
3636
*/
37-
public static MapMessage convertStructuredRecordToMapMessage(MapMessage mapMessage, StructuredRecord record) {
37+
public static MapMessage toMapMessage(MapMessage mapMessage, StructuredRecord record) {
3838
try {
3939
for (Schema.Field field : record.getSchema().getFields()) {
4040
String fieldName = field.getName();
@@ -59,15 +59,6 @@ public static MapMessage convertStructuredRecordToMapMessage(MapMessage mapMessa
5959
case BYTES:
6060
mapMessage.setBytes(fieldName, cast(value, byte[].class));
6161
break;
62-
case ARRAY:
63-
mapMessage.setObject(fieldName, value);
64-
break;
65-
case RECORD:
66-
mapMessage.setObject(fieldName, value);
67-
break;
68-
case MAP:
69-
mapMessage.setObject(fieldName, value);
70-
break;
7162
default:
7263
mapMessage.setString(fieldName, cast(value, String.class));
7364
}

src/main/java/io/cdap/plugin/jms/sink/converters/RecordToMessageConverter.java

+3-9
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ public class RecordToMessageConverter {
3434
* @param record the incoming record
3535
* @return a JMS message
3636
*/
37-
public static Message convertRecordToMessage(Message message, StructuredRecord record) {
37+
public static Message toMessage(Message message, StructuredRecord record) {
3838
try {
3939
for (Schema.Field field : record.getSchema().getFields()) {
4040
String fieldName = field.getName();
@@ -56,14 +56,8 @@ public static Message convertRecordToMessage(Message message, StructuredRecord r
5656
case BOOLEAN:
5757
message.setBooleanProperty(fieldName, cast(value, Boolean.class));
5858
break;
59-
case ARRAY:
60-
message.setObjectProperty(fieldName, value);
61-
break;
62-
case RECORD:
63-
message.setObjectProperty(fieldName, value);
64-
break;
65-
case MAP:
66-
message.setObjectProperty(fieldName, value);
59+
case BYTES:
60+
message.setByteProperty(fieldName, cast(value, Byte.class));
6761
break;
6862
default:
6963
message.setStringProperty(fieldName, cast(value, String.class));

src/main/java/io/cdap/plugin/jms/sink/converters/RecordToObjectMessageConverter.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class RecordToObjectMessageConverter {
3636
* @param record the incoming record
3737
* @return a JMS object message
3838
*/
39-
public static ObjectMessage convertRecordToObjectMessage(ObjectMessage objectMessage, StructuredRecord record) {
39+
public static ObjectMessage toObjectMessage(ObjectMessage objectMessage, StructuredRecord record) {
4040
byte[] body = null;
4141

4242
try {

src/main/java/io/cdap/plugin/jms/sink/converters/RecordToTextMessageConverter.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,13 @@ public class RecordToTextMessageConverter {
3636
* @param record the incoming record
3737
* @return a JMS text message
3838
*/
39-
public static TextMessage convertRecordToTextMessage(TextMessage textMessage, StructuredRecord record) {
39+
public static TextMessage toTextMessage(TextMessage textMessage, StructuredRecord record) {
4040
int numFields = record.getSchema().getFields().size();
4141

4242
if (numFields == 1) {
43-
return convertRecordWithSingleField(textMessage, record);
43+
return withSingleField(textMessage, record);
4444
}
45-
return convertRecordWithMultipleFields(textMessage, record);
45+
return withMultipleFields(textMessage, record);
4646
}
4747

4848
/**
@@ -53,7 +53,7 @@ public static TextMessage convertRecordToTextMessage(TextMessage textMessage, St
5353
* @param record the incoming record
5454
* @return a JMS text message
5555
*/
56-
private static TextMessage convertRecordWithSingleField(TextMessage textMessage, StructuredRecord record) {
56+
private static TextMessage withSingleField(TextMessage textMessage, StructuredRecord record) {
5757
Schema.Field singleField = record.getSchema().getFields().get(0);
5858
String body = record.get(singleField.getName()).toString();
5959
try {
@@ -72,7 +72,7 @@ private static TextMessage convertRecordWithSingleField(TextMessage textMessage,
7272
* @param record the incoming record
7373
* @return a JMS text message
7474
*/
75-
private static TextMessage convertRecordWithMultipleFields(TextMessage textMessage, StructuredRecord record) {
75+
private static TextMessage withMultipleFields(TextMessage textMessage, StructuredRecord record) {
7676
String body;
7777

7878
try {

0 commit comments

Comments
 (0)