summaryrefslogtreecommitdiffhomepage
path: root/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java
diff options
context:
space:
mode:
authorMax Romanov <max.romanov@nginx.com>2019-09-05 15:27:32 +0300
committerMax Romanov <max.romanov@nginx.com>2019-09-05 15:27:32 +0300
commit2b8cab1e2478547398ad9c2fe68e025c180cac54 (patch)
treed317fcf9ee52f0f8967116f531784ae533b0ae5a /src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java
parent3e23afb0d205e503f6cc7d852e34d07da9a5b7f7 (diff)
downloadunit-2b8cab1e2478547398ad9c2fe68e025c180cac54.tar.gz
unit-2b8cab1e2478547398ad9c2fe68e025c180cac54.tar.bz2
Java: introducing websocket support.
Diffstat (limited to 'src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java')
-rw-r--r--src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java156
1 files changed, 156 insertions, 0 deletions
diff --git a/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java b/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java
new file mode 100644
index 00000000..be679a35
--- /dev/null
+++ b/src/java/nginx/unit/websocket/pojo/PojoEndpointBase.java
@@ -0,0 +1,156 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package nginx.unit.websocket.pojo;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Map;
+import java.util.Set;
+
+import javax.websocket.CloseReason;
+import javax.websocket.Endpoint;
+import javax.websocket.EndpointConfig;
+import javax.websocket.MessageHandler;
+import javax.websocket.Session;
+
+import org.apache.juli.logging.Log;
+import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.util.ExceptionUtils;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * Base implementation (client and server have different concrete
+ * implementations) of the wrapper that converts a POJO instance into a
+ * WebSocket endpoint instance.
+ */
+public abstract class PojoEndpointBase extends Endpoint {
+
+ private final Log log = LogFactory.getLog(PojoEndpointBase.class); // must not be static
+ private static final StringManager sm = StringManager.getManager(PojoEndpointBase.class);
+
+ private Object pojo;
+ private Map<String,String> pathParameters;
+ private PojoMethodMapping methodMapping;
+
+
+ protected final void doOnOpen(Session session, EndpointConfig config) {
+ PojoMethodMapping methodMapping = getMethodMapping();
+ Object pojo = getPojo();
+ Map<String,String> pathParameters = getPathParameters();
+
+ // Add message handlers before calling onOpen since that may trigger a
+ // message which in turn could trigger a response and/or close the
+ // session
+ for (MessageHandler mh : methodMapping.getMessageHandlers(pojo,
+ pathParameters, session, config)) {
+ session.addMessageHandler(mh);
+ }
+
+ if (methodMapping.getOnOpen() != null) {
+ try {
+ methodMapping.getOnOpen().invoke(pojo,
+ methodMapping.getOnOpenArgs(
+ pathParameters, session, config));
+
+ } catch (IllegalAccessException e) {
+ // Reflection related problems
+ log.error(sm.getString(
+ "pojoEndpointBase.onOpenFail",
+ pojo.getClass().getName()), e);
+ handleOnOpenOrCloseError(session, e);
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ handleOnOpenOrCloseError(session, cause);
+ } catch (Throwable t) {
+ handleOnOpenOrCloseError(session, t);
+ }
+ }
+ }
+
+
+ private void handleOnOpenOrCloseError(Session session, Throwable t) {
+ // If really fatal - re-throw
+ ExceptionUtils.handleThrowable(t);
+
+ // Trigger the error handler and close the session
+ onError(session, t);
+ try {
+ session.close();
+ } catch (IOException ioe) {
+ log.warn(sm.getString("pojoEndpointBase.closeSessionFail"), ioe);
+ }
+ }
+
+ @Override
+ public final void onClose(Session session, CloseReason closeReason) {
+
+ if (methodMapping.getOnClose() != null) {
+ try {
+ methodMapping.getOnClose().invoke(pojo,
+ methodMapping.getOnCloseArgs(pathParameters, session, closeReason));
+ } catch (Throwable t) {
+ log.error(sm.getString("pojoEndpointBase.onCloseFail",
+ pojo.getClass().getName()), t);
+ handleOnOpenOrCloseError(session, t);
+ }
+ }
+
+ // Trigger the destroy method for any associated decoders
+ Set<MessageHandler> messageHandlers = session.getMessageHandlers();
+ for (MessageHandler messageHandler : messageHandlers) {
+ if (messageHandler instanceof PojoMessageHandlerWholeBase<?>) {
+ ((PojoMessageHandlerWholeBase<?>) messageHandler).onClose();
+ }
+ }
+ }
+
+
+ @Override
+ public final void onError(Session session, Throwable throwable) {
+
+ if (methodMapping.getOnError() == null) {
+ log.error(sm.getString("pojoEndpointBase.onError",
+ pojo.getClass().getName()), throwable);
+ } else {
+ try {
+ methodMapping.getOnError().invoke(
+ pojo,
+ methodMapping.getOnErrorArgs(pathParameters, session,
+ throwable));
+ } catch (Throwable t) {
+ ExceptionUtils.handleThrowable(t);
+ log.error(sm.getString("pojoEndpointBase.onErrorFail",
+ pojo.getClass().getName()), t);
+ }
+ }
+ }
+
+ protected Object getPojo() { return pojo; }
+ protected void setPojo(Object pojo) { this.pojo = pojo; }
+
+
+ protected Map<String,String> getPathParameters() { return pathParameters; }
+ protected void setPathParameters(Map<String,String> pathParameters) {
+ this.pathParameters = pathParameters;
+ }
+
+
+ protected PojoMethodMapping getMethodMapping() { return methodMapping; }
+ protected void setMethodMapping(PojoMethodMapping methodMapping) {
+ this.methodMapping = methodMapping;
+ }
+}