ko-ws-tyrus/src/main/java/org/netbeans/html/wstyrus/TyrusContext.java
author Jaroslav Tulach <jtulach@netbeans.org>
Tue, 26 Aug 2014 18:13:30 +0200
changeset 838 bdc3d696dd4a
parent 790 30f20d9c0986
child 886 88d62267a0b5
permissions -rw-r--r--
During the API review process (bug 246133) the reviewers decided that in order to include html4j to NetBeans Platform, we need to stop using org.apidesign namespace and switch to NetBeans one. Repackaging all SPI packages into org.netbeans.html.smthng.spi.
jaroslav@260
     1
/**
jaroslav@358
     2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
jaroslav@260
     3
 *
jaroslav@551
     4
 * Copyright 2013-2014 Oracle and/or its affiliates. All rights reserved.
jaroslav@260
     5
 *
jaroslav@358
     6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
jaroslav@358
     7
 * Other names may be trademarks of their respective owners.
jaroslav@260
     8
 *
jaroslav@358
     9
 * The contents of this file are subject to the terms of either the GNU
jaroslav@358
    10
 * General Public License Version 2 only ("GPL") or the Common
jaroslav@358
    11
 * Development and Distribution License("CDDL") (collectively, the
jaroslav@358
    12
 * "License"). You may not use this file except in compliance with the
jaroslav@358
    13
 * License. You can obtain a copy of the License at
jaroslav@358
    14
 * http://www.netbeans.org/cddl-gplv2.html
jaroslav@358
    15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
jaroslav@358
    16
 * specific language governing permissions and limitations under the
jaroslav@358
    17
 * License.  When distributing the software, include this License Header
jaroslav@358
    18
 * Notice in each file and include the License file at
jaroslav@358
    19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
jaroslav@358
    20
 * particular file as subject to the "Classpath" exception as provided
jaroslav@358
    21
 * by Oracle in the GPL Version 2 section of the License file that
jaroslav@358
    22
 * accompanied this code. If applicable, add the following below the
jaroslav@358
    23
 * License Header, with the fields enclosed by brackets [] replaced by
jaroslav@358
    24
 * your own identifying information:
jaroslav@358
    25
 * "Portions Copyrighted [year] [name of copyright owner]"
jaroslav@358
    26
 *
jaroslav@358
    27
 * Contributor(s):
jaroslav@358
    28
 *
jaroslav@358
    29
 * The Original Software is NetBeans. The Initial Developer of the Original
jaroslav@551
    30
 * Software is Oracle. Portions Copyright 2013-2014 Oracle. All Rights Reserved.
jaroslav@358
    31
 *
jaroslav@358
    32
 * If you wish your version of this file to be governed by only the CDDL
jaroslav@358
    33
 * or only the GPL Version 2, indicate your decision by adding
jaroslav@358
    34
 * "[Contributor] elects to include this software in this distribution
jaroslav@358
    35
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
jaroslav@358
    36
 * single choice of license, a recipient has the option to distribute
jaroslav@358
    37
 * your version of this file under either the CDDL, the GPL Version 2 or
jaroslav@358
    38
 * to extend the choice of license to its licensees as provided above.
jaroslav@358
    39
 * However, if you add GPL Version 2 code and therefore, elected the GPL
jaroslav@358
    40
 * Version 2 license, then the option applies only if the new code is
jaroslav@358
    41
 * made subject to such option by the copyright holder.
jaroslav@260
    42
 */
jaroslav@362
    43
package org.netbeans.html.wstyrus;
jaroslav@260
    44
jaroslav@260
    45
import java.io.IOException;
jaroslav@446
    46
import java.io.InputStream;
jaroslav@260
    47
import java.net.URI;
jaroslav@260
    48
import java.net.URISyntaxException;
jaroslav@260
    49
import java.util.Iterator;
jaroslav@260
    50
import javax.websocket.ClientEndpoint;
jaroslav@260
    51
import javax.websocket.ContainerProvider;
jaroslav@260
    52
import javax.websocket.OnClose;
jaroslav@260
    53
import javax.websocket.OnError;
jaroslav@260
    54
import javax.websocket.OnMessage;
jaroslav@260
    55
import javax.websocket.OnOpen;
jaroslav@260
    56
import javax.websocket.Session;
jaroslav@260
    57
import javax.websocket.WebSocketContainer;
jaroslav@263
    58
import net.java.html.json.OnReceive;
jtulach@838
    59
import org.netbeans.html.context.spi.Contexts;
jtulach@838
    60
import org.netbeans.html.json.spi.JSONCall;
jtulach@838
    61
import org.netbeans.html.json.spi.Transfer;
jtulach@838
    62
import org.netbeans.html.json.spi.WSTransfer;
jaroslav@362
    63
import org.netbeans.html.wstyrus.TyrusContext.Comm;
jaroslav@260
    64
import org.json.JSONArray;
jaroslav@260
    65
import org.json.JSONException;
jaroslav@260
    66
import org.json.JSONObject;
jaroslav@260
    67
import org.json.JSONTokener;
jaroslav@260
    68
import org.openide.util.lookup.ServiceProvider;
jaroslav@260
    69
jaroslav@263
    70
/** This is an implementation module that provides support for
jaroslav@263
    71
 * WebSocket protocol for {@link OnReceive} communication end point for
jaroslav@263
    72
 * JDK7.
jaroslav@263
    73
 * <p>
jaroslav@263
    74
 * Don't deal with this module directly, rather use the 
jaroslav@263
    75
 * {@link OnReceive @OnReceive(url="ws://...", ...)} API to establish your
jaroslav@263
    76
 * WebSocket connection.
jaroslav@263
    77
 * <p>
jaroslav@263
    78
 * There is no need to include this module in your application if you are
jaroslav@263
    79
 * running on JDK8. JDK8 WebView provides its own implementation of the
jaroslav@263
    80
 * WebSocket API based on WebSocket object inside a browser. This is included
jtulach@838
    81
 * in the <code>org.netbeans.html:ko4j:1.0</code> module.
jaroslav@260
    82
 *
jtulach@790
    83
 * @author Jaroslav Tulach
jaroslav@260
    84
 */
jaroslav@260
    85
@ServiceProvider(service = Contexts.Provider.class)
jaroslav@446
    86
public final class TyrusContext 
jaroslav@446
    87
implements Contexts.Provider, WSTransfer<Comm>, Transfer {
jaroslav@260
    88
    @Override
jaroslav@260
    89
    public void fillContext(Contexts.Builder context, Class<?> requestor) {
jaroslav@260
    90
        // default WebSocket transfer implementation is registered
jaroslav@260
    91
        // in ko-fx module with 100, provide this one as a fallback only
jaroslav@260
    92
        context.register(WSTransfer.class, this, 1000);
jaroslav@446
    93
        context.register(Transfer.class, this, 1000);
jaroslav@260
    94
    }
jaroslav@260
    95
jaroslav@260
    96
    @Override
jaroslav@260
    97
    public Comm open(String url, JSONCall callback) {
jaroslav@260
    98
        try {
jaroslav@260
    99
            return new Comm(new URI(url), callback);
jaroslav@260
   100
        } catch (URISyntaxException ex) {
jaroslav@260
   101
            throw new IllegalStateException(ex);
jaroslav@260
   102
        }
jaroslav@260
   103
    }
jaroslav@260
   104
jaroslav@260
   105
    @Override
jaroslav@260
   106
    public void send(Comm socket, JSONCall data) {
jaroslav@260
   107
        socket.session.getAsyncRemote().sendText(data.getMessage());
jaroslav@260
   108
    }
jaroslav@260
   109
jaroslav@260
   110
    @Override
jaroslav@260
   111
    public void close(Comm socket) {
jaroslav@260
   112
        try {
jaroslav@269
   113
            final Session s = socket.session;
jaroslav@269
   114
            if (s != null) {
jaroslav@269
   115
                s.close();
jaroslav@269
   116
            }
jaroslav@260
   117
        } catch (IOException ex) {
jaroslav@260
   118
            socket.callback.notifyError(ex);
jaroslav@260
   119
        }
jaroslav@260
   120
    }
jaroslav@446
   121
jaroslav@446
   122
    @Override
jaroslav@446
   123
    public void extract(Object obj, String[] props, Object[] values) {
jaroslav@446
   124
        LoadJSON.extractJSON(obj, props, values);
jaroslav@446
   125
    }
jaroslav@446
   126
jaroslav@446
   127
    @Override
jaroslav@446
   128
    public Object toJSON(InputStream is) throws IOException {
jaroslav@446
   129
        return LoadJSON.parse(is);
jaroslav@446
   130
    }
jaroslav@446
   131
jaroslav@446
   132
    @Override
jaroslav@446
   133
    public void loadJSON(JSONCall call) {
jaroslav@446
   134
        LoadJSON.loadJSON(call);
jaroslav@446
   135
    }
jaroslav@260
   136
    
jaroslav@263
   137
    /** Implementation class in an implementation. Represents a {@link ClientEndpoint} of the
jaroslav@263
   138
     * WebSocket channel. You are unlikely to get on hold of it.
jaroslav@263
   139
     */
jaroslav@260
   140
    @ClientEndpoint
jaroslav@260
   141
    public static final class Comm {
jaroslav@260
   142
        private final JSONCall callback;
jaroslav@260
   143
        private Session session;
jaroslav@260
   144
jaroslav@260
   145
        Comm(final URI url, JSONCall callback) {
jaroslav@260
   146
            this.callback = callback;
jaroslav@260
   147
            try {
jaroslav@260
   148
                final WebSocketContainer c = ContainerProvider.getWebSocketContainer();
jaroslav@260
   149
                c.connectToServer(Comm.this, url);
jaroslav@470
   150
            } catch (Exception ex) {
jaroslav@260
   151
                wasAnError(ex);
jaroslav@260
   152
            }
jaroslav@260
   153
        }
jaroslav@260
   154
jaroslav@260
   155
        @OnOpen
jaroslav@260
   156
        public synchronized void open(Session s) {
jaroslav@260
   157
            this.session = s;
jaroslav@260
   158
            callback.notifySuccess(null);
jaroslav@260
   159
        }
jaroslav@260
   160
jaroslav@260
   161
        @OnClose
jaroslav@260
   162
        public void close() {
jaroslav@260
   163
            this.session = null;
jaroslav@260
   164
            callback.notifyError(null);
jaroslav@260
   165
        }
jaroslav@260
   166
jaroslav@260
   167
        @OnMessage
jaroslav@260
   168
        public void message(final String orig, Session s) {
jaroslav@262
   169
            Object json;
jaroslav@262
   170
            String data = orig.trim();
jaroslav@262
   171
            try {
jaroslav@262
   172
                JSONTokener tok = new JSONTokener(data);
jaroslav@262
   173
                Object obj = data.startsWith("[") ? new JSONArray(tok) : new JSONObject(tok);
jaroslav@262
   174
                json = convertToArray(obj);
jaroslav@262
   175
            } catch (JSONException ex) {
jaroslav@262
   176
                json = data;
jaroslav@260
   177
            }
jaroslav@262
   178
            callback.notifySuccess(json);
jaroslav@260
   179
        }
jaroslav@260
   180
jaroslav@260
   181
        @OnError
jaroslav@260
   182
        public void wasAnError(Throwable t) {
jaroslav@260
   183
            callback.notifyError(t);
jaroslav@260
   184
        }
jaroslav@260
   185
jaroslav@260
   186
        static Object convertToArray(Object o) throws JSONException {
jaroslav@260
   187
            if (o instanceof JSONArray) {
jaroslav@260
   188
                JSONArray ja = (JSONArray) o;
jaroslav@260
   189
                Object[] arr = new Object[ja.length()];
jaroslav@260
   190
                for (int i = 0; i < arr.length; i++) {
jaroslav@260
   191
                    arr[i] = convertToArray(ja.get(i));
jaroslav@260
   192
                }
jaroslav@260
   193
                return arr;
jaroslav@260
   194
            } else if (o instanceof JSONObject) {
jaroslav@260
   195
                JSONObject obj = (JSONObject) o;
jaroslav@260
   196
                Iterator it = obj.keys();
jaroslav@260
   197
                while (it.hasNext()) {
jaroslav@260
   198
                    String key = (String) it.next();
jaroslav@260
   199
                    obj.put(key, convertToArray(obj.get(key)));
jaroslav@260
   200
                }
jaroslav@260
   201
                return obj;
jaroslav@260
   202
            } else {
jaroslav@260
   203
                return o;
jaroslav@260
   204
            }
jaroslav@260
   205
        }
jaroslav@260
   206
        
jaroslav@260
   207
    } // end of Comm
jaroslav@260
   208
}