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.lang.reflect.Method;
21 import java.nio.ByteBuffer;
22 
23 import javax.websocket.EncodeException;
24 import javax.websocket.MessageHandler;
25 import javax.websocket.RemoteEndpoint;
26 import javax.websocket.Session;
27 
28 import org.apache.tomcat.util.ExceptionUtils;
29 import nginx.unit.websocket.WrappedMessageHandler;
30 
31 /**
32  * Common implementation code for the POJO message handlers.
33  *
34  * @param <T>   The type of message to handle
35  */
36 public abstract class PojoMessageHandlerBase<T>
37         implements WrappedMessageHandler {
38 
39     protected final Object pojo;
40     protected final Method method;
41     protected final Session session;
42     protected final Object[] params;
43     protected final int indexPayload;
44     protected final boolean convert;
45     protected final int indexSession;
46     protected final long maxMessageSize;
47 
PojoMessageHandlerBase(Object pojo, Method method, Session session, Object[] params, int indexPayload, boolean convert, int indexSession, long maxMessageSize)48     public PojoMessageHandlerBase(Object pojo, Method method,
49             Session session, Object[] params, int indexPayload, boolean convert,
50             int indexSession, long maxMessageSize) {
51         this.pojo = pojo;
52         this.method = method;
53         // TODO: The method should already be accessible here but the following
54         // code seems to be necessary in some as yet not fully understood cases.
55         try {
56             this.method.setAccessible(true);
57         } catch (Exception e) {
58             // It is better to make sure the method is accessible, but
59             // ignore exceptions and hope for the best
60         }
61         this.session = session;
62         this.params = params;
63         this.indexPayload = indexPayload;
64         this.convert = convert;
65         this.indexSession = indexSession;
66         this.maxMessageSize = maxMessageSize;
67     }
68 
69 
processResult(Object result)70     protected final void processResult(Object result) {
71         if (result == null) {
72             return;
73         }
74 
75         RemoteEndpoint.Basic remoteEndpoint = session.getBasicRemote();
76         try {
77             if (result instanceof String) {
78                 remoteEndpoint.sendText((String) result);
79             } else if (result instanceof ByteBuffer) {
80                 remoteEndpoint.sendBinary((ByteBuffer) result);
81             } else if (result instanceof byte[]) {
82                 remoteEndpoint.sendBinary(ByteBuffer.wrap((byte[]) result));
83             } else {
84                 remoteEndpoint.sendObject(result);
85             }
86         } catch (IOException | EncodeException ioe) {
87             throw new IllegalStateException(ioe);
88         }
89     }
90 
91 
92     /**
93      * Expose the POJO if it is a message handler so the Session is able to
94      * match requests to remove handlers if the original handler has been
95      * wrapped.
96      */
97     @Override
getWrappedHandler()98     public final MessageHandler getWrappedHandler() {
99         if (pojo instanceof MessageHandler) {
100             return (MessageHandler) pojo;
101         } else {
102             return null;
103         }
104     }
105 
106 
107     @Override
getMaxMessageSize()108     public final long getMaxMessageSize() {
109         return maxMessageSize;
110     }
111 
112 
handlePojoMethodException(Throwable t)113     protected final void handlePojoMethodException(Throwable t) {
114         t = ExceptionUtils.unwrapInvocationTargetException(t);
115         ExceptionUtils.handleThrowable(t);
116         if (t instanceof RuntimeException) {
117             throw (RuntimeException) t;
118         } else {
119             throw new RuntimeException(t.getMessage(), t);
120         }
121     }
122 }
123