JSR-356 - reworked Config to maintain user provided config
+ If a user provided config is supplied, then that config should be used for init(EndpointConfig) and other various accesses to the configuration object. This refactor stops using an internal EndpointConfig object always and moves the internal config fields into the JsrSession object instead.
This commit is contained in:
parent
e35914e400
commit
46e9493c85
|
@ -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.jsr356;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
/**
|
||||
* Basic EndpointConfig (used when no EndpointConfig is provided or discovered)
|
||||
*/
|
||||
public class BasicEndpointConfig implements EndpointConfig
|
||||
{
|
||||
private List<Class<? extends Decoder>> decoders;
|
||||
private List<Class<? extends Encoder>> encoders;
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public BasicEndpointConfig()
|
||||
{
|
||||
decoders = Collections.emptyList();
|
||||
encoders = Collections.emptyList();
|
||||
userProperties = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders()
|
||||
{
|
||||
return encoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
}
|
|
@ -35,26 +35,34 @@ import javax.websocket.Session;
|
|||
|
||||
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.extensions.ExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.client.io.UpgradeListener;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.JsrClientMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.ConfiguredEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrClientMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrEventDriverFactory;
|
||||
|
||||
public class ClientContainer implements ContainerService
|
||||
/**
|
||||
* Container for Client use of the javax.websocket API.
|
||||
* <p>
|
||||
* This should be specific to a JVM if run in a standalone mode. or specific to a WebAppContext if running on the Jetty server.
|
||||
*/
|
||||
public class ClientContainer extends CommonContainer
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(ClientContainer.class);
|
||||
private final DecoderMetadataFactory decoderMetadataFactory;
|
||||
private ConcurrentHashMap<Class<?>, JsrClientMetadata> endpointClientMetadataCache = new ConcurrentHashMap<>();
|
||||
|
||||
/** Tracking for all declared Client endpoints */
|
||||
private final ConcurrentHashMap<Class<?>, JsrClientMetadata> endpointClientMetadataCache;
|
||||
/** The jetty websocket client in use for this container */
|
||||
private WebSocketClient client;
|
||||
|
||||
public ClientContainer()
|
||||
{
|
||||
decoderMetadataFactory = new DecoderMetadataFactory();
|
||||
super();
|
||||
endpointClientMetadataCache = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
private Session connect(Object websocket, ClientEndpointConfig config, URI path) throws IOException
|
||||
|
@ -123,13 +131,13 @@ public class ClientContainer implements ContainerService
|
|||
// Annotated takes precedence here
|
||||
JsrClientMetadata metadata = new JsrClientMetadata(this,annotatedEndpointClass);
|
||||
Object websocket = annotatedEndpointClass.newInstance();
|
||||
return connect(websocket,metadata.getEndpointConfigCopy(),path);
|
||||
return connect(websocket,metadata.getConfig(),path);
|
||||
}
|
||||
else if (Endpoint.class.isAssignableFrom(annotatedEndpointClass))
|
||||
{
|
||||
// Try if extends Endpoint (alternate use)
|
||||
Object websocket = annotatedEndpointClass.newInstance();
|
||||
ClientEndpointConfig cec = new JettyClientEndpointConfig();
|
||||
ClientEndpointConfig cec = new EmptyClientEndpointConfig();
|
||||
return connect(websocket,cec,path);
|
||||
}
|
||||
else
|
||||
|
@ -174,12 +182,6 @@ public class ClientContainer implements ContainerService
|
|||
return basemetadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DecoderMetadataFactory getDecoderMetadataFactory()
|
||||
{
|
||||
return decoderMetadataFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getDefaultAsyncSendTimeout()
|
||||
{
|
||||
|
@ -218,6 +220,7 @@ public class ClientContainer implements ContainerService
|
|||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Session> getOpenSessions()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
public abstract class CommonConfig implements EndpointConfig
|
||||
{
|
||||
/** User Properties for the Endpoint */
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public CommonConfig(CommonConfig copy)
|
||||
{
|
||||
userProperties = copy.userProperties;
|
||||
}
|
||||
|
||||
protected CommonConfig(CommonContainer container)
|
||||
{
|
||||
userProperties = new HashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.BooleanDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.CharacterDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.DoubleDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.FloatDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.IntegerDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.LongDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ShortDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.StringDecoder;
|
||||
|
||||
/**
|
||||
* Service Interface for working with Jetty Internal Container.
|
||||
*/
|
||||
public abstract class CommonContainer implements WebSocketContainer
|
||||
{
|
||||
/** Tracking all primitive decoders for the container */
|
||||
private final DecoderFactory decoderFactory;
|
||||
/** Tracking all primitive encoders for the container */
|
||||
private final EncoderFactory encoderFactory;
|
||||
|
||||
public CommonContainer()
|
||||
{
|
||||
decoderFactory = new DecoderFactory();
|
||||
encoderFactory = new EncoderFactory();
|
||||
|
||||
// ---------------------------------------
|
||||
// Register Decoder Primitives
|
||||
// ---------------------------------------
|
||||
|
||||
boolean streamed = false;
|
||||
// TEXT based - Classes Based
|
||||
MessageType msgType = MessageType.TEXT;
|
||||
decoderFactory.register(Boolean.class,BooleanDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Byte.class,ByteDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Character.class,CharacterDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Double.class,DoubleDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Float.class,FloatDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Integer.class,IntegerDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Long.class,LongDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Short.class,ShortDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(String.class,StringDecoder.class,msgType,streamed);
|
||||
|
||||
// TEXT based - Primitive Types
|
||||
msgType = MessageType.TEXT;
|
||||
decoderFactory.register(Boolean.TYPE,BooleanDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Byte.TYPE,ByteDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Character.TYPE,CharacterDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Double.TYPE,DoubleDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Float.TYPE,FloatDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Integer.TYPE,IntegerDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Long.TYPE,LongDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(Short.TYPE,ShortDecoder.class,msgType,streamed);
|
||||
|
||||
// BINARY based
|
||||
msgType = MessageType.BINARY;
|
||||
decoderFactory.register(ByteBuffer.class,ByteBufferDecoder.class,msgType,streamed);
|
||||
decoderFactory.register(byte[].class,ByteArrayDecoder.class,msgType,streamed);
|
||||
}
|
||||
|
||||
public DecoderFactory getDecoderFactory()
|
||||
{
|
||||
return decoderFactory;
|
||||
}
|
||||
|
||||
public EncoderFactory getEncoderFactory()
|
||||
{
|
||||
return encoderFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get set of open sessions.
|
||||
*
|
||||
* @return the set of open sessions
|
||||
*/
|
||||
public abstract Set<Session> getOpenSessions();
|
||||
|
||||
/**
|
||||
* Start the container
|
||||
*/
|
||||
public abstract void start();
|
||||
|
||||
/**
|
||||
* Stop the container
|
||||
*/
|
||||
public abstract void stop();
|
||||
}
|
|
@ -18,22 +18,12 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import javax.websocket.WebSocketContainer;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
/**
|
||||
* Service Interface for working with Jetty Internal Container.
|
||||
* Tag indicating a component that needs to be configured.
|
||||
*/
|
||||
public interface ContainerService extends WebSocketContainer
|
||||
public interface Configurable
|
||||
{
|
||||
public DecoderMetadataFactory getDecoderMetadataFactory();
|
||||
|
||||
/**
|
||||
* Start the service
|
||||
*/
|
||||
public void start();
|
||||
|
||||
/**
|
||||
* Stop the service
|
||||
*/
|
||||
public void stop();
|
||||
public void init(EndpointConfig config);
|
||||
}
|
|
@ -0,0 +1,246 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.ReflectUtils;
|
||||
|
||||
/**
|
||||
* Factory for {@link DecoderMetadata}
|
||||
* <p>
|
||||
* Relies on search order of parent {@link DecoderFactory} instances as such.
|
||||
* <ul>
|
||||
* <li>Endpoint declared decoders</li>
|
||||
* <li>EndpointConfig declared decoders</li>
|
||||
* <li>Container declared decoders (primitives)</li>
|
||||
* </ul>
|
||||
*/
|
||||
public class DecoderFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(DecoderFactory.class);
|
||||
/** Decoders by Type */
|
||||
private final Map<Class<?>, DecoderMetadata> typeMap;
|
||||
/** Registered Decoders at this level */
|
||||
private Map<Class<? extends Decoder>, List<DecoderMetadata>> registered;
|
||||
/** Parent Factory */
|
||||
private DecoderFactory parentFactory;
|
||||
|
||||
public DecoderFactory()
|
||||
{
|
||||
this.typeMap = new ConcurrentHashMap<>();
|
||||
this.registered = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public DecoderFactory(DecoderFactory parentFactory)
|
||||
{
|
||||
this();
|
||||
this.parentFactory = parentFactory;
|
||||
}
|
||||
|
||||
private Class<?> getDecoderMessageClass(Class<? extends Decoder> decoder, Class<?> interfaceClass)
|
||||
{
|
||||
Class<?> decoderClass = ReflectUtils.findGenericClassFor(decoder,interfaceClass);
|
||||
if (decoderClass == null)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid type declared for interface ");
|
||||
err.append(interfaceClass.getName());
|
||||
err.append(" on class ");
|
||||
err.append(decoder);
|
||||
throw new IllegalArgumentException(err.toString());
|
||||
}
|
||||
return decoderClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the list of registered decoder classes.
|
||||
* <p>
|
||||
* Includes all decoders at this level and above.
|
||||
*
|
||||
* @return the list of registered decoder classes.
|
||||
*/
|
||||
public List<Class<? extends Decoder>> getList()
|
||||
{
|
||||
List<Class<? extends Decoder>> decoders = new ArrayList<>();
|
||||
decoders.addAll(registered.keySet());
|
||||
if (parentFactory != null)
|
||||
{
|
||||
decoders.addAll(parentFactory.getList());
|
||||
}
|
||||
return decoders;
|
||||
}
|
||||
|
||||
public List<DecoderMetadata> getMetadata(Class<? extends Decoder> decoder)
|
||||
{
|
||||
LOG.debug("getMetadata({})",decoder);
|
||||
List<DecoderMetadata> ret = registered.get(decoder);
|
||||
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Not found, Try parent factory (if declared)
|
||||
if (parentFactory != null)
|
||||
{
|
||||
ret = parentFactory.registered.get(decoder);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return register(decoder);
|
||||
}
|
||||
|
||||
public DecoderMetadata getMetadataFor(Class<?> type)
|
||||
{
|
||||
DecoderMetadata metadata = typeMap.get(type);
|
||||
if (metadata == null)
|
||||
{
|
||||
if (parentFactory != null)
|
||||
{
|
||||
return parentFactory.getMetadataFor(type);
|
||||
}
|
||||
}
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public DecoderWrapper getWrapperFor(Class<?> type)
|
||||
{
|
||||
DecoderMetadata metadata = getMetadataFor(type);
|
||||
if (metadata != null)
|
||||
{
|
||||
return newWrapper(metadata);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public DecoderWrapper newWrapper(DecoderMetadata metadata)
|
||||
{
|
||||
Class<? extends Decoder> decoderClass = metadata.getDecoderClass();
|
||||
try
|
||||
{
|
||||
Decoder decoder = decoderClass.newInstance();
|
||||
return new DecoderWrapper(decoder,metadata);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new IllegalStateException("Unable to instantiate Decoder: " + decoderClass.getName());
|
||||
}
|
||||
}
|
||||
|
||||
public List<DecoderMetadata> register(Class<? extends Decoder> decoder)
|
||||
{
|
||||
List<DecoderMetadata> metadatas = new ArrayList<>();
|
||||
|
||||
if (Decoder.Binary.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.Binary.class);
|
||||
metadatas.add(new DecoderMetadata(objType,decoder,MessageType.BINARY,false));
|
||||
}
|
||||
if (Decoder.BinaryStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.BinaryStream.class);
|
||||
metadatas.add(new DecoderMetadata(objType,decoder,MessageType.BINARY,true));
|
||||
}
|
||||
if (Decoder.Text.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.Text.class);
|
||||
metadatas.add(new DecoderMetadata(objType,decoder,MessageType.TEXT,false));
|
||||
}
|
||||
if (Decoder.TextStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.TextStream.class);
|
||||
metadatas.add(new DecoderMetadata(objType,decoder,MessageType.TEXT,true));
|
||||
}
|
||||
|
||||
if (!ReflectUtils.isDefaultConstructable(decoder))
|
||||
{
|
||||
throw new InvalidSignatureException("Decoder must have public, no-args constructor: " + decoder.getName());
|
||||
}
|
||||
|
||||
if (metadatas.size() <= 0)
|
||||
{
|
||||
throw new InvalidSignatureException("Not a valid Decoder class: " + decoder.getName());
|
||||
}
|
||||
|
||||
return trackMetadata(decoder,metadatas);
|
||||
}
|
||||
|
||||
public void register(Class<?> typeClass, Class<? extends Decoder> decoderClass, MessageType msgType, boolean streamed)
|
||||
{
|
||||
List<DecoderMetadata> metadatas = new ArrayList<>();
|
||||
metadatas.add(new DecoderMetadata(typeClass,decoderClass,msgType,streamed));
|
||||
trackMetadata(decoderClass,metadatas);
|
||||
}
|
||||
|
||||
public List<DecoderMetadata> registerAll(Class<? extends Decoder>[] decoders)
|
||||
{
|
||||
List<DecoderMetadata> metadatas = new ArrayList<>();
|
||||
|
||||
for (Class<? extends Decoder> decoder : decoders)
|
||||
{
|
||||
metadatas.addAll(register(decoder));
|
||||
}
|
||||
|
||||
return metadatas;
|
||||
}
|
||||
|
||||
private List<DecoderMetadata> trackMetadata(Class<? extends Decoder> decoder, List<DecoderMetadata> metadatas)
|
||||
{
|
||||
for (DecoderMetadata metadata : metadatas)
|
||||
{
|
||||
trackType(metadata);
|
||||
}
|
||||
|
||||
LOG.debug("Registered {} with [{} entries]",decoder.getName(),metadatas.size());
|
||||
registered.put(decoder,metadatas);
|
||||
return metadatas;
|
||||
}
|
||||
|
||||
private void trackType(DecoderMetadata metadata)
|
||||
{
|
||||
Class<?> type = metadata.getObjectType();
|
||||
if (typeMap.containsKey(type))
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Duplicate decoder for type: ");
|
||||
err.append(type);
|
||||
err.append(" (class ").append(metadata.getDecoderClass().getName());
|
||||
DecoderMetadata dup = typeMap.get(type);
|
||||
err.append(" duplicates ");
|
||||
err.append(dup.getDecoderClass().getName());
|
||||
err.append(")");
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
|
||||
typeMap.put(type,metadata);
|
||||
}
|
||||
}
|
|
@ -1,168 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.BooleanDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.CharacterDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.DoubleDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.FloatDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.IntegerDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.LongDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ShortDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.StringDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.ReflectUtils;
|
||||
|
||||
/**
|
||||
* Global Factory for all declared Decoders in all endpoints.
|
||||
*/
|
||||
public class DecoderMetadataFactory
|
||||
{
|
||||
public static class DefaultsDecoderFactory extends DecoderMetadataFactory
|
||||
{
|
||||
public static final DefaultsDecoderFactory INSTANCE = new DefaultsDecoderFactory();
|
||||
|
||||
private Map<Type, Class<? extends Decoder>> typeMap = new HashMap<>();
|
||||
|
||||
public DefaultsDecoderFactory()
|
||||
{
|
||||
boolean streamed = false;
|
||||
// TEXT based - Classes
|
||||
MessageType msgType = MessageType.TEXT;
|
||||
register(Boolean.class,BooleanDecoder.class,msgType,streamed);
|
||||
register(Byte.class,ByteDecoder.class,msgType,streamed);
|
||||
register(Character.class,CharacterDecoder.class,msgType,streamed);
|
||||
register(Double.class,DoubleDecoder.class,msgType,streamed);
|
||||
register(Float.class,FloatDecoder.class,msgType,streamed);
|
||||
register(Integer.class,IntegerDecoder.class,msgType,streamed);
|
||||
register(Long.class,LongDecoder.class,msgType,streamed);
|
||||
register(Short.class,ShortDecoder.class,msgType,streamed);
|
||||
register(String.class,StringDecoder.class,msgType,streamed);
|
||||
|
||||
// TEXT based - Primitives
|
||||
msgType = MessageType.TEXT;
|
||||
register(Boolean.TYPE,BooleanDecoder.class,msgType,streamed);
|
||||
register(Byte.TYPE,ByteDecoder.class,msgType,streamed);
|
||||
register(Character.TYPE,CharacterDecoder.class,msgType,streamed);
|
||||
register(Double.TYPE,DoubleDecoder.class,msgType,streamed);
|
||||
register(Float.TYPE,FloatDecoder.class,msgType,streamed);
|
||||
register(Integer.TYPE,IntegerDecoder.class,msgType,streamed);
|
||||
register(Long.TYPE,LongDecoder.class,msgType,streamed);
|
||||
register(Short.TYPE,ShortDecoder.class,msgType,streamed);
|
||||
|
||||
// BINARY based
|
||||
msgType = MessageType.BINARY;
|
||||
register(ByteBuffer.class,ByteBufferDecoder.class,msgType,streamed);
|
||||
register(byte[].class,ByteArrayDecoder.class,msgType,streamed);
|
||||
}
|
||||
|
||||
public Class<? extends Decoder> getDecoder(Class<?> type)
|
||||
{
|
||||
return typeMap.get(type);
|
||||
}
|
||||
|
||||
private void register(Class<?> typeClass, Class<? extends Decoder> decoderClass, MessageType msgType, boolean streamed)
|
||||
{
|
||||
List<DecoderMetadata> metadatas = new ArrayList<>();
|
||||
metadatas.add(new DecoderMetadata(typeClass,decoderClass,msgType,streamed));
|
||||
cache.put(decoderClass,metadatas);
|
||||
typeMap.put(typeClass,decoderClass);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final Logger LOG = Log.getLogger(DecoderMetadataFactory.class);
|
||||
protected Map<Class<? extends Decoder>, List<DecoderMetadata>> cache = new ConcurrentHashMap<>();
|
||||
|
||||
private Class<?> getDecoderMessageClass(Class<? extends Decoder> decoder, Class<?> interfaceClass)
|
||||
{
|
||||
Class<?> decoderClass = ReflectUtils.findGenericClassFor(decoder,interfaceClass);
|
||||
if (decoderClass == null)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Invalid type declared for interface ");
|
||||
err.append(interfaceClass.getName());
|
||||
err.append(" on class ");
|
||||
err.append(decoder);
|
||||
throw new IllegalArgumentException(err.toString());
|
||||
}
|
||||
return decoderClass;
|
||||
}
|
||||
|
||||
public List<DecoderMetadata> getMetadata(Class<? extends Decoder> decoder)
|
||||
{
|
||||
LOG.debug("getDecoder({})",decoder);
|
||||
List<DecoderMetadata> ret = cache.get(decoder);
|
||||
|
||||
if (ret == null)
|
||||
{
|
||||
ret = new ArrayList<>();
|
||||
|
||||
if (Decoder.Binary.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.Binary.class);
|
||||
ret.add(new DecoderMetadata(objType,decoder,MessageType.BINARY,false));
|
||||
}
|
||||
if (Decoder.BinaryStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.BinaryStream.class);
|
||||
ret.add(new DecoderMetadata(objType,decoder,MessageType.BINARY,true));
|
||||
}
|
||||
if (Decoder.Text.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.Text.class);
|
||||
ret.add(new DecoderMetadata(objType,decoder,MessageType.TEXT,false));
|
||||
}
|
||||
if (Decoder.TextStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> objType = getDecoderMessageClass(decoder,Decoder.TextStream.class);
|
||||
ret.add(new DecoderMetadata(objType,decoder,MessageType.TEXT,true));
|
||||
}
|
||||
|
||||
if (ret.size() <= 0)
|
||||
{
|
||||
throw new InvalidSignatureException("Not a valid Decoder class: " + decoder.getName());
|
||||
}
|
||||
|
||||
LOG.debug("New Hit [{} entries]",ret.size());
|
||||
cache.put(decoder,ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG.debug("From Cache");
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
|
@ -19,11 +19,14 @@
|
|||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
|
||||
/**
|
||||
* Expose a {@link Decoder} instance along with its associated {@link DecoderMetadata}
|
||||
* Expose a configured {@link Decoder} instance along with its associated {@link DecoderMetadata}
|
||||
*/
|
||||
public class DecoderWrapper
|
||||
public class DecoderWrapper implements Configurable
|
||||
{
|
||||
private final Decoder decoder;
|
||||
private final DecoderMetadata metadata;
|
||||
|
@ -43,4 +46,10 @@ public class DecoderWrapper
|
|||
{
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
this.decoder.init(config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,187 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderMetadataFactory.DefaultsDecoderFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.MethodUtils;
|
||||
|
||||
/**
|
||||
* The collection of decoder instances declared for an Endpoint.
|
||||
* <p>
|
||||
* Decoder classes can arrive from:
|
||||
* <ul>
|
||||
* <li>{@link EndpointConfig#getDecoders()}</li>
|
||||
* <li>@ClientEndpoint.decoders()</li>
|
||||
* <li>@ServerEndpoint.decoders()</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* This class is also responsible for tracking the lifecycle of all the decoders.
|
||||
*/
|
||||
public class Decoders
|
||||
{
|
||||
private final DecoderMetadataFactory metadataFactory;
|
||||
|
||||
/**
|
||||
* Map of Object Type to Decoder
|
||||
*/
|
||||
private final Map<Class<?>, DecoderWrapper> decoderMap = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Decoder Classes from {@link EndpointConfig#getDecoders()}
|
||||
*
|
||||
* @param metadataFactory
|
||||
* the factory to create {@link DecoderMetadata} references
|
||||
* @param config
|
||||
* the endpoint config with the decoder configuration
|
||||
*
|
||||
* @throws DeploymentException
|
||||
* if unable to instantiate decoders
|
||||
*/
|
||||
public Decoders(DecoderMetadataFactory metadataFactory, EndpointConfig config) throws DeploymentException
|
||||
{
|
||||
Objects.requireNonNull(metadataFactory,"DecoderMetadataFactory cannot be null");
|
||||
this.metadataFactory = metadataFactory;
|
||||
|
||||
if (config != null)
|
||||
{
|
||||
for (Class<? extends Decoder> decoder : config.getDecoders())
|
||||
{
|
||||
try
|
||||
{
|
||||
addAllMetadata(decoder);
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
throw new DeploymentException("Invalid configuration: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void add(DecoderWrapper wrapper) throws IllegalStateException
|
||||
{
|
||||
// Check for duplicate object types
|
||||
Class<?> key = wrapper.getMetadata().getObjectType();
|
||||
if (decoderMap.containsKey(key))
|
||||
{
|
||||
DecoderWrapper other = decoderMap.get(key);
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Encountered duplicate Decoder handling type <");
|
||||
err.append(MethodUtils.toString(key));
|
||||
err.append(">, ").append(wrapper.getMetadata().getDecoder().getName());
|
||||
err.append(" and ").append(other.getMetadata().getDecoder().getName());
|
||||
err.append(" both implement this type");
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
|
||||
decoderMap.put(key,wrapper);
|
||||
}
|
||||
|
||||
private DecoderWrapper addAllMetadata(Class<? extends Decoder> decoder) throws IllegalStateException
|
||||
{
|
||||
DecoderWrapper wrapper = null;
|
||||
|
||||
for (DecoderMetadata metadata : metadataFactory.getMetadata(decoder))
|
||||
{
|
||||
Decoder decoderImpl;
|
||||
try
|
||||
{
|
||||
decoderImpl = decoder.newInstance();
|
||||
wrapper = new DecoderWrapper(decoderImpl,metadata);
|
||||
add(wrapper);
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException cause)
|
||||
{
|
||||
throw new IllegalStateException("Unable to instantiate Decoder: " + decoder.getName(),cause);
|
||||
}
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
public Decoder getDecoder(Class<?> type) throws DeploymentException
|
||||
{
|
||||
return getDecoderWrapper(type).getDecoder();
|
||||
}
|
||||
|
||||
public DecoderWrapper getDecoderWrapper(Class<?> type) throws IllegalStateException
|
||||
{
|
||||
Objects.requireNonNull(type,"Type cannot be null");
|
||||
DecoderWrapper wrapper = decoderMap.get(type);
|
||||
if (wrapper == null)
|
||||
{
|
||||
// try DEFAULT implementations
|
||||
Class<? extends Decoder> defaultDecoder = DefaultsDecoderFactory.INSTANCE.getDecoder(type);
|
||||
if (defaultDecoder == null)
|
||||
{
|
||||
throw new IllegalStateException("Unable to find decoder for type: " + type);
|
||||
}
|
||||
wrapper = addAllMetadata(defaultDecoder);
|
||||
}
|
||||
|
||||
// simple lookup, return it
|
||||
if (wrapper != null)
|
||||
{
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
// Slow mode, test isAssignable on each key
|
||||
for (Entry<Class<?>, DecoderWrapper> entry : decoderMap.entrySet())
|
||||
{
|
||||
Class<?> key = entry.getKey();
|
||||
if (key.isAssignableFrom(type))
|
||||
{
|
||||
// we found a hit, return it
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
throw new InvalidSignatureException("Unable to find appropriate Decoder for type: " + type);
|
||||
}
|
||||
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
for (DecoderWrapper decoder : decoderMap.values())
|
||||
{
|
||||
decoder.getDecoder().init(config);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<Class<?>> keySet()
|
||||
{
|
||||
return decoderMap.keySet();
|
||||
}
|
||||
|
||||
public Collection<DecoderWrapper> wrapperSet()
|
||||
{
|
||||
return decoderMap.values();
|
||||
}
|
||||
}
|
|
@ -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.jsr356;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
/**
|
||||
* Represents all of the declared {@link Encoder}s that the Container is aware of.
|
||||
*/
|
||||
public class EncoderFactory
|
||||
{
|
||||
public EncoderFactory()
|
||||
{
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public EncoderFactory(EncoderFactory encoderFactory)
|
||||
{
|
||||
// TODO Auto-generated constructor stub
|
||||
}
|
||||
|
||||
public Encoder getEncoder(Class<?> targetType)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<Class<? extends Encoder>> getList()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public void registerAll(Class<? extends Encoder>[] encoders)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadata;
|
||||
|
||||
/**
|
||||
* Expose a configured {@link Encoder} instance along with its associated {@link EncoderMetadata}
|
||||
*/
|
||||
public class EncoderWrapper implements Configurable
|
||||
{
|
||||
private final Encoder encoder;
|
||||
private final EncoderMetadata metadata;
|
||||
|
||||
public EncoderWrapper(Encoder encoder, EncoderMetadata metadata)
|
||||
{
|
||||
this.encoder = encoder;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
public Encoder getEncoder()
|
||||
{
|
||||
return encoder;
|
||||
}
|
||||
|
||||
public EncoderMetadata getMetadata()
|
||||
{
|
||||
return metadata;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
this.encoder.init(config);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
/**
|
||||
* Exception during initialization of the Endpoint
|
||||
*/
|
||||
public class InitException extends IllegalStateException
|
||||
{
|
||||
private static final long serialVersionUID = -4691138423037387558L;
|
||||
|
||||
public InitException(String s)
|
||||
{
|
||||
super(s);
|
||||
}
|
||||
|
||||
public InitException(String message, Throwable cause)
|
||||
{
|
||||
super(message,cause);
|
||||
}
|
||||
|
||||
public InitException(Throwable cause)
|
||||
{
|
||||
super(cause);
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.Extension;
|
||||
import javax.websocket.HandshakeResponse;
|
||||
|
||||
public class JettyClientEndpointConfig implements ClientEndpointConfig
|
||||
{
|
||||
public static class NoopConfigurator extends ClientEndpointConfig.Configurator
|
||||
{
|
||||
public static final NoopConfigurator INSTANCE = new NoopConfigurator();
|
||||
|
||||
@Override
|
||||
public void afterResponse(HandshakeResponse hr)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> headers)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
||||
|
||||
private Configurator configurator;
|
||||
private List<Class<? extends Decoder>> decoders;
|
||||
private List<Class<? extends Encoder>> encoders;
|
||||
private List<String> subprotocols;
|
||||
private List<Extension> extensions;
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public JettyClientEndpointConfig()
|
||||
{
|
||||
decoders = new ArrayList<>();
|
||||
encoders = new ArrayList<>();
|
||||
subprotocols = new ArrayList<>();
|
||||
extensions = new ArrayList<>();
|
||||
userProperties = new HashMap<>();
|
||||
}
|
||||
|
||||
public JettyClientEndpointConfig(ClientEndpoint anno) throws DeploymentException
|
||||
{
|
||||
this();
|
||||
addAll(anno.decoders(),this.decoders);
|
||||
addAll(anno.encoders(),this.encoders);
|
||||
addAll(anno.subprotocols(),this.subprotocols);
|
||||
// no extensions declared in annotation
|
||||
// no userProperties in annotation
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
this.configurator = NoopConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ClientEndpoint.configurator() of ");
|
||||
err.append(anno.configurator().getName());
|
||||
err.append(" defined as annotation in ");
|
||||
err.append(anno.getClass().getName());
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor
|
||||
*
|
||||
* @param copy
|
||||
* the endpoint configuration to copy
|
||||
* @throws DeploymentException
|
||||
*/
|
||||
public JettyClientEndpointConfig(JettyClientEndpointConfig copy) throws DeploymentException
|
||||
{
|
||||
this();
|
||||
this.decoders.addAll(copy.decoders);
|
||||
this.encoders.addAll(copy.encoders);
|
||||
this.subprotocols.addAll(copy.subprotocols);
|
||||
this.extensions.addAll(copy.extensions);
|
||||
this.userProperties.putAll(copy.userProperties);
|
||||
if (copy.configurator instanceof NoopConfigurator)
|
||||
{
|
||||
this.configurator = NoopConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Class<? extends Configurator> configuratorClass = copy.configurator.getClass();
|
||||
try
|
||||
{
|
||||
this.configurator = configuratorClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ClientEndpointConfig.Configurator of ");
|
||||
err.append(configuratorClass);
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void addAll(T[] arr, List<T> lst)
|
||||
{
|
||||
if (arr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (T t : arr)
|
||||
{
|
||||
lst.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator()
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders()
|
||||
{
|
||||
return encoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPreferredSubprotocols()
|
||||
{
|
||||
return subprotocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
}
|
|
@ -27,19 +27,17 @@ import javax.websocket.SendHandler;
|
|||
|
||||
public class JsrAsyncRemote implements RemoteEndpoint.Async
|
||||
{
|
||||
|
||||
private final org.eclipse.jetty.websocket.api.RemoteEndpoint jettyRemote;
|
||||
|
||||
protected JsrAsyncRemote(org.eclipse.jetty.websocket.api.RemoteEndpoint endpoint)
|
||||
protected JsrAsyncRemote(JsrSession session)
|
||||
{
|
||||
this.jettyRemote = endpoint;
|
||||
this.jettyRemote = session.getRemote();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void flushBatch() throws IOException
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,8 +63,8 @@ public class JsrAsyncRemote implements RemoteEndpoint.Async
|
|||
@Override
|
||||
public void sendBinary(ByteBuffer data, SendHandler handler)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
// TODO: wrap the send handler?
|
||||
jettyRemote.sendBytesByFuture(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -19,16 +19,20 @@
|
|||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.URI;
|
||||
import java.security.Principal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Extension;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.RemoteEndpoint.Async;
|
||||
|
@ -36,36 +40,107 @@ import javax.websocket.RemoteEndpoint.Basic;
|
|||
import javax.websocket.Session;
|
||||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.AbstractJsrEventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
|
||||
|
||||
public class JsrSession extends WebSocketSession implements javax.websocket.Session
|
||||
public class JsrSession extends WebSocketSession implements javax.websocket.Session, Configurable
|
||||
{
|
||||
private final ClientContainer container;
|
||||
private static final Logger LOG = Log.getLogger(JsrSession.class);
|
||||
private final CommonContainer container;
|
||||
private final String id;
|
||||
private final EndpointConfig config;
|
||||
/** Factory for Decoders */
|
||||
private final DecoderFactory decoderFactory;
|
||||
private Map<Type, DecoderWrapper> activeDecoders;
|
||||
/** Factory for Encoders */
|
||||
private final EncoderFactory encoderFactory;
|
||||
private Map<Type, EncoderWrapper> activeEncoders;
|
||||
/** Factory for MessageHandlers */
|
||||
private final MessageHandlerFactory messageHandlerFactory;
|
||||
/** Array of MessageHandlerWrappers, indexed by {@link MessageType#ordinal()} */
|
||||
private final MessageHandlerWrapper wrappers[];
|
||||
private Set<MessageHandler> messageHandlerSet;
|
||||
private List<Extension> negotiatedExtensions;
|
||||
private Map<String, List<String>> jsrParameterMap;
|
||||
private Map<String, String> pathParameters = new HashMap<>();
|
||||
private Map<String, Object> userProperties;
|
||||
private Decoders decoders;
|
||||
private MessageHandlers messageHandlers;
|
||||
private JsrAsyncRemote asyncRemote;
|
||||
private JsrBasicRemote basicRemote;
|
||||
|
||||
public JsrSession(URI requestURI, EventDriver websocket, LogicalConnection connection, ClientContainer container, String id)
|
||||
{
|
||||
super(requestURI,websocket,connection);
|
||||
if (websocket instanceof AbstractJsrEventDriver)
|
||||
{
|
||||
this.config = ((AbstractJsrEventDriver)websocket).getConfig();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.config = new BasicEndpointConfig();
|
||||
}
|
||||
this.container = container;
|
||||
this.id = id;
|
||||
this.decoderFactory = new DecoderFactory(container.getDecoderFactory());
|
||||
this.encoderFactory = new EncoderFactory(container.getEncoderFactory());
|
||||
this.activeDecoders = new HashMap<>();
|
||||
this.activeEncoders = new HashMap<>();
|
||||
this.messageHandlerFactory = new MessageHandlerFactory();
|
||||
this.wrappers = new MessageHandlerWrapper[MessageType.values().length];
|
||||
this.messageHandlerSet = new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addMessageHandler(MessageHandler listener) throws IllegalStateException
|
||||
public void addMessageHandler(MessageHandler handler) throws IllegalStateException
|
||||
{
|
||||
this.messageHandlers.add(listener);
|
||||
Objects.requireNonNull(handler,"MessageHandler cannot be null");
|
||||
|
||||
synchronized (wrappers)
|
||||
{
|
||||
for (MessageHandlerMetadata metadata : messageHandlerFactory.getMetadata(handler.getClass()))
|
||||
{
|
||||
DecoderWrapper decoder = decoderFactory.getWrapperFor(metadata.getMessageClass());
|
||||
MessageType key = decoder.getMetadata().getMessageType();
|
||||
MessageHandlerWrapper other = wrappers[key.ordinal()];
|
||||
if (other != null)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Encountered duplicate MessageHandler handling message type <");
|
||||
err.append(key.name());
|
||||
err.append(">, ").append(metadata.getHandlerClass().getName());
|
||||
err.append("<");
|
||||
err.append(metadata.getMessageClass().getName());
|
||||
err.append("> and ");
|
||||
err.append(other.getMetadata().getHandlerClass().getName());
|
||||
err.append("<");
|
||||
err.append(other.getMetadata().getMessageClass().getName());
|
||||
err.append("> both implement this message type");
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageHandlerWrapper wrapper = new MessageHandlerWrapper(handler,metadata,decoder);
|
||||
wrappers[key.ordinal()] = wrapper;
|
||||
}
|
||||
}
|
||||
|
||||
// Update handlerSet
|
||||
messageHandlerSet.clear();
|
||||
for (MessageHandlerWrapper wrapper : wrappers)
|
||||
{
|
||||
if (wrapper == null)
|
||||
{
|
||||
// skip empty
|
||||
continue;
|
||||
}
|
||||
messageHandlerSet.add(wrapper.getHandler());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -79,7 +154,7 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
{
|
||||
if (asyncRemote == null)
|
||||
{
|
||||
asyncRemote = new JsrAsyncRemote(getRemote());
|
||||
asyncRemote = new JsrAsyncRemote(this);
|
||||
}
|
||||
return asyncRemote;
|
||||
}
|
||||
|
@ -100,9 +175,14 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
return this.container;
|
||||
}
|
||||
|
||||
public Decoders getDecodersFacade()
|
||||
public DecoderFactory getDecoderFactory()
|
||||
{
|
||||
return this.decoders;
|
||||
return decoderFactory;
|
||||
}
|
||||
|
||||
public EncoderFactory getEncoderFactory()
|
||||
{
|
||||
return encoderFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -129,20 +209,23 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
return getPolicy().getMaxTextMessageSize();
|
||||
}
|
||||
|
||||
public MessageHandlers getMessageHandlerFacade()
|
||||
public MessageHandlerFactory getMessageHandlerFactory()
|
||||
{
|
||||
return messageHandlers;
|
||||
return messageHandlerFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<MessageHandler> getMessageHandlers()
|
||||
{
|
||||
return messageHandlers.getUnmodifiableHandlerSet();
|
||||
return Collections.unmodifiableSet(messageHandlerSet);
|
||||
}
|
||||
|
||||
public MessageHandlerWrapper getMessageHandlerWrapper(MessageType msgType)
|
||||
public MessageHandlerWrapper getMessageHandlerWrapper(MessageType type)
|
||||
{
|
||||
return messageHandlers.getWrapper(msgType);
|
||||
synchronized (wrappers)
|
||||
{
|
||||
return wrappers[type.ordinal()];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -211,18 +294,50 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
return config.getUserProperties();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig endpointconfig)
|
||||
{
|
||||
// Initialize encoders
|
||||
for (EncoderWrapper wrapper : activeEncoders.values())
|
||||
{
|
||||
wrapper.getEncoder().init(config);
|
||||
}
|
||||
|
||||
// Initialize decoders
|
||||
for (DecoderWrapper wrapper : activeDecoders.values())
|
||||
{
|
||||
wrapper.getDecoder().init(config);
|
||||
}
|
||||
|
||||
// Init message handlers
|
||||
for (MessageHandlerWrapper wrapper : wrappers)
|
||||
{
|
||||
if (wrapper != null)
|
||||
{
|
||||
// TODO wrapper.init(config);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessageHandler(MessageHandler handler)
|
||||
{
|
||||
messageHandlers.remove(handler);
|
||||
}
|
||||
|
||||
public void setDecodersFacade(Decoders decoders)
|
||||
{
|
||||
this.decoders = decoders;
|
||||
try
|
||||
{
|
||||
for (MessageHandlerMetadata metadata : messageHandlerFactory.getMetadata(handler.getClass()))
|
||||
{
|
||||
DecoderMetadata decoder = decoderFactory.getMetadataFor(metadata.getMessageClass());
|
||||
MessageType key = decoder.getMessageType();
|
||||
wrappers[key.ordinal()] = null;
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOG.warn("Unable to identify MessageHandler: " + handler.getClass().getName(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -242,9 +357,4 @@ public class JsrSession extends WebSocketSession implements javax.websocket.Sess
|
|||
{
|
||||
getPolicy().setMaxTextMessageBufferSize(length);
|
||||
}
|
||||
|
||||
public void setMessageHandlerFacade(MessageHandlers messageHandlers)
|
||||
{
|
||||
this.messageHandlers = messageHandlers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,69 +16,71 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.messages;
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import javax.websocket.MessageHandler;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.Decoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.ReflectUtils;
|
||||
|
||||
/**
|
||||
* Creates {@link MessageHandlerMetadata} objects from a provided {@link MessageHandler} classes.
|
||||
* Factory for {@link MessageHandlerMetadata}
|
||||
*/
|
||||
public class MessageHandlerMetadataFactory
|
||||
public class MessageHandlerFactory
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MessageHandlerMetadataFactory.class);
|
||||
private final Decoders decoders;
|
||||
private static final Logger LOG = Log.getLogger(MessageHandlerFactory.class);
|
||||
/** Registered MessageHandlers at this level */
|
||||
private Map<Class<? extends MessageHandler>, List<MessageHandlerMetadata>> registered;
|
||||
|
||||
public MessageHandlerMetadataFactory(Decoders decoders)
|
||||
public MessageHandlerFactory()
|
||||
{
|
||||
this.decoders = decoders;
|
||||
}
|
||||
|
||||
public DecoderWrapper getDecoderWrapper(Class<?> onMessageClass)
|
||||
{
|
||||
return decoders.getDecoderWrapper(onMessageClass);
|
||||
registered = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
public List<MessageHandlerMetadata> getMetadata(Class<? extends MessageHandler> handler) throws IllegalStateException
|
||||
{
|
||||
List<MessageHandlerMetadata> ret = new ArrayList<>();
|
||||
LOG.debug("getMetadata({})",handler);
|
||||
List<MessageHandlerMetadata> ret = registered.get(handler);
|
||||
if (ret != null)
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
return register(handler);
|
||||
}
|
||||
|
||||
public List<MessageHandlerMetadata> register(Class<? extends MessageHandler> handler)
|
||||
{
|
||||
List<MessageHandlerMetadata> metadatas = new ArrayList<>();
|
||||
|
||||
boolean partial = false;
|
||||
|
||||
if (MessageHandler.Partial.class.isAssignableFrom(handler))
|
||||
{
|
||||
LOG.debug("supports Partial: {}",handler);
|
||||
partial = true;
|
||||
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handler,MessageHandler.Partial.class);
|
||||
LOG.debug("Partial message class: {}",onMessageClass);
|
||||
MessageType onMessageType = identifyMessageType(onMessageClass);
|
||||
LOG.debug("Partial message type: {}",onMessageType);
|
||||
ret.add(new MessageHandlerMetadata(handler,onMessageType,onMessageClass,partial));
|
||||
metadatas.add(new MessageHandlerMetadata(handler,onMessageClass,partial));
|
||||
}
|
||||
|
||||
if (MessageHandler.Whole.class.isAssignableFrom(handler))
|
||||
{
|
||||
LOG.debug("supports Whole: {}",handler.getName());
|
||||
partial = false;
|
||||
Class<?> onMessageClass = ReflectUtils.findGenericClassFor(handler,MessageHandler.Whole.class);
|
||||
LOG.debug("Whole message class: {}",onMessageClass);
|
||||
MessageType onMessageType = identifyMessageType(onMessageClass);
|
||||
LOG.debug("Whole message type: {}",onMessageType);
|
||||
MessageHandlerMetadata metadata = new MessageHandlerMetadata(handler,onMessageType,onMessageClass,partial);
|
||||
ret.add(metadata);
|
||||
metadatas.add(new MessageHandlerMetadata(handler,onMessageClass,partial));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private MessageType identifyMessageType(Class<?> onMessageClass) throws IllegalStateException
|
||||
{
|
||||
DecoderWrapper wrapper = getDecoderWrapper(onMessageClass);
|
||||
return wrapper.getMetadata().getMessageType();
|
||||
registered.put(handler,metadatas);
|
||||
return metadatas;
|
||||
}
|
||||
}
|
|
@ -16,15 +16,17 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.messages;
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.MessageHandler.Partial;
|
||||
import javax.websocket.MessageHandler.Whole;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
|
||||
|
||||
/**
|
||||
* Expose a {@link MessageHandler} instance along with its associated {@link MessageHandlerMetadata}
|
||||
* Expose a {@link MessageHandler} instance along with its associated {@link MessageHandlerMetadata} and {@link DecoderWrapper}
|
||||
*/
|
||||
public class MessageHandlerWrapper
|
||||
{
|
|
@ -1,130 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.websocket.MessageHandler;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadataFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerWrapper;
|
||||
|
||||
/**
|
||||
* Facade around {@link MessageHandlerMetadataFactory} with {@link MessageType} tracking and enforced JSR-356 PFD1 rules and limits around websocket message
|
||||
* type
|
||||
*/
|
||||
public class MessageHandlers
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(MessageHandlers.class);
|
||||
|
||||
/**
|
||||
* Factory for MessageHandlerMetadata instances.
|
||||
*/
|
||||
private final MessageHandlerMetadataFactory factory;
|
||||
/**
|
||||
* Array of MessageHandlerWrappers, indexed by {@link MessageType#ordinal()}
|
||||
*/
|
||||
private final MessageHandlerWrapper wrappers[];
|
||||
|
||||
public MessageHandlers(MessageHandlerMetadataFactory factory)
|
||||
{
|
||||
Objects.requireNonNull(factory,"MessageHandlerMetadataFactory cannot be null");
|
||||
this.factory = factory;
|
||||
this.wrappers = new MessageHandlerWrapper[MessageType.values().length];
|
||||
}
|
||||
|
||||
public void add(MessageHandler handler)
|
||||
{
|
||||
Objects.requireNonNull(handler,"MessageHandler cannot be null");
|
||||
|
||||
synchronized (wrappers)
|
||||
{
|
||||
for (MessageHandlerMetadata metadata : factory.getMetadata(handler.getClass()))
|
||||
{
|
||||
MessageType key = metadata.getMessageType();
|
||||
MessageHandlerWrapper other = wrappers[key.ordinal()];
|
||||
if (other != null)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Encountered duplicate MessageHandler handling message type <");
|
||||
err.append(metadata.getMessageType().name());
|
||||
err.append(">, ").append(metadata.getHandlerClass().getName());
|
||||
err.append("<");
|
||||
err.append(metadata.getMessageClass().getName());
|
||||
err.append("> and ");
|
||||
err.append(other.getMetadata().getHandlerClass().getName());
|
||||
err.append("<");
|
||||
err.append(other.getMetadata().getMessageClass().getName());
|
||||
err.append("> both implement this message type");
|
||||
throw new IllegalStateException(err.toString());
|
||||
}
|
||||
else
|
||||
{
|
||||
DecoderWrapper decoder = factory.getDecoderWrapper(metadata.getMessageClass());
|
||||
MessageHandlerWrapper wrapper = new MessageHandlerWrapper(handler,metadata,decoder);
|
||||
wrappers[key.ordinal()] = wrapper;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Set<MessageHandler> getUnmodifiableHandlerSet()
|
||||
{
|
||||
Set<MessageHandler> ret = new HashSet<>();
|
||||
for (MessageHandlerWrapper wrapper : wrappers)
|
||||
{
|
||||
if (wrapper == null)
|
||||
{
|
||||
// skip empty
|
||||
continue;
|
||||
}
|
||||
ret.add(wrapper.getHandler());
|
||||
}
|
||||
return Collections.unmodifiableSet(ret);
|
||||
}
|
||||
|
||||
public MessageHandlerWrapper getWrapper(MessageType msgType)
|
||||
{
|
||||
synchronized (wrappers)
|
||||
{
|
||||
return wrappers[msgType.ordinal()];
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(MessageHandler handler)
|
||||
{
|
||||
try
|
||||
{
|
||||
for (MessageHandlerMetadata metadata : factory.getMetadata(handler.getClass()))
|
||||
{
|
||||
wrappers[metadata.getMessageType().ordinal()] = null;
|
||||
}
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
LOG.warn("Unable to identify MessageHandler: " + handler.getClass().getName(),e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -124,7 +124,7 @@ public class AnnotatedEndpointScanner extends AbstractMethodAnnotationScanner<Js
|
|||
if (isAnnotation(annotation,OnMessage.class))
|
||||
{
|
||||
assertIsPublicNonStatic(method);
|
||||
assertIsReturn(method,Void.TYPE);
|
||||
// assertIsReturn(method,Void.TYPE); // no validation, it can be any return type
|
||||
OnMessageCallable onmessage = new OnMessageCallable(pojo,method);
|
||||
visitMethod(onmessage,pojo,method,paramsOnMessage,OnMessage.class);
|
||||
|
||||
|
@ -187,6 +187,7 @@ public class AnnotatedEndpointScanner extends AbstractMethodAnnotationScanner<Js
|
|||
{
|
||||
for (IJsrParamId paramId : paramIds)
|
||||
{
|
||||
LOG.debug("{}.process()",paramId);
|
||||
if (paramId.process(param,callable))
|
||||
{
|
||||
// Successfully identified
|
||||
|
|
|
@ -22,9 +22,9 @@ import java.lang.reflect.Method;
|
|||
import java.util.Map;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.CallableMethod;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
public abstract class JsrCallable extends CallableMethod
|
||||
|
@ -32,8 +32,6 @@ public abstract class JsrCallable extends CallableMethod
|
|||
protected final Param[] params;
|
||||
protected final Object[] args;
|
||||
protected int idxSession = -1;
|
||||
// Optional decoder (used for OnMessage)
|
||||
protected Decoder decoder;
|
||||
|
||||
public JsrCallable(Class<?> pojo, Method method)
|
||||
{
|
||||
|
@ -56,7 +54,6 @@ public abstract class JsrCallable extends CallableMethod
|
|||
public JsrCallable(JsrCallable copy)
|
||||
{
|
||||
this(copy.getPojo(),copy.getMethod());
|
||||
this.decoder = copy.decoder;
|
||||
this.idxSession = copy.idxSession;
|
||||
System.arraycopy(copy.params,0,this.params,0,params.length);
|
||||
System.arraycopy(copy.args,0,this.args,0,args.length);
|
||||
|
@ -98,17 +95,12 @@ public abstract class JsrCallable extends CallableMethod
|
|||
return null;
|
||||
}
|
||||
|
||||
public Decoder getDecoder()
|
||||
{
|
||||
return decoder;
|
||||
}
|
||||
|
||||
public Param[] getParams()
|
||||
{
|
||||
return params;
|
||||
}
|
||||
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
// Default the session.
|
||||
// Session is an optional parameter (always)
|
||||
|
@ -135,8 +127,5 @@ public abstract class JsrCallable extends CallableMethod
|
|||
}
|
||||
}
|
||||
|
||||
public void setDecoder(Decoder decoder)
|
||||
{
|
||||
this.decoder = decoder;
|
||||
}
|
||||
public abstract void setDecoderClass(Class<? extends Decoder> decoderClass);
|
||||
}
|
||||
|
|
|
@ -22,17 +22,17 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.RemoteEndpoint;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
|
||||
/**
|
||||
* The live event methods found for a specific Annotated Endpoint
|
||||
|
@ -94,25 +94,35 @@ public class JsrEvents
|
|||
this.onPong = (metadata.onPong == null)?null:new OnMessagePongCallable(metadata.onPong);
|
||||
}
|
||||
|
||||
public void callBinary(Object websocket, ByteBuffer buf, boolean fin) throws DecodeException
|
||||
public void callBinary(RemoteEndpoint.Async endpoint, Object websocket, ByteBuffer buf, boolean fin) throws DecodeException
|
||||
{
|
||||
if (onBinary == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
onBinary.call(websocket,buf,fin);
|
||||
|
||||
Object ret = onBinary.call(websocket,buf,fin);
|
||||
if (ret != null)
|
||||
{
|
||||
endpoint.sendObject(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void callBinaryStream(Object websocket, InputStream stream) throws DecodeException, IOException
|
||||
public void callBinaryStream(RemoteEndpoint.Async endpoint, Object websocket, InputStream stream) throws DecodeException, IOException
|
||||
{
|
||||
if (onBinaryStream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
onBinaryStream.call(websocket,stream);
|
||||
|
||||
Object ret = onBinaryStream.call(websocket,stream);
|
||||
if (ret != null)
|
||||
{
|
||||
endpoint.sendObject(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void callClose(Object websocket, CloseInfo close)
|
||||
public void callClose(Object websocket, CloseReason close)
|
||||
{
|
||||
if (onClose == null)
|
||||
{
|
||||
|
@ -139,22 +149,35 @@ public class JsrEvents
|
|||
onOpen.call(websocket,config);
|
||||
}
|
||||
|
||||
public void callText(Object websocket, String text, boolean fin) throws DecodeException
|
||||
public void callText(RemoteEndpoint.Async endpoint, Object websocket, String text, boolean fin) throws DecodeException
|
||||
{
|
||||
if (onText == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
onText.call(websocket,text,fin);
|
||||
Object ret = onText.call(websocket,text,fin);
|
||||
if (ret != null)
|
||||
{
|
||||
endpoint.sendObject(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public void callTextStream(Object websocket, Reader reader) throws DecodeException, IOException
|
||||
public void callTextStream(RemoteEndpoint.Async endpoint, Object websocket, Reader reader) throws DecodeException, IOException
|
||||
{
|
||||
if (onTextStream == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
onTextStream.call(websocket,reader);
|
||||
Object ret = onTextStream.call(websocket,reader);
|
||||
if (ret != null)
|
||||
{
|
||||
endpoint.sendObject(ret);
|
||||
}
|
||||
}
|
||||
|
||||
public JsrMetadata<?> getMetadata()
|
||||
{
|
||||
return metadata;
|
||||
}
|
||||
|
||||
public boolean hasBinary()
|
||||
|
@ -177,10 +200,8 @@ public class JsrEvents
|
|||
return (onTextStream != null);
|
||||
}
|
||||
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
Map<String, String> pathParams = session.getPathParameters();
|
||||
|
||||
if (onOpen != null)
|
||||
{
|
||||
onOpen.init(session);
|
||||
|
|
|
@ -20,12 +20,16 @@ package org.eclipse.jetty.websocket.jsr356.annotations;
|
|||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.ReflectUtils;
|
||||
|
||||
/**
|
||||
* Static reference to a specific annotated classes metadata.
|
||||
*
|
||||
|
@ -96,7 +100,38 @@ public abstract class JsrMetadata<T extends Annotation>
|
|||
|
||||
public void customizeParamsOnMessage(LinkedList<IJsrParamId> params)
|
||||
{
|
||||
/* do nothing */
|
||||
for (Class<? extends Decoder> decoder : getConfiguredDecoders())
|
||||
{
|
||||
if (Decoder.Text.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> type = ReflectUtils.findGenericClassFor(decoder,Decoder.Text.class);
|
||||
params.add(new JsrParamIdTextDecoder(decoder,type));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Decoder.TextStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> type = ReflectUtils.findGenericClassFor(decoder,Decoder.TextStream.class);
|
||||
params.add(new JsrParamIdTextDecoder(decoder,type));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Decoder.Binary.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> type = ReflectUtils.findGenericClassFor(decoder,Decoder.Binary.class);
|
||||
params.add(new JsrParamIdBinaryDecoder(decoder,type));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Decoder.BinaryStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
Class<?> type = ReflectUtils.findGenericClassFor(decoder,Decoder.BinaryStream.class);
|
||||
params.add(new JsrParamIdBinaryDecoder(decoder,type));
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Invalid Decoder: " + decoder);
|
||||
}
|
||||
}
|
||||
|
||||
public void customizeParamsOnOpen(LinkedList<IJsrParamId> params)
|
||||
|
@ -105,4 +140,6 @@ public abstract class JsrMetadata<T extends Annotation>
|
|||
}
|
||||
|
||||
public abstract T getAnnotation();
|
||||
|
||||
protected abstract List<Class<? extends Decoder>> getConfiguredDecoders();
|
||||
}
|
||||
|
|
|
@ -48,14 +48,14 @@ public class JsrParamIdBinary extends JsrParamIdOnMessage implements IJsrParamId
|
|||
if (param.type.isAssignableFrom(ByteBuffer.class))
|
||||
{
|
||||
param.bind(Role.MESSAGE_BINARY);
|
||||
callable.setDecoder(ByteBufferDecoder.INSTANCE);
|
||||
callable.setDecoderClass(ByteBufferDecoder.class);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (param.type.isAssignableFrom(byte[].class))
|
||||
{
|
||||
param.bind(Role.MESSAGE_BINARY);
|
||||
callable.setDecoder(ByteArrayDecoder.INSTANCE);
|
||||
callable.setDecoderClass(ByteArrayDecoder.class);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import javax.websocket.Decoder;
|
|||
import javax.websocket.OnMessage;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -30,12 +29,13 @@ import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
|||
*/
|
||||
public class JsrParamIdBinaryDecoder extends JsrParamIdOnMessage implements IJsrParamId
|
||||
{
|
||||
private final DecoderWrapper ref;
|
||||
private Class<?> supportedType;
|
||||
private final Class<? extends Decoder> decoder;
|
||||
private final Class<?> supportedType;
|
||||
|
||||
public JsrParamIdBinaryDecoder(DecoderWrapper ref)
|
||||
public JsrParamIdBinaryDecoder(Class<? extends Decoder> decoder, Class<?> supportedType)
|
||||
{
|
||||
this.ref = ref;
|
||||
this.decoder = decoder;
|
||||
this.supportedType = supportedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,7 +45,7 @@ public class JsrParamIdBinaryDecoder extends JsrParamIdOnMessage implements IJsr
|
|||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_BINARY);
|
||||
callable.setDecoder(ref.getDecoder());
|
||||
callable.setDecoderClass(decoder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -43,7 +43,7 @@ public class JsrParamIdPong extends JsrParamIdOnMessage implements IJsrParamId
|
|||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_PONG);
|
||||
callable.setDecoder(new PongMessageDecoder());
|
||||
callable.setDecoderClass(PongMessageDecoder.class);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -54,7 +54,7 @@ public class JsrParamIdText extends JsrParamIdOnMessage implements IJsrParamId
|
|||
if (param.type.isAssignableFrom(String.class))
|
||||
{
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(StringDecoder.INSTANCE);
|
||||
callable.setDecoderClass(StringDecoder.class);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -63,56 +63,56 @@ public class JsrParamIdText extends JsrParamIdOnMessage implements IJsrParamId
|
|||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(BooleanDecoder.INSTANCE);
|
||||
callable.setDecoderClass(BooleanDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Byte.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(ByteDecoder.INSTANCE);
|
||||
callable.setDecoderClass(ByteDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Character.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(CharacterDecoder.INSTANCE);
|
||||
callable.setDecoderClass(CharacterDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Double.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(DoubleDecoder.INSTANCE);
|
||||
callable.setDecoderClass(DoubleDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Float.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(FloatDecoder.INSTANCE);
|
||||
callable.setDecoderClass(FloatDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Integer.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(IntegerDecoder.INSTANCE);
|
||||
callable.setDecoderClass(IntegerDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Long.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(LongDecoder.INSTANCE);
|
||||
callable.setDecoderClass(LongDecoder.class);
|
||||
return true;
|
||||
}
|
||||
if (param.type.isAssignableFrom(Short.class))
|
||||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT);
|
||||
callable.setDecoder(ShortDecoder.INSTANCE);
|
||||
callable.setDecoderClass(ShortDecoder.class);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ import javax.websocket.Decoder;
|
|||
import javax.websocket.OnMessage;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -30,13 +29,13 @@ import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
|||
*/
|
||||
public class JsrParamIdTextDecoder extends JsrParamIdOnMessage implements IJsrParamId
|
||||
{
|
||||
private final DecoderWrapper ref;
|
||||
private Class<?> supportedType;
|
||||
private final Class<? extends Decoder> decoder;
|
||||
private final Class<?> supportedType;
|
||||
|
||||
public JsrParamIdTextDecoder(DecoderWrapper ref)
|
||||
public JsrParamIdTextDecoder(Class<? extends Decoder> decoder, Class<?> supportedType)
|
||||
{
|
||||
this.ref = ref;
|
||||
this.supportedType = ref.getMetadata().getObjectType();
|
||||
this.decoder = decoder;
|
||||
this.supportedType = supportedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -46,7 +45,7 @@ public class JsrParamIdTextDecoder extends JsrParamIdOnMessage implements IJsrPa
|
|||
{
|
||||
assertPartialMessageSupportDisabled(param,callable);
|
||||
param.bind(Role.MESSAGE_TEXT_STREAM); // TODO: is this sane? for Text & TextStream ?
|
||||
callable.setDecoder(ref.getDecoder());
|
||||
callable.setDecoderClass(decoder);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -22,10 +22,11 @@ import java.lang.reflect.Method;
|
|||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCodes;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnClose;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.CloseInfo;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -64,9 +65,15 @@ public class OnCloseCallable extends JsrCallable
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxCloseReason = findIndexForRole(Role.CLOSE_REASON);
|
||||
super.init(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDecoderClass(Class<? extends Decoder> decoderClass)
|
||||
{
|
||||
/* ignore, not relevant for onClose */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,10 @@ package org.eclipse.jetty.websocket.jsr356.annotations;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnError;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
|
||||
/**
|
||||
* Callable for {@link OnError} annotated methods
|
||||
|
@ -49,9 +51,16 @@ public class OnErrorCallable extends JsrCallable
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxThrowable = findIndexForRole(Param.Role.ERROR_CAUSE);
|
||||
super.init(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDecoderClass(Class<? extends Decoder> decoderClass)
|
||||
{
|
||||
/* ignore, not relevant for onClose */
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ import java.nio.ByteBuffer;
|
|||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -52,23 +52,23 @@ public class OnMessageBinaryCallable extends OnMessageCallable
|
|||
super(copy);
|
||||
}
|
||||
|
||||
public void call(Object endpoint, ByteBuffer buf, boolean partialFlag) throws DecodeException
|
||||
public Object call(Object endpoint, ByteBuffer buf, boolean partialFlag) throws DecodeException
|
||||
{
|
||||
super.args[idxMessageObject] = binaryDecoder.decode(buf);
|
||||
if (idxPartialMessageFlag >= 0)
|
||||
{
|
||||
super.args[idxPartialMessageFlag] = partialFlag;
|
||||
}
|
||||
super.call(endpoint,super.args);
|
||||
return super.call(endpoint,super.args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxMessageObject = findIndexForRole(Role.MESSAGE_BINARY);
|
||||
assertRoleRequired(idxMessageObject,"Binary Message Object");
|
||||
super.init(session);
|
||||
assertDecoderRequired();
|
||||
binaryDecoder = (Decoder.Binary<?>)getDecoder();
|
||||
super.init(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.lang.reflect.Method;
|
|||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -51,19 +51,19 @@ public class OnMessageBinaryStreamCallable extends OnMessageCallable
|
|||
super(copy);
|
||||
}
|
||||
|
||||
public void call(Object endpoint, InputStream stream) throws DecodeException, IOException
|
||||
public Object call(Object endpoint, InputStream stream) throws DecodeException, IOException
|
||||
{
|
||||
super.args[idxMessageObject] = binaryDecoder.decode(stream);
|
||||
super.call(endpoint,super.args);
|
||||
return super.call(endpoint,super.args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxMessageObject = findIndexForRole(Role.MESSAGE_BINARY_STREAM);
|
||||
assertRoleRequired(idxMessageObject,"Binary InputStream Message Object");
|
||||
super.init(session);
|
||||
assertDecoderRequired();
|
||||
binaryDecoder = (Decoder.BinaryStream<?>)getDecoder();
|
||||
super.init(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,12 +21,19 @@ package org.eclipse.jetty.websocket.jsr356.annotations;
|
|||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.InitException;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.MethodUtils;
|
||||
|
||||
public class OnMessageCallable extends JsrCallable
|
||||
{
|
||||
protected final Class<?> returnType;
|
||||
protected Encoder returnEncoder;
|
||||
protected Class<? extends Decoder> decoderClass;
|
||||
protected Decoder decoder;
|
||||
protected int idxPartialMessageFlag = -1;
|
||||
protected int idxMessageObject = -1;
|
||||
protected Param.Role messageRole;
|
||||
|
@ -34,11 +41,15 @@ public class OnMessageCallable extends JsrCallable
|
|||
public OnMessageCallable(Class<?> pojo, Method method)
|
||||
{
|
||||
super(pojo,method);
|
||||
this.returnType = method.getReturnType();
|
||||
}
|
||||
|
||||
public OnMessageCallable(OnMessageCallable copy)
|
||||
{
|
||||
super(copy);
|
||||
this.returnType = copy.returnType;
|
||||
this.decoderClass = copy.decoderClass;
|
||||
this.decoder = copy.decoder;
|
||||
this.idxPartialMessageFlag = copy.idxPartialMessageFlag;
|
||||
this.idxMessageObject = copy.idxMessageObject;
|
||||
this.messageRole = copy.messageRole;
|
||||
|
@ -88,6 +99,16 @@ public class OnMessageCallable extends JsrCallable
|
|||
return -1;
|
||||
}
|
||||
|
||||
public Decoder getDecoder()
|
||||
{
|
||||
return decoder;
|
||||
}
|
||||
|
||||
public Class<? extends Decoder> getDecoderClass()
|
||||
{
|
||||
return decoderClass;
|
||||
}
|
||||
|
||||
public Param getMessageObjectParam()
|
||||
{
|
||||
if (idxMessageObject < 0)
|
||||
|
@ -105,11 +126,46 @@ public class OnMessageCallable extends JsrCallable
|
|||
return super.params[idxMessageObject];
|
||||
}
|
||||
|
||||
public Encoder getReturnEncoder()
|
||||
{
|
||||
return returnEncoder;
|
||||
}
|
||||
|
||||
public Class<?> getReturnType()
|
||||
{
|
||||
return returnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
super.init(session);
|
||||
this.returnEncoder = session.getEncoderFactory().getEncoder(returnType);
|
||||
|
||||
if (decoderClass != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.decoder = decoderClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
throw new InitException("Unable to create decoder: " + decoderClass.getName(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPartialMessageSupported()
|
||||
{
|
||||
return (idxPartialMessageFlag >= 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDecoderClass(Class<? extends Decoder> decoderClass)
|
||||
{
|
||||
this.decoderClass = decoderClass;
|
||||
}
|
||||
|
||||
public void setPartialMessageFlag(Param param)
|
||||
{
|
||||
idxPartialMessageFlag = param.index;
|
||||
|
|
|
@ -24,9 +24,9 @@ import java.nio.ByteBuffer;
|
|||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.PongMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrPongMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -47,14 +47,14 @@ public class OnMessagePongCallable extends OnMessageCallable
|
|||
super(copy);
|
||||
}
|
||||
|
||||
public void call(Object endpoint, ByteBuffer buf) throws DecodeException
|
||||
public Object call(Object endpoint, ByteBuffer buf) throws DecodeException
|
||||
{
|
||||
super.args[idxMessageObject] = new JsrPongMessage(buf);
|
||||
super.call(endpoint,super.args);
|
||||
return super.call(endpoint,super.args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxMessageObject = findIndexForRole(Role.MESSAGE_PONG);
|
||||
assertRoleRequired(idxMessageObject,"Pong Message Object");
|
||||
|
|
|
@ -24,8 +24,8 @@ import java.lang.reflect.Method;
|
|||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -52,23 +52,23 @@ public class OnMessageTextCallable extends OnMessageCallable
|
|||
super(copy);
|
||||
}
|
||||
|
||||
public void call(Object endpoint, String str, boolean partialFlag) throws DecodeException
|
||||
public Object call(Object endpoint, String str, boolean partialFlag) throws DecodeException
|
||||
{
|
||||
super.args[idxMessageObject] = textDecoder.decode(str);
|
||||
if (idxPartialMessageFlag >= 0)
|
||||
{
|
||||
super.args[idxPartialMessageFlag] = partialFlag;
|
||||
}
|
||||
super.call(endpoint,super.args);
|
||||
return super.call(endpoint,super.args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxMessageObject = findIndexForRole(Role.MESSAGE_TEXT);
|
||||
assertRoleRequired(idxMessageObject,"Text Message Object");
|
||||
super.init(session);
|
||||
assertDecoderRequired();
|
||||
textDecoder = (Decoder.Text<?>)getDecoder();
|
||||
super.init(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,8 +25,8 @@ import java.lang.reflect.Method;
|
|||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -51,19 +51,19 @@ public class OnMessageTextStreamCallable extends OnMessageCallable
|
|||
super(copy);
|
||||
}
|
||||
|
||||
public void call(Object endpoint, Reader reader) throws DecodeException, IOException
|
||||
public Object call(Object endpoint, Reader reader) throws DecodeException, IOException
|
||||
{
|
||||
super.args[idxMessageObject] = textDecoder.decode(reader);
|
||||
super.call(endpoint,super.args);
|
||||
return super.call(endpoint,super.args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxMessageObject = findIndexForRole(Role.MESSAGE_TEXT_STREAM);
|
||||
assertRoleRequired(idxMessageObject,"Text Reader Message Object");
|
||||
super.init(session);
|
||||
assertDecoderRequired();
|
||||
textDecoder = (Decoder.TextStream<?>)getDecoder();
|
||||
super.init(session);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,10 +20,11 @@ package org.eclipse.jetty.websocket.jsr356.annotations;
|
|||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.Param.Role;
|
||||
|
||||
/**
|
||||
|
@ -55,9 +56,15 @@ public class OnOpenCallable extends JsrCallable
|
|||
}
|
||||
|
||||
@Override
|
||||
public void init(Session session)
|
||||
public void init(JsrSession session)
|
||||
{
|
||||
idxEndpointConfig = findIndexForRole(Role.ENDPOINT_CONFIG);
|
||||
super.init(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDecoderClass(Class<? extends Decoder> decoderClass)
|
||||
{
|
||||
/* ignore, not relevant for onClose */
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.annotations;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.MethodUtils;
|
||||
import org.eclipse.jetty.websocket.jsr356.utils.ReflectUtils;
|
||||
|
||||
public class Param
|
||||
{
|
||||
|
@ -93,7 +93,7 @@ public class Param
|
|||
StringBuilder str = new StringBuilder();
|
||||
str.append("Param[");
|
||||
str.append("index=").append(index);
|
||||
str.append(",type=").append(MethodUtils.toString(type));
|
||||
str.append(",type=").append(ReflectUtils.toShortName(type));
|
||||
str.append(",role=").append(role);
|
||||
if (pathParamName != null)
|
||||
{
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.client;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.Extension;
|
||||
|
||||
public class AnnotatedClientEndpointConfig implements ClientEndpointConfig
|
||||
{
|
||||
private final List<Class<? extends Decoder>> decoders;
|
||||
private final List<Class<? extends Encoder>> encoders;
|
||||
private final List<Extension> extensions;
|
||||
private final List<String> preferredSubprotocols;
|
||||
private final Configurator configurator;
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public AnnotatedClientEndpointConfig(ClientEndpoint anno) throws DeploymentException
|
||||
{
|
||||
this.decoders = Collections.unmodifiableList(Arrays.asList(anno.decoders()));
|
||||
this.encoders = Collections.unmodifiableList(Arrays.asList(anno.encoders()));
|
||||
this.preferredSubprotocols = Collections.unmodifiableList(Arrays.asList(anno.subprotocols()));
|
||||
|
||||
// no extensions declared in annotation
|
||||
this.extensions = Collections.emptyList();
|
||||
// no userProperties in annotation
|
||||
this.userProperties = new HashMap<>();
|
||||
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
this.configurator = EmptyConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ClientEndpoint.configurator() of ");
|
||||
err.append(anno.configurator().getName());
|
||||
err.append(" defined as annotation in ");
|
||||
err.append(anno.getClass().getName());
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator()
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders()
|
||||
{
|
||||
return encoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPreferredSubprotocols()
|
||||
{
|
||||
return preferredSubprotocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.client;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.Extension;
|
||||
|
||||
public class EmptyClientEndpointConfig implements ClientEndpointConfig
|
||||
{
|
||||
private final List<Class<? extends Decoder>> decoders;
|
||||
private final List<Class<? extends Encoder>> encoders;
|
||||
private final List<Extension> extensions;
|
||||
private final List<String> preferredSubprotocols;
|
||||
private final Configurator configurator;
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public EmptyClientEndpointConfig()
|
||||
{
|
||||
this.decoders = new ArrayList<>();
|
||||
this.encoders = new ArrayList<>();
|
||||
this.preferredSubprotocols = new ArrayList<>();
|
||||
this.extensions = new ArrayList<>();
|
||||
this.userProperties = new HashMap<>();
|
||||
this.configurator = EmptyConfigurator.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator()
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders()
|
||||
{
|
||||
return encoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getPreferredSubprotocols()
|
||||
{
|
||||
return preferredSubprotocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.client;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.HandshakeResponse;
|
||||
|
||||
public class EmptyConfigurator extends ClientEndpointConfig.Configurator
|
||||
{
|
||||
public static final EmptyConfigurator INSTANCE = new EmptyConfigurator();
|
||||
|
||||
@Override
|
||||
public void afterResponse(HandshakeResponse hr)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void beforeRequest(Map<String, List<String>> headers)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
}
|
|
@ -16,10 +16,9 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
package org.eclipse.jetty.websocket.jsr356.client;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
|
@ -27,6 +26,8 @@ import org.eclipse.jetty.websocket.common.events.EventDriver;
|
|||
import org.eclipse.jetty.websocket.common.events.EventDriverImpl;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.ConfiguredEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrAnnotatedEventDriver;
|
||||
|
||||
/**
|
||||
* Event Driver for classes annotated with @{@link ClientEndpoint}
|
||||
|
@ -62,7 +63,7 @@ public class JsrClientEndpointImpl implements EventDriverImpl
|
|||
JsrEvents events = new JsrEvents(basemetadata); // copy constructor.
|
||||
|
||||
// Create copy of base config
|
||||
ClientEndpointConfig config = basemetadata.getEndpointConfigCopy();
|
||||
AnnotatedClientEndpointConfig config = basemetadata.getConfig();
|
||||
return new JsrAnnotatedEventDriver(policy,endpoint,events,config);
|
||||
}
|
||||
|
|
@ -16,30 +16,22 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
package org.eclipse.jetty.websocket.jsr356.client;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.ClientEndpoint;
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.Decoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.JettyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.IJsrParamId;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdBinaryDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdTextDecoder;
|
||||
|
||||
public class JsrClientMetadata extends JsrMetadata<ClientEndpoint>
|
||||
{
|
||||
private final ClientEndpoint endpoint;
|
||||
private final JettyClientEndpointConfig config;
|
||||
private final Decoders decoders;
|
||||
private final AnnotatedClientEndpointConfig config;
|
||||
|
||||
public JsrClientMetadata(ClientContainer container, Class<?> websocket) throws DeploymentException
|
||||
{
|
||||
|
@ -53,31 +45,7 @@ public class JsrClientMetadata extends JsrMetadata<ClientEndpoint>
|
|||
}
|
||||
|
||||
this.endpoint = anno;
|
||||
this.config = new JettyClientEndpointConfig(anno);
|
||||
this.decoders = new Decoders(container.getDecoderMetadataFactory(),config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeParamsOnMessage(LinkedList<IJsrParamId> params)
|
||||
{
|
||||
for (DecoderWrapper wrapper : decoders.wrapperSet())
|
||||
{
|
||||
Class<? extends Decoder> decoder = wrapper.getMetadata().getDecoder();
|
||||
|
||||
if (Decoder.Text.class.isAssignableFrom(decoder) || Decoder.TextStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
params.add(new JsrParamIdTextDecoder(wrapper));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Decoder.Binary.class.isAssignableFrom(decoder) || Decoder.BinaryStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
params.add(new JsrParamIdBinaryDecoder(wrapper));
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Invalid Decoder: " + decoder);
|
||||
}
|
||||
this.config = new AnnotatedClientEndpointConfig(anno);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -86,9 +54,14 @@ public class JsrClientMetadata extends JsrMetadata<ClientEndpoint>
|
|||
return endpoint;
|
||||
}
|
||||
|
||||
public ClientEndpointConfig getEndpointConfigCopy() throws DeploymentException
|
||||
public AnnotatedClientEndpointConfig getConfig()
|
||||
{
|
||||
// Copy constructor
|
||||
return new JettyClientEndpointConfig(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<Class<? extends Decoder>> getConfiguredDecoders()
|
||||
{
|
||||
return config.getDecoders();
|
||||
}
|
||||
}
|
|
@ -30,16 +30,6 @@ import org.eclipse.jetty.websocket.jsr356.utils.ReflectUtils;
|
|||
|
||||
public class Encoders
|
||||
{
|
||||
private static final List<Class<?>> TYPES = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
TYPES.add(Encoder.Text.class);
|
||||
TYPES.add(Encoder.TextStream.class);
|
||||
TYPES.add(Encoder.Binary.class);
|
||||
TYPES.add(Encoder.BinaryStream.class);
|
||||
}
|
||||
|
||||
private static class EncoderRef
|
||||
{
|
||||
Class<?> type;
|
||||
|
@ -52,6 +42,16 @@ public class Encoders
|
|||
}
|
||||
}
|
||||
|
||||
private static final List<Class<?>> TYPES = new ArrayList<>();
|
||||
|
||||
static
|
||||
{
|
||||
TYPES.add(Encoder.Text.class);
|
||||
TYPES.add(Encoder.TextStream.class);
|
||||
TYPES.add(Encoder.Binary.class);
|
||||
TYPES.add(Encoder.BinaryStream.class);
|
||||
}
|
||||
|
||||
private final List<EncoderRef> encoders;
|
||||
|
||||
public Encoders()
|
||||
|
@ -127,6 +127,12 @@ public class Encoders
|
|||
this.encoders.add(ref);
|
||||
}
|
||||
|
||||
public void addAll(Class<? extends Encoder>[] encoderArr)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
public Encoder getEncoder(Class<?> type)
|
||||
{
|
||||
Class<?> targetType = type;
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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 javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCode;
|
||||
import javax.websocket.CloseReason.CloseCodes;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
|
||||
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.AbstractEventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
|
||||
public abstract class AbstractJsrEventDriver extends AbstractEventDriver implements EventDriver
|
||||
{
|
||||
protected final EndpointConfig config;
|
||||
protected JsrSession jsrsession;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
|
||||
public AbstractJsrEventDriver(WebSocketPolicy policy, Object websocket, EndpointConfig config)
|
||||
{
|
||||
super(policy,websocket);
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
public EndpointConfig getConfig()
|
||||
{
|
||||
return config;
|
||||
}
|
||||
|
||||
public Session getJsrSession()
|
||||
{
|
||||
return this.jsrsession;
|
||||
}
|
||||
|
||||
protected void init(JsrSession jsrsession)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onClose(CloseInfo close)
|
||||
{
|
||||
if (hasCloseBeenCalled)
|
||||
{
|
||||
// avoid duplicate close events (possible when using harsh Session.disconnect())
|
||||
return;
|
||||
}
|
||||
hasCloseBeenCalled = true;
|
||||
|
||||
CloseCode closecode = CloseCodes.getCloseCode(close.getStatusCode());
|
||||
CloseReason closereason = new CloseReason(closecode,close.getReason());
|
||||
onClose(closereason);
|
||||
}
|
||||
|
||||
protected abstract void onClose(CloseReason closereason);
|
||||
|
||||
@Override
|
||||
public void onFrame(Frame frame)
|
||||
{
|
||||
/* Ignored, not supported by JSR-356 */
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void openSession(WebSocketSession session)
|
||||
{
|
||||
// Cast should be safe, as it was created by JsrSessionFactory
|
||||
this.jsrsession = (JsrSession)session;
|
||||
|
||||
// Allow jsr session to init
|
||||
this.jsrsession.init(config);
|
||||
|
||||
// Allow event driver to init itself
|
||||
init(jsrsession);
|
||||
|
||||
// Allow end-user socket to adjust configuration
|
||||
super.openSession(session);
|
||||
}
|
||||
|
||||
public void setEndpointconfig(EndpointConfig endpointconfig)
|
||||
{
|
||||
throw new RuntimeException("Why are you reconfiguring the endpoint?");
|
||||
// this.config = endpointconfig;
|
||||
}
|
||||
}
|
|
@ -23,19 +23,16 @@ import java.io.InputStream;
|
|||
import java.io.Reader;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
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.AbstractEventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageInputStream;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageReader;
|
||||
|
@ -47,24 +44,21 @@ import org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents;
|
|||
/**
|
||||
* Base implementation for JSR-356 Annotated event drivers.
|
||||
*/
|
||||
public class JsrAnnotatedEventDriver extends AbstractEventDriver implements EventDriver
|
||||
public class JsrAnnotatedEventDriver extends AbstractJsrEventDriver implements EventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JsrAnnotatedEventDriver.class);
|
||||
private final JsrEvents events;
|
||||
private final EndpointConfig endpointconfig;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
private JsrSession jsrsession;
|
||||
|
||||
public JsrAnnotatedEventDriver(WebSocketPolicy policy, Object websocket, JsrEvents events, EndpointConfig endpointconfig)
|
||||
public JsrAnnotatedEventDriver(WebSocketPolicy policy, Object websocket, JsrEvents events, EndpointConfig config)
|
||||
{
|
||||
super(policy,websocket);
|
||||
super(policy,websocket,config);
|
||||
this.events = events;
|
||||
this.endpointconfig = endpointconfig;
|
||||
}
|
||||
|
||||
public Session getJsrSession()
|
||||
@Override
|
||||
protected void init(JsrSession jsrsession)
|
||||
{
|
||||
return this.jsrsession;
|
||||
this.events.init(jsrsession);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -90,7 +84,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
// Partial Message Support (does not use messageAppender)
|
||||
try
|
||||
{
|
||||
events.callBinary(websocket,buffer,fin);
|
||||
events.callBinary(jsrsession.getAsyncRemote(),websocket,buffer,fin);
|
||||
}
|
||||
catch (DecodeException e)
|
||||
{
|
||||
|
@ -125,7 +119,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
{
|
||||
try
|
||||
{
|
||||
events.callBinaryStream(websocket,stream);
|
||||
events.callBinaryStream(jsrsession.getAsyncRemote(),websocket,stream);
|
||||
}
|
||||
catch (DecodeException | IOException e)
|
||||
{
|
||||
|
@ -159,7 +153,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
try
|
||||
{
|
||||
// FIN is always true here
|
||||
events.callBinary(websocket,ByteBuffer.wrap(data),true);
|
||||
events.callBinary(jsrsession.getAsyncRemote(),websocket,ByteBuffer.wrap(data),true);
|
||||
}
|
||||
catch (DecodeException e)
|
||||
{
|
||||
|
@ -168,21 +162,15 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CloseInfo close)
|
||||
protected void onClose(CloseReason closereason)
|
||||
{
|
||||
if (hasCloseBeenCalled)
|
||||
{
|
||||
// avoid duplicate close events (possible when using harsh Session.disconnect())
|
||||
return;
|
||||
}
|
||||
hasCloseBeenCalled = true;
|
||||
events.callClose(websocket,close);
|
||||
events.callClose(websocket,closereason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
events.callOpen(websocket,endpointconfig);
|
||||
events.callOpen(websocket,config);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -208,7 +196,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
{
|
||||
try
|
||||
{
|
||||
events.callBinaryStream(websocket,stream);
|
||||
events.callBinaryStream(jsrsession.getAsyncRemote(),websocket,stream);
|
||||
}
|
||||
catch (DecodeException | IOException e)
|
||||
{
|
||||
|
@ -221,7 +209,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
{
|
||||
try
|
||||
{
|
||||
events.callTextStream(websocket,reader);
|
||||
events.callTextStream(jsrsession.getAsyncRemote(),websocket,reader);
|
||||
}
|
||||
catch (DecodeException | IOException e)
|
||||
{
|
||||
|
@ -254,7 +242,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
try
|
||||
{
|
||||
String text = BufferUtil.toUTF8String(buffer);
|
||||
events.callText(websocket,text,fin);
|
||||
events.callText(jsrsession.getAsyncRemote(),websocket,text,fin);
|
||||
}
|
||||
catch (DecodeException e)
|
||||
{
|
||||
|
@ -291,7 +279,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
{
|
||||
try
|
||||
{
|
||||
events.callTextStream(websocket,stream);
|
||||
events.callTextStream(jsrsession.getAsyncRemote(),websocket,stream);
|
||||
}
|
||||
catch (DecodeException | IOException e)
|
||||
{
|
||||
|
@ -322,7 +310,7 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
try
|
||||
{
|
||||
// FIN is always true here
|
||||
events.callText(websocket,message,true);
|
||||
events.callText(jsrsession.getAsyncRemote(),websocket,message,true);
|
||||
}
|
||||
catch (DecodeException e)
|
||||
{
|
||||
|
@ -330,17 +318,6 @@ public class JsrAnnotatedEventDriver extends AbstractEventDriver implements Even
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
// Cast should be safe, as it was created by JsrSessionFactory
|
||||
this.jsrsession = (JsrSession)session;
|
||||
// Initialize the events
|
||||
this.events.init(jsrsession);
|
||||
// TODO: Initialize the decoders
|
||||
super.openSession(session);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -24,65 +24,38 @@ import java.io.Reader;
|
|||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCode;
|
||||
import javax.websocket.CloseReason.CloseCodes;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.MessageHandler.Whole;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
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.AbstractEventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageInputStream;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageReader;
|
||||
import org.eclipse.jetty.websocket.jsr356.ContainerService;
|
||||
import org.eclipse.jetty.websocket.jsr356.Decoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlers;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.BinaryPartialMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.BinaryWholeMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadataFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.TextPartialMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.TextWholeMessage;
|
||||
|
||||
/**
|
||||
* EventDriver for websocket that extend from {@link javax.websocket.Endpoint}
|
||||
*/
|
||||
public class JsrEndpointEventDriver extends AbstractEventDriver implements EventDriver
|
||||
public class JsrEndpointEventDriver extends AbstractJsrEventDriver implements EventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JsrEndpointEventDriver.class);
|
||||
|
||||
private final Endpoint endpoint;
|
||||
private JsrSession jsrsession;
|
||||
private EndpointConfig endpointconfig;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
|
||||
public JsrEndpointEventDriver(WebSocketPolicy policy, Endpoint endpoint, EndpointConfig config)
|
||||
{
|
||||
super(policy,endpoint);
|
||||
super(policy,endpoint,config);
|
||||
this.endpoint = endpoint;
|
||||
this.endpointconfig = config;
|
||||
}
|
||||
|
||||
public EndpointConfig getEndpointconfig()
|
||||
{
|
||||
return endpointconfig;
|
||||
}
|
||||
|
||||
public Session getJsrSession()
|
||||
{
|
||||
return this.jsrsession;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,27 +110,18 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
}
|
||||
|
||||
@Override
|
||||
public void onClose(CloseInfo close)
|
||||
protected void onClose(CloseReason closereason)
|
||||
{
|
||||
if (hasCloseBeenCalled)
|
||||
{
|
||||
// avoid duplicate close events (possible when using harsh Session.disconnect())
|
||||
return;
|
||||
}
|
||||
hasCloseBeenCalled = true;
|
||||
|
||||
CloseCode closecode = CloseCodes.getCloseCode(close.getStatusCode());
|
||||
CloseReason closereason = new CloseReason(closecode,close.getReason());
|
||||
endpoint.onClose(this.jsrsession,closereason);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
LOG.debug("onConnect({}, {})",jsrsession,endpointconfig);
|
||||
LOG.debug("onConnect({}, {})",jsrsession,config);
|
||||
try
|
||||
{
|
||||
endpoint.onOpen(jsrsession,endpointconfig);
|
||||
endpoint.onOpen(jsrsession,config);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
|
@ -241,41 +205,6 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
/* Ignored, handled by TextWholeMessage */
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
// Cast should be safe, as it was created by JsrSessionFactory
|
||||
this.jsrsession = (JsrSession)session;
|
||||
|
||||
try
|
||||
{
|
||||
// Create Decoders
|
||||
ContainerService container = (ContainerService)jsrsession.getContainer();
|
||||
Decoders decoders = new Decoders(container.getDecoderMetadataFactory(),endpointconfig);
|
||||
jsrsession.setDecodersFacade(decoders);
|
||||
|
||||
// Create MessageHandlers
|
||||
MessageHandlerMetadataFactory metadataFactory = new MessageHandlerMetadataFactory(decoders);
|
||||
MessageHandlers messageHandlers = new MessageHandlers(metadataFactory);
|
||||
jsrsession.setMessageHandlerFacade(messageHandlers);
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
throw new WebSocketException(e);
|
||||
}
|
||||
|
||||
// Allow end-user socket to adjust configuration
|
||||
super.openSession(session);
|
||||
|
||||
// Initialize Decoders
|
||||
jsrsession.getDecodersFacade().init(endpointconfig);
|
||||
}
|
||||
|
||||
public void setEndpointconfig(EndpointConfig endpointconfig)
|
||||
{
|
||||
this.endpointconfig = endpointconfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.eclipse.jetty.websocket.jsr356.endpoints;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.JsrClientEndpointImpl;
|
||||
|
||||
public class JsrEventDriverFactory extends EventDriverFactory
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.websocket.MessageHandler.Partial;
|
|||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageAppender;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
|
||||
|
||||
public class BinaryPartialMessage implements MessageAppender
|
||||
{
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.eclipse.jetty.websocket.api.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.message.SimpleBinaryMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
|
||||
|
||||
public class BinaryWholeMessage extends SimpleBinaryMessage
|
||||
{
|
||||
|
|
|
@ -26,6 +26,7 @@ import javax.websocket.MessageHandler.Partial;
|
|||
|
||||
import org.eclipse.jetty.util.BufferUtil;
|
||||
import org.eclipse.jetty.websocket.common.message.MessageAppender;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
|
||||
|
||||
public class TextPartialMessage implements MessageAppender
|
||||
{
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.eclipse.jetty.websocket.api.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.message.SimpleTextMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageHandlerWrapper;
|
||||
|
||||
public class TextWholeMessage extends SimpleTextMessage
|
||||
{
|
||||
|
|
|
@ -16,31 +16,37 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
package org.eclipse.jetty.websocket.jsr356.metadata;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
|
||||
/**
|
||||
* Metadata for a {@link Decoder}
|
||||
* Immutable Metadata for a {@link Decoder}
|
||||
*/
|
||||
public class DecoderMetadata
|
||||
{
|
||||
/** The Class for the Decoder itself */
|
||||
private final Class<? extends Decoder> decoderClass;
|
||||
/** The Class that the Decoder declares it decodes */
|
||||
private final Class<?> objType;
|
||||
private final Class<? extends Decoder> decoder;
|
||||
/** The Basic type of message the decoder handles */
|
||||
private final MessageType messageType;
|
||||
/** Flag indicating if Decoder is for streaming (or not) */
|
||||
private final boolean streamed;
|
||||
|
||||
public DecoderMetadata(Class<?> objType, Class<? extends Decoder> decoder, MessageType messageType, boolean streamed)
|
||||
public DecoderMetadata(Class<?> objType, Class<? extends Decoder> decoderClass, MessageType messageType, boolean streamed)
|
||||
{
|
||||
this.objType = objType;
|
||||
this.decoder = decoder;
|
||||
this.decoderClass = decoderClass;
|
||||
this.messageType = messageType;
|
||||
this.streamed = streamed;
|
||||
}
|
||||
|
||||
public Class<? extends Decoder> getDecoder()
|
||||
public Class<? extends Decoder> getDecoderClass()
|
||||
{
|
||||
return decoder;
|
||||
return decoderClass;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
|
@ -0,0 +1,66 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.metadata;
|
||||
|
||||
import javax.websocket.Encoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
|
||||
/**
|
||||
* Immutable Metadata for a {@link Encoder}
|
||||
*/
|
||||
public class EncoderMetadata
|
||||
{
|
||||
/** The Class for the Encoder itself */
|
||||
private final Class<? extends Encoder> encoderClass;
|
||||
/** The Class that the Encoder declares it encodes */
|
||||
private final Class<?> objType;
|
||||
/** The Basic type of message the encoder handles */
|
||||
private final MessageType messageType;
|
||||
/** Flag indicating if Encoder is for streaming (or not) */
|
||||
private final boolean streamed;
|
||||
|
||||
public EncoderMetadata(Class<?> objType, Class<? extends Encoder> encoderClass, MessageType messageType, boolean streamed)
|
||||
{
|
||||
this.objType = objType;
|
||||
this.encoderClass = encoderClass;
|
||||
this.messageType = messageType;
|
||||
this.streamed = streamed;
|
||||
}
|
||||
|
||||
public Class<? extends Encoder> getEncoderClass()
|
||||
{
|
||||
return encoderClass;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
public Class<?> getObjectType()
|
||||
{
|
||||
return objType;
|
||||
}
|
||||
|
||||
public boolean isStreamed()
|
||||
{
|
||||
return streamed;
|
||||
}
|
||||
}
|
|
@ -16,15 +16,12 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.messages;
|
||||
package org.eclipse.jetty.websocket.jsr356.metadata;
|
||||
|
||||
import javax.websocket.MessageHandler;
|
||||
import javax.websocket.Session;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
|
||||
/**
|
||||
* An immutable holder for {@link MessageHandler} metadata, representing a single interface on a message handling class.
|
||||
* An immutable metadata for a {@link MessageHandler}, representing a single interface on a message handling class.
|
||||
* <p>
|
||||
* A message handling class can contain more than 1 valid {@link MessageHandler} interface, this will result in multiple {@link MessageHandlerMetadata}
|
||||
* instances, each tracking one of the {@link MessageHandler} interfaces declared.
|
||||
|
@ -49,43 +46,12 @@ public class MessageHandlerMetadata
|
|||
* Or said another way, the first parameter type on this interface's onMessage() method.
|
||||
*/
|
||||
private final Class<?> messageClass;
|
||||
/**
|
||||
* The 'websocket message type' used for registration limits per JSR-356 / PFD1 section 2.1.3 Receiving Messages
|
||||
*/
|
||||
private final MessageType messageType;
|
||||
|
||||
protected MessageHandlerMetadata(Class<? extends MessageHandler> handlerClass, MessageType messageType, Class<?> messageClass, boolean partial)
|
||||
public MessageHandlerMetadata(Class<? extends MessageHandler> handlerClass, Class<?> messageClass, boolean partial)
|
||||
{
|
||||
this.handlerClass = handlerClass;
|
||||
this.isPartialSupported = partial;
|
||||
this.messageClass = messageClass;
|
||||
this.messageType = messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make equals/hashcode only use messageType (for best result with {@link Session#getMessageHandlers()})
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
MessageHandlerMetadata other = (MessageHandlerMetadata)obj;
|
||||
if (messageType != other.messageType)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Class<? extends MessageHandler> getHandlerClass()
|
||||
|
@ -98,23 +64,6 @@ public class MessageHandlerMetadata
|
|||
return messageClass;
|
||||
}
|
||||
|
||||
public MessageType getMessageType()
|
||||
{
|
||||
return messageType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make equals/hashcode only use messageType (for best result with {@link Session#getMessageHandlers()})
|
||||
*/
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + ((messageType == null)?0:messageType.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean isPartialSupported()
|
||||
{
|
||||
return isPartialSupported;
|
|
@ -19,9 +19,6 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.utils;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
|
@ -29,49 +26,19 @@ import java.util.Set;
|
|||
*/
|
||||
public class DeploymentTypeUtils
|
||||
{
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_CLASS_MAP;
|
||||
private static final Map<Class<?>, Class<?>> CLASS_PRIMITIVE_MAP;
|
||||
|
||||
static
|
||||
{
|
||||
Map<Class<?>, Class<?>> primitives = new HashMap<>();
|
||||
|
||||
// Map of classes to primitive types
|
||||
primitives.put(Boolean.class,Boolean.TYPE);
|
||||
primitives.put(Byte.class,Byte.TYPE);
|
||||
primitives.put(Character.class,Character.TYPE);
|
||||
primitives.put(Double.class,Double.TYPE);
|
||||
primitives.put(Float.class,Float.TYPE);
|
||||
primitives.put(Integer.class,Integer.TYPE);
|
||||
primitives.put(Long.class,Long.TYPE);
|
||||
primitives.put(Short.class,Short.TYPE);
|
||||
primitives.put(Void.class,Void.TYPE);
|
||||
|
||||
CLASS_PRIMITIVE_MAP = Collections.unmodifiableMap(primitives);
|
||||
|
||||
// Map of primitive types to classes
|
||||
Map<Class<?>, Class<?>> types = new HashMap<>();
|
||||
for (Map.Entry<Class<?>, Class<?>> classEntry : primitives.entrySet())
|
||||
{
|
||||
types.put(classEntry.getValue(),classEntry.getKey());
|
||||
}
|
||||
|
||||
PRIMITIVE_CLASS_MAP = Collections.unmodifiableMap(types);
|
||||
}
|
||||
|
||||
public static Class<?> getPrimitiveClass(Class<?> primitiveType)
|
||||
{
|
||||
return PRIMITIVE_CLASS_MAP.get(primitiveType);
|
||||
return Primitives.getPrimitiveClass(primitiveType);
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getPrimitiveClasses()
|
||||
{
|
||||
return CLASS_PRIMITIVE_MAP.keySet();
|
||||
return Primitives.getPrimitiveClasses();
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getPrimitives()
|
||||
{
|
||||
return PRIMITIVE_CLASS_MAP.keySet();
|
||||
return Primitives.getPrimitives();
|
||||
}
|
||||
|
||||
public static boolean isAssignableClass(Class<?> type, Class<?> targetClass)
|
||||
|
@ -88,7 +55,7 @@ public class DeploymentTypeUtils
|
|||
if (!targetClass.isPrimitive())
|
||||
{
|
||||
// going from primitive to class, make sure it matches
|
||||
Class<?> primitive = CLASS_PRIMITIVE_MAP.get(targetClass);
|
||||
Class<?> primitive = Primitives.getPrimitiveType(targetClass);
|
||||
return primitive.equals(type);
|
||||
}
|
||||
|
||||
|
@ -130,7 +97,7 @@ public class DeploymentTypeUtils
|
|||
if (targetClass.isPrimitive())
|
||||
{
|
||||
// Class to Primitive (autoboxing)
|
||||
Class<?> targetPrimitive = CLASS_PRIMITIVE_MAP.get(type);
|
||||
Class<?> targetPrimitive = Primitives.getPrimitiveType(type);
|
||||
return targetClass.equals(targetPrimitive);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,97 +19,11 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.utils;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
public final class MethodUtils
|
||||
{
|
||||
private static StringBuilder appendTypeName(StringBuilder sb, Type type, boolean ellipses)
|
||||
{
|
||||
if (type instanceof Class<?>)
|
||||
{
|
||||
Class<?> ctype = (Class<?>)type;
|
||||
if (ctype.isArray())
|
||||
{
|
||||
try
|
||||
{
|
||||
int dimensions = 0;
|
||||
while (ctype.isArray())
|
||||
{
|
||||
dimensions++;
|
||||
ctype = ctype.getComponentType();
|
||||
}
|
||||
sb.append(ctype.getName());
|
||||
for (int i = 0; i < dimensions; i++)
|
||||
{
|
||||
if (ellipses)
|
||||
{
|
||||
sb.append("...");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("[]");
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
catch (Throwable ignore)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(ctype.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(type.toString());
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
public static String toString(Class<?> pojo, Method method)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(pojo.getName());
|
||||
str.append(" ");
|
||||
// method modifiers
|
||||
int mod = method.getModifiers() & Modifier.methodModifiers();
|
||||
if (mod != 0)
|
||||
{
|
||||
str.append(Modifier.toString(mod)).append(' ');
|
||||
}
|
||||
|
||||
// return type
|
||||
Type retType = method.getGenericReturnType();
|
||||
appendTypeName(str,retType,false).append(' ');
|
||||
|
||||
// method name
|
||||
str.append(method.getName());
|
||||
|
||||
// method parameters
|
||||
str.append('(');
|
||||
Type[] params = method.getGenericParameterTypes();
|
||||
for (int j = 0; j < params.length; j++)
|
||||
{
|
||||
boolean ellipses = method.isVarArgs() && (j == (params.length - 1));
|
||||
appendTypeName(str,params[j],ellipses);
|
||||
if (j < (params.length - 1))
|
||||
{
|
||||
str.append(", ");
|
||||
}
|
||||
}
|
||||
str.append(')');
|
||||
|
||||
// TODO: show exceptions?
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static String toString(Type type)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
appendTypeName(str,type,true);
|
||||
return str.toString();
|
||||
return ReflectUtils.toString(pojo,method);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.utils;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class Primitives
|
||||
{
|
||||
private static final Map<Class<?>, Class<?>> PRIMITIVE_CLASS_MAP;
|
||||
private static final Map<Class<?>, Class<?>> CLASS_PRIMITIVE_MAP;
|
||||
|
||||
static
|
||||
{
|
||||
Map<Class<?>, Class<?>> primitives = new HashMap<>();
|
||||
|
||||
// Map of classes to primitive types
|
||||
primitives.put(Boolean.class,Boolean.TYPE);
|
||||
primitives.put(Byte.class,Byte.TYPE);
|
||||
primitives.put(Character.class,Character.TYPE);
|
||||
primitives.put(Double.class,Double.TYPE);
|
||||
primitives.put(Float.class,Float.TYPE);
|
||||
primitives.put(Integer.class,Integer.TYPE);
|
||||
primitives.put(Long.class,Long.TYPE);
|
||||
primitives.put(Short.class,Short.TYPE);
|
||||
primitives.put(Void.class,Void.TYPE);
|
||||
|
||||
CLASS_PRIMITIVE_MAP = Collections.unmodifiableMap(primitives);
|
||||
|
||||
// Map of primitive types to classes
|
||||
Map<Class<?>, Class<?>> types = new HashMap<>();
|
||||
for (Map.Entry<Class<?>, Class<?>> classEntry : primitives.entrySet())
|
||||
{
|
||||
types.put(classEntry.getValue(),classEntry.getKey());
|
||||
}
|
||||
|
||||
PRIMITIVE_CLASS_MAP = Collections.unmodifiableMap(types);
|
||||
}
|
||||
|
||||
public static Class<?> getPrimitiveClass(Class<?> primitiveType)
|
||||
{
|
||||
return PRIMITIVE_CLASS_MAP.get(primitiveType);
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getPrimitiveClasses()
|
||||
{
|
||||
return CLASS_PRIMITIVE_MAP.keySet();
|
||||
}
|
||||
|
||||
public static Set<Class<?>> getPrimitives()
|
||||
{
|
||||
return PRIMITIVE_CLASS_MAP.keySet();
|
||||
}
|
||||
|
||||
public static Class<?> getPrimitiveType(Class<?> primitiveClass)
|
||||
{
|
||||
return CLASS_PRIMITIVE_MAP.get(primitiveClass);
|
||||
}
|
||||
}
|
|
@ -18,6 +18,9 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.jsr356.utils;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
|
@ -49,6 +52,17 @@ public class ReflectUtils
|
|||
return (genericClass == null) && (genericType != null) && (genericType instanceof TypeVariable<?>);
|
||||
}
|
||||
|
||||
public void setGenericFromType(Type type, int index)
|
||||
{
|
||||
// debug("setGenericFromType(%s,%d)",toShortName(type),index);
|
||||
this.genericType = type;
|
||||
this.genericIndex = index;
|
||||
if (type instanceof Class)
|
||||
{
|
||||
this.genericClass = (Class<?>)type;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
|
@ -64,17 +78,51 @@ public class ReflectUtils
|
|||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public void setGenericFromType(Type type, int index)
|
||||
private static StringBuilder appendTypeName(StringBuilder sb, Type type, boolean ellipses)
|
||||
{
|
||||
if (type instanceof Class<?>)
|
||||
{
|
||||
// debug("setGenericFromType(%s,%d)",toShortName(type),index);
|
||||
this.genericType = type;
|
||||
this.genericIndex = index;
|
||||
if (type instanceof Class)
|
||||
Class<?> ctype = (Class<?>)type;
|
||||
if (ctype.isArray())
|
||||
{
|
||||
this.genericClass = (Class<?>)type;
|
||||
try
|
||||
{
|
||||
int dimensions = 0;
|
||||
while (ctype.isArray())
|
||||
{
|
||||
dimensions++;
|
||||
ctype = ctype.getComponentType();
|
||||
}
|
||||
sb.append(ctype.getName());
|
||||
for (int i = 0; i < dimensions; i++)
|
||||
{
|
||||
if (ellipses)
|
||||
{
|
||||
sb.append("...");
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append("[]");
|
||||
}
|
||||
}
|
||||
return sb;
|
||||
}
|
||||
catch (Throwable ignore)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
sb.append(ctype.getName());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.append(type.toString());
|
||||
}
|
||||
|
||||
return sb;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -99,6 +147,83 @@ public class ReflectUtils
|
|||
return null;
|
||||
}
|
||||
|
||||
private static int findTypeParameterIndex(Class<?> clazz, TypeVariable<?> needVar)
|
||||
{
|
||||
// debug("findTypeParameterIndex(%s, [%s])",toShortName(clazz),toShortName(needVar));
|
||||
TypeVariable<?> params[] = clazz.getTypeParameters();
|
||||
for (int i = 0; i < params.length; i++)
|
||||
{
|
||||
if (params[i].getName().equals(needVar.getName()))
|
||||
{
|
||||
// debug("Type Parameter found at index: [%d]",i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// debug("Type Parameter NOT found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static boolean isDefaultConstructable(Class<?> clazz)
|
||||
{
|
||||
int mods = clazz.getModifiers();
|
||||
if (Modifier.isAbstract(mods) || !Modifier.isPublic(mods))
|
||||
{
|
||||
// Needs to be public, non-abstract
|
||||
return false;
|
||||
}
|
||||
|
||||
Class<?>[] noargs = new Class<?>[0];
|
||||
try
|
||||
{
|
||||
// Needs to have a no-args constructor
|
||||
Constructor<?> constructor = clazz.getConstructor(noargs);
|
||||
// Constructor needs to be public
|
||||
return Modifier.isPublic(constructor.getModifiers());
|
||||
}
|
||||
catch (NoSuchMethodException | SecurityException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean resolveGenericRef(GenericRef ref, Class<?> clazz, Type type)
|
||||
{
|
||||
if (type instanceof Class)
|
||||
{
|
||||
if (type == ref.ifaceClass)
|
||||
{
|
||||
// is this a straight ref or a TypeVariable?
|
||||
// debug("Found ref (as class): %s",toShortName(type));
|
||||
ref.setGenericFromType(type,0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep digging
|
||||
return resolveGenericRef(ref,type);
|
||||
}
|
||||
}
|
||||
|
||||
if (type instanceof ParameterizedType)
|
||||
{
|
||||
ParameterizedType ptype = (ParameterizedType)type;
|
||||
Type rawType = ptype.getRawType();
|
||||
if (rawType == ref.ifaceClass)
|
||||
{
|
||||
// debug("Found ref on [%s] as ParameterizedType [%s]",toShortName(clazz),toShortName(ptype));
|
||||
// Always get the raw type parameter, let unwrap() solve for what it is
|
||||
ref.setGenericFromType(ptype.getActualTypeArguments()[0],0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep digging
|
||||
return resolveGenericRef(ref,rawType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean resolveGenericRef(GenericRef ref, Type type)
|
||||
{
|
||||
if ((type == null) || (type == Object.class))
|
||||
|
@ -181,72 +306,6 @@ public class ReflectUtils
|
|||
return false;
|
||||
}
|
||||
|
||||
private static int findTypeParameterIndex(Class<?> clazz, TypeVariable<?> needVar)
|
||||
{
|
||||
// debug("findTypeParameterIndex(%s, [%s])",toShortName(clazz),toShortName(needVar));
|
||||
TypeVariable<?> params[] = clazz.getTypeParameters();
|
||||
for (int i = 0; i < params.length; i++)
|
||||
{
|
||||
if (params[i].getName().equals(needVar.getName()))
|
||||
{
|
||||
// debug("Type Parameter found at index: [%d]",i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
// debug("Type Parameter NOT found");
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static boolean resolveGenericRef(GenericRef ref, Class<?> clazz, Type type)
|
||||
{
|
||||
if (type instanceof Class)
|
||||
{
|
||||
if (type == ref.ifaceClass)
|
||||
{
|
||||
// is this a straight ref or a TypeVariable?
|
||||
// debug("Found ref (as class): %s",toShortName(type));
|
||||
ref.setGenericFromType(type,0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep digging
|
||||
return resolveGenericRef(ref,(Class<?>)type);
|
||||
}
|
||||
}
|
||||
|
||||
if (type instanceof ParameterizedType)
|
||||
{
|
||||
ParameterizedType ptype = (ParameterizedType)type;
|
||||
Type rawType = ptype.getRawType();
|
||||
if (rawType == ref.ifaceClass)
|
||||
{
|
||||
// debug("Found ref on [%s] as ParameterizedType [%s]",toShortName(clazz),toShortName(ptype));
|
||||
// Always get the raw type parameter, let unwrap() solve for what it is
|
||||
ref.setGenericFromType(ptype.getActualTypeArguments()[0],0);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Keep digging
|
||||
return resolveGenericRef(ref,(Class<?>)rawType);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String trimClassName(String name)
|
||||
{
|
||||
int idx = name.lastIndexOf('.');
|
||||
name = name.substring(idx + 1);
|
||||
idx = name.lastIndexOf('$');
|
||||
if (idx >= 0)
|
||||
{
|
||||
name = name.substring(idx + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public static String toShortName(Type type)
|
||||
{
|
||||
if (type == null)
|
||||
|
@ -270,7 +329,9 @@ public class ReflectUtils
|
|||
for (int i = 0; i < args.length; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
{
|
||||
str.append(",");
|
||||
}
|
||||
str.append(args[i]);
|
||||
}
|
||||
str.append(">");
|
||||
|
@ -279,4 +340,53 @@ public class ReflectUtils
|
|||
|
||||
return type.toString();
|
||||
}
|
||||
|
||||
public static String toString(Class<?> pojo, Method method)
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(pojo.getName());
|
||||
str.append(" ");
|
||||
// method modifiers
|
||||
int mod = method.getModifiers() & Modifier.methodModifiers();
|
||||
if (mod != 0)
|
||||
{
|
||||
str.append(Modifier.toString(mod)).append(' ');
|
||||
}
|
||||
|
||||
// return type
|
||||
Type retType = method.getGenericReturnType();
|
||||
appendTypeName(str,retType,false).append(' ');
|
||||
|
||||
// method name
|
||||
str.append(method.getName());
|
||||
|
||||
// method parameters
|
||||
str.append('(');
|
||||
Type[] params = method.getGenericParameterTypes();
|
||||
for (int j = 0; j < params.length; j++)
|
||||
{
|
||||
boolean ellipses = method.isVarArgs() && (j == (params.length - 1));
|
||||
appendTypeName(str,params[j],ellipses);
|
||||
if (j < (params.length - 1))
|
||||
{
|
||||
str.append(", ");
|
||||
}
|
||||
}
|
||||
str.append(')');
|
||||
|
||||
// TODO: show exceptions?
|
||||
return str.toString();
|
||||
}
|
||||
|
||||
public static String trimClassName(String name)
|
||||
{
|
||||
int idx = name.lastIndexOf('.');
|
||||
name = name.substring(idx + 1);
|
||||
idx = name.lastIndexOf('$');
|
||||
if (idx >= 0)
|
||||
{
|
||||
name = name.substring(idx + 1);
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,155 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.DateDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.IntegerDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.LongDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.StringDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.TimeDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.DualDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.Fruit;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.FruitDecoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DecoderFactoryTest
|
||||
{
|
||||
private DecoderFactory factory;
|
||||
|
||||
private void assertDecoderType(Class<? extends Decoder> decoder, MessageType expectedMsgType, Type expectedObjType)
|
||||
{
|
||||
List<DecoderMetadata> metadatas = factory.getMetadata(decoder);
|
||||
Assert.assertThat("Metadatas.size",metadatas.size(),is(1));
|
||||
DecoderMetadata metadata = metadatas.get(0);
|
||||
Assert.assertThat("Metadata.messageType",metadata.getMessageType(),is(expectedMsgType));
|
||||
Assert.assertThat("Metadata.objectType",metadata.getObjectType(),is(expectedObjType));
|
||||
}
|
||||
|
||||
private void assertMetadataFor(Class<?> type, Class<? extends Decoder> expectedDecoderClass, MessageType expectedType)
|
||||
{
|
||||
DecoderMetadata metadata = factory.getMetadataFor(type);
|
||||
Assert.assertEquals("metadata.decoderClass",metadata.getDecoderClass(),expectedDecoderClass);
|
||||
Assert.assertThat("metadata.messageType",metadata.getMessageType(),is(expectedType));
|
||||
Assert.assertEquals("metadata.objectType",metadata.getObjectType(),type);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void initDecoderFactory()
|
||||
{
|
||||
CommonContainer container = new ClientContainer();
|
||||
// create factory based on parent factory with primitives.
|
||||
factory = new DecoderFactory(container.getDecoderFactory());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteArrayDecoder()
|
||||
{
|
||||
assertDecoderType(ByteArrayDecoder.class,MessageType.BINARY,byte[].class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteBufferDecoder()
|
||||
{
|
||||
assertDecoderType(ByteBufferDecoder.class,MessageType.BINARY,ByteBuffer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetFruitDecoder()
|
||||
{
|
||||
assertDecoderType(FruitDecoder.class,MessageType.TEXT,Fruit.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetIntegerDecoder()
|
||||
{
|
||||
assertDecoderType(IntegerDecoder.class,MessageType.TEXT,Integer.TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLongDecoder()
|
||||
{
|
||||
assertDecoderType(LongDecoder.class,MessageType.TEXT,Long.TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForByteArray()
|
||||
{
|
||||
factory.register(ByteArrayDecoder.class);
|
||||
assertMetadataFor(byte[].class,ByteArrayDecoder.class,MessageType.BINARY);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetMetadataForDate()
|
||||
{
|
||||
factory.register(DateDecoder.class);
|
||||
assertMetadataFor(Date.class,DateDecoder.class,MessageType.TEXT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStringDecoder()
|
||||
{
|
||||
assertDecoderType(StringDecoder.class,MessageType.TEXT,String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTextDecoder_Dual()
|
||||
{
|
||||
try
|
||||
{
|
||||
// has duplicated support for the same target Type
|
||||
factory.getMetadata(DualDecoder.class);
|
||||
Assert.fail("Should have thrown IllegalStateException for attempting to register Decoders with duplicate implementation");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRegisterDuplicate()
|
||||
{
|
||||
// Register the DateDecoder (decodes java.util.Date)
|
||||
factory.register(DateDecoder.class);
|
||||
try
|
||||
{
|
||||
// Register the TimeDecoder (which also wants to decode java.util.Date)
|
||||
factory.register(TimeDecoder.class);
|
||||
Assert.fail("Should have thrown IllegalStateException for attempting to register Decoders with duplicate implementation");
|
||||
}
|
||||
catch (IllegalStateException e)
|
||||
{
|
||||
Assert.assertThat(e.getMessage(),containsString("Duplicate"));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.CharacterDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.DualDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.Fruit;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.FruitDecoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DecodersTest
|
||||
{
|
||||
private DecoderMetadataFactory factory = new DecoderMetadataFactory();
|
||||
|
||||
@Test
|
||||
public void testGetTextDecoder_Character() throws DeploymentException
|
||||
{
|
||||
SimpleClientEndpointConfig config = new SimpleClientEndpointConfig();
|
||||
config.addDecoder(FruitDecoder.class);
|
||||
Decoders decoders = new Decoders(factory,config);
|
||||
|
||||
Decoder txtDecoder = decoders.getDecoder(Character.class);
|
||||
Assert.assertThat("Text Decoder",txtDecoder,notNullValue());
|
||||
Assert.assertThat("Text Decoder",txtDecoder,instanceOf(CharacterDecoder.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTextDecoder_Dual()
|
||||
{
|
||||
try
|
||||
{
|
||||
SimpleClientEndpointConfig config = new SimpleClientEndpointConfig();
|
||||
config.addDecoder(DualDecoder.class); // has duplicated support for the same target Type
|
||||
@SuppressWarnings("unused")
|
||||
Decoders decoders = new Decoders(factory,config);
|
||||
Assert.fail("Should have thrown DeploymentException");
|
||||
}
|
||||
catch (DeploymentException e)
|
||||
{
|
||||
Assert.assertThat("Error Message",e.getMessage(),containsString("duplicate"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTextDecoder_Fruit() throws DeploymentException
|
||||
{
|
||||
SimpleClientEndpointConfig config = new SimpleClientEndpointConfig();
|
||||
config.addDecoder(FruitDecoder.class);
|
||||
Decoders decoders = new Decoders(factory,config);
|
||||
|
||||
Decoder txtDecoder = decoders.getDecoder(Fruit.class);
|
||||
Assert.assertThat("Text Decoder",txtDecoder,notNullValue());
|
||||
Assert.assertThat("Text Decoder",txtDecoder,instanceOf(FruitDecoder.class));
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderMetadataFactory.DefaultsDecoderFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteArrayDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.ByteBufferDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.LongDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.decoders.StringDecoder;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class DefaultsDecoderFactoryTest
|
||||
{
|
||||
private static DefaultsDecoderFactory factory = new DefaultsDecoderFactory();
|
||||
|
||||
private void assertDefaultDecoderType(Class<? extends Decoder> decoder, MessageType expectedMsgType, Type expectedObjType)
|
||||
{
|
||||
List<DecoderMetadata> metadatas = factory.getMetadata(decoder);
|
||||
Assert.assertThat("Metadatas.size",metadatas.size(),is(1));
|
||||
DecoderMetadata metadata = metadatas.get(0);
|
||||
Assert.assertThat("Metadata.messageType",metadata.getMessageType(),is(expectedMsgType));
|
||||
Assert.assertThat("Metadata.objectType",metadata.getObjectType(),is(expectedObjType));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteArrayDecoder()
|
||||
{
|
||||
assertDefaultDecoderType(ByteArrayDecoder.class,MessageType.BINARY,byte[].class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetByteBufferDecoder()
|
||||
{
|
||||
assertDefaultDecoderType(ByteBufferDecoder.class,MessageType.BINARY,ByteBuffer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLongDecoder()
|
||||
{
|
||||
assertDefaultDecoderType(LongDecoder.class,MessageType.TEXT,Long.TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetStringDecoder()
|
||||
{
|
||||
assertDefaultDecoderType(StringDecoder.class,MessageType.TEXT,String.class);
|
||||
}
|
||||
}
|
|
@ -20,83 +20,90 @@ package org.eclipse.jetty.websocket.jsr356;
|
|||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.MessageHandler;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.EmptyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrEndpointEventDriver;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayWholeHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteBufferPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.LongMessageHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.StringWholeHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadataFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.DummyConnection;
|
||||
import org.eclipse.jetty.websocket.jsr356.samples.DummyEndpoint;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MessageHandlersTest
|
||||
public class JsrSessionTest
|
||||
{
|
||||
private MessageHandlerMetadataFactory factory;
|
||||
private Decoders decoders;
|
||||
private ClientContainer container;
|
||||
private JsrSession session;
|
||||
|
||||
@Before
|
||||
public void init() throws DeploymentException
|
||||
public void initSession()
|
||||
{
|
||||
SimpleClientEndpointConfig config = new SimpleClientEndpointConfig();
|
||||
DecoderMetadataFactory metadataFactory = new DecoderMetadataFactory();
|
||||
decoders = new Decoders(metadataFactory,config);
|
||||
factory = new MessageHandlerMetadataFactory(decoders);
|
||||
container = new ClientContainer();
|
||||
String id = JsrSessionTest.class.getSimpleName();
|
||||
URI requestURI = URI.create("ws://localhost/" + id);
|
||||
WebSocketPolicy policy = WebSocketPolicy.newClientPolicy();
|
||||
ClientEndpointConfig config = new EmptyClientEndpointConfig();
|
||||
DummyEndpoint websocket = new DummyEndpoint();
|
||||
EventDriver driver = new JsrEndpointEventDriver(policy,websocket,config);
|
||||
DummyConnection connection = new DummyConnection();
|
||||
session = new JsrSession(requestURI,driver,connection,container,id);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBinaryHandler() throws DeploymentException
|
||||
public void testMessageHandlerBinary() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
mhs.add(new ByteBufferPartialHandler());
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.BINARY);
|
||||
session.addMessageHandler(new ByteBufferPartialHandler());
|
||||
MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteBufferPartialHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),ByteBuffer.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetBothHandler() throws DeploymentException
|
||||
public void testMessageHandlerBoth() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
mhs.add(new StringWholeHandler());
|
||||
mhs.add(new ByteArrayWholeHandler());
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.TEXT);
|
||||
session.addMessageHandler(new StringWholeHandler());
|
||||
session.addMessageHandler(new ByteArrayWholeHandler());
|
||||
MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
|
||||
wrapper = mhs.getWrapper(MessageType.BINARY);
|
||||
wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteArrayWholeHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),byte[].class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetTextHandler() throws DeploymentException
|
||||
public void testMessageHandlerReplaceTextHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
mhs.add(new StringWholeHandler());
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.TEXT);
|
||||
Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReplaceTextHandler() throws DeploymentException
|
||||
{
|
||||
MessageHandlers mhs = new MessageHandlers(factory);
|
||||
MessageHandler oldText = new StringWholeHandler();
|
||||
mhs.add(oldText); // add a TEXT handler
|
||||
mhs.add(new ByteArrayWholeHandler()); // add BINARY handler
|
||||
mhs.remove(oldText); // remove original TEXT handler
|
||||
mhs.add(new LongMessageHandler()); // add new TEXT handler
|
||||
MessageHandlerWrapper wrapper = mhs.getWrapper(MessageType.BINARY);
|
||||
session.addMessageHandler(oldText); // add a TEXT handler
|
||||
session.addMessageHandler(new ByteArrayWholeHandler()); // add BINARY handler
|
||||
session.removeMessageHandler(oldText); // remove original TEXT handler
|
||||
session.addMessageHandler(new LongMessageHandler()); // add new TEXT handler
|
||||
MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.BINARY);
|
||||
Assert.assertThat("Binary Handler",wrapper.getHandler(),instanceOf(ByteArrayWholeHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),byte[].class);
|
||||
wrapper = mhs.getWrapper(MessageType.TEXT);
|
||||
wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(LongMessageHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),Long.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessageHandlerText() throws DeploymentException
|
||||
{
|
||||
session.addMessageHandler(new StringWholeHandler());
|
||||
MessageHandlerWrapper wrapper = session.getMessageHandlerWrapper(MessageType.TEXT);
|
||||
Assert.assertThat("Text Handler",wrapper.getHandler(),instanceOf(StringWholeHandler.class));
|
||||
Assert.assertEquals("Message Class",wrapper.getMetadata().getMessageClass(),String.class);
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.messages;
|
||||
package org.eclipse.jetty.websocket.jsr356;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
|
@ -25,30 +25,25 @@ import java.util.List;
|
|||
|
||||
import javax.websocket.DeploymentException;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderMetadataFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.Decoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.MessageType;
|
||||
import org.eclipse.jetty.websocket.jsr356.SimpleClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.ByteArrayPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.handlers.StringPartialHandler;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.MessageHandlerMetadataFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.DecoderMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.metadata.MessageHandlerMetadata;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
public class MessageHandlerMetadataFactoryTest
|
||||
public class MessageHandlerFactoryTest
|
||||
{
|
||||
private MessageHandlerMetadataFactory factory;
|
||||
private Decoders decoders;
|
||||
private MessageHandlerFactory factory;
|
||||
private DecoderFactory decoders;
|
||||
|
||||
@Before
|
||||
public void init() throws DeploymentException
|
||||
{
|
||||
SimpleClientEndpointConfig config = new SimpleClientEndpointConfig();
|
||||
DecoderMetadataFactory metadataFactory = new DecoderMetadataFactory();
|
||||
decoders = new Decoders(metadataFactory,config);
|
||||
factory = new MessageHandlerMetadataFactory(decoders);
|
||||
ClientContainer container = new ClientContainer();
|
||||
decoders = new DecoderFactory(container.getDecoderFactory());
|
||||
factory = new MessageHandlerFactory();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -57,9 +52,10 @@ public class MessageHandlerMetadataFactoryTest
|
|||
List<MessageHandlerMetadata> metadatas = factory.getMetadata(ByteArrayPartialHandler.class);
|
||||
Assert.assertThat("Metadata.list.size",metadatas.size(),is(1));
|
||||
|
||||
MessageHandlerMetadata metadata = metadatas.get(0);
|
||||
Assert.assertThat("Message Type",metadata.getMessageType(),is(MessageType.BINARY));
|
||||
Assert.assertThat("Message Class",metadata.getMessageClass(),is((Type)byte[].class));
|
||||
MessageHandlerMetadata handlerMetadata = metadatas.get(0);
|
||||
DecoderMetadata decoderMetadata = decoders.getMetadataFor(handlerMetadata.getMessageClass());
|
||||
Assert.assertThat("Message Type",decoderMetadata.getMessageType(),is(MessageType.BINARY));
|
||||
Assert.assertThat("Message Class",handlerMetadata.getMessageClass(),is((Type)byte[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -68,8 +64,9 @@ public class MessageHandlerMetadataFactoryTest
|
|||
List<MessageHandlerMetadata> metadatas = factory.getMetadata(StringPartialHandler.class);
|
||||
Assert.assertThat("Metadata.list.size",metadatas.size(),is(1));
|
||||
|
||||
MessageHandlerMetadata metadata = metadatas.get(0);
|
||||
Assert.assertThat("Message Type",metadata.getMessageType(),is(MessageType.TEXT));
|
||||
Assert.assertThat("Message Class",metadata.getMessageClass(),is((Type)String.class));
|
||||
MessageHandlerMetadata handlerMetadata = metadatas.get(0);
|
||||
DecoderMetadata decoderMetadata = decoders.getMetadataFor(handlerMetadata.getMessageClass());
|
||||
Assert.assertThat("Message Type",decoderMetadata.getMessageType(),is(MessageType.TEXT));
|
||||
Assert.assertThat("Message Class",handlerMetadata.getMessageClass(),is((Type)String.class));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.decoders;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
/**
|
||||
* Decode Date
|
||||
*/
|
||||
public class DateDecoder implements Decoder.Text<Date>
|
||||
{
|
||||
@Override
|
||||
public Date decode(String s) throws DecodeException
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat("yyyy.MM.dd").parse(s);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new DecodeException(s,e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDecode(String s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.decoders;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
/**
|
||||
* Decode Date and Time
|
||||
*/
|
||||
public class DateTimeDecoder implements Decoder.Text<Date>
|
||||
{
|
||||
@Override
|
||||
public Date decode(String s) throws DecodeException
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat("yyyy.MM.dd G 'at' HH:mm:ss z").parse(s);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new DecodeException(s,e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDecode(String s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.decoders;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.websocket.DecodeException;
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
/**
|
||||
* Decode Time
|
||||
*/
|
||||
public class TimeDecoder implements Decoder.Text<Date>
|
||||
{
|
||||
@Override
|
||||
public Date decode(String s) throws DecodeException
|
||||
{
|
||||
try
|
||||
{
|
||||
return new SimpleDateFormat("HH:mm:ss z").parse(s);
|
||||
}
|
||||
catch (ParseException e)
|
||||
{
|
||||
throw new DecodeException(s,e.getMessage(),e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init(EndpointConfig config)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean willDecode(String s)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@ import javax.websocket.DeploymentException;
|
|||
import org.eclipse.jetty.websocket.common.events.annotated.CallableMethod;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.JsrClientMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicOpenCloseSessionSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicOpenCloseSocket;
|
||||
import org.junit.Assert;
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
|||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrCallable;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.JsrClientMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicBinaryMessageByteBufferSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicCloseReasonSessionSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.BasicCloseReasonSocket;
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.websocket.common.events.annotated.InvalidSignatureException;
|
||||
import org.eclipse.jetty.websocket.jsr356.ClientContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.client.JsrClientMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.InvalidCloseIntSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.InvalidErrorErrorSocket;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.samples.InvalidErrorExceptionSocket;
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.samples;
|
||||
|
||||
import java.net.InetSocketAddress;
|
||||
|
||||
import org.eclipse.jetty.io.ByteBufferPool;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.io.IOState;
|
||||
|
||||
public class DummyConnection implements LogicalConnection
|
||||
{
|
||||
private IOState iostate;
|
||||
|
||||
public DummyConnection()
|
||||
{
|
||||
this.iostate = new IOState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(int statusCode, String reason)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnect()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public ByteBufferPool getBufferPool()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getIdleTimeout()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IOState getIOState()
|
||||
{
|
||||
return this.iostate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getLocalAddress()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxIdleTimeout()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketPolicy getPolicy()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InetSocketAddress getRemoteAddress()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession getSession()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isReading()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outgoingFrame(Frame frame, WriteCallback callback)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resume()
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTimeout(long ms)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNextIncomingFrames(IncomingFrames incoming)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSession(WebSocketSession session)
|
||||
{
|
||||
}
|
||||
|
||||
@Override
|
||||
public SuspendToken suspend()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.samples;
|
||||
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
|
||||
public class DummyEndpoint extends Endpoint
|
||||
{
|
||||
@Override
|
||||
public void onOpen(Session session, EndpointConfig config)
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.jsr356.LEVEL=DEBUG
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.Extension;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
public class AnnotatedServerEndpointConfig implements ServerEndpointConfig
|
||||
{
|
||||
private final Class<?> endpointClass;
|
||||
private final String path;
|
||||
private final List<Class<? extends Decoder>> decoders;
|
||||
private final List<Class<? extends Encoder>> encoders;
|
||||
private final Configurator configurator;
|
||||
private final List<String> subprotocols;
|
||||
|
||||
private Map<String, Object> userProperties;
|
||||
private List<Extension> extensions;
|
||||
|
||||
public AnnotatedServerEndpointConfig(Class<?> endpointClass, ServerEndpoint anno) throws DeploymentException
|
||||
{
|
||||
this.decoders = Collections.unmodifiableList(Arrays.asList(anno.decoders()));
|
||||
this.encoders = Collections.unmodifiableList(Arrays.asList(anno.encoders()));
|
||||
this.subprotocols = Collections.unmodifiableList(Arrays.asList(anno.subprotocols()));
|
||||
|
||||
// supplied by init lifecycle
|
||||
this.extensions = new ArrayList<>();
|
||||
this.path = anno.value();
|
||||
this.endpointClass = endpointClass;
|
||||
// no userProperties in annotation
|
||||
this.userProperties = new HashMap<>();
|
||||
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
this.configurator = BasicServerEndpointConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ClientEndpoint.configurator() of ");
|
||||
err.append(anno.configurator().getName());
|
||||
err.append(" defined as annotation in ");
|
||||
err.append(anno.getClass().getName());
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders()
|
||||
{
|
||||
return encoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getEndpointClass()
|
||||
{
|
||||
return endpointClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSubprotocols()
|
||||
{
|
||||
return subprotocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator()
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
}
|
|
@ -29,9 +29,10 @@ import javax.websocket.server.ServerEndpointConfig.Configurator;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
|
||||
public class JettyServerEndpointConfigurator extends Configurator
|
||||
public class BasicServerEndpointConfigurator extends Configurator
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JettyServerEndpointConfigurator.class);
|
||||
private static final Logger LOG = Log.getLogger(BasicServerEndpointConfigurator.class);
|
||||
public static final Configurator INSTANCE = new BasicServerEndpointConfigurator();
|
||||
|
||||
@Override
|
||||
public boolean checkOrigin(String originHeaderValue)
|
|
@ -1,209 +0,0 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.Encoder;
|
||||
import javax.websocket.Extension;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
public class JettyServerEndpointConfig implements ServerEndpointConfig
|
||||
{
|
||||
public static class BaseConfigurator extends ServerEndpointConfig.Configurator
|
||||
{
|
||||
public static final BaseConfigurator INSTANCE = new BaseConfigurator();
|
||||
}
|
||||
|
||||
private final Class<?> endpointClass;
|
||||
private final String path;
|
||||
private Configurator configurator;
|
||||
private List<Class<? extends Decoder>> decoders;
|
||||
private List<Class<? extends Encoder>> encoders;
|
||||
private List<String> subprotocols;
|
||||
private List<Extension> extensions;
|
||||
private Map<String, Object> userProperties;
|
||||
|
||||
public JettyServerEndpointConfig(Class<?> endpointClass, ServerEndpoint anno) throws DeploymentException
|
||||
{
|
||||
this(endpointClass,anno.value());
|
||||
addAll(anno.decoders(),this.decoders);
|
||||
addAll(anno.encoders(),this.encoders);
|
||||
addAll(anno.subprotocols(),this.subprotocols);
|
||||
// no extensions declared in annotation
|
||||
// no userProperties in annotation
|
||||
if (anno.configurator() == null)
|
||||
{
|
||||
this.configurator = BaseConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
this.configurator = anno.configurator().newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ServerEndpoint.configurator() of ");
|
||||
err.append(anno.configurator().getName());
|
||||
err.append(" defined as annotation in ");
|
||||
err.append(anno.getClass().getName());
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public JettyServerEndpointConfig(Class<?> endpointClass, String path)
|
||||
{
|
||||
this.endpointClass = endpointClass;
|
||||
this.path = path;
|
||||
|
||||
this.configurator = new BaseConfigurator();
|
||||
this.decoders = new ArrayList<>();
|
||||
this.encoders = new ArrayList<>();
|
||||
this.subprotocols = new ArrayList<>();
|
||||
this.extensions = new ArrayList<>();
|
||||
this.userProperties = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy Constructor
|
||||
*
|
||||
* @param copy
|
||||
* the endpoint configuration to copy
|
||||
* @throws DeploymentException
|
||||
*/
|
||||
public JettyServerEndpointConfig(JettyServerEndpointConfig copy) throws DeploymentException
|
||||
{
|
||||
this(copy.endpointClass,copy.path);
|
||||
this.decoders.addAll(copy.decoders);
|
||||
this.encoders.addAll(copy.encoders);
|
||||
this.subprotocols.addAll(copy.subprotocols);
|
||||
this.extensions.addAll(copy.extensions);
|
||||
this.userProperties.putAll(copy.userProperties);
|
||||
if (copy.configurator instanceof BaseConfigurator)
|
||||
{
|
||||
this.configurator = BaseConfigurator.INSTANCE;
|
||||
}
|
||||
else
|
||||
{
|
||||
Class<? extends Configurator> configuratorClass = copy.configurator.getClass();
|
||||
try
|
||||
{
|
||||
this.configurator = configuratorClass.newInstance();
|
||||
}
|
||||
catch (InstantiationException | IllegalAccessException e)
|
||||
{
|
||||
StringBuilder err = new StringBuilder();
|
||||
err.append("Unable to instantiate ServerEndpointConfig.Configurator of ");
|
||||
err.append(configuratorClass);
|
||||
throw new DeploymentException(err.toString(),e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void addAll(T[] arr, List<T> lst)
|
||||
{
|
||||
if (arr == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
for (T t : arr)
|
||||
{
|
||||
lst.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator()
|
||||
{
|
||||
return configurator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Decoder>> getDecoders()
|
||||
{
|
||||
return decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Class<? extends Encoder>> getEncoders()
|
||||
{
|
||||
return encoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getEndpointClass()
|
||||
{
|
||||
return endpointClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Extension> getExtensions()
|
||||
{
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getSubprotocols()
|
||||
{
|
||||
return subprotocols;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getUserProperties()
|
||||
{
|
||||
return userProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("JettyServerEndpointConfig [endpointClass=");
|
||||
builder.append(endpointClass);
|
||||
builder.append(", path=");
|
||||
builder.append(path);
|
||||
builder.append(", configurator=");
|
||||
builder.append(configurator);
|
||||
builder.append(", decoders=");
|
||||
builder.append(decoders);
|
||||
builder.append(", encoders=");
|
||||
builder.append(encoders);
|
||||
builder.append(", subprotocols=");
|
||||
builder.append(subprotocols);
|
||||
builder.append(", extensions=");
|
||||
builder.append(extensions);
|
||||
builder.append("]");
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
|
@ -67,7 +67,7 @@ public class JsrServerEndpointImpl implements EventDriverImpl
|
|||
JsrEvents events = new JsrEvents(basemetadata); // copy constructor.
|
||||
|
||||
// Create copy of base config
|
||||
ServerEndpointConfig config = basemetadata.getEndpointConfigCopy();
|
||||
ServerEndpointConfig config = basemetadata.getConfig();
|
||||
return new JsrAnnotatedEventDriver(policy,endpoint,events,config);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,25 +19,24 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.server;
|
||||
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.websocket.Decoder;
|
||||
import javax.websocket.DeploymentException;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
import javax.websocket.server.ServerEndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.InvalidWebSocketException;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderWrapper;
|
||||
import org.eclipse.jetty.websocket.jsr356.Decoders;
|
||||
import org.eclipse.jetty.websocket.jsr356.DecoderFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.EncoderFactory;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.IJsrParamId;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrMetadata;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdBinaryDecoder;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdTextDecoder;
|
||||
|
||||
public class JsrServerMetadata extends JsrMetadata<ServerEndpoint>
|
||||
{
|
||||
private final ServerEndpoint endpoint;
|
||||
private final JettyServerEndpointConfig config;
|
||||
private final Decoders decoders;
|
||||
private final AnnotatedServerEndpointConfig config;
|
||||
private final DecoderFactory decoders;
|
||||
private final EncoderFactory encoders;
|
||||
|
||||
protected JsrServerMetadata(ServerContainer container, Class<?> websocket) throws DeploymentException
|
||||
{
|
||||
|
@ -50,8 +49,12 @@ public class JsrServerMetadata extends JsrMetadata<ServerEndpoint>
|
|||
}
|
||||
|
||||
this.endpoint = anno;
|
||||
this.config = new JettyServerEndpointConfig(websocket,anno);
|
||||
this.decoders = new Decoders(container.getDecoderMetadataFactory(),config);
|
||||
this.config = new AnnotatedServerEndpointConfig(websocket,anno);
|
||||
this.decoders = new DecoderFactory(container.getDecoderFactory());
|
||||
this.encoders = new EncoderFactory(container.getEncoderFactory());
|
||||
|
||||
this.decoders.registerAll(anno.decoders());
|
||||
this.encoders.registerAll(anno.encoders());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -65,28 +68,11 @@ public class JsrServerMetadata extends JsrMetadata<ServerEndpoint>
|
|||
{
|
||||
params.addFirst(JsrParamPath.INSTANCE);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void customizeParamsOnMessage(LinkedList<IJsrParamId> params)
|
||||
protected List<Class<? extends Decoder>> getConfiguredDecoders()
|
||||
{
|
||||
for (DecoderWrapper wrapper : decoders.wrapperSet())
|
||||
{
|
||||
Class<? extends Decoder> decoder = wrapper.getMetadata().getDecoder();
|
||||
|
||||
if (Decoder.Text.class.isAssignableFrom(decoder) || Decoder.TextStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
params.add(new JsrParamIdTextDecoder(wrapper));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Decoder.Binary.class.isAssignableFrom(decoder) || Decoder.BinaryStream.class.isAssignableFrom(decoder))
|
||||
{
|
||||
params.add(new JsrParamIdBinaryDecoder(wrapper));
|
||||
continue;
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Invalid Decoder: " + decoder);
|
||||
}
|
||||
return config.getDecoders();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -101,10 +87,9 @@ public class JsrServerMetadata extends JsrMetadata<ServerEndpoint>
|
|||
return endpoint;
|
||||
}
|
||||
|
||||
public ServerEndpointConfig getEndpointConfigCopy() throws DeploymentException
|
||||
public AnnotatedServerEndpointConfig getConfig()
|
||||
{
|
||||
// Copy constructor
|
||||
return new JettyServerEndpointConfig(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
public String getPath()
|
||||
|
|
|
@ -60,7 +60,7 @@ public class ServerContainer extends ClientContainer implements javax.websocket.
|
|||
|
||||
public void addEndpoint(JsrServerMetadata metadata) throws DeploymentException
|
||||
{
|
||||
addEndpoint(metadata.getEndpointConfigCopy());
|
||||
addEndpoint(metadata.getConfig());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -1 +1 @@
|
|||
org.eclipse.jetty.websocket.jsr356.server.JettyServerEndpointConfigurator
|
||||
org.eclipse.jetty.websocket.jsr356.server.BasicServerEndpointConfigurator
|
|
@ -46,6 +46,6 @@ public class JettyServerEndpointConfiguratorTest
|
|||
|
||||
ServerEndpointConfig.Configurator configr = iter.next();
|
||||
assertThat("Configurator",configr,notNullValue());
|
||||
assertThat("COnfigurator type",configr,instanceOf(JettyServerEndpointConfigurator.class));
|
||||
assertThat("COnfigurator type",configr,instanceOf(BasicServerEndpointConfigurator.class));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server;
|
||||
|
||||
import java.net.URI;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.TestingDir;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.eclipse.jetty.websocket.jsr356.server.samples.echo.EchoReturnEndpoint;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
|
||||
public class OnMessageReturnTest
|
||||
{
|
||||
@Rule
|
||||
public TestingDir testdir = new TestingDir();
|
||||
|
||||
@Test
|
||||
public void testEchoReturn() throws Exception
|
||||
{
|
||||
WSServer wsb = new WSServer(testdir,"app");
|
||||
wsb.copyWebInf("empty-web.xml");
|
||||
wsb.copyClass(EchoReturnEndpoint.class);
|
||||
|
||||
try
|
||||
{
|
||||
wsb.start();
|
||||
URI uri = wsb.getServerBaseURI();
|
||||
|
||||
WebAppContext webapp = wsb.createWebAppContext();
|
||||
wsb.deployWebapp(webapp);
|
||||
wsb.dump();
|
||||
|
||||
WebSocketClient client = new WebSocketClient();
|
||||
try
|
||||
{
|
||||
client.start();
|
||||
JettyEchoSocket clientEcho = new JettyEchoSocket();
|
||||
Future<Session> future = client.connect(clientEcho,uri.resolve("echoreturn"));
|
||||
// wait for connect
|
||||
future.get(1,TimeUnit.SECONDS);
|
||||
clientEcho.sendMessage("Hello World");
|
||||
Queue<String> msgs = clientEcho.awaitMessages(1);
|
||||
Assert.assertEquals("Expected message","Hello World",msgs.poll());
|
||||
}
|
||||
finally
|
||||
{
|
||||
client.stop();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
wsb.stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -20,14 +20,13 @@ package org.eclipse.jetty.websocket.jsr356.server;
|
|||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.CloseReason.CloseCode;
|
||||
|
||||
import org.eclipse.jetty.util.BlockingArrayQueue;
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.junit.Assert;
|
||||
|
@ -40,8 +39,8 @@ public abstract class TrackingSocket
|
|||
private static final Logger LOG = Log.getLogger(TrackingSocket.class);
|
||||
|
||||
public CloseReason closeReason;
|
||||
public BlockingQueue<String> eventQueue = new BlockingArrayQueue<String>();
|
||||
public BlockingQueue<Throwable> errorQueue = new BlockingArrayQueue<>();
|
||||
public EventQueue<String> eventQueue = new EventQueue<String>();
|
||||
public EventQueue<Throwable> errorQueue = new EventQueue<>();
|
||||
public CountDownLatch openLatch = new CountDownLatch(1);
|
||||
public CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
public CountDownLatch dataLatch = new CountDownLatch(1);
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.server.samples.echo;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import javax.websocket.CloseReason;
|
||||
import javax.websocket.OnMessage;
|
||||
import javax.websocket.OnOpen;
|
||||
import javax.websocket.Session;
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.EventQueue;
|
||||
|
||||
@ServerEndpoint(value = "/echoreturn")
|
||||
public class EchoReturnEndpoint
|
||||
{
|
||||
private Session session = null;
|
||||
public CloseReason close = null;
|
||||
public EventQueue<String> messageQueue = new EventQueue<>();
|
||||
|
||||
public void onClose(CloseReason close)
|
||||
{
|
||||
this.close = close;
|
||||
}
|
||||
|
||||
@OnMessage
|
||||
public String onMessage(String message)
|
||||
{
|
||||
this.messageQueue.offer(message);
|
||||
// Return the message
|
||||
return message;
|
||||
}
|
||||
|
||||
@OnOpen
|
||||
public void onOpen(Session session)
|
||||
{
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
public void sendText(String text) throws IOException
|
||||
{
|
||||
if (session != null)
|
||||
{
|
||||
session.getBasicRemote().sendText(text);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
org.eclipse.jetty.util.log.class=org.eclipse.jetty.util.log.StdErrLog
|
||||
org.eclipse.jetty.LEVEL=WARN
|
||||
|
||||
# org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
org.eclipse.jetty.websocket.LEVEL=DEBUG
|
||||
# org.eclipse.jetty.websocket.LEVEL=WARN
|
||||
# org.eclipse.jetty.websocket.common.io.LEVEL=DEBUG
|
||||
|
||||
|
|
|
@ -42,18 +42,18 @@ public class CallableMethod
|
|||
this.paramTypes = method.getParameterTypes();
|
||||
}
|
||||
|
||||
public void call(Object obj, Object... args)
|
||||
public Object 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
|
||||
return null; // no call event method determined
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
LOG.warn("Cannot call {} on null object",this.method);
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
|
||||
if (args.length < paramTypes.length)
|
||||
|
@ -64,7 +64,7 @@ public class CallableMethod
|
|||
|
||||
try
|
||||
{
|
||||
this.method.invoke(obj,args);
|
||||
return this.method.invoke(obj,args);
|
||||
}
|
||||
catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue