393473 - Add support for JSR-356 (javax.websocket) draft
+ Refactoring EventDriver to be more pluggable (for jsr endpoints)
This commit is contained in:
parent
529820d411
commit
4fb1bc80da
|
@ -0,0 +1,33 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.encoders;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.websocket.EncodeException;
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
public class DefaultBinaryEncoder implements Encoder.Binary<ByteBuffer>
|
||||
{
|
||||
@Override
|
||||
public ByteBuffer encode(ByteBuffer message) throws EncodeException
|
||||
{
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.encoders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.websocket.EncodeException;
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
|
||||
public class DefaultBinaryStreamEncoder implements Encoder.BinaryStream<ByteBuffer>
|
||||
{
|
||||
@Override
|
||||
public void encode(ByteBuffer message, OutputStream out) throws EncodeException, IOException
|
||||
{
|
||||
BufferUtil.writeTo(message,out);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.encoders;
|
||||
|
||||
import javax.websocket.EncodeException;
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
public class DefaultTextEncoder implements Encoder.Text<String>
|
||||
{
|
||||
@Override
|
||||
public String encode(String message) throws EncodeException
|
||||
{
|
||||
return message;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.encoders;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
import javax.websocket.EncodeException;
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
public class DefaultTextStreamEncoder implements Encoder.TextStream<String>
|
||||
{
|
||||
@Override
|
||||
public void encode(String message, Writer writer) throws EncodeException, IOException
|
||||
{
|
||||
writer.append(message);
|
||||
writer.flush();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.AbstractMethodAnnotationScanner;
|
||||
|
||||
/**
|
||||
* Cache for discovered javax.websocket {@link WebSocketEndpoint @WebSocketEndpoint} annotated websockets
|
||||
*/
|
||||
public class JavaxPojoAnnotationCache extends AbstractMethodAnnotationScanner<JavaxPojoMetadata>
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JavaxPojoAnnotationCache.class);
|
||||
public static final JavaxPojoAnnotationCache INSTANCE = new JavaxPojoAnnotationCache();
|
||||
|
||||
public synchronized static JavaxPojoMetadata discover(Class<?> websocket)
|
||||
{
|
||||
// TODO: move to server side deployer
|
||||
// WebSocketEndpoint anno = websocket.getAnnotation(WebSocketEndpoint.class);
|
||||
// if (anno == null)
|
||||
// {
|
||||
// return null;
|
||||
// }
|
||||
|
||||
JavaxPojoMetadata metadata = INSTANCE.cache.get(websocket);
|
||||
if (metadata == null)
|
||||
{
|
||||
metadata = new JavaxPojoMetadata();
|
||||
INSTANCE.scanMethodAnnotations(metadata,websocket);
|
||||
INSTANCE.cache.put(websocket,metadata);
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public static JavaxPojoMetadata discover(Object websocket)
|
||||
{
|
||||
return discover(websocket.getClass());
|
||||
}
|
||||
|
||||
private ConcurrentHashMap<Class<?>, JavaxPojoMetadata> cache;
|
||||
|
||||
public JavaxPojoAnnotationCache()
|
||||
{
|
||||
cache = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodAnnotation(JavaxPojoMetadata metadata, Class<?> pojo, Method method, Annotation annotation)
|
||||
{
|
||||
LOG.debug("onMethodAnnotation({}, {}, {}, {})",metadata,pojo,method,annotation);
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
/**
|
||||
* Represents the metadata associated with Annotation discovery of a specific class.
|
||||
*/
|
||||
public class JavaxPojoMetadata
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
||||
public class JsrAnnotatedEventDriver implements EventDriver
|
||||
{
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBinaryMessage(byte[] data)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CloseInfo close)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrame(Frame frame)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextMessage(String message)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverImpl;
|
||||
|
||||
public class JsrAnnotatedImpl implements EventDriverImpl
|
||||
{
|
||||
|
||||
@Override
|
||||
public EventDriver create(Object websocket, WebSocketPolicy policy)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeRule()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Object websocket)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,125 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
||||
public class JsrEndpointEventDriver implements EventDriver
|
||||
{
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBinaryMessage(byte[] data)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CloseInfo close)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable t)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFrame(Frame frame)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextMessage(String message)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverImpl;
|
||||
|
||||
public class JsrEndpointImpl implements EventDriverImpl
|
||||
{
|
||||
|
||||
@Override
|
||||
public EventDriver create(Object websocket, WebSocketPolicy policy)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeRule()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Object websocket)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -236,6 +236,11 @@ public class WebSocketClient extends ContainerLifeCycle
|
|||
return cookieStore;
|
||||
}
|
||||
|
||||
public EventDriverFactory getEventDriverFactory()
|
||||
{
|
||||
return eventDriverFactory;
|
||||
}
|
||||
|
||||
public Executor getExecutor()
|
||||
{
|
||||
return executor;
|
||||
|
|
|
@ -0,0 +1,187 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.CloseException;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
|
||||
/**
|
||||
* EventDriver is the main interface between the User's WebSocket POJO and the internal jetty implementation of WebSocket.
|
||||
*/
|
||||
public abstract class AbstractEventDriver implements IncomingFrames, EventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(EventDriver.class);
|
||||
protected final WebSocketPolicy policy;
|
||||
protected final Object websocket;
|
||||
protected WebSocketSession session;
|
||||
|
||||
public AbstractEventDriver(WebSocketPolicy policy, Object websocket)
|
||||
{
|
||||
this.policy = policy;
|
||||
this.websocket = websocket;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void incomingError(WebSocketException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("incoming(WebSocketException)",e);
|
||||
}
|
||||
|
||||
if (e instanceof CloseException)
|
||||
{
|
||||
CloseException close = (CloseException)e;
|
||||
terminateConnection(close.getStatusCode(),close.getMessage());
|
||||
}
|
||||
|
||||
onError(e);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("{}.onFrame({})",websocket.getClass().getSimpleName(),frame);
|
||||
}
|
||||
|
||||
onFrame(frame);
|
||||
|
||||
try
|
||||
{
|
||||
switch (frame.getType().getOpCode())
|
||||
{
|
||||
case OpCode.CLOSE:
|
||||
{
|
||||
boolean validate = true;
|
||||
CloseInfo close = new CloseInfo(frame,validate);
|
||||
|
||||
// notify user websocket pojo
|
||||
onClose(close);
|
||||
|
||||
// process handshake
|
||||
if (session.getConnection().getIOState().onCloseHandshake(true))
|
||||
{
|
||||
// handshake resolved, disconnect.
|
||||
session.getConnection().disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
// respond
|
||||
session.close(close.getStatusCode(),close.getReason());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case OpCode.PING:
|
||||
{
|
||||
byte pongBuf[] = new byte[0];
|
||||
if (frame.hasPayload())
|
||||
{
|
||||
pongBuf = BufferUtil.toArray(frame.getPayload());
|
||||
}
|
||||
session.getRemote().sendPong(ByteBuffer.wrap(pongBuf));
|
||||
break;
|
||||
}
|
||||
case OpCode.BINARY:
|
||||
{
|
||||
onBinaryFrame(frame.getPayload(),frame.isFin());
|
||||
return;
|
||||
}
|
||||
case OpCode.TEXT:
|
||||
{
|
||||
onTextFrame(frame.getPayload(),frame.isFin());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NotUtf8Exception e)
|
||||
{
|
||||
terminateConnection(StatusCode.BAD_PAYLOAD,e.getMessage());
|
||||
}
|
||||
catch (CloseException e)
|
||||
{
|
||||
terminateConnection(e.getStatusCode(),e.getMessage());
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
unhandled(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
LOG.debug("openSession({})",session);
|
||||
this.session = session;
|
||||
this.onConnect();
|
||||
}
|
||||
|
||||
protected void terminateConnection(int statusCode, String rawreason)
|
||||
{
|
||||
String reason = rawreason;
|
||||
reason = StringUtil.truncate(reason,(WebSocketFrame.MAX_CONTROL_PAYLOAD - 2));
|
||||
LOG.debug("terminateConnection({},{})",statusCode,rawreason);
|
||||
session.close(statusCode,reason);
|
||||
}
|
||||
|
||||
private void unhandled(Throwable t)
|
||||
{
|
||||
LOG.warn("Unhandled Error (closing connection)",t);
|
||||
|
||||
// Unhandled Error, close the connection.
|
||||
switch (policy.getBehavior())
|
||||
{
|
||||
case SERVER:
|
||||
terminateConnection(StatusCode.SERVER_ERROR,t.getClass().getSimpleName());
|
||||
break;
|
||||
case CLIENT:
|
||||
terminateConnection(StatusCode.POLICY_VIOLATION,t.getClass().getSimpleName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,201 +1,35 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.Utf8Appendable.NotUtf8Exception;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.CloseException;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.common.OpCode;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
|
||||
/**
|
||||
* EventDriver is the main interface between the User's WebSocket POJO and the internal jetty implementation of WebSocket.
|
||||
*/
|
||||
public abstract class EventDriver implements IncomingFrames
|
||||
public interface EventDriver extends IncomingFrames
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(EventDriver.class);
|
||||
protected final WebSocketPolicy policy;
|
||||
protected final Object websocket;
|
||||
protected WebSocketSession session;
|
||||
public WebSocketPolicy getPolicy();
|
||||
|
||||
public EventDriver(WebSocketPolicy policy, Object websocket)
|
||||
{
|
||||
this.policy = policy;
|
||||
this.websocket = websocket;
|
||||
}
|
||||
public WebSocketSession getSession();
|
||||
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return policy;
|
||||
}
|
||||
public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
return session;
|
||||
}
|
||||
public void onBinaryMessage(byte[] data);
|
||||
|
||||
@Override
|
||||
public final void incomingError(WebSocketException e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("incoming(WebSocketException)",e);
|
||||
}
|
||||
public void onClose(CloseInfo close);
|
||||
|
||||
if (e instanceof CloseException)
|
||||
{
|
||||
CloseException close = (CloseException)e;
|
||||
terminateConnection(close.getStatusCode(),close.getMessage());
|
||||
}
|
||||
public void onConnect();
|
||||
|
||||
onError(e);
|
||||
}
|
||||
public void onError(Throwable t);
|
||||
|
||||
@Override
|
||||
public void incomingFrame(Frame frame)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
LOG.debug("{}.onFrame({})",websocket.getClass().getSimpleName(),frame);
|
||||
}
|
||||
public void onFrame(Frame frame);
|
||||
|
||||
onFrame(frame);
|
||||
public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||
|
||||
try
|
||||
{
|
||||
switch (frame.getType().getOpCode())
|
||||
{
|
||||
case OpCode.CLOSE:
|
||||
{
|
||||
boolean validate = true;
|
||||
CloseInfo close = new CloseInfo(frame,validate);
|
||||
public void onTextMessage(String message);
|
||||
|
||||
// notify user websocket pojo
|
||||
onClose(close);
|
||||
|
||||
// process handshake
|
||||
if (session.getConnection().getIOState().onCloseHandshake(true))
|
||||
{
|
||||
// handshake resolved, disconnect.
|
||||
session.getConnection().disconnect();
|
||||
}
|
||||
else
|
||||
{
|
||||
// respond
|
||||
session.close(close.getStatusCode(),close.getReason());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
case OpCode.PING:
|
||||
{
|
||||
byte pongBuf[] = new byte[0];
|
||||
if (frame.hasPayload())
|
||||
{
|
||||
pongBuf = BufferUtil.toArray(frame.getPayload());
|
||||
}
|
||||
session.getRemote().sendPong(ByteBuffer.wrap(pongBuf));
|
||||
break;
|
||||
}
|
||||
case OpCode.BINARY:
|
||||
{
|
||||
onBinaryFrame(frame.getPayload(),frame.isFin());
|
||||
return;
|
||||
}
|
||||
case OpCode.TEXT:
|
||||
{
|
||||
onTextFrame(frame.getPayload(),frame.isFin());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (NotUtf8Exception e)
|
||||
{
|
||||
terminateConnection(StatusCode.BAD_PAYLOAD,e.getMessage());
|
||||
}
|
||||
catch (CloseException e)
|
||||
{
|
||||
terminateConnection(e.getStatusCode(),e.getMessage());
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
unhandled(t);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||
|
||||
public abstract void onBinaryMessage(byte[] data);
|
||||
|
||||
public abstract void onClose(CloseInfo close);
|
||||
|
||||
public abstract void onConnect();
|
||||
|
||||
public abstract void onError(Throwable t);
|
||||
|
||||
public abstract void onFrame(Frame frame);
|
||||
|
||||
public abstract void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||
|
||||
public abstract void onTextMessage(String message);
|
||||
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
LOG.debug("openSession({})",session);
|
||||
this.session = session;
|
||||
this.onConnect();
|
||||
}
|
||||
|
||||
protected void terminateConnection(int statusCode, String rawreason)
|
||||
{
|
||||
String reason = rawreason;
|
||||
reason = StringUtil.truncate(reason,(WebSocketFrame.MAX_CONTROL_PAYLOAD - 2));
|
||||
LOG.debug("terminateConnection({},{})",statusCode,rawreason);
|
||||
session.close(statusCode,reason);
|
||||
}
|
||||
|
||||
private void unhandled(Throwable t)
|
||||
{
|
||||
LOG.warn("Unhandled Error (closing connection)",t);
|
||||
|
||||
// Unhandled Error, close the connection.
|
||||
switch (policy.getBehavior())
|
||||
{
|
||||
case SERVER:
|
||||
terminateConnection(StatusCode.SERVER_ERROR,t.getClass().getSimpleName());
|
||||
break;
|
||||
case CLIENT:
|
||||
terminateConnection(StatusCode.POLICY_VIOLATION,t.getClass().getSimpleName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
public void openSession(WebSocketSession session);
|
||||
}
|
|
@ -18,340 +18,75 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
||||
/**
|
||||
* Create EventDriver implementations.
|
||||
*/
|
||||
public class EventDriverFactory
|
||||
{
|
||||
/**
|
||||
* Parameter list for @OnWebSocketMessage (Binary mode)
|
||||
*/
|
||||
private static final ParamList validBinaryParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketConnect
|
||||
*/
|
||||
private static final ParamList validConnectParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketClose
|
||||
*/
|
||||
private static final ParamList validCloseParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketError
|
||||
*/
|
||||
private static final ParamList validErrorParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketFrame
|
||||
*/
|
||||
private static final ParamList validFrameParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketMessage (Text mode)
|
||||
*/
|
||||
private static final ParamList validTextParams;
|
||||
|
||||
static
|
||||
{
|
||||
validConnectParams = new ParamList();
|
||||
validConnectParams.addParams(Session.class);
|
||||
|
||||
validCloseParams = new ParamList();
|
||||
validCloseParams.addParams(int.class,String.class);
|
||||
validCloseParams.addParams(Session.class,int.class,String.class);
|
||||
|
||||
validErrorParams = new ParamList();
|
||||
validErrorParams.addParams(Throwable.class);
|
||||
validErrorParams.addParams(Session.class,Throwable.class);
|
||||
|
||||
validTextParams = new ParamList();
|
||||
validTextParams.addParams(String.class);
|
||||
validTextParams.addParams(Session.class,String.class);
|
||||
validTextParams.addParams(Reader.class);
|
||||
validTextParams.addParams(Session.class,Reader.class);
|
||||
|
||||
validBinaryParams = new ParamList();
|
||||
validBinaryParams.addParams(byte[].class,int.class,int.class);
|
||||
validBinaryParams.addParams(Session.class,byte[].class,int.class,int.class);
|
||||
validBinaryParams.addParams(InputStream.class);
|
||||
validBinaryParams.addParams(Session.class,InputStream.class);
|
||||
|
||||
validFrameParams = new ParamList();
|
||||
validFrameParams.addParams(Frame.class);
|
||||
validFrameParams.addParams(Session.class,Frame.class);
|
||||
}
|
||||
|
||||
private ConcurrentHashMap<Class<?>, EventMethods> cache;
|
||||
private static final Logger LOG = Log.getLogger(EventDriverFactory.class);
|
||||
private final WebSocketPolicy policy;
|
||||
private final List<EventDriverImpl> implementations;
|
||||
|
||||
public EventDriverFactory(WebSocketPolicy policy)
|
||||
{
|
||||
this.policy = policy;
|
||||
this.cache = new ConcurrentHashMap<>();
|
||||
this.implementations = new ArrayList<>();
|
||||
|
||||
addImplementation(new JettyListenerImpl());
|
||||
addImplementation(new JettyAnnotatedImpl());
|
||||
}
|
||||
|
||||
private void assertIsPublicNonStatic(Method method)
|
||||
public void addImplementation(EventDriverImpl impl)
|
||||
{
|
||||
int mods = method.getModifiers();
|
||||
if (!Modifier.isPublic(mods))
|
||||
if (implementations.contains(impl))
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid declaration of ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("Method modifier must be public");
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
LOG.warn("Ignoring attempt to add duplicate EventDriverImpl: " + impl);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(mods))
|
||||
implementations.add(impl);
|
||||
}
|
||||
|
||||
public List<EventDriverImpl> getImplementations()
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid declaration of ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("Method modifier may not be static");
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
return implementations;
|
||||
}
|
||||
|
||||
private void assertIsReturn(Method method, Class<?> type)
|
||||
public boolean removeImplementation(EventDriverImpl impl)
|
||||
{
|
||||
if (!type.equals(method.getReturnType()))
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid declaration of ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("Return type must be ").append(type);
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
return this.implementations.remove(impl);
|
||||
}
|
||||
|
||||
private void assertUnset(EventMethod event, Class<? extends Annotation> annoClass, Method method)
|
||||
{
|
||||
if (event != null)
|
||||
{
|
||||
// Attempt to add duplicate frame type (a no-no)
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Duplicate @").append(annoClass.getSimpleName()).append(" declaration on ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("@").append(annoClass.getSimpleName()).append(" previously declared at ");
|
||||
err.append(event.getMethod());
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void assertValidSignature(Method method, Class<? extends Annotation> annoClass, ParamList validParams)
|
||||
{
|
||||
assertIsPublicNonStatic(method);
|
||||
assertIsReturn(method,Void.TYPE);
|
||||
|
||||
boolean valid = false;
|
||||
|
||||
// validate parameters
|
||||
Class<?> actual[] = method.getParameterTypes();
|
||||
for (Class<?>[] params : validParams)
|
||||
{
|
||||
if (isSameParameters(actual,params))
|
||||
{
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
throw InvalidSignatureException.build(method,annoClass,validParams);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the basic discovery mechanism for WebSocket events from the provided pojo.
|
||||
*
|
||||
* @param pojo
|
||||
* the pojo to scan
|
||||
* @return the discovered event methods
|
||||
* @throws InvalidWebSocketException
|
||||
*/
|
||||
private EventMethods discoverMethods(Class<?> pojo) throws InvalidWebSocketException
|
||||
{
|
||||
WebSocket anno = pojo.getAnnotation(WebSocket.class);
|
||||
if (anno == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return scanAnnotatedMethods(pojo);
|
||||
}
|
||||
|
||||
public EventMethods getMethods(Class<?> pojo) throws InvalidWebSocketException
|
||||
{
|
||||
if (pojo == null)
|
||||
{
|
||||
throw new InvalidWebSocketException("Cannot get methods for null class");
|
||||
}
|
||||
if (cache.containsKey(pojo))
|
||||
{
|
||||
return cache.get(pojo);
|
||||
}
|
||||
EventMethods methods = discoverMethods(pojo);
|
||||
if (methods == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
cache.put(pojo,methods);
|
||||
return methods;
|
||||
}
|
||||
|
||||
private boolean isSameParameters(Class<?>[] actual, Class<?>[] params)
|
||||
{
|
||||
if (actual.length != params.length)
|
||||
{
|
||||
// skip
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = params.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (!actual[i].equals(params[i]))
|
||||
{
|
||||
return false; // not valid
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean isSignatureMatch(Method method, ParamList validParams)
|
||||
{
|
||||
assertIsPublicNonStatic(method);
|
||||
assertIsReturn(method,Void.TYPE);
|
||||
|
||||
// validate parameters
|
||||
Class<?> actual[] = method.getParameterTypes();
|
||||
for (Class<?>[] params : validParams)
|
||||
{
|
||||
if (isSameParameters(actual,params))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private EventMethods scanAnnotatedMethods(Class<?> pojo)
|
||||
{
|
||||
Class<?> clazz = pojo;
|
||||
EventMethods events = new EventMethods(pojo);
|
||||
|
||||
clazz = pojo;
|
||||
while (clazz.getAnnotation(WebSocket.class) != null)
|
||||
{
|
||||
for (Method method : clazz.getDeclaredMethods())
|
||||
{
|
||||
if (method.getAnnotation(OnWebSocketConnect.class) != null)
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketConnect.class,validConnectParams);
|
||||
assertUnset(events.onConnect,OnWebSocketConnect.class,method);
|
||||
events.onConnect = new EventMethod(pojo,method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getAnnotation(OnWebSocketMessage.class) != null)
|
||||
{
|
||||
if (isSignatureMatch(method,validTextParams))
|
||||
{
|
||||
// Text mode
|
||||
// TODO
|
||||
|
||||
assertUnset(events.onText,OnWebSocketMessage.class,method);
|
||||
events.onText = new EventMethod(pojo,method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (isSignatureMatch(method,validBinaryParams))
|
||||
{
|
||||
// Binary Mode
|
||||
// TODO
|
||||
assertUnset(events.onBinary,OnWebSocketMessage.class,method);
|
||||
events.onBinary = new EventMethod(pojo,method);
|
||||
continue;
|
||||
}
|
||||
|
||||
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,validTextParams,validBinaryParams);
|
||||
}
|
||||
|
||||
if (method.getAnnotation(OnWebSocketClose.class) != null)
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketClose.class,validCloseParams);
|
||||
assertUnset(events.onClose,OnWebSocketClose.class,method);
|
||||
events.onClose = new EventMethod(pojo,method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getAnnotation(OnWebSocketError.class) != null)
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketError.class,validErrorParams);
|
||||
assertUnset(events.onError,OnWebSocketError.class,method);
|
||||
events.onError = new EventMethod(pojo,method);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.getAnnotation(OnWebSocketFrame.class) != null)
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketFrame.class,validFrameParams);
|
||||
assertUnset(events.onFrame,OnWebSocketFrame.class,method);
|
||||
events.onFrame = new EventMethod(pojo,method);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Not a tagged method we are interested in, ignore
|
||||
}
|
||||
|
||||
// try superclass now
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
|
||||
return events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("EventMethodsCache [cache.count=%d]",cache.size());
|
||||
StringBuilder msg = new StringBuilder();
|
||||
msg.append(this.getClass().getSimpleName());
|
||||
msg.append("[implementations=[");
|
||||
boolean delim = false;
|
||||
for (EventDriverImpl impl : implementations)
|
||||
{
|
||||
if (delim)
|
||||
{
|
||||
msg.append(',');
|
||||
}
|
||||
msg.append(impl.toString());
|
||||
delim = true;
|
||||
}
|
||||
msg.append("]");
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -368,21 +103,32 @@ public class EventDriverFactory
|
|||
throw new InvalidWebSocketException("null websocket object");
|
||||
}
|
||||
|
||||
if (websocket instanceof WebSocketListener)
|
||||
for (EventDriverImpl impl : implementations)
|
||||
{
|
||||
WebSocketPolicy pojoPolicy = policy.clonePolicy();
|
||||
WebSocketListener listener = (WebSocketListener)websocket;
|
||||
return new ListenerEventDriver(pojoPolicy,listener);
|
||||
if (impl.supports(websocket))
|
||||
{
|
||||
return impl.create(websocket,policy);
|
||||
}
|
||||
}
|
||||
|
||||
EventMethods methods = getMethods(websocket.getClass());
|
||||
if (methods != null)
|
||||
// Create a clear error message for the developer
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append(websocket.getClass().getName());
|
||||
err.append(" is not a valid WebSocket object.");
|
||||
err.append(" Object must obey one of the following rules: ");
|
||||
|
||||
int len = implementations.size();
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
WebSocketPolicy pojoPolicy = policy.clonePolicy();
|
||||
return new AnnotatedEventDriver(pojoPolicy,websocket,methods);
|
||||
EventDriverImpl impl = implementations.get(i);
|
||||
if (i > 0)
|
||||
{
|
||||
err.append("or ");
|
||||
}
|
||||
err.append('(').append(i + 1).append(") ");
|
||||
err.append(impl.describeRule());
|
||||
}
|
||||
|
||||
throw new InvalidWebSocketException(websocket.getClass().getName() + " does not implement " + WebSocketListener.class.getName()
|
||||
+ " or declare @WebSocket");
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
||||
/**
|
||||
* A specific implementation of a EventDriver.
|
||||
*/
|
||||
public interface EventDriverImpl
|
||||
{
|
||||
/**
|
||||
* Create the EventDriver based on this implementation.
|
||||
*
|
||||
* @param websocket
|
||||
* the websocket to wrap
|
||||
* @param policy
|
||||
* the policy to use
|
||||
* @return the created EventDriver
|
||||
*/
|
||||
EventDriver create(Object websocket, WebSocketPolicy policy);
|
||||
|
||||
/**
|
||||
* human readable string describing the rule that would support this EventDriver.
|
||||
* <p>
|
||||
* Used to help developer with possible object annotations, listeners, or base classes.
|
||||
*
|
||||
* @return the human readable description of this event driver rule(s).
|
||||
*/
|
||||
String describeRule();
|
||||
|
||||
/**
|
||||
* Test for if this implementation can support the provided websocket.
|
||||
*
|
||||
* @param websocket
|
||||
* the possible websocket to test
|
||||
* @return true if implementation can support it, false if otherwise.
|
||||
*/
|
||||
boolean supports(Object websocket);
|
||||
}
|
|
@ -36,13 +36,13 @@ import org.eclipse.jetty.websocket.common.message.SimpleTextMessage;
|
|||
/**
|
||||
* Handler for Annotated User WebSocket objects.
|
||||
*/
|
||||
public class AnnotatedEventDriver extends EventDriver
|
||||
public class JettyAnnotatedEventDriver extends AbstractEventDriver
|
||||
{
|
||||
private final EventMethods events;
|
||||
private final JettyAnnotatedMetadata events;
|
||||
private MessageAppender activeMessage;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
|
||||
public AnnotatedEventDriver(WebSocketPolicy policy, Object websocket, EventMethods events)
|
||||
public JettyAnnotatedEventDriver(WebSocketPolicy policy, Object websocket, JettyAnnotatedMetadata events)
|
||||
{
|
||||
super(policy,websocket);
|
||||
this.events = events;
|
|
@ -0,0 +1,63 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
|
||||
public class JettyAnnotatedImpl implements EventDriverImpl
|
||||
{
|
||||
private ConcurrentHashMap<Class<?>, JettyAnnotatedMetadata> cache = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public EventDriver create(Object websocket, WebSocketPolicy policy)
|
||||
{
|
||||
Class<?> websocketClass = websocket.getClass();
|
||||
JettyAnnotatedMetadata metadata = cache.get(websocketClass);
|
||||
if (metadata == null)
|
||||
{
|
||||
JettyAnnotatedScanner scanner = new JettyAnnotatedScanner();
|
||||
metadata = scanner.scan(websocketClass);
|
||||
cache.put(websocketClass,metadata);
|
||||
}
|
||||
|
||||
return new JettyAnnotatedEventDriver(policy,websocket,metadata);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeRule()
|
||||
{
|
||||
return "class is annotated with @" + WebSocket.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Object websocket)
|
||||
{
|
||||
WebSocket anno = websocket.getClass().getAnnotation(WebSocket.class);
|
||||
return (anno != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("{} [cache.count=%d]",this.getClass().getSimpleName(),cache.size());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.CallableMethod;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.OptionalSessionCallableMethod;
|
||||
|
||||
public class JettyAnnotatedMetadata
|
||||
{
|
||||
/** @OnWebSocketConnect () */
|
||||
public CallableMethod onConnect;
|
||||
/** @OnWebSocketMessage (byte[], or ByteBuffer, or InputStream) */
|
||||
public OptionalSessionCallableMethod onBinary;
|
||||
/** @OnWebSocketMessage (String, or Reader) */
|
||||
public OptionalSessionCallableMethod onText;
|
||||
/** @OnWebSocketFrame (Frame) */
|
||||
public OptionalSessionCallableMethod onFrame;
|
||||
/** @OnWebSocketError (Throwable) */
|
||||
public OptionalSessionCallableMethod onError;
|
||||
/** @OnWebSocketClose (Frame) */
|
||||
public OptionalSessionCallableMethod onClose;
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append("JettyPojoMetadata[");
|
||||
s.append("onConnect=").append(onConnect);
|
||||
s.append(",onBinary=").append(onBinary);
|
||||
s.append(",onText=").append(onText);
|
||||
s.append(",onFrame=").append(onFrame);
|
||||
s.append(",onError=").append(onError);
|
||||
s.append(",onClose=").append(onClose);
|
||||
s.append("]");
|
||||
return s.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,170 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketConnect;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketFrame;
|
||||
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.AbstractMethodAnnotationScanner;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.CallableMethod;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.OptionalSessionCallableMethod;
|
||||
|
||||
public class JettyAnnotatedScanner extends AbstractMethodAnnotationScanner<JettyAnnotatedMetadata>
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyAnnotatedScanner.class);
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketMessage (Binary mode)
|
||||
*/
|
||||
private static final ParamList validBinaryParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketConnect
|
||||
*/
|
||||
private static final ParamList validConnectParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketClose
|
||||
*/
|
||||
private static final ParamList validCloseParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketError
|
||||
*/
|
||||
private static final ParamList validErrorParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketFrame
|
||||
*/
|
||||
private static final ParamList validFrameParams;
|
||||
|
||||
/**
|
||||
* Parameter list for @OnWebSocketMessage (Text mode)
|
||||
*/
|
||||
private static final ParamList validTextParams;
|
||||
|
||||
static
|
||||
{
|
||||
validConnectParams = new ParamList();
|
||||
validConnectParams.addParams(Session.class);
|
||||
|
||||
validCloseParams = new ParamList();
|
||||
validCloseParams.addParams(int.class,String.class);
|
||||
validCloseParams.addParams(Session.class,int.class,String.class);
|
||||
|
||||
validErrorParams = new ParamList();
|
||||
validErrorParams.addParams(Throwable.class);
|
||||
validErrorParams.addParams(Session.class,Throwable.class);
|
||||
|
||||
validTextParams = new ParamList();
|
||||
validTextParams.addParams(String.class);
|
||||
validTextParams.addParams(Session.class,String.class);
|
||||
validTextParams.addParams(Reader.class);
|
||||
validTextParams.addParams(Session.class,Reader.class);
|
||||
|
||||
validBinaryParams = new ParamList();
|
||||
validBinaryParams.addParams(byte[].class,int.class,int.class);
|
||||
validBinaryParams.addParams(Session.class,byte[].class,int.class,int.class);
|
||||
validBinaryParams.addParams(InputStream.class);
|
||||
validBinaryParams.addParams(Session.class,InputStream.class);
|
||||
|
||||
validFrameParams = new ParamList();
|
||||
validFrameParams.addParams(Frame.class);
|
||||
validFrameParams.addParams(Session.class,Frame.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMethodAnnotation(JettyAnnotatedMetadata metadata, Class<?> pojo, Method method, Annotation annotation)
|
||||
{
|
||||
LOG.debug("onMethodAnnotation({}, {}, {}, {})",metadata,pojo,method,annotation);
|
||||
|
||||
if (isAnnotation(annotation,OnWebSocketConnect.class))
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketConnect.class,validConnectParams);
|
||||
assertUnset(metadata.onConnect,OnWebSocketConnect.class,method);
|
||||
metadata.onConnect = new CallableMethod(pojo,method);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAnnotation(annotation,OnWebSocketMessage.class))
|
||||
{
|
||||
if (isSignatureMatch(method,validTextParams))
|
||||
{
|
||||
// Text mode
|
||||
assertUnset(metadata.onText,OnWebSocketMessage.class,method);
|
||||
metadata.onText = new OptionalSessionCallableMethod(pojo,method);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSignatureMatch(method,validBinaryParams))
|
||||
{
|
||||
// Binary Mode
|
||||
// TODO
|
||||
assertUnset(metadata.onBinary,OnWebSocketMessage.class,method);
|
||||
metadata.onBinary = new OptionalSessionCallableMethod(pojo,method);
|
||||
return;
|
||||
}
|
||||
|
||||
throw InvalidSignatureException.build(method,OnWebSocketMessage.class,validTextParams,validBinaryParams);
|
||||
}
|
||||
|
||||
if (isAnnotation(annotation,OnWebSocketClose.class))
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketClose.class,validCloseParams);
|
||||
assertUnset(metadata.onClose,OnWebSocketClose.class,method);
|
||||
metadata.onClose = new OptionalSessionCallableMethod(pojo,method);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAnnotation(annotation,OnWebSocketError.class))
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketError.class,validErrorParams);
|
||||
assertUnset(metadata.onError,OnWebSocketError.class,method);
|
||||
metadata.onError = new OptionalSessionCallableMethod(pojo,method);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isAnnotation(annotation,OnWebSocketFrame.class))
|
||||
{
|
||||
assertValidSignature(method,OnWebSocketFrame.class,validFrameParams);
|
||||
assertUnset(metadata.onFrame,OnWebSocketFrame.class,method);
|
||||
metadata.onFrame = new OptionalSessionCallableMethod(pojo,method);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public JettyAnnotatedMetadata scan(Class<?> pojo)
|
||||
{
|
||||
JettyAnnotatedMetadata metadata = new JettyAnnotatedMetadata();
|
||||
scanMethodAnnotations(metadata,pojo);
|
||||
return metadata;
|
||||
}
|
||||
}
|
|
@ -34,14 +34,14 @@ import org.eclipse.jetty.websocket.common.message.SimpleTextMessage;
|
|||
/**
|
||||
* Handler for {@link WebSocketListener} based User WebSocket implementations.
|
||||
*/
|
||||
public class ListenerEventDriver extends EventDriver
|
||||
public class JettyListenerEventDriver extends AbstractEventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ListenerEventDriver.class);
|
||||
private static final Logger LOG = Log.getLogger(JettyListenerEventDriver.class);
|
||||
private final WebSocketListener listener;
|
||||
private MessageAppender activeMessage;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
|
||||
public ListenerEventDriver(WebSocketPolicy policy, WebSocketListener listener)
|
||||
public JettyListenerEventDriver(WebSocketPolicy policy, WebSocketListener listener)
|
||||
{
|
||||
super(policy,listener);
|
||||
this.listener = listener;
|
|
@ -0,0 +1,44 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
||||
public class JettyListenerImpl implements EventDriverImpl
|
||||
{
|
||||
@Override
|
||||
public EventDriver create(Object websocket, WebSocketPolicy policy)
|
||||
{
|
||||
WebSocketListener listener = (WebSocketListener)websocket;
|
||||
return new JettyListenerEventDriver(policy,listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String describeRule()
|
||||
{
|
||||
return "class implements " + WebSocketListener.class.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Object websocket)
|
||||
{
|
||||
return (websocket instanceof WebSocketListener);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,195 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events.annotated;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.events.ParamList;
|
||||
|
||||
/**
|
||||
* Basic scanner for Annotated Methods
|
||||
*/
|
||||
public abstract class AbstractMethodAnnotationScanner<T>
|
||||
{
|
||||
protected void assertIsPublicNonStatic(Method method)
|
||||
{
|
||||
int mods = method.getModifiers();
|
||||
if (!Modifier.isPublic(mods))
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid declaration of ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("Method modifier must be public");
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
|
||||
if (Modifier.isStatic(mods))
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid declaration of ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("Method modifier may not be static");
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertIsReturn(Method method, Class<?> type)
|
||||
{
|
||||
if (!type.equals(method.getReturnType()))
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid declaration of ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("Return type must be ").append(type);
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertIsVoidReturn(Method method)
|
||||
{
|
||||
assertIsReturn(method,Void.TYPE);
|
||||
}
|
||||
|
||||
protected void assertUnset(CallableMethod callable, Class<? extends Annotation> annoClass, Method method)
|
||||
{
|
||||
if (callable != null)
|
||||
{
|
||||
// Attempt to add duplicate frame type (a no-no)
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Duplicate @").append(annoClass.getSimpleName()).append(" declaration on ");
|
||||
err.append(method);
|
||||
err.append(StringUtil.__LINE_SEPARATOR);
|
||||
|
||||
err.append("@").append(annoClass.getSimpleName()).append(" previously declared at ");
|
||||
err.append(callable.getMethod());
|
||||
|
||||
throw new InvalidWebSocketException(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
protected void assertValidSignature(Method method, Class<? extends Annotation> annoClass, ParamList validParams)
|
||||
{
|
||||
assertIsPublicNonStatic(method);
|
||||
assertIsReturn(method,Void.TYPE);
|
||||
|
||||
boolean valid = false;
|
||||
|
||||
// validate parameters
|
||||
Class<?> actual[] = method.getParameterTypes();
|
||||
for (Class<?>[] params : validParams)
|
||||
{
|
||||
if (isSameParameters(actual,params))
|
||||
{
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!valid)
|
||||
{
|
||||
throw InvalidSignatureException.build(method,annoClass,validParams);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isAnnotation(Annotation annotation, Class<? extends Annotation> annotationClass)
|
||||
{
|
||||
return annotation.annotationType().equals(annotationClass);
|
||||
}
|
||||
|
||||
public boolean isSameParameters(Class<?>[] actual, Class<?>[] params)
|
||||
{
|
||||
if (actual.length != params.length)
|
||||
{
|
||||
// skip
|
||||
return false;
|
||||
}
|
||||
|
||||
int len = params.length;
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
if (!actual[i].equals(params[i]))
|
||||
{
|
||||
return false; // not valid
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected boolean isSignatureMatch(Method method, ParamList validParams)
|
||||
{
|
||||
assertIsPublicNonStatic(method);
|
||||
assertIsReturn(method,Void.TYPE);
|
||||
|
||||
// validate parameters
|
||||
Class<?> actual[] = method.getParameterTypes();
|
||||
for (Class<?>[] params : validParams)
|
||||
{
|
||||
if (isSameParameters(actual,params))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean isTypeAnnotated(Class<?> pojo, Class<? extends Annotation> expectedAnnotation)
|
||||
{
|
||||
return pojo.getAnnotation(expectedAnnotation) != null;
|
||||
}
|
||||
|
||||
public abstract void onMethodAnnotation(T metadata, Class<?> pojo, Method method, Annotation annotation);
|
||||
|
||||
public void scanMethodAnnotations(T metadata, Class<?> pojo)
|
||||
{
|
||||
Class<?> clazz = pojo;
|
||||
|
||||
while ((clazz != null) && Object.class.isAssignableFrom(clazz))
|
||||
{
|
||||
for (Method method : clazz.getDeclaredMethods())
|
||||
{
|
||||
Annotation annotations[] = method.getAnnotations();
|
||||
if ((annotations == null) || (annotations.length <= 0))
|
||||
{
|
||||
continue; // skip
|
||||
}
|
||||
for (Annotation annotation : annotations)
|
||||
{
|
||||
onMethodAnnotation(metadata,clazz,method,annotation);
|
||||
}
|
||||
}
|
||||
|
||||
clazz = clazz.getSuperclass();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,96 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events.annotated;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
|
||||
/**
|
||||
* A Callable Method
|
||||
*/
|
||||
public class CallableMethod
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(CallableMethod.class);
|
||||
protected final Class<?> pojo;
|
||||
protected final Method method;
|
||||
protected Class<?>[] paramTypes;
|
||||
|
||||
public CallableMethod(Class<?> pojo, Method method)
|
||||
{
|
||||
this.pojo = pojo;
|
||||
this.method = method;
|
||||
this.paramTypes = method.getParameterTypes();
|
||||
}
|
||||
|
||||
public void call(Object obj, Object... args)
|
||||
{
|
||||
if ((this.pojo == null) || (this.method == null))
|
||||
{
|
||||
LOG.warn("Cannot execute call: pojo={}, method={}",pojo,method);
|
||||
return; // no call event method determined
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
LOG.warn("Cannot call {} on null object",this.method);
|
||||
return;
|
||||
}
|
||||
|
||||
if (args.length < paramTypes.length)
|
||||
{
|
||||
throw new IllegalArgumentException("Call arguments length [" + args.length + "] must always be greater than or equal to captured args length ["
|
||||
+ paramTypes.length + "]");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
this.method.invoke(obj,args);
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
|
||||
{
|
||||
String err = String.format("Cannot call method %s on %s with args: %s",method,pojo,args);
|
||||
throw new WebSocketException(err,e);
|
||||
}
|
||||
}
|
||||
|
||||
public Method getMethod()
|
||||
{
|
||||
return method;
|
||||
}
|
||||
|
||||
public Class<?>[] getParamTypes()
|
||||
{
|
||||
return paramTypes;
|
||||
}
|
||||
|
||||
public Class<?> getPojo()
|
||||
{
|
||||
return pojo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s]",this.getClass().getSimpleName(),method.toGenericString());
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
package org.eclipse.jetty.websocket.common.events.annotated;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
|
@ -108,7 +108,7 @@ public class EventMethod
|
|||
}
|
||||
}
|
||||
|
||||
protected Method getMethod()
|
||||
public Method getMethod()
|
||||
{
|
||||
return method;
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
package org.eclipse.jetty.websocket.common.events.annotated;
|
||||
|
||||
/**
|
||||
* A representation of the methods available to call for a particular class.
|
|
@ -16,13 +16,14 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
package org.eclipse.jetty.websocket.common.events.annotated;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.eclipse.jetty.util.StringUtil;
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.events.ParamList;
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
public class InvalidSignatureException extends InvalidWebSocketException
|
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2012 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events.annotated;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
|
||||
/**
|
||||
* Simple CallableMethod that manages the optional {@link Session} argument
|
||||
*/
|
||||
public class OptionalSessionCallableMethod extends CallableMethod
|
||||
{
|
||||
private final boolean wantsSession;
|
||||
private final boolean streaming;
|
||||
|
||||
public OptionalSessionCallableMethod(Class<?> pojo, Method method)
|
||||
{
|
||||
super(pojo,method);
|
||||
|
||||
boolean foundConnection = false;
|
||||
boolean foundStreaming = false;
|
||||
|
||||
if (paramTypes != null)
|
||||
{
|
||||
for (Class<?> paramType : paramTypes)
|
||||
{
|
||||
if (Session.class.isAssignableFrom(paramType))
|
||||
{
|
||||
foundConnection = true;
|
||||
}
|
||||
if (Reader.class.isAssignableFrom(paramType) || InputStream.class.isAssignableFrom(paramType))
|
||||
{
|
||||
foundStreaming = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.wantsSession = foundConnection;
|
||||
this.streaming = foundStreaming;
|
||||
}
|
||||
|
||||
public void call(Object obj, Session connection, Object... args)
|
||||
{
|
||||
if (wantsSession)
|
||||
{
|
||||
Object fullArgs[] = new Object[args.length + 1];
|
||||
fullArgs[0] = connection;
|
||||
System.arraycopy(args,0,fullArgs,1,args.length);
|
||||
call(obj,fullArgs);
|
||||
}
|
||||
else
|
||||
{
|
||||
call(obj,args);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isSessionAware()
|
||||
{
|
||||
return wantsSession;
|
||||
}
|
||||
|
||||
public boolean isStreaming()
|
||||
{
|
||||
return streaming;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s]",this.getClass().getSimpleName(),method.toGenericString());
|
||||
}
|
||||
}
|
|
@ -23,7 +23,7 @@ import java.io.InputStream;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.common.events.AnnotatedEventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.JettyAnnotatedEventDriver;
|
||||
|
||||
/**
|
||||
* Support class for reading binary message data as an InputStream.
|
||||
|
@ -35,14 +35,14 @@ public class MessageInputStream extends InputStream implements MessageAppender
|
|||
* Threshold (of bytes) to perform compaction at
|
||||
*/
|
||||
private static final int COMPACT_THRESHOLD = 5;
|
||||
private final AnnotatedEventDriver driver;
|
||||
private final JettyAnnotatedEventDriver driver;
|
||||
private final ByteBuffer buf;
|
||||
private int size;
|
||||
private boolean finished;
|
||||
private boolean needsNotification;
|
||||
private int readPosition;
|
||||
|
||||
public MessageInputStream(AnnotatedEventDriver driver)
|
||||
public MessageInputStream(JettyAnnotatedEventDriver driver)
|
||||
{
|
||||
this.driver = driver;
|
||||
this.buf = ByteBuffer.allocate(BUFFER_SIZE);
|
||||
|
|
|
@ -23,7 +23,7 @@ import java.io.Reader;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
import org.eclipse.jetty.websocket.common.events.AnnotatedEventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.JettyAnnotatedEventDriver;
|
||||
|
||||
/**
|
||||
* Support class for reading text message data as an Reader.
|
||||
|
@ -32,13 +32,13 @@ import org.eclipse.jetty.websocket.common.events.AnnotatedEventDriver;
|
|||
*/
|
||||
public class MessageReader extends Reader implements MessageAppender
|
||||
{
|
||||
private final AnnotatedEventDriver driver;
|
||||
private final JettyAnnotatedEventDriver driver;
|
||||
private final Utf8StringBuilder utf;
|
||||
private int size;
|
||||
private boolean finished;
|
||||
private boolean needsNotification;
|
||||
|
||||
public MessageReader(AnnotatedEventDriver driver)
|
||||
public MessageReader(JettyAnnotatedEventDriver driver)
|
||||
{
|
||||
this.driver = driver;
|
||||
this.utf = new Utf8StringBuilder();
|
||||
|
|
|
@ -24,41 +24,15 @@ import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadBinarySignatureSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadDuplicateBinarySocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadDuplicateFrameSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadTextSignatureSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.FrameSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.MyEchoBinarySocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.MyEchoSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.MyStatelessEchoSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.NoopSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.NotASocket;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import examples.AdapterConnectCloseSocket;
|
||||
import examples.AnnotatedBinaryArraySocket;
|
||||
import examples.AnnotatedBinaryStreamSocket;
|
||||
import examples.AnnotatedTextSocket;
|
||||
import examples.AnnotatedTextStreamSocket;
|
||||
import examples.ListenerBasicSocket;
|
||||
|
||||
public class EventDriverFactoryTest
|
||||
{
|
||||
private void assertHasEventMethod(String message, EventMethod actual)
|
||||
{
|
||||
Assert.assertThat(message + " EventMethod",actual,notNullValue());
|
||||
|
||||
Assert.assertThat(message + " EventMethod.pojo",actual.pojo,notNullValue());
|
||||
Assert.assertThat(message + " EventMethod.method",actual.method,notNullValue());
|
||||
}
|
||||
|
||||
private void assertNoEventMethod(String message, EventMethod actual)
|
||||
{
|
||||
Assert.assertThat(message + "Event method",actual,nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 5 methods (extends WebSocketAdapter)
|
||||
*/
|
||||
|
@ -70,291 +44,7 @@ public class EventDriverFactoryTest
|
|||
EventDriver driver = factory.wrap(socket);
|
||||
|
||||
String classId = AdapterConnectCloseSocket.class.getSimpleName();
|
||||
Assert.assertThat("EventDriver for " + classId,driver,instanceOf(ListenerEventDriver.class));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration (duplicate OnWebSocketBinary declarations)
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadDuplicateBinarySocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
factory.getMethods(BadDuplicateBinarySocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate @OnWebSocketMessage declaration"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration (duplicate frame type methods)
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadDuplicateFrameSocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
factory.getMethods(BadDuplicateFrameSocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate @OnWebSocketFrame"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration a method with a non-void return type
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadSignature_NonVoidReturn()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
factory.getMethods(BadBinarySignatureSocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("must be void"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration a method with a public static method
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadSignature_Static()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
factory.getMethods(BadTextSignatureSocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("may not be static"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for binary array messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBinaryArraySocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(AnnotatedBinaryArraySocket.class);
|
||||
|
||||
String classId = AnnotatedBinaryArraySocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertHasEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertNoEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onBinary.hasSession",methods.onBinary.isHasSession());
|
||||
Assert.assertFalse(classId + ".onBinary.isStreaming",methods.onBinary.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for binary stream messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBinaryStreamSocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(AnnotatedBinaryStreamSocket.class);
|
||||
|
||||
String classId = AnnotatedBinaryStreamSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertHasEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertNoEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onBinary.hasSession",methods.onBinary.isHasSession());
|
||||
Assert.assertTrue(classId + ".onBinary.isStreaming",methods.onBinary.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 4 methods (3 methods from parent)
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedMyEchoBinarySocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(MyEchoBinarySocket.class);
|
||||
|
||||
String classId = MyEchoBinarySocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertHasEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertHasEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 3 methods
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedMyEchoSocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(MyEchoSocket.class);
|
||||
|
||||
String classId = MyEchoSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertHasEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for annotated for text messages w/connection param
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedMyStatelessEchoSocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(MyStatelessEchoSocket.class);
|
||||
|
||||
String classId = MyStatelessEchoSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertNoEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertNoEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertHasEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
|
||||
Assert.assertTrue(classId + ".onText.hasSession",methods.onText.isHasSession());
|
||||
Assert.assertFalse(classId + ".onText.isStreaming",methods.onText.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and no methods
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedNoop()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(NoopSocket.class);
|
||||
|
||||
String classId = NoopSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("Methods for " + classId,methods,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertNoEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertNoEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertNoEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 1 methods
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedOnFrame()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(FrameSocket.class);
|
||||
|
||||
String classId = FrameSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertNoEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertNoEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertNoEventMethod(classId + ".onText",methods.onText);
|
||||
assertHasEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for simple text messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedTextSocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(AnnotatedTextSocket.class);
|
||||
|
||||
String classId = AnnotatedTextSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertHasEventMethod(classId + ".onException",methods.onError);
|
||||
assertHasEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onText.hasSession",methods.onText.isHasSession());
|
||||
Assert.assertFalse(classId + ".onText.isStreaming",methods.onText.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for text stream messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedTextStreamSocket()
|
||||
{
|
||||
EventDriverFactory factory = new EventDriverFactory(WebSocketPolicy.newClientPolicy());
|
||||
EventMethods methods = factory.getMethods(AnnotatedTextStreamSocket.class);
|
||||
|
||||
String classId = AnnotatedTextStreamSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,methods,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",methods.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",methods.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",methods.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",methods.onError);
|
||||
assertHasEventMethod(classId + ".onText",methods.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",methods.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onText.hasSession",methods.onText.isHasSession());
|
||||
Assert.assertTrue(classId + ".onText.isStreaming",methods.onText.isStreaming());
|
||||
Assert.assertThat("EventDriver for " + classId,driver,instanceOf(JettyListenerEventDriver.class));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -388,6 +78,6 @@ public class EventDriverFactoryTest
|
|||
EventDriver driver = factory.wrap(socket);
|
||||
|
||||
String classId = ListenerBasicSocket.class.getSimpleName();
|
||||
Assert.assertThat("EventDriver for " + classId,driver,instanceOf(ListenerEventDriver.class));
|
||||
Assert.assertThat("EventDriver for " + classId,driver,instanceOf(JettyListenerEventDriver.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,340 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common.events;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadBinarySignatureSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadDuplicateBinarySocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadDuplicateFrameSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.BadTextSignatureSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.FrameSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.MyEchoBinarySocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.MyEchoSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.MyStatelessEchoSocket;
|
||||
import org.eclipse.jetty.websocket.common.annotations.NoopSocket;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.CallableMethod;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import examples.AnnotatedBinaryArraySocket;
|
||||
import examples.AnnotatedBinaryStreamSocket;
|
||||
import examples.AnnotatedTextSocket;
|
||||
import examples.AnnotatedTextStreamSocket;
|
||||
|
||||
public class JettyAnnotatedScannerTest
|
||||
{
|
||||
private void assertHasEventMethod(String message, CallableMethod actual)
|
||||
{
|
||||
Assert.assertThat(message + " CallableMethod",actual,notNullValue());
|
||||
|
||||
Assert.assertThat(message + " CallableMethod.pojo",actual.getPojo(),notNullValue());
|
||||
Assert.assertThat(message + " CallableMethod.method",actual.getMethod(),notNullValue());
|
||||
}
|
||||
|
||||
private void assertNoEventMethod(String message, CallableMethod actual)
|
||||
{
|
||||
Assert.assertThat(message + " CallableMethod",actual,nullValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration (duplicate OnWebSocketBinary declarations)
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadDuplicateBinarySocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
impl.scan(BadDuplicateBinarySocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate @OnWebSocketMessage declaration"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration (duplicate frame type methods)
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadDuplicateFrameSocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
impl.scan(BadDuplicateFrameSocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate @OnWebSocketFrame"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration a method with a non-void return type
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadSignature_NonVoidReturn()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
impl.scan(BadBinarySignatureSocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("must be void"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for bad declaration a method with a public static method
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBadSignature_Static()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
try
|
||||
{
|
||||
// Should toss exception
|
||||
impl.scan(BadTextSignatureSocket.class);
|
||||
Assert.fail("Should have thrown " + InvalidWebSocketException.class);
|
||||
}
|
||||
catch (InvalidWebSocketException e)
|
||||
{
|
||||
// Validate that we have clear error message to the developer
|
||||
Assert.assertThat(e.getMessage(),containsString("may not be static"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for binary array messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBinaryArraySocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(AnnotatedBinaryArraySocket.class);
|
||||
|
||||
String classId = AnnotatedBinaryArraySocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertHasEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertNoEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onBinary.isSessionAware",metadata.onBinary.isSessionAware());
|
||||
Assert.assertFalse(classId + ".onBinary.isStreaming",metadata.onBinary.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for binary stream messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedBinaryStreamSocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(AnnotatedBinaryStreamSocket.class);
|
||||
|
||||
String classId = AnnotatedBinaryStreamSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertHasEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertNoEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onBinary.isSessionAware",metadata.onBinary.isSessionAware());
|
||||
Assert.assertTrue(classId + ".onBinary.isStreaming",metadata.onBinary.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 4 methods (3 methods from parent)
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedMyEchoBinarySocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(MyEchoBinarySocket.class);
|
||||
|
||||
String classId = MyEchoBinarySocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertHasEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertHasEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 3 methods
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedMyEchoSocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(MyEchoSocket.class);
|
||||
|
||||
String classId = MyEchoSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertHasEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for annotated for text messages w/connection param
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedMyStatelessEchoSocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(MyStatelessEchoSocket.class);
|
||||
|
||||
String classId = MyStatelessEchoSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertNoEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertNoEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertHasEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
|
||||
Assert.assertTrue(classId + ".onText.isSessionAware",metadata.onText.isSessionAware());
|
||||
Assert.assertFalse(classId + ".onText.isStreaming",metadata.onText.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and no methods
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedNoop()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(NoopSocket.class);
|
||||
|
||||
String classId = NoopSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("Methods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertNoEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertNoEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertNoEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for no exceptions and 1 methods
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedOnFrame()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(FrameSocket.class);
|
||||
|
||||
String classId = FrameSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertNoEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertNoEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertNoEventMethod(classId + ".onText",metadata.onText);
|
||||
assertHasEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for simple text messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedTextSocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(AnnotatedTextSocket.class);
|
||||
|
||||
String classId = AnnotatedTextSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertHasEventMethod(classId + ".onException",metadata.onError);
|
||||
assertHasEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onText.isSessionAware",metadata.onText.isSessionAware());
|
||||
Assert.assertFalse(classId + ".onText.isStreaming",metadata.onText.isStreaming());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Case for socket for text stream messages
|
||||
*/
|
||||
@Test
|
||||
public void testAnnotatedTextStreamSocket()
|
||||
{
|
||||
JettyAnnotatedScanner impl = new JettyAnnotatedScanner();
|
||||
JettyAnnotatedMetadata metadata = impl.scan(AnnotatedTextStreamSocket.class);
|
||||
|
||||
String classId = AnnotatedTextStreamSocket.class.getSimpleName();
|
||||
|
||||
Assert.assertThat("EventMethods for " + classId,metadata,notNullValue());
|
||||
|
||||
assertNoEventMethod(classId + ".onBinary",metadata.onBinary);
|
||||
assertHasEventMethod(classId + ".onClose",metadata.onClose);
|
||||
assertHasEventMethod(classId + ".onConnect",metadata.onConnect);
|
||||
assertNoEventMethod(classId + ".onException",metadata.onError);
|
||||
assertHasEventMethod(classId + ".onText",metadata.onText);
|
||||
assertNoEventMethod(classId + ".onFrame",metadata.onFrame);
|
||||
|
||||
Assert.assertFalse(classId + ".onText.isSessionAware",metadata.onText.isSessionAware());
|
||||
Assert.assertTrue(classId + ".onText.isStreaming",metadata.onText.isStreaming());
|
||||
}
|
||||
}
|
|
@ -244,6 +244,11 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
return this.creator;
|
||||
}
|
||||
|
||||
public EventDriverFactory getEventDriverFactory()
|
||||
{
|
||||
return eventDriverFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ExtensionFactory getExtensionFactory()
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue