All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vmware.xenon.common.WebSocketService Maven / Gradle / Ivy

There is a newer version: 1.6.18
Show newest version
/*
 * Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
 *
 * 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.vmware.xenon.common;

import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

/**
 * A service which allow to attach remote services to a node via WebSocket connection. For every attached service
 * actual service implementation lives on a remote client attached to a not via WebSocket (for example, in a web
 * browser).
 * 

* All such services are exposed by a Xenon node as /core/ws-service/{some-uuid}. Service links are always generated by * the node. When a request to a such remote service comes in, it is forwarded to client over a WebSocket and its * response is forwarded to original caller. Hence these services have a real link and remote implementation body. *

* This service provides an easy way to support pushing updates to a web client, such as observing needed services * or service factories for changes. *

* Remote services may subscribe for updates using special web socket based API and these subscriptions are * automatically removed whenever web socket connection is closed. *

* See {@link com.vmware.xenon.common.http.netty.NettyHttpClientRequestHandler} for more details on WebSocket interaction * protocol. */ public final class WebSocketService extends StatelessService { private final ChannelHandlerContext ctx; private final URI uri; private Map pendingOperations = new ConcurrentHashMap<>(); private static class OperationResponse { long id; Map responseHeaders; int statusCode; String responseJsonBody; } public WebSocketService(ChannelHandlerContext ctx, URI uri) { this.ctx = ctx; this.uri = uri; super.toggleOption(ServiceOption.HTML_USER_INTERFACE, true); } public void handleWebSocketMessage(String body) { OperationResponse or = Utils.fromJson(body, OperationResponse.class); Operation op = this.pendingOperations.remove(or.id); if (op == null) { logFine("Unknown operation id: %d", or.id); return; } for (Map.Entry entry : or.responseHeaders.entrySet()) { op.addResponseHeader(entry.getKey(), entry.getValue()); } op.setStatusCode(or.statusCode); if (or.responseJsonBody != null) { op.setContentType(Operation.MEDIA_TYPE_APPLICATION_JSON); op.setBodyNoCloning(or.responseJsonBody); } op.complete(); } @Override public void authorizeRequest(Operation op) { op.complete(); } @Override public void handleRequest(Operation op) { prepareRequest(op); Operation.SerializedOperation serializedOperation = Operation.SerializedOperation .create(op); this.pendingOperations.put(op.getId(), op); ChannelFuture promise = this.ctx.writeAndFlush(new TextWebSocketFrame("POST " + this.uri.toString() + Operation.CR_LF + Utils.toJson(serializedOperation))); promise.addListener(new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { if (!future.isSuccess()) { op.fail(future.cause()); WebSocketService.this.pendingOperations.remove(op.getId()); } } }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy