// Path: web/src/main/java/org/projectodd/wunderboss/web/async/WebsocketUtil.java
// public class WebsocketUtil {
// 
//     // Overcomes the problem of Clojure's reify being incompatible with
//     // generics and Undertow's dependence on ParameterizedType
//     static public MessageHandler.Whole<String> createTextHandler(final MessageHandler.Whole proxy) {
//         return new MessageHandler.Whole<String>() {
//             public void onMessage(String msg) {
//                 proxy.onMessage(msg);
//             }};
//     }
// 
//     // The binary version of createTextHandler
//     static public MessageHandler.Whole<byte[]> createBinaryHandler(final MessageHandler.Whole proxy) {
//         return new MessageHandler.Whole<byte[]>() {
//             public void onMessage(byte[] msg) {
//                 proxy.onMessage(msg);
//             }};
//     }
// 
//     static public RuntimeException wrongMessageType(Class clazz) {
//         return new IllegalArgumentException("message is neither a String or byte[], but is " +
//                                                    clazz.getName());
//     }
// 
//     static public void notifyComplete(Channel channel, Channel.OnComplete callback, Throwable error) {
//         if (callback != null) {
//             try {
//                 callback.handle(error);
//             } catch (Exception e) {
//                 channel.notifyError(e);
//             }
//         } else if (error != null) {
//             channel.notifyError(error);
//         }
//     }
// }


import org.projectodd.wunderboss.web.async.WebsocketUtil;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.SendHandler;
import javax.websocket.SendResult;
import javax.websocket.Session;
import java.io.IOException;
import java.nio.ByteBuffer;
                        final boolean shouldClose,
                        final OnComplete onComplete) throws Exception {
        if (!isOpen()) {
            return false;
        }

        SendHandler handler = new SendHandler() {
            @Override
            public void onResult(SendResult sendResult) {
                Throwable ex = sendResult.getException();
                if (sendResult.isOK()) {
                    if (shouldClose) {
                        try {
                            close();
                        } catch (IOException e) {
                            ex = e;
                        }
                    }
                }
                notifyComplete(onComplete, ex);
            }
        };

        if (message == null) {
            handler.onResult(new SendResult());
        } else if (message instanceof String) {
            this.session.getAsyncRemote().sendText((String)message, handler);
        } else if (message instanceof byte[]) {
            this.session.getAsyncRemote().sendBinary(ByteBuffer.wrap((byte[])message), handler);
        } else {
// Path: web/src/main/java/org/projectodd/wunderboss/web/async/WebsocketUtil.java
// public class WebsocketUtil {
// 
//     // Overcomes the problem of Clojure's reify being incompatible with
//     // generics and Undertow's dependence on ParameterizedType
//     static public MessageHandler.Whole<String> createTextHandler(final MessageHandler.Whole proxy) {
//         return new MessageHandler.Whole<String>() {
//             public void onMessage(String msg) {
//                 proxy.onMessage(msg);
//             }};
//     }
// 
//     // The binary version of createTextHandler
//     static public MessageHandler.Whole<byte[]> createBinaryHandler(final MessageHandler.Whole proxy) {
//         return new MessageHandler.Whole<byte[]>() {
//             public void onMessage(byte[] msg) {
//                 proxy.onMessage(msg);
//             }};
//     }
// 
//     static public RuntimeException wrongMessageType(Class clazz) {
//         return new IllegalArgumentException("message is neither a String or byte[], but is " +
//                                                    clazz.getName());
//     }
// 
//     static public void notifyComplete(Channel channel, Channel.OnComplete callback, Throwable error) {
//         if (callback != null) {
//             try {
//                 callback.handle(error);
//             } catch (Exception e) {
//                 channel.notifyError(e);
//             }
//         } else if (error != null) {
//             channel.notifyError(error);
//         }
//     }
// }


// Path: web/src/main/java/org/projectodd/wunderboss/web/async/websocket/JavaxWebsocketChannel.java
import org.projectodd.wunderboss.web.async.WebsocketUtil;
import javax.websocket.CloseReason;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.SendHandler;
import javax.websocket.SendResult;
import javax.websocket.Session;
import java.io.IOException;
import java.nio.ByteBuffer;

                        final boolean shouldClose,
                        final OnComplete onComplete) throws Exception {
        if (!isOpen()) {
            return false;
        }

        SendHandler handler = new SendHandler() {
            @Override
            public void onResult(SendResult sendResult) {
                Throwable ex = sendResult.getException();
                if (sendResult.isOK()) {
                    if (shouldClose) {
                        try {
                            close();
                        } catch (IOException e) {
                            ex = e;
                        }
                    }
                }
                notifyComplete(onComplete, ex);
            }
        };

        if (message == null) {
            handler.onResult(new SendResult());
        } else if (message instanceof String) {
            this.session.getAsyncRemote().sendText((String)message, handler);
        } else if (message instanceof byte[]) {
            this.session.getAsyncRemote().sendBinary(ByteBuffer.wrap((byte[])message), handler);
        } else {
            throw WebsocketUtil.wrongMessageType(message.getClass());