1 /*
2  * Copyright 2013-2019 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.aws.messaging.support.converter;
18
19 import java.io.ByteArrayInputStream;
20 import java.io.ByteArrayOutputStream;
21 import java.io.IOException;
22 import java.io.ObjectInputStream;
23 import java.io.ObjectOutputStream;
24 import java.io.Serializable;
25 import java.nio.charset.Charset;
26
27 import org.apache.commons.codec.binary.Base64;
28 import org.apache.commons.codec.binary.Base64InputStream;
29 import org.apache.commons.codec.binary.Base64OutputStream;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import org.springframework.messaging.Message;
34 import org.springframework.messaging.MessageHeaders;
35 import org.springframework.messaging.converter.AbstractMessageConverter;
36 import org.springframework.messaging.converter.MessageConversionException;
37 import org.springframework.util.MimeType;
38
39 /**
40  * @author Agim Emruli
41  */

42 public class ObjectMessageConverter extends AbstractMessageConverter {
43
44     private static final Logger LOGGER = LoggerFactory
45             .getLogger(ObjectMessageConverter.class);
46
47     private static final String DEFAULT_ENCODING = "UTF-8";
48
49     private final Charset encoding;
50
51     public ObjectMessageConverter(String encoding) {
52         super(new MimeType("application""x-java-serialized-object",
53                 Charset.forName(encoding)));
54         this.encoding = Charset.forName(encoding);
55     }
56
57     public ObjectMessageConverter() {
58         this(DEFAULT_ENCODING);
59     }
60
61     @Override
62     protected boolean supports(Class<?> clazz) {
63         return true;
64     }
65
66     @SuppressWarnings("deprecation")
67     @Override
68     public Object convertFromInternal(Message<?> message, Class<?> targetClass,
69             Object conversionHint) {
70         String messagePayload = message.getPayload().toString();
71         byte[] rawContent = messagePayload.getBytes(this.encoding);
72         if (!(Base64.isBase64(rawContent))) {
73             throw new MessageConversionException(
74                     "Error converting payload '" + messagePayload
75                             + "' because it is not a valid base64 encoded stream!",
76                     null);
77         }
78         ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(rawContent);
79         Base64InputStream base64InputStream = new Base64InputStream(byteArrayInputStream);
80         Serializable result;
81         ObjectInputStream objectInputStream = null;
82         try {
83             objectInputStream = new ObjectInputStream(base64InputStream);
84             result = (Serializable) objectInputStream.readObject();
85         }
86         catch (ClassNotFoundException e) {
87             throw new MessageConversionException(
88                     "Error loading class from message payload, make sure class is in classpath!",
89                     e);
90         }
91         catch (IOException e) {
92             throw new MessageConversionException(
93                     "Error reading payload from binary representation", e);
94         }
95         finally {
96             if (objectInputStream != null) {
97                 try {
98                     objectInputStream.close();
99                 }
100                 catch (IOException e) {
101                     LOGGER.warn(
102                             "Error closing object output stream while reading message payload",
103                             e);
104                 }
105             }
106         }
107
108         return result;
109     }
110
111     @SuppressWarnings("deprecation")
112     @Override
113     public Object convertToInternal(Object payload, MessageHeaders headers,
114             Object conversionHint) {
115         if (!(payload instanceof Serializable)) {
116             throw new IllegalArgumentException(
117                     "Can't convert payload, it must be of type Serializable");
118         }
119
120         ByteArrayOutputStream content = new ByteArrayOutputStream();
121         Base64OutputStream base64OutputStream = new Base64OutputStream(content, true, 0,
122                 null);
123         ObjectOutputStream objectOutputStream = null;
124         try {
125             objectOutputStream = new ObjectOutputStream(base64OutputStream);
126             objectOutputStream.writeObject(payload);
127             objectOutputStream.flush();
128         }
129         catch (IOException e) {
130             throw new MessageConversionException(
131                     "Error converting payload into binary representation", e);
132         }
133         finally {
134             if (objectOutputStream != null) {
135                 try {
136                     objectOutputStream.close();
137                 }
138                 catch (IOException e) {
139                     LOGGER.warn(
140                             "Error closing object output stream while writing message payload",
141                             e);
142                 }
143             }
144         }
145
146         return new String(content.toByteArray(), 0, content.size(), this.encoding);
147     }
148
149 }
150