JSR-356 - updates to Session tracking and start of PathMappings
+ Refactored websocket-commons Session creation to be factory based + Introduced new org.eclipse.jetty.websocket.common.SessionFactory + Made websocket-client and websocket-server use new SessionFactory + Introduced JsrSessionFactory to allow for consistent Session creation even in the Jsr (no more duplciate Session creation) + Using JsrSessionFactory in javax-websocket-client-impl + Introducing PathMappings to hopefully replace jetty-util's PathMap + Using standard ClientEndpointConfig when appropriate. + Introducing JettyClientEndpointConfig for annotation based configurations + Renaming EchoSocket used in javax.websocket client testing to JettyEchoSocket to better indicate that its the Jetty server side implementation and not the javax.websocket client side socket. + Changed IncomingFrames.incomingError() parameter from WebSocketException to Throwable to match behavior on the JSR
This commit is contained in:
parent
4dea484853
commit
e0d353629f
|
@ -1,106 +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.Arrays;
|
||||
import java.util.Collections;
|
||||
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;
|
||||
|
||||
/**
|
||||
* The DefaultClientEndpointConfig to use.
|
||||
*/
|
||||
public class DefaultClientEndpointConfig implements ClientEndpointConfig
|
||||
{
|
||||
public static class DefaultClientEndpointConfigurator extends ClientEndpointConfig.Configurator
|
||||
{
|
||||
public static final DefaultClientEndpointConfigurator INSTANCE = new DefaultClientEndpointConfigurator();
|
||||
}
|
||||
|
||||
private List<Class<? extends Decoder>> decoders;
|
||||
private List<Class<? extends Encoder>> encoders;
|
||||
private List<Extension> extensions;
|
||||
private Map<String, Object> userProperties;
|
||||
private List<String> preferredSubprotocols;
|
||||
|
||||
private DefaultClientEndpointConfig()
|
||||
{
|
||||
this.extensions = new ArrayList<>();
|
||||
this.userProperties = new HashMap<>();
|
||||
this.preferredSubprotocols = new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor from annotation.
|
||||
*
|
||||
* @param decoders
|
||||
* the array of decoder classes on the annotation
|
||||
* @param encoders
|
||||
* the array of encoder classes on the annotation
|
||||
*/
|
||||
public DefaultClientEndpointConfig(Class<? extends Decoder>[] decoders, Class<? extends Encoder>[] encoders)
|
||||
{
|
||||
this();
|
||||
this.decoders = Collections.unmodifiableList(Arrays.asList(decoders));
|
||||
this.encoders = Collections.unmodifiableList(Arrays.asList(encoders));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Configurator getConfigurator()
|
||||
{
|
||||
return DefaultClientEndpointConfigurator.INSTANCE;
|
||||
}
|
||||
|
||||
@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,180 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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);
|
||||
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 ClientEndpoint.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;
|
||||
}
|
||||
}
|
|
@ -24,7 +24,6 @@ import java.util.HashSet;
|
|||
import java.util.Set;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import javax.websocket.ClientEndpointConfig;
|
||||
import javax.websocket.DeploymentException;
|
||||
|
@ -38,7 +37,6 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
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.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.ConfiguredEndpoint;
|
||||
import org.eclipse.jetty.websocket.jsr356.endpoints.JsrEventDriverFactory;
|
||||
|
||||
|
@ -50,7 +48,6 @@ public class JettyWebSocketContainer implements WebSocketContainer
|
|||
private static final Logger LOG = Log.getLogger(JettyWebSocketContainer.class);
|
||||
private final DecoderMetadataFactory decoderMetadataFactory;
|
||||
private WebSocketClient client;
|
||||
private AtomicLong idgen = new AtomicLong(0);
|
||||
|
||||
public JettyWebSocketContainer()
|
||||
{
|
||||
|
@ -58,6 +55,7 @@ public class JettyWebSocketContainer implements WebSocketContainer
|
|||
|
||||
client = new WebSocketClient();
|
||||
client.setEventDriverFactory(new JsrEventDriverFactory(client.getPolicy(),this));
|
||||
client.setSessionFactory(new JsrSessionFactory(this));
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -71,7 +69,13 @@ public class JettyWebSocketContainer implements WebSocketContainer
|
|||
|
||||
private Session connect(Object websocket, ClientEndpointConfig config, URI path) throws IOException
|
||||
{
|
||||
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(websocket,config);
|
||||
ClientEndpointConfig cec = config;
|
||||
if (cec == null)
|
||||
{
|
||||
cec = ClientEndpointConfig.Builder.create().build();
|
||||
}
|
||||
|
||||
ConfiguredEndpoint endpoint = new ConfiguredEndpoint(websocket,cec);
|
||||
ClientUpgradeRequest req = new ClientUpgradeRequest();
|
||||
if (config != null)
|
||||
{
|
||||
|
@ -88,8 +92,7 @@ public class JettyWebSocketContainer implements WebSocketContainer
|
|||
Future<org.eclipse.jetty.websocket.api.Session> futSess = client.connect(endpoint,path,req);
|
||||
try
|
||||
{
|
||||
WebSocketSession sess = (WebSocketSession)futSess.get();
|
||||
return new JsrSession(this,sess,getNextId());
|
||||
return (JsrSession)futSess.get();
|
||||
}
|
||||
catch (InterruptedException | ExecutionException e)
|
||||
{
|
||||
|
@ -180,11 +183,6 @@ public class JettyWebSocketContainer implements WebSocketContainer
|
|||
return ret;
|
||||
}
|
||||
|
||||
public String getNextId()
|
||||
{
|
||||
return String.format("websocket-%d",idgen.incrementAndGet());
|
||||
}
|
||||
|
||||
public Set<Session> getOpenSessions()
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
|
|
|
@ -37,14 +37,14 @@ import javax.websocket.Session;
|
|||
import javax.websocket.WebSocketContainer;
|
||||
|
||||
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;
|
||||
|
||||
public class JsrSession implements Session
|
||||
public class JsrSession extends WebSocketSession implements javax.websocket.Session
|
||||
{
|
||||
private final JettyWebSocketContainer container;
|
||||
/** Jetty API Session Impl */
|
||||
private final WebSocketSession jettySession;
|
||||
private final String id;
|
||||
private List<Extension> negotiatedExtensions;
|
||||
private Map<String, List<String>> jsrParameterMap;
|
||||
|
@ -55,10 +55,10 @@ public class JsrSession implements Session
|
|||
private JsrAsyncRemote asyncRemote;
|
||||
private JsrBasicRemote basicRemote;
|
||||
|
||||
public JsrSession(JettyWebSocketContainer container, WebSocketSession session, String id)
|
||||
public JsrSession(URI requestURI, EventDriver websocket, LogicalConnection connection, JettyWebSocketContainer container, String id)
|
||||
{
|
||||
super(requestURI,websocket,connection);
|
||||
this.container = container;
|
||||
this.jettySession = session;
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
|
@ -69,15 +69,9 @@ public class JsrSession implements Session
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
public void close(CloseReason closeReason) throws IOException
|
||||
{
|
||||
jettySession.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close(CloseReason closeStatus) throws IOException
|
||||
{
|
||||
jettySession.close(closeStatus.getCloseCode().getCode(),closeStatus.getReasonPhrase());
|
||||
close(closeReason.getCloseCode().getCode(),closeReason.getReasonPhrase());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -85,7 +79,7 @@ public class JsrSession implements Session
|
|||
{
|
||||
if (asyncRemote == null)
|
||||
{
|
||||
asyncRemote = new JsrAsyncRemote(jettySession.getRemote());
|
||||
asyncRemote = new JsrAsyncRemote(getRemote());
|
||||
}
|
||||
return asyncRemote;
|
||||
}
|
||||
|
@ -95,7 +89,7 @@ public class JsrSession implements Session
|
|||
{
|
||||
if (basicRemote == null)
|
||||
{
|
||||
basicRemote = new JsrBasicRemote(jettySession);
|
||||
basicRemote = new JsrBasicRemote(this);
|
||||
}
|
||||
return basicRemote;
|
||||
}
|
||||
|
@ -106,6 +100,11 @@ public class JsrSession implements Session
|
|||
return this.container;
|
||||
}
|
||||
|
||||
public Decoders getDecodersFacade()
|
||||
{
|
||||
return this.decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId()
|
||||
{
|
||||
|
@ -115,19 +114,24 @@ public class JsrSession implements Session
|
|||
@Override
|
||||
public int getMaxBinaryMessageBufferSize()
|
||||
{
|
||||
return jettySession.getPolicy().getMaxBinaryMessageSize();
|
||||
return getPolicy().getMaxBinaryMessageSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getMaxIdleTimeout()
|
||||
{
|
||||
return jettySession.getPolicy().getIdleTimeout();
|
||||
return getPolicy().getIdleTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxTextMessageBufferSize()
|
||||
{
|
||||
return jettySession.getPolicy().getMaxTextMessageSize();
|
||||
return getPolicy().getMaxTextMessageSize();
|
||||
}
|
||||
|
||||
public MessageHandlers getMessageHandlerFacade()
|
||||
{
|
||||
return messageHandlers;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -147,7 +151,7 @@ public class JsrSession implements Session
|
|||
if (negotiatedExtensions == null)
|
||||
{
|
||||
negotiatedExtensions = new ArrayList<Extension>();
|
||||
for (ExtensionConfig cfg : jettySession.getUpgradeResponse().getExtensions())
|
||||
for (ExtensionConfig cfg : getUpgradeResponse().getExtensions())
|
||||
{
|
||||
negotiatedExtensions.add(new JsrExtension(cfg));
|
||||
}
|
||||
|
@ -158,7 +162,7 @@ public class JsrSession implements Session
|
|||
@Override
|
||||
public String getNegotiatedSubprotocol()
|
||||
{
|
||||
return jettySession.getUpgradeResponse().getAcceptedSubProtocol();
|
||||
return getUpgradeResponse().getAcceptedSubProtocol();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -176,25 +180,25 @@ public class JsrSession implements Session
|
|||
@Override
|
||||
public String getProtocolVersion()
|
||||
{
|
||||
return jettySession.getProtocolVersion();
|
||||
return getProtocolVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQueryString()
|
||||
{
|
||||
return jettySession.getUpgradeRequest().getRequestURI().getQuery();
|
||||
return getUpgradeRequest().getRequestURI().getQuery();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<String>> getRequestParameterMap()
|
||||
{
|
||||
return jettySession.getUpgradeRequest().getParameterMap();
|
||||
return getUpgradeRequest().getParameterMap();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getRequestURI()
|
||||
{
|
||||
return jettySession.getUpgradeRequest().getRequestURI();
|
||||
return getUpgradeRequest().getRequestURI();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -210,39 +214,37 @@ public class JsrSession implements Session
|
|||
return userProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpen()
|
||||
{
|
||||
return jettySession.isOpen();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSecure()
|
||||
{
|
||||
return jettySession.isSecure();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeMessageHandler(MessageHandler handler)
|
||||
{
|
||||
messageHandlers.remove(handler);
|
||||
}
|
||||
|
||||
public void setDecodersFacade(Decoders decoders)
|
||||
{
|
||||
this.decoders = decoders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxBinaryMessageBufferSize(int length)
|
||||
{
|
||||
jettySession.getPolicy().setMaxBinaryMessageBufferSize(length);
|
||||
getPolicy().setMaxBinaryMessageBufferSize(length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxIdleTimeout(long milliseconds)
|
||||
{
|
||||
jettySession.getPolicy().setIdleTimeout(milliseconds);
|
||||
getPolicy().setIdleTimeout(milliseconds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxTextMessageBufferSize(int length)
|
||||
{
|
||||
jettySession.getPolicy().setMaxTextMessageBufferSize(length);
|
||||
getPolicy().setMaxTextMessageBufferSize(length);
|
||||
}
|
||||
|
||||
public void setMessageHandlerFacade(MessageHandlers messageHandlers)
|
||||
{
|
||||
this.messageHandlers = messageHandlers;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.net.URI;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
||||
public class JsrSessionFactory implements SessionFactory
|
||||
{
|
||||
private AtomicLong idgen = new AtomicLong(0);
|
||||
private final JettyWebSocketContainer container;
|
||||
|
||||
public JsrSessionFactory(JettyWebSocketContainer container)
|
||||
{
|
||||
this.container = container;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
return new JsrSession(requestURI,websocket,connection,container,getNextId());
|
||||
}
|
||||
|
||||
public String getNextId()
|
||||
{
|
||||
return String.format("websocket-%d",idgen.incrementAndGet());
|
||||
}
|
||||
}
|
|
@ -46,7 +46,7 @@ import org.eclipse.jetty.websocket.jsr356.JettyWebSocketContainer;
|
|||
import org.eclipse.jetty.websocket.jsr356.JsrSession;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents;
|
||||
|
||||
public class JsrClientAnnotatedEventDriver extends AbstractEventDriver implements EventDriver, IJsrSession
|
||||
public class JsrClientAnnotatedEventDriver extends AbstractEventDriver implements EventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JsrClientAnnotatedEventDriver.class);
|
||||
private final JettyWebSocketContainer container;
|
||||
|
@ -56,14 +56,15 @@ public class JsrClientAnnotatedEventDriver extends AbstractEventDriver implement
|
|||
private ClientEndpointConfig endpointconfig;
|
||||
private MessageAppender activeMessage;
|
||||
|
||||
public JsrClientAnnotatedEventDriver(JettyWebSocketContainer container, WebSocketPolicy policy, Object websocket, JsrEvents events)
|
||||
public JsrClientAnnotatedEventDriver(JettyWebSocketContainer container, WebSocketPolicy policy, Object websocket, JsrEvents events,
|
||||
ClientEndpointConfig endpointconfig)
|
||||
{
|
||||
super(policy,websocket);
|
||||
this.container = container;
|
||||
this.events = events;
|
||||
this.endpointconfig = endpointconfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session getJsrSession()
|
||||
{
|
||||
return this.jsrsession;
|
||||
|
@ -317,8 +318,8 @@ public class JsrClientAnnotatedEventDriver extends AbstractEventDriver implement
|
|||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
String id = container.getNextId();
|
||||
this.jsrsession = new JsrSession(container,session,id);
|
||||
// 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
|
||||
|
|
|
@ -31,6 +31,9 @@ import org.eclipse.jetty.websocket.jsr356.JettyWebSocketContainer;
|
|||
import org.eclipse.jetty.websocket.jsr356.annotations.AnnotatedEndpointScanner;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrEvents;
|
||||
|
||||
/**
|
||||
* Event Driver for classes annotated with @{@link ClientEndpoint}
|
||||
*/
|
||||
public class JsrClientEndpointImpl implements EventDriverImpl
|
||||
{
|
||||
private ConcurrentHashMap<Class<?>, JsrClientMetadata> cache = new ConcurrentHashMap<>();
|
||||
|
@ -45,12 +48,17 @@ public class JsrClientEndpointImpl implements EventDriverImpl
|
|||
public EventDriver create(Object websocket, WebSocketPolicy policy) throws DeploymentException
|
||||
{
|
||||
Object endpoint = websocket;
|
||||
ClientEndpointConfig config = null;
|
||||
if (websocket instanceof ConfiguredEndpoint)
|
||||
{
|
||||
ConfiguredEndpoint ce = (ConfiguredEndpoint)websocket;
|
||||
endpoint = ce.getEndpoint();
|
||||
config = (ClientEndpointConfig)ce.getConfig();
|
||||
// Classes annotated with @ClientEndpoint cannot be created with
|
||||
// an external ClientEndpointConfig, this information MUST come
|
||||
// from the @ClientEndpoint annotation.
|
||||
if (ce.getConfig() != null)
|
||||
{
|
||||
throw new IllegalStateException("Cannot create @ClientEndpoint websocket with an external EndpointConfig");
|
||||
}
|
||||
}
|
||||
|
||||
Class<?> endpointClass = endpoint.getClass();
|
||||
|
@ -67,8 +75,11 @@ public class JsrClientEndpointImpl implements EventDriverImpl
|
|||
// At this point we have a base metadata, now we need to copy it for
|
||||
// this specific instance of the WebSocket Endpoint (as we will be
|
||||
// modifying the metadata)
|
||||
JsrEvents events = new JsrEvents(basemetadata);
|
||||
return new JsrClientAnnotatedEventDriver(container,policy,endpoint,events);
|
||||
JsrEvents events = new JsrEvents(basemetadata); // copy constructor.
|
||||
|
||||
// Create copy of base config
|
||||
ClientEndpointConfig config = basemetadata.getEndpointConfigCopy();
|
||||
return new JsrClientAnnotatedEventDriver(container,policy,endpoint,events,config);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -28,7 +28,7 @@ import javax.websocket.DeploymentException;
|
|||
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.DefaultClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.JettyClientEndpointConfig;
|
||||
import org.eclipse.jetty.websocket.jsr356.JettyWebSocketContainer;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.IJsrParamId;
|
||||
import org.eclipse.jetty.websocket.jsr356.annotations.JsrMetadata;
|
||||
|
@ -38,7 +38,7 @@ import org.eclipse.jetty.websocket.jsr356.annotations.JsrParamIdTextDecoder;
|
|||
public class JsrClientMetadata extends JsrMetadata<ClientEndpoint>
|
||||
{
|
||||
private final ClientEndpoint endpoint;
|
||||
private final ClientEndpointConfig config;
|
||||
private final JettyClientEndpointConfig config;
|
||||
private final Decoders decoders;
|
||||
|
||||
public JsrClientMetadata(JettyWebSocketContainer container, Class<?> websocket) throws DeploymentException
|
||||
|
@ -52,7 +52,7 @@ public class JsrClientMetadata extends JsrMetadata<ClientEndpoint>
|
|||
}
|
||||
|
||||
this.endpoint = anno;
|
||||
this.config = new DefaultClientEndpointConfig(anno.decoders(),anno.encoders());
|
||||
this.config = new JettyClientEndpointConfig(anno);
|
||||
this.decoders = new Decoders(container.getDecoderMetadataFactory(),config);
|
||||
}
|
||||
|
||||
|
@ -84,4 +84,10 @@ public class JsrClientMetadata extends JsrMetadata<ClientEndpoint>
|
|||
{
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
public ClientEndpointConfig getEndpointConfigCopy() throws DeploymentException
|
||||
{
|
||||
// Copy constructor
|
||||
return new JettyClientEndpointConfig(config);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,8 @@ import javax.websocket.Endpoint;
|
|||
import javax.websocket.EndpointConfig;
|
||||
import javax.websocket.Session;
|
||||
|
||||
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;
|
||||
|
@ -48,8 +50,10 @@ import org.eclipse.jetty.websocket.jsr356.messages.TextPartialMessage;
|
|||
import org.eclipse.jetty.websocket.jsr356.messages.TextStreamMessage;
|
||||
import org.eclipse.jetty.websocket.jsr356.messages.TextWholeMessage;
|
||||
|
||||
public class JsrEndpointEventDriver extends AbstractEventDriver implements EventDriver, IJsrSession
|
||||
public class JsrEndpointEventDriver extends AbstractEventDriver implements EventDriver
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(JsrEndpointEventDriver.class);
|
||||
|
||||
private final JettyWebSocketContainer container;
|
||||
private final Endpoint endpoint;
|
||||
private JsrSession jsrsession;
|
||||
|
@ -57,14 +61,19 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
private MessageAppender activeMessage;
|
||||
private boolean hasCloseBeenCalled = false;
|
||||
|
||||
public JsrEndpointEventDriver(JettyWebSocketContainer container, WebSocketPolicy policy, Endpoint endpoint)
|
||||
public JsrEndpointEventDriver(JettyWebSocketContainer container, WebSocketPolicy policy, Endpoint endpoint, EndpointConfig config)
|
||||
{
|
||||
super(policy,endpoint);
|
||||
this.container = container;
|
||||
this.endpoint = endpoint;
|
||||
this.endpointconfig = config;
|
||||
}
|
||||
|
||||
public EndpointConfig getEndpointconfig()
|
||||
{
|
||||
return endpointconfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Session getJsrSession()
|
||||
{
|
||||
return this.jsrsession;
|
||||
|
@ -123,7 +132,15 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
@Override
|
||||
public void onConnect()
|
||||
{
|
||||
endpoint.onOpen(jsrsession,endpointconfig);
|
||||
LOG.debug("onConnect({}, {})",jsrsession,endpointconfig);
|
||||
try
|
||||
{
|
||||
endpoint.onOpen(jsrsession,endpointconfig);
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
LOG.warn("Uncaught exception",t);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -188,11 +205,26 @@ public class JsrEndpointEventDriver extends AbstractEventDriver implements Event
|
|||
@Override
|
||||
public void openSession(WebSocketSession session)
|
||||
{
|
||||
String id = container.getNextId();
|
||||
this.jsrsession = new JsrSession(container,session,id);
|
||||
// TODO: Initialize the Decoders
|
||||
// TODO: Initialize the MessageHandlers
|
||||
// TODO: Set the Configuration?
|
||||
// Cast should be safe, as it was created by JsrSessionFactory
|
||||
this.jsrsession = (JsrSession)session;
|
||||
// TODO: Create Decoders (Facade)
|
||||
// TODO: Create MessageHandlers (Facade)
|
||||
|
||||
// Allow end-user socket to adjust configuration
|
||||
super.openSession(session);
|
||||
|
||||
// TODO: Initialize Decoders
|
||||
// TODO: Initialize MessageHandlers
|
||||
}
|
||||
|
||||
public void setEndpointconfig(EndpointConfig endpointconfig)
|
||||
{
|
||||
this.endpointconfig = endpointconfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s]",JsrEndpointEventDriver.class.getSimpleName(),endpoint.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
|
||||
import javax.websocket.Endpoint;
|
||||
import javax.websocket.EndpointConfig;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
@ -38,15 +39,17 @@ public class JsrEndpointImpl implements EventDriverImpl
|
|||
public EventDriver create(Object websocket, WebSocketPolicy policy)
|
||||
{
|
||||
Object endpoint = websocket;
|
||||
EndpointConfig config = null;
|
||||
|
||||
if (endpoint instanceof ConfiguredEndpoint)
|
||||
{
|
||||
// unwrap
|
||||
ConfiguredEndpoint ce = (ConfiguredEndpoint)websocket;
|
||||
endpoint = ce.getEndpoint();
|
||||
config = ce.getConfig();
|
||||
}
|
||||
|
||||
return new JsrEndpointEventDriver(container,policy,(Endpoint)endpoint);
|
||||
return new JsrEndpointEventDriver(container,policy,(Endpoint)endpoint,config);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.eclipse.jetty.websocket.servlet.WebSocketServletFactory;
|
|||
|
||||
public class EchoHandler extends WebSocketHandler implements WebSocketCreator
|
||||
{
|
||||
public EchoSocket socket = new EchoSocket();
|
||||
public JettyEchoSocket socket = new JettyEchoSocket();
|
||||
|
||||
@Override
|
||||
public void configure(WebSocketServletFactory factory)
|
||||
|
|
|
@ -24,11 +24,11 @@ import org.eclipse.jetty.util.log.Logger;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketAdapter;
|
||||
|
||||
/**
|
||||
* Jetty Echo Socket
|
||||
* Jetty Echo Socket. using Jetty techniques.
|
||||
*/
|
||||
public class EchoSocket extends WebSocketAdapter
|
||||
public class JettyEchoSocket extends WebSocketAdapter
|
||||
{
|
||||
private static final Logger LOG = Log.getLogger(EchoSocket.class);
|
||||
private static final Logger LOG = Log.getLogger(JettyEchoSocket.class);
|
||||
|
||||
@Override
|
||||
public void onWebSocketBinary(byte[] payload, int offset, int len)
|
|
@ -0,0 +1,143 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.pathmap;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.server.pathmap.PathMappings.MappedResource;
|
||||
|
||||
/**
|
||||
* Path Mappings of PathSpec to Resource.
|
||||
* <p>
|
||||
* Sorted into search order upon entry into the Set
|
||||
*
|
||||
* @param <E>
|
||||
*/
|
||||
public class PathMappings<E> implements Iterable<MappedResource<E>>
|
||||
{
|
||||
public static class MappedResource<E> implements Comparable<MappedResource<E>>
|
||||
{
|
||||
private final PathSpec pathSpec;
|
||||
private final E resource;
|
||||
|
||||
public MappedResource(PathSpec pathSpec, E resource)
|
||||
{
|
||||
this.pathSpec = pathSpec;
|
||||
this.resource = resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison is based solely on the pathSpec
|
||||
*/
|
||||
@Override
|
||||
public int compareTo(MappedResource<E> other)
|
||||
{
|
||||
return this.pathSpec.compareTo(other.pathSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
MappedResource<?> other = (MappedResource<?>)obj;
|
||||
if (pathSpec == null)
|
||||
{
|
||||
if (other.pathSpec != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!pathSpec.equals(other.pathSpec))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public PathSpec getPathSpec()
|
||||
{
|
||||
return pathSpec;
|
||||
}
|
||||
|
||||
public E getResource()
|
||||
{
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("MappedResource[pathSpec=%s,resource=%s]",pathSpec,resource);
|
||||
}
|
||||
}
|
||||
|
||||
private Set<MappedResource<E>> mappings = new TreeSet<MappedResource<E>>();
|
||||
private MappedResource<E> defaultResource = null;
|
||||
|
||||
public MappedResource<E> getMatch(String path)
|
||||
{
|
||||
for (MappedResource<E> mr : mappings)
|
||||
{
|
||||
if (mr.getPathSpec().matches(path))
|
||||
{
|
||||
return mr;
|
||||
}
|
||||
}
|
||||
return defaultResource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<MappedResource<E>> iterator()
|
||||
{
|
||||
return mappings.iterator();
|
||||
}
|
||||
|
||||
public void put(PathSpec pathSpec, E resource)
|
||||
{
|
||||
MappedResource<E> entry = new MappedResource<>(pathSpec,resource);
|
||||
if (pathSpec.group == PathSpecGroup.DEFAULT)
|
||||
{
|
||||
defaultResource = entry;
|
||||
}
|
||||
// TODO: warning on replacement of existing mapping?
|
||||
mappings.add(entry);
|
||||
}
|
||||
}
|
|
@ -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.server.pathmap;
|
||||
|
||||
import javax.websocket.server.ServerEndpoint;
|
||||
|
||||
/**
|
||||
* PathSpec for WebSocket @{@link ServerEndpoint} declarations.
|
||||
*/
|
||||
public class PathParamSpec extends PathSpec
|
||||
{
|
||||
public PathParamSpec(String pathParamSpec)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,259 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.pathmap;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
/**
|
||||
* The base PathSpec, based on Regex patterns.
|
||||
*/
|
||||
public class PathSpec implements Comparable<PathSpec>
|
||||
{
|
||||
protected String pathSpec;
|
||||
protected PathSpecGroup group;
|
||||
protected int pathDepth;
|
||||
protected int specLength;
|
||||
protected Pattern pattern;
|
||||
|
||||
protected PathSpec()
|
||||
{
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
public PathSpec(String pathSpec)
|
||||
{
|
||||
this.pathSpec = pathSpec;
|
||||
boolean inGrouping = false;
|
||||
this.pathDepth = 0;
|
||||
this.specLength = pathSpec.length();
|
||||
for (char c : pathSpec.toCharArray())
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '[':
|
||||
inGrouping = true;
|
||||
break;
|
||||
case ']':
|
||||
inGrouping = false;
|
||||
break;
|
||||
case '/':
|
||||
if (!inGrouping)
|
||||
{
|
||||
this.pathDepth++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.pattern = Pattern.compile(pathSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(PathSpec other)
|
||||
{
|
||||
// Grouping (increasing)
|
||||
int diff = this.group.ordinal() - other.group.ordinal();
|
||||
if (diff != 0)
|
||||
{
|
||||
return diff;
|
||||
}
|
||||
|
||||
// Spec Length (decreasing)
|
||||
diff = other.specLength - this.specLength;
|
||||
if (diff != 0)
|
||||
{
|
||||
return diff;
|
||||
}
|
||||
|
||||
// Path Spec Name (alphabetical)
|
||||
return this.pathSpec.compareTo(other.pathSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (obj == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
PathSpec other = (PathSpec)obj;
|
||||
if (pathSpec == null)
|
||||
{
|
||||
if (other.pathSpec != null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (!pathSpec.equals(other.pathSpec))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public Matcher getMatcher(String path)
|
||||
{
|
||||
return this.pattern.matcher(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of path elements that this path spec declares.
|
||||
* <p>
|
||||
* This is used to determine longest match logic.
|
||||
*
|
||||
* @return the depth of the path segments that this spec declares
|
||||
*/
|
||||
public int getPathDepth()
|
||||
{
|
||||
return pathDepth;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the portion of the path that is after the path spec.
|
||||
*
|
||||
* @param path
|
||||
* the path to match against
|
||||
* @return the path info portion of the string
|
||||
*/
|
||||
public String getPathInfo(String path)
|
||||
{
|
||||
// Path Info only valid for PREFIX_GLOB types
|
||||
if (group == PathSpecGroup.PREFIX_GLOB)
|
||||
{
|
||||
Matcher matcher = getMatcher(path);
|
||||
if (matcher.matches())
|
||||
{
|
||||
if (matcher.groupCount() >= 1)
|
||||
{
|
||||
String pathInfo = matcher.group(1);
|
||||
if ("".equals(pathInfo))
|
||||
{
|
||||
return "/";
|
||||
}
|
||||
else
|
||||
{
|
||||
return pathInfo;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The as-provided path spec.
|
||||
*
|
||||
* @return the as-provided path spec
|
||||
*/
|
||||
public String getPathSpec()
|
||||
{
|
||||
return pathSpec;
|
||||
}
|
||||
|
||||
public Pattern getPattern()
|
||||
{
|
||||
return pattern;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the relative path.
|
||||
*
|
||||
* @param base
|
||||
* the base the path is relative to
|
||||
* @param path
|
||||
* the additional path
|
||||
* @return the base plus path with pathSpec portion removed
|
||||
*/
|
||||
public String getRelativePath(String base, String path)
|
||||
{
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode()
|
||||
{
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = (prime * result) + ((pathSpec == null)?0:pathSpec.hashCode());
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test to see if the provided path matches this path spec
|
||||
*
|
||||
* @param path
|
||||
* the path to test
|
||||
* @return true if the path matches this path spec, false otherwise
|
||||
*/
|
||||
public boolean matches(String path)
|
||||
{
|
||||
return getMatcher(path).matches();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the portion of the path that matches a path spec.
|
||||
*
|
||||
* @param path
|
||||
* the path to match against
|
||||
* @return the match, or null if no match at all
|
||||
*/
|
||||
public String getPathMatch(String path)
|
||||
{
|
||||
Matcher matcher = getMatcher(path);
|
||||
if (matcher.matches())
|
||||
{
|
||||
if (matcher.groupCount() >= 1)
|
||||
{
|
||||
int idx = matcher.start(1);
|
||||
if (idx > 0)
|
||||
{
|
||||
if (path.charAt(idx - 1) == '/')
|
||||
{
|
||||
idx--;
|
||||
}
|
||||
return path.substring(0,idx);
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder str = new StringBuilder();
|
||||
str.append(this.getClass().getSimpleName()).append("[\"");
|
||||
str.append(pathSpec);
|
||||
str.append("\",pathDepth=").append(pathDepth);
|
||||
str.append(",group=").append(group);
|
||||
str.append(",pattern=").append(pattern);
|
||||
str.append("]");
|
||||
return str.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.pathmap;
|
||||
|
||||
/**
|
||||
* Types of path spec groups.
|
||||
* <p>
|
||||
* This is used to facilitate proper pathspec search order.
|
||||
* <p>
|
||||
* Search Order: {@link PathSpecGroup#ordinal()} [increasin], {@link PathSpec#specLength} [decreasing], {@link PathSpec#pathSpec} [natural sort order]
|
||||
*/
|
||||
public enum PathSpecGroup
|
||||
{
|
||||
/**
|
||||
* For exactly defined path specs, no glob.
|
||||
*/
|
||||
EXACT,
|
||||
/**
|
||||
* For path specs that have a hardcoded prefix and a trailing wildcard glob.
|
||||
* <p>
|
||||
*
|
||||
* <pre>
|
||||
* "/downloads/*" - servlet spec
|
||||
* "/api/*" - servlet spec
|
||||
* "^/rest/.*$" - regex spec
|
||||
* "/bookings/{guest-id}" - websocket spec
|
||||
* "/rewards/{vip-level}" - websocket spec
|
||||
* </pre>
|
||||
*/
|
||||
PREFIX_GLOB,
|
||||
/**
|
||||
* For path specs that have a hardcoded prefix and suffix with wildcard glob in the middle.
|
||||
*
|
||||
* <pre>
|
||||
* "^/downloads/[^/]*.zip$" - regex spec
|
||||
* "/a/{var}/c" - websocket spec
|
||||
* </pre>
|
||||
*
|
||||
* Note: there is no known servlet spec variant of this kind of path spec
|
||||
*/
|
||||
MIDDLE_GLOB,
|
||||
/**
|
||||
* For path specs that have a wildcard glob with a hardcoded suffix
|
||||
*
|
||||
* <pre>
|
||||
* "*.do" - servlet spec
|
||||
* "*.css" - servlet spec
|
||||
* "^.*\.zip$" - regex spec
|
||||
* </pre>
|
||||
*
|
||||
* Note: there is no known websocket spec variant of this kind of path spec
|
||||
*/
|
||||
SUFFIX_GLOB,
|
||||
/**
|
||||
* The default spec for accessing the Root and/or Default behavior.
|
||||
*
|
||||
* <pre>
|
||||
* "/" - servlet spec (Default Servlet)
|
||||
* "/" - websocket spec (Root Context)
|
||||
* "^/$" - regex spec (Root Context)
|
||||
* </pre>
|
||||
*/
|
||||
DEFAULT;
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.pathmap;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class ServletPathSpec extends PathSpec
|
||||
{
|
||||
public static final String PATH_SPEC_SEPARATORS = ":,";
|
||||
|
||||
/**
|
||||
* Get multi-path spec splits.
|
||||
*
|
||||
* @param servletPathSpec
|
||||
* the path spec that might contain multiple declared path specs
|
||||
* @return the individual path specs found.
|
||||
*/
|
||||
public static ServletPathSpec[] getMultiPathSpecs(String servletPathSpec)
|
||||
{
|
||||
String pathSpecs[] = servletPathSpec.split(PATH_SPEC_SEPARATORS);
|
||||
int len = pathSpecs.length;
|
||||
ServletPathSpec sps[] = new ServletPathSpec[len];
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
sps[i] = new ServletPathSpec(pathSpecs[i]);
|
||||
}
|
||||
return sps;
|
||||
}
|
||||
|
||||
public ServletPathSpec(String servletPathSpec)
|
||||
{
|
||||
super();
|
||||
assertValidServletPathSpec(servletPathSpec);
|
||||
|
||||
// The Path Spec for Default Servlet
|
||||
if ((servletPathSpec == null) || (servletPathSpec.length() == 0) || "/".equals(servletPathSpec))
|
||||
{
|
||||
super.pathSpec = "/";
|
||||
super.pattern = Pattern.compile("^(/.*)$");
|
||||
super.pathDepth = -1; // force this to be last in sort order
|
||||
this.specLength = 1;
|
||||
this.group = PathSpecGroup.DEFAULT;
|
||||
return;
|
||||
}
|
||||
|
||||
StringBuilder regex = new StringBuilder();
|
||||
regex.append("^");
|
||||
this.specLength = servletPathSpec.length();
|
||||
super.pathDepth = 0;
|
||||
char lastChar = servletPathSpec.charAt(specLength - 1);
|
||||
// prefix based
|
||||
if ((servletPathSpec.charAt(0) == '/') && (specLength > 1) && (lastChar == '*'))
|
||||
{
|
||||
this.group = PathSpecGroup.PREFIX_GLOB;
|
||||
}
|
||||
// suffix based
|
||||
else if (servletPathSpec.charAt(0) == '*')
|
||||
{
|
||||
this.group = PathSpecGroup.SUFFIX_GLOB;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.group = PathSpecGroup.EXACT;
|
||||
}
|
||||
|
||||
for (int i = 0; i < specLength; i++)
|
||||
{
|
||||
int cp = servletPathSpec.codePointAt(i);
|
||||
if (cp >= 128)
|
||||
{
|
||||
regex.appendCodePoint(cp);
|
||||
}
|
||||
else
|
||||
{
|
||||
char c = (char)cp;
|
||||
switch (c)
|
||||
{
|
||||
case '*':
|
||||
if (group != PathSpecGroup.PREFIX_GLOB)
|
||||
{
|
||||
regex.append(".*");
|
||||
}
|
||||
break;
|
||||
case '.':
|
||||
regex.append("\\.");
|
||||
break;
|
||||
case '/':
|
||||
super.pathDepth++;
|
||||
if ((group == PathSpecGroup.PREFIX_GLOB) && (i == (specLength - 2)))
|
||||
{
|
||||
regex.append("(/.*)?");
|
||||
}
|
||||
else
|
||||
{
|
||||
regex.append('/');
|
||||
}
|
||||
break;
|
||||
default:
|
||||
regex.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((group == PathSpecGroup.EXACT) && (lastChar != '/'))
|
||||
{
|
||||
super.pathDepth++;
|
||||
regex.append("/?$");
|
||||
}
|
||||
else
|
||||
{
|
||||
regex.append('$');
|
||||
}
|
||||
|
||||
super.pathSpec = servletPathSpec;
|
||||
super.pattern = Pattern.compile(regex.toString());
|
||||
}
|
||||
|
||||
private void assertValidServletPathSpec(String servletPathSpec)
|
||||
{
|
||||
if ((servletPathSpec == null) || servletPathSpec.equals(""))
|
||||
{
|
||||
return; // empty path spec
|
||||
}
|
||||
|
||||
// Ensure we don't have path spec separators here in our single path spec.
|
||||
for (char c : PATH_SPEC_SEPARATORS.toCharArray())
|
||||
{
|
||||
if (servletPathSpec.indexOf(c) >= 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: encountered Path Spec Separator [" + PATH_SPEC_SEPARATORS
|
||||
+ "] within specified path spec. did you forget to split this path spec up?");
|
||||
}
|
||||
}
|
||||
|
||||
int len = servletPathSpec.length();
|
||||
// path spec must either start with '/' or '*.'
|
||||
if (servletPathSpec.charAt(0) == '/')
|
||||
{
|
||||
// Prefix Based
|
||||
if (len == 1)
|
||||
{
|
||||
return; // simple '/' path spec
|
||||
}
|
||||
int idx = servletPathSpec.indexOf('*');
|
||||
if (idx < 0)
|
||||
{
|
||||
return; // no hit on glob '*'
|
||||
}
|
||||
// only allowed to have '*' at the end of the path spec
|
||||
if (idx != (len - 1))
|
||||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: glob '*' can only exist at end of prefix based matches");
|
||||
}
|
||||
}
|
||||
else if (servletPathSpec.startsWith("*."))
|
||||
{
|
||||
// Suffix Based
|
||||
int idx = servletPathSpec.indexOf('/');
|
||||
// cannot have path separator
|
||||
if (idx >= 0)
|
||||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have path separators");
|
||||
}
|
||||
|
||||
idx = servletPathSpec.indexOf('*',2);
|
||||
// only allowed to have 1 glob '*', at the start of the path spec
|
||||
if (idx >= 1)
|
||||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: suffix based path spec cannot have multiple glob '*'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("Servlet Spec 12.2 violation: path spec must start with \"/\" or \"*.\"");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.pathmap;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
import org.eclipse.jetty.websocket.jsr356.server.pathmap.PathMappings.MappedResource;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class PathMappingsTest
|
||||
{
|
||||
private void assertMatch(PathMappings<String> pathmap, String path, String expectedValue)
|
||||
{
|
||||
String msg = String.format(".getMatch(\"%s\")",path);
|
||||
MappedResource<String> match = pathmap.getMatch(path);
|
||||
Assert.assertThat(msg,match,notNullValue());
|
||||
String actualMatch = match.getResource();
|
||||
Assert.assertEquals(msg,expectedValue,actualMatch);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test the match order rules imposed by the Servlet API.
|
||||
* <p>
|
||||
* <ul>
|
||||
* <li>Exact match</li>
|
||||
* <li>Longest prefix match</li>
|
||||
* <li>Longest suffix match</li>
|
||||
* <li>default</li>
|
||||
* </ul>
|
||||
*/
|
||||
@Test
|
||||
public void testServletMatchOrder()
|
||||
{
|
||||
PathMappings<String> p = new PathMappings<>();
|
||||
|
||||
p.put(new ServletPathSpec("/abs/path"),"path");
|
||||
p.put(new ServletPathSpec("/abs/path/longer"),"longpath");
|
||||
p.put(new ServletPathSpec("/animal/bird/*"),"birds");
|
||||
p.put(new ServletPathSpec("/animal/fish/*"),"fishes");
|
||||
p.put(new ServletPathSpec("/animal/*"),"animals");
|
||||
p.put(new ServletPathSpec("*.tar.gz"),"tarball");
|
||||
p.put(new ServletPathSpec("*.gz"),"gzipped");
|
||||
p.put(new ServletPathSpec("/"),"default");
|
||||
|
||||
for (MappedResource<String> res : p)
|
||||
{
|
||||
System.out.printf(" %s%n",res);
|
||||
}
|
||||
|
||||
assertMatch(p,"/abs/path","path");
|
||||
assertMatch(p,"/abs/path/longer","longpath");
|
||||
assertMatch(p,"/abs/path/foo","default");
|
||||
assertMatch(p,"/main.css","default");
|
||||
assertMatch(p,"/downloads/script.gz","gzipped");
|
||||
assertMatch(p,"/downloads/distribution.tar.gz","tarball");
|
||||
assertMatch(p,"/downloads/readme.txt","default");
|
||||
assertMatch(p,"/downloads/logs.tgz","default");
|
||||
assertMatch(p,"/animal/horse/mustang","animals");
|
||||
assertMatch(p,"/animal/bird/eagle/bald","birds");
|
||||
assertMatch(p,"/animal/fish/shark/hammerhead","fishes");
|
||||
assertMatch(p,"/animal/insect/ladybug","animals");
|
||||
}
|
||||
}
|
|
@ -16,14 +16,14 @@
|
|||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.jsr356.endpoints;
|
||||
package org.eclipse.jetty.websocket.jsr356.server.pathmap;
|
||||
|
||||
import javax.websocket.Session;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Used to tag and expose JSR based EventDriver's that expose the JSR {@link Session}
|
||||
*/
|
||||
public interface IJsrSession
|
||||
public class PathSpecTest
|
||||
{
|
||||
public Session getJsrSession();
|
||||
@Test
|
||||
public void test()
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// 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.pathmap;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class ServletPathSpecTest
|
||||
{
|
||||
private void assertBadServletPathSpec(String pathSpec)
|
||||
{
|
||||
try
|
||||
{
|
||||
new ServletPathSpec(pathSpec);
|
||||
fail("Expected IllegalArgumentException for a bad servlet pathspec on: " + pathSpec);
|
||||
}
|
||||
catch (IllegalArgumentException e)
|
||||
{
|
||||
// expected path
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadServletPathSpecA()
|
||||
{
|
||||
assertBadServletPathSpec("foo");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadServletPathSpecB()
|
||||
{
|
||||
assertBadServletPathSpec("/foo/*.do");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadServletPathSpecC()
|
||||
{
|
||||
assertBadServletPathSpec("foo/*.do");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadServletPathSpecD()
|
||||
{
|
||||
assertBadServletPathSpec("foo/*.*do");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBadServletPathSpecE()
|
||||
{
|
||||
assertBadServletPathSpec("*do");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPathSpec()
|
||||
{
|
||||
ServletPathSpec spec = new ServletPathSpec("/");
|
||||
assertEquals("Spec.pathSpec","/",spec.getPathSpec());
|
||||
assertEquals("Spec.pattern","^(/.*)$",spec.getPattern().pattern());
|
||||
assertEquals("Spec.pathDepth",-1,spec.getPathDepth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyPathSpec()
|
||||
{
|
||||
ServletPathSpec spec = new ServletPathSpec("");
|
||||
assertEquals("Spec.pathSpec","/",spec.getPathSpec());
|
||||
assertEquals("Spec.pattern","^(/.*)$",spec.getPattern().pattern());
|
||||
assertEquals("Spec.pathDepth",-1,spec.getPathDepth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExactPathSpec()
|
||||
{
|
||||
ServletPathSpec spec = new ServletPathSpec("/abs/path");
|
||||
assertEquals("Spec.pathSpec","/abs/path",spec.getPathSpec());
|
||||
assertEquals("Spec.pattern","^/abs/path/?$",spec.getPattern().pattern());
|
||||
assertEquals("Spec.pathDepth",3,spec.getPathDepth());
|
||||
|
||||
assertTrue("Spec.matches",spec.matches("/abs/path"));
|
||||
assertTrue("Spec.matches",spec.matches("/abs/path/"));
|
||||
|
||||
assertFalse("!Spec.matches",spec.matches("/abs/path/more"));
|
||||
assertFalse("!Spec.matches",spec.matches("/foo"));
|
||||
assertFalse("!Spec.matches",spec.matches("/foo/abs/path"));
|
||||
assertFalse("!Spec.matches",spec.matches("/foo/abs/path/"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPathInfo()
|
||||
{
|
||||
assertEquals("pathInfo exact",null,new ServletPathSpec("/Foo/bar").getPathInfo("/Foo/bar"));
|
||||
assertEquals("pathInfo prefix","/bar",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/bar"));
|
||||
assertEquals("pathInfo prefix","/*",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/*"));
|
||||
assertEquals("pathInfo prefix","/",new ServletPathSpec("/Foo/*").getPathInfo("/Foo/"));
|
||||
assertEquals("pathInfo prefix",null,new ServletPathSpec("/Foo/*").getPathInfo("/Foo"));
|
||||
assertEquals("pathInfo suffix",null,new ServletPathSpec("*.ext").getPathInfo("/Foo/bar.ext"));
|
||||
assertEquals("pathInfo default",null,new ServletPathSpec("/").getPathInfo("/Foo/bar.ext"));
|
||||
|
||||
assertEquals("pathInfo default","/xxx/zzz",new ServletPathSpec("/*").getPathInfo("/xxx/zzz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNullPathSpec()
|
||||
{
|
||||
ServletPathSpec spec = new ServletPathSpec(null);
|
||||
assertEquals("Spec.pathSpec","/",spec.getPathSpec());
|
||||
assertEquals("Spec.pattern","^(/.*)$",spec.getPattern().pattern());
|
||||
assertEquals("Spec.pathDepth",-1,spec.getPathDepth());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPathMatch()
|
||||
{
|
||||
assertEquals("pathMatch exact","/Foo/bar",new ServletPathSpec("/Foo/bar").getPathMatch("/Foo/bar"));
|
||||
assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo/bar"));
|
||||
assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo/"));
|
||||
assertEquals("pathMatch prefix","/Foo",new ServletPathSpec("/Foo/*").getPathMatch("/Foo"));
|
||||
assertEquals("pathMatch suffix","/Foo/bar.ext",new ServletPathSpec("*.ext").getPathMatch("/Foo/bar.ext"));
|
||||
assertEquals("pathMatch default","/Foo/bar.ext",new ServletPathSpec("/").getPathMatch("/Foo/bar.ext"));
|
||||
|
||||
// FIXME: not sure I understand this test
|
||||
// assertEquals("pathMatch default","",new ServletPathSpec("/*").getPathMatch("/xxx/zzz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrefixPathSpec()
|
||||
{
|
||||
ServletPathSpec spec = new ServletPathSpec("/downloads/*");
|
||||
assertEquals("Spec.pathSpec","/downloads/*",spec.getPathSpec());
|
||||
assertEquals("Spec.pattern","^/downloads(/.*)?$",spec.getPattern().pattern());
|
||||
assertEquals("Spec.pathDepth",2,spec.getPathDepth());
|
||||
|
||||
assertTrue("Spec.matches",spec.matches("/downloads/logo.jpg"));
|
||||
assertTrue("Spec.matches",spec.matches("/downloads/distribution.tar.gz"));
|
||||
assertTrue("Spec.matches",spec.matches("/downloads/distribution.tgz"));
|
||||
assertTrue("Spec.matches",spec.matches("/downloads/distribution.zip"));
|
||||
|
||||
assertTrue("Spec.matches",spec.matches("/downloads"));
|
||||
|
||||
assertEquals("Spec.pathInfo","/",spec.getPathInfo("/downloads/"));
|
||||
assertEquals("Spec.pathInfo","/distribution.zip",spec.getPathInfo("/downloads/distribution.zip"));
|
||||
assertEquals("Spec.pathInfo","/dist/9.0/distribution.tar.gz",spec.getPathInfo("/downloads/dist/9.0/distribution.tar.gz"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuffixPathSpec()
|
||||
{
|
||||
ServletPathSpec spec = new ServletPathSpec("*.gz");
|
||||
assertEquals("Spec.pathSpec","*.gz",spec.getPathSpec());
|
||||
assertEquals("Spec.pattern","^.*\\.gz$",spec.getPattern().pattern());
|
||||
assertEquals("Spec.pathDepth",0,spec.getPathDepth());
|
||||
|
||||
assertTrue("Spec.matches",spec.matches("/downloads/distribution.tar.gz"));
|
||||
assertTrue("Spec.matches",spec.matches("/downloads/jetty.log.gz"));
|
||||
|
||||
assertFalse("!Spec.matches",spec.matches("/downloads/distribution.zip"));
|
||||
assertFalse("!Spec.matches",spec.matches("/downloads/distribution.tgz"));
|
||||
assertFalse("!Spec.matches",spec.matches("/abs/path"));
|
||||
|
||||
assertEquals("Spec.pathInfo",null,spec.getPathInfo("/downloads/distribution.tar.gz"));
|
||||
}
|
||||
}
|
|
@ -40,7 +40,7 @@ public interface Session extends Closeable
|
|||
* @see #disconnect()
|
||||
*/
|
||||
@Override
|
||||
void close() throws IOException;
|
||||
void close();
|
||||
|
||||
/**
|
||||
* Request Close the current conversation, giving a reason for the closure. Note the websocket spec defines the acceptable uses of status codes and reason
|
||||
|
@ -55,7 +55,7 @@ public interface Session extends Closeable
|
|||
* @see #close(int, String)
|
||||
* @see #disconnect()
|
||||
*/
|
||||
void close(CloseStatus closeStatus) throws IOException;
|
||||
void close(CloseStatus closeStatus);
|
||||
|
||||
/**
|
||||
* Send a websocket Close frame, with status code.
|
||||
|
@ -72,7 +72,7 @@ public interface Session extends Closeable
|
|||
* @see #close(CloseStatus)
|
||||
* @see #disconnect()
|
||||
*/
|
||||
void close(int statusCode, String reason) throws IOException;
|
||||
void close(int statusCode, String reason);
|
||||
|
||||
/**
|
||||
* Issue a harsh disconnect of the underlying connection.
|
||||
|
|
|
@ -18,15 +18,12 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.api.extensions;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
|
||||
/**
|
||||
* Interface for dealing with Incoming Frames.
|
||||
*/
|
||||
public interface IncomingFrames
|
||||
{
|
||||
// TODO: JSR-356 change to Throwable
|
||||
public void incomingError(WebSocketException e);
|
||||
public void incomingError(Throwable t);
|
||||
|
||||
public void incomingFrame(Frame frame);
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ import org.eclipse.jetty.websocket.client.io.ConnectPromise;
|
|||
import org.eclipse.jetty.websocket.client.io.ConnectionManager;
|
||||
import org.eclipse.jetty.websocket.client.masks.Masker;
|
||||
import org.eclipse.jetty.websocket.client.masks.RandomMasker;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
|
||||
import org.eclipse.jetty.websocket.common.extensions.WebSocketExtensionFactory;
|
||||
|
@ -64,6 +66,7 @@ public class WebSocketClient extends ContainerLifeCycle
|
|||
private final SslContextFactory sslContextFactory;
|
||||
private final WebSocketExtensionFactory extensionRegistry;
|
||||
private EventDriverFactory eventDriverFactory;
|
||||
private SessionFactory sessionFactory;
|
||||
private ByteBufferPool bufferPool;
|
||||
private Executor executor;
|
||||
private Scheduler scheduler;
|
||||
|
@ -85,6 +88,7 @@ public class WebSocketClient extends ContainerLifeCycle
|
|||
this.extensionRegistry = new WebSocketExtensionFactory(policy,bufferPool);
|
||||
this.masker = new RandomMasker();
|
||||
this.eventDriverFactory = new EventDriverFactory(policy);
|
||||
this.sessionFactory = new WebSocketSessionFactory();
|
||||
}
|
||||
|
||||
public Future<Session> connect(Object websocket, URI toUri) throws IOException
|
||||
|
@ -341,6 +345,11 @@ public class WebSocketClient extends ContainerLifeCycle
|
|||
return scheduler;
|
||||
}
|
||||
|
||||
public SessionFactory getSessionFactory()
|
||||
{
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link SslContextFactory} that manages TLS encryption
|
||||
* @see WebSocketClient(SslContextFactory)
|
||||
|
@ -452,4 +461,9 @@ public class WebSocketClient extends ContainerLifeCycle
|
|||
{
|
||||
this.policy.setMaxTextMessageBufferSize(max);
|
||||
}
|
||||
|
||||
public void setSessionFactory(SessionFactory sessionFactory)
|
||||
{
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
|||
import org.eclipse.jetty.websocket.client.ClientUpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.client.io.HttpResponseHeaderParser.ParseException;
|
||||
import org.eclipse.jetty.websocket.common.AcceptHash;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
|
@ -214,7 +215,8 @@ public class UpgradeConnection extends AbstractConnection
|
|||
EventDriver websocket = connectPromise.getDriver();
|
||||
WebSocketPolicy policy = connectPromise.getClient().getPolicy();
|
||||
|
||||
WebSocketSession session = new WebSocketSession(request.getRequestURI(),websocket,connection);
|
||||
SessionFactory sessionFactory = connectPromise.getClient().getSessionFactory();
|
||||
WebSocketSession session = sessionFactory.createSession(request.getRequestURI(),websocket,connection);
|
||||
session.setPolicy(policy);
|
||||
session.setUpgradeResponse(response);
|
||||
|
||||
|
|
|
@ -49,7 +49,6 @@ import org.eclipse.jetty.util.BufferUtil;
|
|||
import org.eclipse.jetty.util.IO;
|
||||
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.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
|
@ -203,7 +202,7 @@ public class BlockheadServer
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incomingFrames.incomingError(e);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(IncomingFramesCapture.class);
|
||||
private LinkedList<WebSocketFrame> frames = new LinkedList<>();
|
||||
private LinkedList<WebSocketException> errors = new LinkedList<>();
|
||||
private LinkedList<Throwable> errors = new LinkedList<>();
|
||||
|
||||
public void assertErrorCount(int expectedCount)
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
public int getErrorCount(Class<? extends WebSocketException> errorType)
|
||||
{
|
||||
int count = 0;
|
||||
for (WebSocketException error : errors)
|
||||
for (Throwable error : errors)
|
||||
{
|
||||
if (errorType.isInstance(error))
|
||||
{
|
||||
|
@ -97,7 +97,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
return count;
|
||||
}
|
||||
|
||||
public LinkedList<WebSocketException> getErrors()
|
||||
public LinkedList<Throwable> getErrors()
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
@ -121,7 +121,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
errors.add(e);
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
||||
/**
|
||||
* Interface for creating jetty {@link MutableSession} objects.
|
||||
*/
|
||||
public interface SessionFactory
|
||||
{
|
||||
public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection);
|
||||
}
|
|
@ -97,7 +97,7 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
|
|||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
public void close()
|
||||
{
|
||||
this.close(StatusCode.NORMAL,null);
|
||||
}
|
||||
|
@ -272,14 +272,14 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
|
|||
* Incoming Errors from Parser
|
||||
*/
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable t)
|
||||
{
|
||||
if (connection.getIOState().isInputClosed())
|
||||
{
|
||||
return; // input is closed
|
||||
}
|
||||
// Forward Errors to User WebSocket Object
|
||||
websocket.incomingError(e);
|
||||
websocket.incomingError(t);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -325,6 +325,11 @@ public class WebSocketSession extends ContainerLifeCycle implements Session, Inc
|
|||
websocket.onClose(new CloseInfo(statusCode,reason));
|
||||
}
|
||||
|
||||
public void notifyError(Throwable cause)
|
||||
{
|
||||
incomingError(cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Open/Activate the session
|
||||
*
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
|
||||
// ------------------------------------------------------------------------
|
||||
// All rights reserved. This program and the accompanying materials
|
||||
// are made available under the terms of the Eclipse Public License v1.0
|
||||
// and Apache License v2.0 which accompanies this distribution.
|
||||
//
|
||||
// The Eclipse Public License is available at
|
||||
// http://www.eclipse.org/legal/epl-v10.html
|
||||
//
|
||||
// The Apache License v2.0 is available at
|
||||
// http://www.opensource.org/licenses/apache2.0.php
|
||||
//
|
||||
// You may elect to redistribute this code under either of these licenses.
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.websocket.common;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
|
||||
/**
|
||||
* Default Session factory, creating WebSocketSession objects.
|
||||
*/
|
||||
public class WebSocketSessionFactory implements SessionFactory
|
||||
{
|
||||
@Override
|
||||
public WebSocketSession createSession(URI requestURI, EventDriver websocket, LogicalConnection connection)
|
||||
{
|
||||
return new WebSocketSession(requestURI,websocket,connection);
|
||||
}
|
||||
}
|
|
@ -27,7 +27,6 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.CloseException;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
|
@ -65,7 +64,7 @@ public abstract class AbstractEventDriver implements IncomingFrames, EventDriver
|
|||
}
|
||||
|
||||
@Override
|
||||
public final void incomingError(WebSocketException e)
|
||||
public final void incomingError(Throwable e)
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
{
|
||||
|
|
|
@ -140,4 +140,10 @@ public class JettyListenerEventDriver extends AbstractEventDriver
|
|||
{
|
||||
listener.onWebSocketText(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return String.format("%s[%s]", JettyListenerEventDriver.class.getSimpleName(), listener.getClass().getName());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
|
|||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
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.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Extension;
|
||||
|
@ -108,7 +107,7 @@ public abstract class AbstractExtension extends ContainerLifeCycle implements Ex
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
nextIncomingError(e);
|
||||
}
|
||||
|
@ -169,7 +168,7 @@ public abstract class AbstractExtension extends ContainerLifeCycle implements Ex
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void nextIncomingError(WebSocketException e)
|
||||
protected void nextIncomingError(Throwable e)
|
||||
{
|
||||
this.nextIncoming.incomingError(e);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,6 @@ import org.eclipse.jetty.util.annotation.ManagedObject;
|
|||
import org.eclipse.jetty.util.component.ContainerLifeCycle;
|
||||
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.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Extension;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
|
@ -192,7 +191,7 @@ public class ExtensionStack extends ContainerLifeCycle implements IncomingFrames
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
nextIncoming.incomingError(e);
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ package org.eclipse.jetty.websocket.common.extensions.fragment;
|
|||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -37,7 +36,7 @@ public class FragmentExtension extends AbstractExtension
|
|||
private int maxLength = -1;
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
// Pass thru
|
||||
nextIncomingError(e);
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.websocket.common.extensions.identity;
|
|||
|
||||
import org.eclipse.jetty.util.QuotedStringTokenizer;
|
||||
import org.eclipse.jetty.util.annotation.ManagedObject;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -37,7 +36,7 @@ public class IdentityExtension extends AbstractExtension
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
// pass through
|
||||
nextIncomingError(e);
|
||||
|
|
|
@ -26,7 +26,6 @@ import org.eclipse.jetty.util.log.Log;
|
|||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.StatusCode;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -147,7 +146,7 @@ public class MuxChannel implements LogicalConnection, IncomingFrames, SuspendTok
|
|||
* Incoming exceptions from Muxer.
|
||||
*/
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incoming.incomingError(e);
|
||||
}
|
||||
|
|
|
@ -31,7 +31,6 @@ import org.eclipse.jetty.websocket.api.StatusCode;
|
|||
import org.eclipse.jetty.websocket.api.UpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.api.UpgradeResponse;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -141,7 +140,7 @@ public class Muxer implements IncomingFrames, MuxParser.Listener
|
|||
* Incoming parser errors
|
||||
*/
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
MuxDropChannel.Reason reason = MuxDropChannel.Reason.PHYSICAL_CONNECTION_FAILED;
|
||||
String phrase = String.format("%s: %s", e.getClass().getName(), e.getMessage());
|
||||
|
|
|
@ -95,7 +95,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
|
||||
// Abnormal Close
|
||||
reason = CloseStatus.trimMaxReasonLength(reason);
|
||||
session.incomingError(new WebSocketException(x)); // TODO: JSR-356 change to Throwable
|
||||
session.notifyError(x);
|
||||
session.notifyClose(StatusCode.NO_CLOSE,reason);
|
||||
|
||||
disconnect(); // disconnect endpoint & connection
|
||||
|
@ -508,7 +508,7 @@ public abstract class AbstractWebSocketConnection extends AbstractConnection imp
|
|||
|
||||
// Initiate close - politely send close frame.
|
||||
// Note: it is not possible in 100% of cases during read timeout to send this close frame.
|
||||
session.incomingError(new WebSocketTimeoutException("Timeout on Read"));
|
||||
session.notifyError(new WebSocketTimeoutException("Timeout on Read"));
|
||||
session.close(StatusCode.NORMAL,"Idle Timeout");
|
||||
|
||||
// Force closure of writeBytes
|
||||
|
|
|
@ -18,7 +18,6 @@
|
|||
|
||||
package org.eclipse.jetty.websocket.common.io;
|
||||
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
|
@ -36,7 +35,7 @@ public class FramePipes
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable t)
|
||||
{
|
||||
/* cannot send exception on */
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
private static final Logger LOG = Log.getLogger(IncomingFramesCapture.class);
|
||||
|
||||
private LinkedList<WebSocketFrame> frames = new LinkedList<>();
|
||||
private LinkedList<WebSocketException> errors = new LinkedList<>();
|
||||
private LinkedList<Throwable> errors = new LinkedList<>();
|
||||
|
||||
public void assertErrorCount(int expectedCount)
|
||||
{
|
||||
|
@ -86,7 +86,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
public int getErrorCount(Class<? extends WebSocketException> errorType)
|
||||
{
|
||||
int count = 0;
|
||||
for (WebSocketException error : errors)
|
||||
for (Throwable error : errors)
|
||||
{
|
||||
if (errorType.isInstance(error))
|
||||
{
|
||||
|
@ -96,7 +96,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
return count;
|
||||
}
|
||||
|
||||
public LinkedList<WebSocketException> getErrors()
|
||||
public LinkedList<Throwable> getErrors()
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
errors.add(e);
|
||||
|
|
|
@ -65,7 +65,7 @@ public class TestABCase4
|
|||
|
||||
Assert.assertEquals( "error on undefined opcode", 1, capture.getErrorCount(WebSocketException.class)) ;
|
||||
|
||||
WebSocketException known = capture.getErrors().get(0);
|
||||
Throwable known = capture.getErrors().get(0);
|
||||
|
||||
Assert.assertTrue("undefined option should be in message",known.getMessage().contains("Unknown opcode: 11"));
|
||||
}
|
||||
|
@ -87,7 +87,7 @@ public class TestABCase4
|
|||
|
||||
Assert.assertEquals( "error on undefined opcode", 1, capture.getErrorCount(WebSocketException.class)) ;
|
||||
|
||||
WebSocketException known = capture.getErrors().get(0);
|
||||
Throwable known = capture.getErrors().get(0);
|
||||
|
||||
Assert.assertTrue("undefined option should be in message",known.getMessage().contains("Unknown opcode: 12"));
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ public class TestABCase4
|
|||
|
||||
Assert.assertEquals( "error on undefined opcode", 1, capture.getErrorCount(WebSocketException.class)) ;
|
||||
|
||||
WebSocketException known = capture.getErrors().get(0);
|
||||
Throwable known = capture.getErrors().get(0);
|
||||
|
||||
Assert.assertTrue("undefined option should be in message",known.getMessage().contains("Unknown opcode: 3"));
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ public class TestABCase4
|
|||
|
||||
Assert.assertEquals( "error on undefined opcode", 1, capture.getErrorCount(WebSocketException.class)) ;
|
||||
|
||||
WebSocketException known = capture.getErrors().get(0);
|
||||
Throwable known = capture.getErrors().get(0);
|
||||
|
||||
Assert.assertTrue("undefined option should be in message",known.getMessage().contains("Unknown opcode: 4"));
|
||||
}
|
||||
|
|
|
@ -20,7 +20,6 @@ package org.eclipse.jetty.websocket.common.extensions;
|
|||
|
||||
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.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
|
||||
|
@ -38,7 +37,7 @@ public class DummyIncomingFrames implements IncomingFrames
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
LOG.debug("incomingError()",e);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,6 @@ import java.net.InetSocketAddress;
|
|||
import org.eclipse.jetty.util.log.Log;
|
||||
import org.eclipse.jetty.util.log.Logger;
|
||||
import org.eclipse.jetty.websocket.api.SuspendToken;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
|
@ -124,7 +123,7 @@ public class LocalWebSocketConnection implements LogicalConnection, IncomingFram
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incoming.incomingError(e);
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.Map;
|
|||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
|
@ -46,7 +47,9 @@ import org.eclipse.jetty.websocket.api.WebSocketException;
|
|||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionFactory;
|
||||
import org.eclipse.jetty.websocket.common.LogicalConnection;
|
||||
import org.eclipse.jetty.websocket.common.SessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSession;
|
||||
import org.eclipse.jetty.websocket.common.WebSocketSessionFactory;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriver;
|
||||
import org.eclipse.jetty.websocket.common.events.EventDriverFactory;
|
||||
import org.eclipse.jetty.websocket.common.extensions.ExtensionStack;
|
||||
|
@ -87,6 +90,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
private final WebSocketPolicy basePolicy;
|
||||
private final EventDriverFactory eventDriverFactory;
|
||||
private final WebSocketExtensionFactory extensionFactory;
|
||||
private SessionFactory sessionFactory;
|
||||
private WebSocketCreator creator;
|
||||
private List<Class<?>> registeredSocketClasses;
|
||||
|
||||
|
@ -110,6 +114,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
this.basePolicy = policy;
|
||||
this.eventDriverFactory = new EventDriverFactory(basePolicy);
|
||||
this.extensionFactory = new WebSocketExtensionFactory(basePolicy,bufferPool);
|
||||
this.sessionFactory = new WebSocketSessionFactory();
|
||||
this.creator = this;
|
||||
|
||||
// Create supportedVersions
|
||||
|
@ -185,14 +190,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
{
|
||||
for (WebSocketSession session : sessions)
|
||||
{
|
||||
try
|
||||
{
|
||||
session.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn("CloseAllConnections Close failure",e);
|
||||
}
|
||||
session.close();
|
||||
}
|
||||
sessions.clear();
|
||||
}
|
||||
|
@ -260,6 +258,11 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
return basePolicy;
|
||||
}
|
||||
|
||||
public SessionFactory getSessionFactory()
|
||||
{
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void init() throws Exception
|
||||
{
|
||||
|
@ -348,6 +351,11 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
this.creator = creator;
|
||||
}
|
||||
|
||||
public void setSessionFactory(SessionFactory sessionFactory)
|
||||
{
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Upgrade the request/response to a WebSocket Connection.
|
||||
* <p>
|
||||
|
@ -416,7 +424,7 @@ public class WebSocketServerFactory extends ContainerLifeCycle implements WebSoc
|
|||
}
|
||||
|
||||
// Setup Session
|
||||
WebSocketSession session = new WebSocketSession(request.getRequestURI(),driver,connection);
|
||||
WebSocketSession session = sessionFactory.createSession(request.getRequestURI(),driver,connection);
|
||||
session.setPolicy(getPolicy().clonePolicy());
|
||||
session.setUpgradeRequest(request);
|
||||
response.setExtensions(extensionStack.getNegotiatedExtensions());
|
||||
|
|
|
@ -95,14 +95,7 @@ public class WebSocketCloseTest
|
|||
public void onWebSocketConnect(Session sess)
|
||||
{
|
||||
LOG.debug("onWebSocketConnect({})",sess);
|
||||
try
|
||||
{
|
||||
sess.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
e.printStackTrace(System.err);
|
||||
}
|
||||
sess.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -41,7 +41,6 @@ import org.eclipse.jetty.server.ServerConnector;
|
|||
import org.eclipse.jetty.server.handler.DefaultHandler;
|
||||
import org.eclipse.jetty.util.thread.QueuedThreadPool;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketBehavior;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketException;
|
||||
import org.eclipse.jetty.websocket.api.WebSocketPolicy;
|
||||
import org.eclipse.jetty.websocket.api.extensions.Frame;
|
||||
import org.eclipse.jetty.websocket.api.extensions.IncomingFrames;
|
||||
|
@ -70,7 +69,7 @@ public class WebSocketLoadRFC6455Test
|
|||
private final IncomingFrames _handler = new IncomingFrames()
|
||||
{
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ import org.eclipse.jetty.util.StringUtil;
|
|||
import org.eclipse.jetty.util.Utf8StringBuilder;
|
||||
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.WriteCallback;
|
||||
import org.eclipse.jetty.websocket.api.extensions.ExtensionConfig;
|
||||
|
@ -383,7 +382,7 @@ public class BlockheadClient implements IncomingFrames, OutgoingFrames
|
|||
* Errors received (after extensions)
|
||||
*/
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
incomingFrames.incomingError(e);
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
{
|
||||
private static final Logger LOG = Log.getLogger(IncomingFramesCapture.class);
|
||||
private EventQueue<WebSocketFrame> frames = new EventQueue<>();
|
||||
private EventQueue<WebSocketException> errors = new EventQueue<>();
|
||||
private EventQueue<Throwable> errors = new EventQueue<>();
|
||||
|
||||
public void assertErrorCount(int expectedCount)
|
||||
{
|
||||
|
@ -90,10 +90,10 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
}
|
||||
}
|
||||
|
||||
public int getErrorCount(Class<? extends WebSocketException> errorType)
|
||||
public int getErrorCount(Class<? extends Throwable> errorType)
|
||||
{
|
||||
int count = 0;
|
||||
for (WebSocketException error : errors)
|
||||
for (Throwable error : errors)
|
||||
{
|
||||
if (errorType.isInstance(error))
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
return count;
|
||||
}
|
||||
|
||||
public Queue<WebSocketException> getErrors()
|
||||
public Queue<Throwable> getErrors()
|
||||
{
|
||||
return errors;
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ public class IncomingFramesCapture implements IncomingFrames
|
|||
}
|
||||
|
||||
@Override
|
||||
public void incomingError(WebSocketException e)
|
||||
public void incomingError(Throwable e)
|
||||
{
|
||||
LOG.debug(e);
|
||||
errors.add(e);
|
||||
|
|
Loading…
Reference in New Issue