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;
|
return cookieStore;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EventDriverFactory getEventDriverFactory()
|
||||||
|
{
|
||||||
|
return eventDriverFactory;
|
||||||
|
}
|
||||||
|
|
||||||
public Executor getExecutor()
|
public Executor getExecutor()
|
||||||
{
|
{
|
||||||
return executor;
|
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;
|
package org.eclipse.jetty.websocket.common.events;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
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.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
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;
|
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||||
|
|
||||||
/**
|
public interface EventDriver extends IncomingFrames
|
||||||
* EventDriver is the main interface between the User's WebSocket POJO and the internal jetty implementation of WebSocket.
|
|
||||||
*/
|
|
||||||
public abstract class EventDriver implements IncomingFrames
|
|
||||||
{
|
{
|
||||||
private static final Logger LOG = Log.getLogger(EventDriver.class);
|
public WebSocketPolicy getPolicy();
|
||||||
protected final WebSocketPolicy policy;
|
|
||||||
protected final Object websocket;
|
|
||||||
protected WebSocketSession session;
|
|
||||||
|
|
||||||
public EventDriver(WebSocketPolicy policy, Object websocket)
|
public WebSocketSession getSession();
|
||||||
{
|
|
||||||
this.policy = policy;
|
|
||||||
this.websocket = websocket;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketPolicy getPolicy()
|
public void onBinaryFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||||
{
|
|
||||||
return policy;
|
|
||||||
}
|
|
||||||
|
|
||||||
public WebSocketSession getSession()
|
public void onBinaryMessage(byte[] data);
|
||||||
{
|
|
||||||
return session;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public void onClose(CloseInfo close);
|
||||||
public final void incomingError(WebSocketException e)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
{
|
|
||||||
LOG.debug("incoming(WebSocketException)",e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (e instanceof CloseException)
|
public void onConnect();
|
||||||
{
|
|
||||||
CloseException close = (CloseException)e;
|
|
||||||
terminateConnection(close.getStatusCode(),close.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
onError(e);
|
public void onError(Throwable t);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public void onFrame(Frame frame);
|
||||||
public void incomingFrame(Frame frame)
|
|
||||||
{
|
|
||||||
if (LOG.isDebugEnabled())
|
|
||||||
{
|
|
||||||
LOG.debug("{}.onFrame({})",websocket.getClass().getSimpleName(),frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
onFrame(frame);
|
public void onTextFrame(ByteBuffer buffer, boolean fin) throws IOException;
|
||||||
|
|
||||||
try
|
public void onTextMessage(String message);
|
||||||
{
|
|
||||||
switch (frame.getType().getOpCode())
|
|
||||||
{
|
|
||||||
case OpCode.CLOSE:
|
|
||||||
{
|
|
||||||
boolean validate = true;
|
|
||||||
CloseInfo close = new CloseInfo(frame,validate);
|
|
||||||
|
|
||||||
// notify user websocket pojo
|
public void openSession(WebSocketSession session);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -18,340 +18,75 @@
|
||||||
|
|
||||||
package org.eclipse.jetty.websocket.common.events;
|
package org.eclipse.jetty.websocket.common.events;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.util.ArrayList;
|
||||||
import java.io.Reader;
|
import java.util.List;
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Method;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
|
|
||||||
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.InvalidWebSocketException;
|
||||||
import org.eclipse.jetty.websocket.api.Session;
|
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
import org.eclipse.jetty.websocket.api.WebSocketListener;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
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.annotations.WebSocket;
|
||||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create EventDriver implementations.
|
* Create EventDriver implementations.
|
||||||
*/
|
*/
|
||||||
public class EventDriverFactory
|
public class EventDriverFactory
|
||||||
{
|
{
|
||||||
/**
|
private static final Logger LOG = Log.getLogger(EventDriverFactory.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);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ConcurrentHashMap<Class<?>, EventMethods> cache;
|
|
||||||
private final WebSocketPolicy policy;
|
private final WebSocketPolicy policy;
|
||||||
|
private final List<EventDriverImpl> implementations;
|
||||||
|
|
||||||
public EventDriverFactory(WebSocketPolicy policy)
|
public EventDriverFactory(WebSocketPolicy policy)
|
||||||
{
|
{
|
||||||
this.policy = 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 (implementations.contains(impl))
|
||||||
if (!Modifier.isPublic(mods))
|
|
||||||
{
|
{
|
||||||
StringBuilder err = new StringBuilder();
|
LOG.warn("Ignoring attempt to add duplicate EventDriverImpl: " + impl);
|
||||||
err.append("Invalid declaration of ");
|
return;
|
||||||
err.append(method);
|
|
||||||
err.append(StringUtil.__LINE_SEPARATOR);
|
|
||||||
|
|
||||||
err.append("Method modifier must be public");
|
|
||||||
|
|
||||||
throw new InvalidWebSocketException(err.toString());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Modifier.isStatic(mods))
|
implementations.add(impl);
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertIsReturn(Method method, Class<?> type)
|
public List<EventDriverImpl> getImplementations()
|
||||||
{
|
{
|
||||||
if (!type.equals(method.getReturnType()))
|
return implementations;
|
||||||
{
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void assertUnset(EventMethod event, Class<? extends Annotation> annoClass, Method method)
|
public boolean removeImplementation(EventDriverImpl impl)
|
||||||
{
|
{
|
||||||
if (event != null)
|
return this.implementations.remove(impl);
|
||||||
{
|
|
||||||
// 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
|
@Override
|
||||||
public String toString()
|
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");
|
throw new InvalidWebSocketException("null websocket object");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (websocket instanceof WebSocketListener)
|
for (EventDriverImpl impl : implementations)
|
||||||
{
|
{
|
||||||
WebSocketPolicy pojoPolicy = policy.clonePolicy();
|
if (impl.supports(websocket))
|
||||||
WebSocketListener listener = (WebSocketListener)websocket;
|
{
|
||||||
return new ListenerEventDriver(pojoPolicy,listener);
|
return impl.create(websocket,policy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EventMethods methods = getMethods(websocket.getClass());
|
// Create a clear error message for the developer
|
||||||
if (methods != null)
|
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();
|
EventDriverImpl impl = implementations.get(i);
|
||||||
return new AnnotatedEventDriver(pojoPolicy,websocket,methods);
|
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()
|
throw new InvalidWebSocketException(err.toString());
|
||||||
+ " or declare @WebSocket");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
* 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 MessageAppender activeMessage;
|
||||||
private boolean hasCloseBeenCalled = false;
|
private boolean hasCloseBeenCalled = false;
|
||||||
|
|
||||||
public AnnotatedEventDriver(WebSocketPolicy policy, Object websocket, EventMethods events)
|
public JettyAnnotatedEventDriver(WebSocketPolicy policy, Object websocket, JettyAnnotatedMetadata events)
|
||||||
{
|
{
|
||||||
super(policy,websocket);
|
super(policy,websocket);
|
||||||
this.events = events;
|
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.
|
* 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 final WebSocketListener listener;
|
||||||
private MessageAppender activeMessage;
|
private MessageAppender activeMessage;
|
||||||
private boolean hasCloseBeenCalled = false;
|
private boolean hasCloseBeenCalled = false;
|
||||||
|
|
||||||
public ListenerEventDriver(WebSocketPolicy policy, WebSocketListener listener)
|
public JettyListenerEventDriver(WebSocketPolicy policy, WebSocketListener listener)
|
||||||
{
|
{
|
||||||
super(policy,listener);
|
super(policy,listener);
|
||||||
this.listener = 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.InputStream;
|
||||||
import java.io.Reader;
|
import java.io.Reader;
|
||||||
|
@ -108,7 +108,7 @@ public class EventMethod
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Method getMethod()
|
public Method getMethod()
|
||||||
{
|
{
|
||||||
return method;
|
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.
|
* 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.annotation.Annotation;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.StringUtil;
|
import org.eclipse.jetty.util.StringUtil;
|
||||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||||
|
import org.eclipse.jetty.websocket.common.events.ParamList;
|
||||||
|
|
||||||
@SuppressWarnings("serial")
|
@SuppressWarnings("serial")
|
||||||
public class InvalidSignatureException extends InvalidWebSocketException
|
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 java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.BufferUtil;
|
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.
|
* 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
|
* Threshold (of bytes) to perform compaction at
|
||||||
*/
|
*/
|
||||||
private static final int COMPACT_THRESHOLD = 5;
|
private static final int COMPACT_THRESHOLD = 5;
|
||||||
private final AnnotatedEventDriver driver;
|
private final JettyAnnotatedEventDriver driver;
|
||||||
private final ByteBuffer buf;
|
private final ByteBuffer buf;
|
||||||
private int size;
|
private int size;
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
private boolean needsNotification;
|
private boolean needsNotification;
|
||||||
private int readPosition;
|
private int readPosition;
|
||||||
|
|
||||||
public MessageInputStream(AnnotatedEventDriver driver)
|
public MessageInputStream(JettyAnnotatedEventDriver driver)
|
||||||
{
|
{
|
||||||
this.driver = driver;
|
this.driver = driver;
|
||||||
this.buf = ByteBuffer.allocate(BUFFER_SIZE);
|
this.buf = ByteBuffer.allocate(BUFFER_SIZE);
|
||||||
|
|
|
@ -23,7 +23,7 @@ import java.io.Reader;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
|
|
||||||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
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.
|
* 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
|
public class MessageReader extends Reader implements MessageAppender
|
||||||
{
|
{
|
||||||
private final AnnotatedEventDriver driver;
|
private final JettyAnnotatedEventDriver driver;
|
||||||
private final Utf8StringBuilder utf;
|
private final Utf8StringBuilder utf;
|
||||||
private int size;
|
private int size;
|
||||||
private boolean finished;
|
private boolean finished;
|
||||||
private boolean needsNotification;
|
private boolean needsNotification;
|
||||||
|
|
||||||
public MessageReader(AnnotatedEventDriver driver)
|
public MessageReader(JettyAnnotatedEventDriver driver)
|
||||||
{
|
{
|
||||||
this.driver = driver;
|
this.driver = driver;
|
||||||
this.utf = new Utf8StringBuilder();
|
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.WebSocketListener;
|
||||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
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.eclipse.jetty.websocket.common.annotations.NotASocket;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import examples.AdapterConnectCloseSocket;
|
import examples.AdapterConnectCloseSocket;
|
||||||
import examples.AnnotatedBinaryArraySocket;
|
|
||||||
import examples.AnnotatedBinaryStreamSocket;
|
|
||||||
import examples.AnnotatedTextSocket;
|
|
||||||
import examples.AnnotatedTextStreamSocket;
|
|
||||||
import examples.ListenerBasicSocket;
|
import examples.ListenerBasicSocket;
|
||||||
|
|
||||||
public class EventDriverFactoryTest
|
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)
|
* Test Case for no exceptions and 5 methods (extends WebSocketAdapter)
|
||||||
*/
|
*/
|
||||||
|
@ -70,291 +44,7 @@ public class EventDriverFactoryTest
|
||||||
EventDriver driver = factory.wrap(socket);
|
EventDriver driver = factory.wrap(socket);
|
||||||
|
|
||||||
String classId = AdapterConnectCloseSocket.class.getSimpleName();
|
String classId = AdapterConnectCloseSocket.class.getSimpleName();
|
||||||
Assert.assertThat("EventDriver for " + classId,driver,instanceOf(ListenerEventDriver.class));
|
Assert.assertThat("EventDriver for " + classId,driver,instanceOf(JettyListenerEventDriver.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());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -388,6 +78,6 @@ public class EventDriverFactoryTest
|
||||||
EventDriver driver = factory.wrap(socket);
|
EventDriver driver = factory.wrap(socket);
|
||||||
|
|
||||||
String classId = ListenerBasicSocket.class.getSimpleName();
|
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;
|
return this.creator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EventDriverFactory getEventDriverFactory()
|
||||||
|
{
|
||||||
|
return eventDriverFactory;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ExtensionFactory getExtensionFactory()
|
public ExtensionFactory getExtensionFactory()
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue