1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements.  See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License.  You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 package nginx.unit.websocket.pojo;
18 
19 import java.io.ByteArrayInputStream;
20 import java.io.IOException;
21 import java.lang.reflect.Method;
22 import java.nio.ByteBuffer;
23 import java.util.ArrayList;
24 import java.util.List;
25 
26 import javax.websocket.DecodeException;
27 import javax.websocket.Decoder;
28 import javax.websocket.Decoder.Binary;
29 import javax.websocket.Decoder.BinaryStream;
30 import javax.websocket.EndpointConfig;
31 import javax.websocket.Session;
32 
33 import org.apache.tomcat.util.res.StringManager;
34 
35 /**
36  * ByteBuffer specific concrete implementation for handling whole messages.
37  */
38 public class PojoMessageHandlerWholeBinary
39         extends PojoMessageHandlerWholeBase<ByteBuffer> {
40 
41     private static final StringManager sm =
42             StringManager.getManager(PojoMessageHandlerWholeBinary.class);
43 
44     private final List<Decoder> decoders = new ArrayList<>();
45 
46     private final boolean isForInputStream;
47 
PojoMessageHandlerWholeBinary(Object pojo, Method method, Session session, EndpointConfig config, List<Class<? extends Decoder>> decoderClazzes, Object[] params, int indexPayload, boolean convert, int indexSession, boolean isForInputStream, long maxMessageSize)48     public PojoMessageHandlerWholeBinary(Object pojo, Method method,
49             Session session, EndpointConfig config,
50             List<Class<? extends Decoder>> decoderClazzes, Object[] params,
51             int indexPayload, boolean convert, int indexSession,
52             boolean isForInputStream, long maxMessageSize) {
53         super(pojo, method, session, params, indexPayload, convert,
54                 indexSession, maxMessageSize);
55 
56         // Update binary text size handled by session
57         if (maxMessageSize > -1 && maxMessageSize > session.getMaxBinaryMessageBufferSize()) {
58             if (maxMessageSize > Integer.MAX_VALUE) {
59                 throw new IllegalArgumentException(sm.getString(
60                         "pojoMessageHandlerWhole.maxBufferSize"));
61             }
62             session.setMaxBinaryMessageBufferSize((int) maxMessageSize);
63         }
64 
65         try {
66             if (decoderClazzes != null) {
67                 for (Class<? extends Decoder> decoderClazz : decoderClazzes) {
68                     if (Binary.class.isAssignableFrom(decoderClazz)) {
69                         Binary<?> decoder = (Binary<?>) decoderClazz.getConstructor().newInstance();
70                         decoder.init(config);
71                         decoders.add(decoder);
72                     } else if (BinaryStream.class.isAssignableFrom(
73                             decoderClazz)) {
74                         BinaryStream<?> decoder = (BinaryStream<?>)
75                                 decoderClazz.getConstructor().newInstance();
76                         decoder.init(config);
77                         decoders.add(decoder);
78                     } else {
79                         // Text decoder - ignore it
80                     }
81                 }
82             }
83         } catch (ReflectiveOperationException e) {
84             throw new IllegalArgumentException(e);
85         }
86         this.isForInputStream = isForInputStream;
87     }
88 
89 
90     @Override
decode(ByteBuffer message)91     protected Object decode(ByteBuffer message) throws DecodeException {
92         for (Decoder decoder : decoders) {
93             if (decoder instanceof Binary) {
94                 if (((Binary<?>) decoder).willDecode(message)) {
95                     return ((Binary<?>) decoder).decode(message);
96                 }
97             } else {
98                 byte[] array = new byte[message.limit() - message.position()];
99                 message.get(array);
100                 ByteArrayInputStream bais = new ByteArrayInputStream(array);
101                 try {
102                     return ((BinaryStream<?>) decoder).decode(bais);
103                 } catch (IOException ioe) {
104                     throw new DecodeException(message, sm.getString(
105                             "pojoMessageHandlerWhole.decodeIoFail"), ioe);
106                 }
107             }
108         }
109         return null;
110     }
111 
112 
113     @Override
convert(ByteBuffer message)114     protected Object convert(ByteBuffer message) {
115         byte[] array = new byte[message.remaining()];
116         message.get(array);
117         if (isForInputStream) {
118             return new ByteArrayInputStream(array);
119         } else {
120             return array;
121         }
122     }
123 
124 
125     @Override
onClose()126     protected void onClose() {
127         for (Decoder decoder : decoders) {
128             decoder.destroy();
129         }
130     }
131 }
132