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.IOException;
20 import java.io.StringReader;
21 import java.lang.reflect.Method;
22 import java.util.ArrayList;
23 import java.util.List;
24 
25 import javax.websocket.DecodeException;
26 import javax.websocket.Decoder;
27 import javax.websocket.Decoder.Text;
28 import javax.websocket.Decoder.TextStream;
29 import javax.websocket.EndpointConfig;
30 import javax.websocket.Session;
31 
32 import org.apache.tomcat.util.res.StringManager;
33 import nginx.unit.websocket.Util;
34 
35 
36 /**
37  * Text specific concrete implementation for handling whole messages.
38  */
39 public class PojoMessageHandlerWholeText
40         extends PojoMessageHandlerWholeBase<String> {
41 
42     private static final StringManager sm =
43             StringManager.getManager(PojoMessageHandlerWholeText.class);
44 
45     private final List<Decoder> decoders = new ArrayList<>();
46     private final Class<?> primitiveType;
47 
PojoMessageHandlerWholeText(Object pojo, Method method, Session session, EndpointConfig config, List<Class<? extends Decoder>> decoderClazzes, Object[] params, int indexPayload, boolean convert, int indexSession, long maxMessageSize)48     public PojoMessageHandlerWholeText(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             long maxMessageSize) {
53         super(pojo, method, session, params, indexPayload, convert,
54                 indexSession, maxMessageSize);
55 
56         // Update max text size handled by session
57         if (maxMessageSize > -1 && maxMessageSize > session.getMaxTextMessageBufferSize()) {
58             if (maxMessageSize > Integer.MAX_VALUE) {
59                 throw new IllegalArgumentException(sm.getString(
60                         "pojoMessageHandlerWhole.maxBufferSize"));
61             }
62             session.setMaxTextMessageBufferSize((int) maxMessageSize);
63         }
64 
65         // Check for primitives
66         Class<?> type = method.getParameterTypes()[indexPayload];
67         if (Util.isPrimitive(type)) {
68             primitiveType = type;
69             return;
70         } else {
71             primitiveType = null;
72         }
73 
74         try {
75             if (decoderClazzes != null) {
76                 for (Class<? extends Decoder> decoderClazz : decoderClazzes) {
77                     if (Text.class.isAssignableFrom(decoderClazz)) {
78                         Text<?> decoder = (Text<?>) decoderClazz.getConstructor().newInstance();
79                         decoder.init(config);
80                         decoders.add(decoder);
81                     } else if (TextStream.class.isAssignableFrom(
82                             decoderClazz)) {
83                         TextStream<?> decoder =
84                                 (TextStream<?>) decoderClazz.getConstructor().newInstance();
85                         decoder.init(config);
86                         decoders.add(decoder);
87                     } else {
88                         // Binary decoder - ignore it
89                     }
90                 }
91             }
92         } catch (ReflectiveOperationException e) {
93             throw new IllegalArgumentException(e);
94         }
95     }
96 
97 
98     @Override
decode(String message)99     protected Object decode(String message) throws DecodeException {
100         // Handle primitives
101         if (primitiveType != null) {
102             return Util.coerceToType(primitiveType, message);
103         }
104         // Handle full decoders
105         for (Decoder decoder : decoders) {
106             if (decoder instanceof Text) {
107                 if (((Text<?>) decoder).willDecode(message)) {
108                     return ((Text<?>) decoder).decode(message);
109                 }
110             } else {
111                 StringReader r = new StringReader(message);
112                 try {
113                     return ((TextStream<?>) decoder).decode(r);
114                 } catch (IOException ioe) {
115                     throw new DecodeException(message, sm.getString(
116                             "pojoMessageHandlerWhole.decodeIoFail"), ioe);
117                 }
118             }
119         }
120         return null;
121     }
122 
123 
124     @Override
convert(String message)125     protected Object convert(String message) {
126         return new StringReader(message);
127     }
128 
129 
130     @Override
onClose()131     protected void onClose() {
132         for (Decoder decoder : decoders) {
133             decoder.destroy();
134         }
135     }
136 }
137