xref: /unit/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java (revision 1157:7ae152bda303)
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.InvocationTargetException;
21 import java.util.Map;
22 import java.util.Set;
23 
24 import javax.websocket.CloseReason;
25 import javax.websocket.Endpoint;
26 import javax.websocket.EndpointConfig;
27 import javax.websocket.MessageHandler;
28 import javax.websocket.Session;
29 
30 import org.apache.juli.logging.Log;
31 import org.apache.juli.logging.LogFactory;
32 import org.apache.tomcat.util.ExceptionUtils;
33 import org.apache.tomcat.util.res.StringManager;
34 
35 /**
36  * Base implementation (client and server have different concrete
37  * implementations) of the wrapper that converts a POJO instance into a
38  * WebSocket endpoint instance.
39  */
40 public abstract class PojoEndpointBase extends Endpoint {
41 
42     private final Log log = LogFactory.getLog(PojoEndpointBase.class); // must not be static
43     private static final StringManager sm = StringManager.getManager(PojoEndpointBase.class);
44 
45     private Object pojo;
46     private Map<String,String> pathParameters;
47     private PojoMethodMapping methodMapping;
48 
49 
doOnOpen(Session session, EndpointConfig config)50     protected final void doOnOpen(Session session, EndpointConfig config) {
51         PojoMethodMapping methodMapping = getMethodMapping();
52         Object pojo = getPojo();
53         Map<String,String> pathParameters = getPathParameters();
54 
55         // Add message handlers before calling onOpen since that may trigger a
56         // message which in turn could trigger a response and/or close the
57         // session
58         for (MessageHandler mh : methodMapping.getMessageHandlers(pojo,
59                 pathParameters, session, config)) {
60             session.addMessageHandler(mh);
61         }
62 
63         if (methodMapping.getOnOpen() != null) {
64             try {
65                 methodMapping.getOnOpen().invoke(pojo,
66                         methodMapping.getOnOpenArgs(
67                                 pathParameters, session, config));
68 
69             } catch (IllegalAccessException e) {
70                 // Reflection related problems
71                 log.error(sm.getString(
72                         "pojoEndpointBase.onOpenFail",
73                         pojo.getClass().getName()), e);
74                 handleOnOpenOrCloseError(session, e);
75             } catch (InvocationTargetException e) {
76                 Throwable cause = e.getCause();
77                 handleOnOpenOrCloseError(session, cause);
78             } catch (Throwable t) {
79                 handleOnOpenOrCloseError(session, t);
80             }
81         }
82     }
83 
84 
handleOnOpenOrCloseError(Session session, Throwable t)85     private void handleOnOpenOrCloseError(Session session, Throwable t) {
86         // If really fatal - re-throw
87         ExceptionUtils.handleThrowable(t);
88 
89         // Trigger the error handler and close the session
90         onError(session, t);
91         try {
92             session.close();
93         } catch (IOException ioe) {
94             log.warn(sm.getString("pojoEndpointBase.closeSessionFail"), ioe);
95         }
96     }
97 
98     @Override
onClose(Session session, CloseReason closeReason)99     public final void onClose(Session session, CloseReason closeReason) {
100 
101         if (methodMapping.getOnClose() != null) {
102             try {
103                 methodMapping.getOnClose().invoke(pojo,
104                         methodMapping.getOnCloseArgs(pathParameters, session, closeReason));
105             } catch (Throwable t) {
106                 log.error(sm.getString("pojoEndpointBase.onCloseFail",
107                         pojo.getClass().getName()), t);
108                 handleOnOpenOrCloseError(session, t);
109             }
110         }
111 
112         // Trigger the destroy method for any associated decoders
113         Set<MessageHandler> messageHandlers = session.getMessageHandlers();
114         for (MessageHandler messageHandler : messageHandlers) {
115             if (messageHandler instanceof PojoMessageHandlerWholeBase<?>) {
116                 ((PojoMessageHandlerWholeBase<?>) messageHandler).onClose();
117             }
118         }
119     }
120 
121 
122     @Override
onError(Session session, Throwable throwable)123     public final void onError(Session session, Throwable throwable) {
124 
125         if (methodMapping.getOnError() == null) {
126             log.error(sm.getString("pojoEndpointBase.onError",
127                     pojo.getClass().getName()), throwable);
128         } else {
129             try {
130                 methodMapping.getOnError().invoke(
131                         pojo,
132                         methodMapping.getOnErrorArgs(pathParameters, session,
133                                 throwable));
134             } catch (Throwable t) {
135                 ExceptionUtils.handleThrowable(t);
136                 log.error(sm.getString("pojoEndpointBase.onErrorFail",
137                         pojo.getClass().getName()), t);
138             }
139         }
140     }
141 
getPojo()142     protected Object getPojo() { return pojo; }
setPojo(Object pojo)143     protected void setPojo(Object pojo) { this.pojo = pojo; }
144 
145 
getPathParameters()146     protected Map<String,String> getPathParameters() { return pathParameters; }
setPathParameters(Map<String,String> pathParameters)147     protected void setPathParameters(Map<String,String> pathParameters) {
148         this.pathParameters = pathParameters;
149     }
150 
151 
getMethodMapping()152     protected PojoMethodMapping getMethodMapping() { return methodMapping; }
setMethodMapping(PojoMethodMapping methodMapping)153     protected void setMethodMapping(PojoMethodMapping methodMapping) {
154         this.methodMapping = methodMapping;
155     }
156 }
157