Browse Source

ExceptionListener added. #53

master
Nikita 12 years ago
parent
commit
67826f263b
  1. 18
      src/main/java/com/corundumstudio/socketio/Configuration.java
  2. 3
      src/main/java/com/corundumstudio/socketio/SocketIOServer.java
  3. 4
      src/main/java/com/corundumstudio/socketio/handler/PacketListener.java
  4. 52
      src/main/java/com/corundumstudio/socketio/listener/DefaultExceptionListener.java
  5. 32
      src/main/java/com/corundumstudio/socketio/listener/ExceptionListener.java
  6. 42
      src/main/java/com/corundumstudio/socketio/listener/ExceptionListenerAdapter.java
  7. 69
      src/main/java/com/corundumstudio/socketio/namespace/Namespace.java
  8. 7
      src/main/java/com/corundumstudio/socketio/namespace/NamespacesHub.java
  9. 2
      src/test/java/com/corundumstudio/socketio/handler/PacketHandlerTest.java

18
src/main/java/com/corundumstudio/socketio/Configuration.java

@ -20,6 +20,8 @@ import io.netty.handler.codec.TooLongFrameException;
import java.io.InputStream; import java.io.InputStream;
import com.corundumstudio.socketio.handler.SuccessAuthorizationListener; import com.corundumstudio.socketio.handler.SuccessAuthorizationListener;
import com.corundumstudio.socketio.listener.DefaultExceptionListener;
import com.corundumstudio.socketio.listener.ExceptionListener;
import com.corundumstudio.socketio.parser.JacksonJsonSupport; import com.corundumstudio.socketio.parser.JacksonJsonSupport;
import com.corundumstudio.socketio.parser.JsonSupport; import com.corundumstudio.socketio.parser.JsonSupport;
import com.corundumstudio.socketio.store.MemoryStoreFactory; import com.corundumstudio.socketio.store.MemoryStoreFactory;
@ -27,6 +29,8 @@ import com.corundumstudio.socketio.store.StoreFactory;
public class Configuration { public class Configuration {
private ExceptionListener exceptionListener = new DefaultExceptionListener();
private String jsonTypeFieldName = "@class"; private String jsonTypeFieldName = "@class";
private String context = "/socket.io"; private String context = "/socket.io";
@ -383,5 +387,19 @@ public class Configuration {
return authorizationListener; return authorizationListener;
} }
/**
* Exception listener invoked on any exception in
* SocketIO listener
*
* @param exceptionListener
*
* @see com.corundumstudio.socketio.listener.ExceptionListener
*/
public void setExceptionListener(ExceptionListener exceptionListener) {
this.exceptionListener = exceptionListener;
}
public ExceptionListener getExceptionListener() {
return exceptionListener;
}
} }

3
src/main/java/com/corundumstudio/socketio/SocketIOServer.java

@ -31,6 +31,7 @@ import com.corundumstudio.socketio.listener.ClientListeners;
import com.corundumstudio.socketio.listener.ConnectListener; import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener; import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener; import com.corundumstudio.socketio.listener.DisconnectListener;
import com.corundumstudio.socketio.listener.ExceptionListener;
import com.corundumstudio.socketio.listener.MultiTypeEventListener; import com.corundumstudio.socketio.listener.MultiTypeEventListener;
import com.corundumstudio.socketio.namespace.Namespace; import com.corundumstudio.socketio.namespace.Namespace;
import com.corundumstudio.socketio.namespace.NamespacesHub; import com.corundumstudio.socketio.namespace.NamespacesHub;
@ -57,7 +58,7 @@ public class SocketIOServer implements ClientListeners {
public SocketIOServer(Configuration configuration) { public SocketIOServer(Configuration configuration) {
this.configuration = configuration; this.configuration = configuration;
this.configCopy = new Configuration(configuration); this.configCopy = new Configuration(configuration);
namespacesHub = new NamespacesHub(configCopy.getJsonSupport(), configCopy.getStoreFactory());
namespacesHub = new NamespacesHub(configCopy.getJsonSupport(), configCopy.getStoreFactory(), configCopy.getExceptionListener());
mainNamespace = addNamespace(Namespace.DEFAULT_NAME); mainNamespace = addNamespace(Namespace.DEFAULT_NAME);
} }

4
src/main/java/com/corundumstudio/socketio/handler/PacketListener.java

@ -90,10 +90,6 @@ public class PacketListener {
default: default:
break; break;
} }
// send ack response if it not executed
// during {@link DataListener#onData} invocation
ackRequest.sendAckData(Collections.emptyList());
} }
} }

52
src/main/java/com/corundumstudio/socketio/listener/DefaultExceptionListener.java

@ -0,0 +1,52 @@
/**
* Copyright 2012 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.corundumstudio.socketio.listener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.corundumstudio.socketio.SocketIOClient;
public class DefaultExceptionListener extends ExceptionListenerAdapter {
private final Logger log = LoggerFactory.getLogger(getClass());
@Override
public void onEventException(Exception e, SocketIOClient client) {
log.error(e.getMessage(), e);
}
@Override
public void onDisconnectException(Exception e, SocketIOClient client) {
log.error(e.getMessage(), e);
}
@Override
public void onConnectException(Exception e, SocketIOClient client) {
log.error(e.getMessage(), e);
}
@Override
public void onMessageException(Exception e, SocketIOClient client) {
log.error(e.getMessage(), e);
}
@Override
public void onJsonException(Exception e, SocketIOClient client) {
log.error(e.getMessage(), e);
}
}

32
src/main/java/com/corundumstudio/socketio/listener/ExceptionListener.java

@ -0,0 +1,32 @@
/**
* Copyright 2012 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.corundumstudio.socketio.listener;
import com.corundumstudio.socketio.SocketIOClient;
public interface ExceptionListener {
void onEventException(Exception e, SocketIOClient client);
void onDisconnectException(Exception e, SocketIOClient client);
void onConnectException(Exception e, SocketIOClient client);
void onMessageException(Exception e, SocketIOClient client);
void onJsonException(Exception e, SocketIOClient client);
}

42
src/main/java/com/corundumstudio/socketio/listener/ExceptionListenerAdapter.java

@ -0,0 +1,42 @@
/**
* Copyright 2012 Nikita Koksharov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.corundumstudio.socketio.listener;
import com.corundumstudio.socketio.SocketIOClient;
public class ExceptionListenerAdapter implements ExceptionListener {
@Override
public void onEventException(Exception e, SocketIOClient client) {
}
@Override
public void onDisconnectException(Exception e, SocketIOClient client) {
}
@Override
public void onConnectException(Exception e, SocketIOClient client) {
}
@Override
public void onMessageException(Exception e, SocketIOClient client) {
}
@Override
public void onJsonException(Exception e, SocketIOClient client) {
}
}

69
src/main/java/com/corundumstudio/socketio/namespace/Namespace.java

@ -26,9 +26,6 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.corundumstudio.socketio.AckRequest; import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.BroadcastOperations; import com.corundumstudio.socketio.BroadcastOperations;
import com.corundumstudio.socketio.MultiTypeArgs; import com.corundumstudio.socketio.MultiTypeArgs;
@ -38,6 +35,7 @@ import com.corundumstudio.socketio.annotation.ScannerEngine;
import com.corundumstudio.socketio.listener.ConnectListener; import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener; import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener; import com.corundumstudio.socketio.listener.DisconnectListener;
import com.corundumstudio.socketio.listener.ExceptionListener;
import com.corundumstudio.socketio.listener.MultiTypeEventListener; import com.corundumstudio.socketio.listener.MultiTypeEventListener;
import com.corundumstudio.socketio.parser.JsonSupport; import com.corundumstudio.socketio.parser.JsonSupport;
import com.corundumstudio.socketio.parser.Packet; import com.corundumstudio.socketio.parser.Packet;
@ -54,8 +52,6 @@ import com.corundumstudio.socketio.transport.NamespaceClient;
*/ */
public class Namespace implements SocketIONamespace { public class Namespace implements SocketIONamespace {
private final Logger log = LoggerFactory.getLogger(getClass());
public static final String DEFAULT_NAME = ""; public static final String DEFAULT_NAME = "";
private final ScannerEngine engine = new ScannerEngine(); private final ScannerEngine engine = new ScannerEngine();
@ -74,12 +70,14 @@ public class Namespace implements SocketIONamespace {
private final String name; private final String name;
private final JsonSupport jsonSupport; private final JsonSupport jsonSupport;
private final StoreFactory storeFactory; private final StoreFactory storeFactory;
private final ExceptionListener exceptionListener;
public Namespace(String name, JsonSupport jsonSupport, StoreFactory storeFactory) {
public Namespace(String name, JsonSupport jsonSupport, StoreFactory storeFactory, ExceptionListener exceptionListener) {
super(); super();
this.name = name; this.name = name;
this.jsonSupport = jsonSupport; this.jsonSupport = jsonSupport;
this.storeFactory = storeFactory; this.storeFactory = storeFactory;
this.exceptionListener = exceptionListener;
} }
public void addClient(SocketIOClient client) { public void addClient(SocketIOClient client) {
@ -140,25 +138,46 @@ public class Namespace implements SocketIONamespace {
if (entry == null) { if (entry == null) {
return; return;
} }
try {
Queue<DataListener> listeners = entry.getListeners(); Queue<DataListener> listeners = entry.getListeners();
for (DataListener dataListener : listeners) { for (DataListener dataListener : listeners) {
Object data = null;
Object data = getEventData(args, dataListener);
dataListener.onData(client, data, ackRequest);
}
} catch (Exception e) {
exceptionListener.onEventException(e, client);
return;
}
// send ack response if it not executed
// during {@link DataListener#onData} invocation
ackRequest.sendAckData(Collections.emptyList());
}
private Object getEventData(List<Object> args, DataListener dataListener) {
if (dataListener instanceof MultiTypeEventListener) { if (dataListener instanceof MultiTypeEventListener) {
data = new MultiTypeArgs(args);
return new MultiTypeArgs(args);
} else { } else {
if (!args.isEmpty()) { if (!args.isEmpty()) {
data = args.get(0);
return args.get(0);
} }
} }
dataListener.onData(client, data, ackRequest);
}
return null;
} }
public void onMessage(NamespaceClient client, String data, AckRequest ackRequest) { public void onMessage(NamespaceClient client, String data, AckRequest ackRequest) {
try {
for (DataListener<String> listener : messageListeners) { for (DataListener<String> listener : messageListeners) {
listener.onData(client, data, ackRequest); listener.onData(client, data, ackRequest);
} }
} catch (Exception e) {
exceptionListener.onMessageException(e, client);
return;
}
// send ack response if it not executed
// during {@link DataListener#onData} invocation
ackRequest.sendAckData(Collections.emptyList());
} }
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
@ -167,9 +186,19 @@ public class Namespace implements SocketIONamespace {
if (queue == null) { if (queue == null) {
return; return;
} }
try {
for (DataListener dataListener : queue) { for (DataListener dataListener : queue) {
dataListener.onData(client, data, ackRequest); dataListener.onData(client, data, ackRequest);
} }
} catch (Exception e) {
exceptionListener.onJsonException(e, client);
return;
}
// send ack response if it not executed
// during {@link DataListener#onData} invocation
ackRequest.sendAckData(Collections.emptyList());
} }
@Override @Override
@ -183,12 +212,12 @@ public class Namespace implements SocketIONamespace {
leave(getName(), client.getSessionId()); leave(getName(), client.getSessionId());
storeFactory.pubSubStore().publish(PubSubStore.LEAVE, new JoinLeaveMessage(client.getSessionId(), getName(), getName())); storeFactory.pubSubStore().publish(PubSubStore.LEAVE, new JoinLeaveMessage(client.getSessionId(), getName(), getName()));
for (DisconnectListener listener : disconnectListeners) {
try { try {
for (DisconnectListener listener : disconnectListeners) {
listener.onDisconnect(client); listener.onDisconnect(client);
} catch (Exception e) {
log.error("Can't execute onDisconnect listener", e);
} }
} catch (Exception e) {
exceptionListener.onDisconnectException(e, client);
} }
} }
@ -198,16 +227,16 @@ public class Namespace implements SocketIONamespace {
} }
public void onConnect(SocketIOClient client) { public void onConnect(SocketIOClient client) {
for (ConnectListener listener : connectListeners) {
join(getName(), client.getSessionId());
storeFactory.pubSubStore().publish(PubSubStore.JOIN, new JoinLeaveMessage(client.getSessionId(), getName(), getName()));
try { try {
for (ConnectListener listener : connectListeners) {
listener.onConnect(client); listener.onConnect(client);
} catch (Exception e) {
log.error("Can't execute onConnect listener", e);
} }
} catch (Exception e) {
exceptionListener.onConnectException(e, client);
} }
join(getName(), client.getSessionId());
storeFactory.pubSubStore().publish(PubSubStore.JOIN, new JoinLeaveMessage(client.getSessionId(), getName(), getName()));
} }
@Override @Override

7
src/main/java/com/corundumstudio/socketio/namespace/NamespacesHub.java

@ -21,6 +21,7 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentMap;
import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.listener.ExceptionListener;
import com.corundumstudio.socketio.misc.CompositeIterable; import com.corundumstudio.socketio.misc.CompositeIterable;
import com.corundumstudio.socketio.parser.JsonSupport; import com.corundumstudio.socketio.parser.JsonSupport;
import com.corundumstudio.socketio.store.StoreFactory; import com.corundumstudio.socketio.store.StoreFactory;
@ -30,16 +31,18 @@ public class NamespacesHub {
private final ConcurrentMap<String, Namespace> namespaces = new ConcurrentHashMap<String, Namespace>(); private final ConcurrentMap<String, Namespace> namespaces = new ConcurrentHashMap<String, Namespace>();
private final JsonSupport jsonSupport; private final JsonSupport jsonSupport;
private final StoreFactory storeFactory; private final StoreFactory storeFactory;
private final ExceptionListener exceptionListener;
public NamespacesHub(JsonSupport jsonSupport, StoreFactory storeFactory) {
public NamespacesHub(JsonSupport jsonSupport, StoreFactory storeFactory, ExceptionListener exceptionListener) {
this.jsonSupport = jsonSupport; this.jsonSupport = jsonSupport;
this.storeFactory = storeFactory; this.storeFactory = storeFactory;
this.exceptionListener = exceptionListener;
} }
public Namespace create(String name) { public Namespace create(String name) {
Namespace namespace = namespaces.get(name); Namespace namespace = namespaces.get(name);
if (namespace == null) { if (namespace == null) {
namespace = new Namespace(name, jsonSupport, storeFactory);
namespace = new Namespace(name, jsonSupport, storeFactory, exceptionListener);
Namespace oldNamespace = namespaces.putIfAbsent(name, namespace); Namespace oldNamespace = namespaces.putIfAbsent(name, namespace);
if (oldNamespace != null) { if (oldNamespace != null) {
namespace = oldNamespace; namespace = oldNamespace;

2
src/test/java/com/corundumstudio/socketio/handler/PacketHandlerTest.java

@ -57,7 +57,7 @@ public class PacketHandlerTest {
private JsonSupport map = new JacksonJsonSupport(new Configuration()); private JsonSupport map = new JacksonJsonSupport(new Configuration());
private Decoder decoder = new Decoder(map, new AckManager(null)); private Decoder decoder = new Decoder(map, new AckManager(null));
private Encoder encoder = new Encoder(new Configuration(), map); private Encoder encoder = new Encoder(new Configuration(), map);
private NamespacesHub namespacesHub = new NamespacesHub(map, null);
private NamespacesHub namespacesHub = new NamespacesHub(map, null, null);
@Mocked @Mocked
private Channel channel; private Channel channel;
private MainBaseClient client = new XHRPollingClient(null, null, UUID.randomUUID(), null, new MemoryStoreFactory(), null); private MainBaseClient client = new XHRPollingClient(null, null, UUID.randomUUID(), null, new MemoryStoreFactory(), null);

Loading…
Cancel
Save