Author: markt Date: Sun Dec 2 21:01:52 2012 New Revision: 1416258 URL: http://svn.apache.org/viewvc?rev=1416258&view=rev Log: WebSocket 1.0 implementation part 7 of many Complete path parameter passing for POJOs
Added: tomcat/trunk/java/org/apache/tomcat/websocket/PathParam.java (with props) Modified: tomcat/trunk/java/javax/websocket/WebSocketPathParam.java tomcat/trunk/java/org/apache/tomcat/websocket/PojoMethodMapping.java tomcat/trunk/java/org/apache/tomcat/websocket/UriTemplate.java tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java tomcat/trunk/webapps/examples/websocket/echo.html Modified: tomcat/trunk/java/javax/websocket/WebSocketPathParam.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/javax/websocket/WebSocketPathParam.java?rev=1416258&r1=1416257&r2=1416258&view=diff ============================================================================== --- tomcat/trunk/java/javax/websocket/WebSocketPathParam.java (original) +++ tomcat/trunk/java/javax/websocket/WebSocketPathParam.java Sun Dec 2 21:01:52 2012 @@ -22,7 +22,7 @@ import java.lang.annotation.RetentionPol import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) +@Target(ElementType.PARAMETER) public @interface WebSocketPathParam { public String value(); } Added: tomcat/trunk/java/org/apache/tomcat/websocket/PathParam.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/PathParam.java?rev=1416258&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/PathParam.java (added) +++ tomcat/trunk/java/org/apache/tomcat/websocket/PathParam.java Sun Dec 2 21:01:52 2012 @@ -0,0 +1,35 @@ +/* + * 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 org.apache.tomcat.websocket; + +public class PathParam { + private final Class<?> type; + private final String name; + + public PathParam(Class<?> type, String name) { + this.type = type; + this.name = name; + } + + public Class<?> getType() { + return type; + } + + public String getName() { + return name; + } +} Propchange: tomcat/trunk/java/org/apache/tomcat/websocket/PathParam.java ------------------------------------------------------------------------------ svn:eol-style = native Modified: tomcat/trunk/java/org/apache/tomcat/websocket/PojoMethodMapping.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/PojoMethodMapping.java?rev=1416258&r1=1416257&r2=1416258&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/PojoMethodMapping.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/PojoMethodMapping.java Sun Dec 2 21:01:52 2012 @@ -16,17 +16,24 @@ */ package org.apache.tomcat.websocket; +import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.Map; +import javax.websocket.Session; import javax.websocket.WebSocketClose; import javax.websocket.WebSocketError; import javax.websocket.WebSocketOpen; +import javax.websocket.WebSocketPathParam; public class PojoMethodMapping { private final Method onOpen; private final Method onClose; private final Method onError; + private final PathParam[] onOpenParams; + private final PathParam[] onCloseParams; + private final PathParam[] onErrorParams; private final UriTemplate template; @@ -54,36 +61,139 @@ public class PojoMethodMapping { if (path.length() > mappingPath.length()) { template = - new UriTemplate(path.substring(mappingPath.length() - 1)); + new UriTemplate(path.substring(mappingPath.length() - 2)); } else { template = null; } + + onOpenParams = getPathParams(onOpen, false); + onCloseParams = getPathParams(onClose, false); + onErrorParams = getPathParams(onError, true); } + public Method getOnOpen() { return onOpen; } - public Object[] getOnOpenArgs(String pathInfo) { - // TODO Auto-generated method stub - return null; + + public Object[] getOnOpenArgs(String pathInfo, Session session) { + return buildArgs(onOpenParams, template, pathInfo, session, null); } + public Method getOnClose() { return onClose; } - public Object[] getOnCloseArgs(String pathInfo) { - // TODO Auto-generated method stub - return null; + + public Object[] getOnCloseArgs(String pathInfo, Session session) { + return buildArgs(onCloseParams, template, pathInfo, session, null); } public Method getOnError() { return onError; } - public Object[] getOnErrorArgs(String pathInfo) { - // TODO Auto-generated method stub - return null; + + public Object[] getOnErrorArgs(String pathInfo, Session session, + Throwable throwable) { + return buildArgs(onErrorParams, template, pathInfo, session, throwable); + } + + + private static PathParam[] getPathParams(Method m, boolean isError) { + if (m == null) { + return new PathParam[0]; + } + + boolean foundError = !isError; + Class<?>[] types = m.getParameterTypes(); + Annotation[][] paramsAnnotations = m.getParameterAnnotations(); + PathParam[] result = new PathParam[types.length]; + + for (int i = 0; i < types.length; i++) { + Class<?> type = types[i]; + if (type.equals(Session.class)) { + result[i] = new PathParam(type, null); + } else if (type.equals(Throwable.class)) { + foundError = true; + result[i] = new PathParam(type, null); + } else { + Annotation[] paramAnnotations = paramsAnnotations[i]; + for (Annotation paramAnnotation : paramAnnotations) { + if (paramAnnotation.annotationType().equals( + WebSocketPathParam.class)) { + result[i] = new PathParam(type, + ((WebSocketPathParam) paramAnnotation).value()); + break; + } + } + // Parameters without annotations are not permitted + if (result[i] == null) { + throw new IllegalArgumentException(); + } + } + } + + if (!foundError) { + throw new IllegalArgumentException(); + } + + return result; + } + + + private static Object[] buildArgs(PathParam[] pathParams, + UriTemplate template, String pathInfo, Session session, + Throwable throwable) { + Object[] result = new Object[pathParams.length]; + Map<String, String> pathValues = template.match(pathInfo); + + for (int i = 0; i < pathParams.length; i++) { + Class<?> type = pathParams[i].getType(); + if (type.equals(Session.class)) { + result[i] = session; + } else if (type.equals(Throwable.class)) { + result[i] = throwable; + } else { + String name = pathParams[i].getName(); + String value = pathValues.get(name); + if (value == null) { + result[i] = null; + } else { + result[i] = coerceToType(type, value); + } + } + } + return result; + } + + + private static Object coerceToType(Class<?> type, String value) { + + if (type.equals(String.class)) { + return value; + } else if (type.equals(boolean.class) || type.equals(Boolean.class)) { + return Boolean.valueOf(value); + } else if (type.equals(byte.class) || type.equals(Byte.class)) { + return Byte.valueOf(value); + } else if (value.length() == 1 && + type.equals(char.class) || type.equals(Character.class)) { + return Character.valueOf(value.charAt(0)); + } else if (type.equals(double.class) || type.equals(Double.class)) { + return Double.valueOf(value); + } else if (type.equals(float.class) || type.equals(Float.class)) { + return Float.valueOf(value); + } else if (type.equals(int.class) || type.equals(Integer.class)) { + return Integer.valueOf(value); + } else if (type.equals(long.class) || type.equals(Long.class)) { + return Long.valueOf(value); + } else if (type.equals(short.class) || type.equals(Short.class)) { + return Short.valueOf(value); + } else { + // TODO + throw new IllegalArgumentException(); + } } } Modified: tomcat/trunk/java/org/apache/tomcat/websocket/UriTemplate.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/UriTemplate.java?rev=1416258&r1=1416257&r2=1416258&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/UriTemplate.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/UriTemplate.java Sun Dec 2 21:01:52 2012 @@ -57,6 +57,11 @@ public class UriTemplate { } + public boolean contains(String name) { + return names.contains(name); + } + + /** * Extract the path parameters from the provided pathInfo based on the * template with which this UriTemplate was constructed. Modified: tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java?rev=1416258&r1=1416257&r2=1416258&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java (original) +++ tomcat/trunk/java/org/apache/tomcat/websocket/WsEndpointPojo.java Sun Dec 2 21:01:52 2012 @@ -17,7 +17,6 @@ package org.apache.tomcat.websocket; import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import javax.websocket.CloseReason; import javax.websocket.DefaultServerConfiguration; @@ -29,12 +28,9 @@ public class WsEndpointPojo extends Endp private final Object pojo; private final EndpointConfiguration config; - private final Method onOpen; - private final Object[] onOpenArgs; - private final Method onClose; - private final Object[] onCloseArgs; - private final Method onError; - private final Object[] onErrorArgs; + private final String pathInfo; + private final PojoMethodMapping methodMapping; + private Session session = null; public WsEndpointPojo(Class<?> clazzPojo, PojoMethodMapping methodMapping, String ServletPath, String pathInfo) @@ -48,26 +44,8 @@ public class WsEndpointPojo extends Endp } }; - onOpen = methodMapping.getOnOpen(); - if (onOpen == null) { - onOpenArgs = null; - } else { - onOpenArgs = methodMapping.getOnOpenArgs(pathInfo); - } - - onClose = methodMapping.getOnClose(); - if (onClose == null) { - onCloseArgs = null; - } else { - onCloseArgs = methodMapping.getOnCloseArgs(pathInfo); - } - - onError = methodMapping.getOnError(); - if (onError == null) { - onErrorArgs = null; - } else { - onErrorArgs = methodMapping.getOnErrorArgs(pathInfo); - } + this.methodMapping = methodMapping; + this.pathInfo = pathInfo; } @Override @@ -77,10 +55,12 @@ public class WsEndpointPojo extends Endp @Override public void onOpen(Session session) { - // TODO Insert the session into the method args - if (onOpen != null) { + this.session = session; + + if (methodMapping.getOnOpen() != null) { try { - onOpen.invoke(pojo, onOpenArgs); + methodMapping.getOnOpen().invoke( + pojo, methodMapping.getOnOpenArgs(pathInfo, session)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block @@ -91,9 +71,10 @@ public class WsEndpointPojo extends Endp @Override public void onClose(CloseReason closeReason) { - if (onClose != null) { + if (methodMapping.getOnClose() != null) { try { - onClose.invoke(pojo, onCloseArgs); + methodMapping.getOnClose().invoke( + pojo, methodMapping.getOnCloseArgs(pathInfo, session)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block @@ -104,10 +85,11 @@ public class WsEndpointPojo extends Endp @Override public void onError(Throwable throwable) { - if (onError != null) { + if (methodMapping.getOnError() != null) { try { - // TODO Insert throwable - onError.invoke(pojo, onErrorArgs); + methodMapping.getOnError().invoke(pojo, + methodMapping.getOnErrorArgs( + pathInfo, session, throwable)); } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { // TODO Auto-generated catch block Modified: tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java?rev=1416258&r1=1416257&r2=1416258&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java (original) +++ tomcat/trunk/webapps/examples/WEB-INF/classes/websocket/echo/EchoAnnotation.java Sun Dec 2 21:01:52 2012 @@ -18,12 +18,13 @@ package websocket.echo; import javax.websocket.WebSocketEndpoint; import javax.websocket.WebSocketOpen; +import javax.websocket.WebSocketPathParam; -@WebSocketEndpoint("/websocket/echoAnnotation") +@WebSocketEndpoint("/websocket/echoAnnotation/{test}") public class EchoAnnotation { @WebSocketOpen - public void printOpen() { - System.out.println("EchoAnnotation.printOpen()"); + public void printOpen(@WebSocketPathParam("test") String test) { + System.out.println("EchoAnnotation.printOpen() with [" + test + "]"); } } Modified: tomcat/trunk/webapps/examples/websocket/echo.html URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/examples/websocket/echo.html?rev=1416258&r1=1416257&r2=1416258&view=diff ============================================================================== --- tomcat/trunk/webapps/examples/websocket/echo.html (original) +++ tomcat/trunk/webapps/examples/websocket/echo.html Sun Dec 2 21:01:52 2012 @@ -141,7 +141,7 @@ <input id="radio3" type="radio" name="group1" value="/examples/websocket/echoProgrammatic" onclick="updateTarget(this.value);"> <label for="radio2">new programmatic</label> <!-- echo example using new annotation API on the server side --> - <input id="radio3" type="radio" name="group1" value="/examples/websocket/echoAnnotation" + <input id="radio4" type="radio" name="group1" value="/examples/websocket/echoAnnotation/HelloWorld" onclick="updateTarget(this.value);"> <label for="radio2">new annotation</label> </div> <div> --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org