Add CoAP over Websocket interface in cloud
[iotivity.git] / cloud / stack / src / main / java / org / iotivity / cloud / base / ServerSystem.java
1 /*
2  * //******************************************************************
3  * //
4  * // Copyright 2016 Samsung Electronics All Rights Reserved.
5  * //
6  * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
7  * //
8  * // Licensed under the Apache License, Version 2.0 (the "License");
9  * // you may not use this file except in compliance with the License.
10  * // You may obtain a copy of the License at
11  * //
12  * //      http://www.apache.org/licenses/LICENSE-2.0
13  * //
14  * // Unless required by applicable law or agreed to in writing, software
15  * // distributed under the License is distributed on an "AS IS" BASIS,
16  * // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * // See the License for the specific language governing permissions and
18  * // limitations under the License.
19  * //
20  * //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
21  */
22 package org.iotivity.cloud.base;
23
24 import io.netty.channel.ChannelHandler.Sharable;
25 import io.netty.channel.ChannelHandlerContext;
26 import io.netty.channel.SimpleChannelInboundHandler;
27 import io.netty.util.AttributeKey;
28
29 import java.util.ArrayList;
30 import java.util.List;
31
32 import org.iotivity.cloud.base.connector.CoapClient;
33 import org.iotivity.cloud.base.device.CoapDevice;
34 import org.iotivity.cloud.base.device.Device;
35 import org.iotivity.cloud.base.device.IRequestChannel;
36 import org.iotivity.cloud.base.exception.ClientException;
37 import org.iotivity.cloud.base.exception.ServerException;
38 import org.iotivity.cloud.base.exception.ServerException.InternalServerErrorException;
39 import org.iotivity.cloud.base.protocols.IRequest;
40 import org.iotivity.cloud.base.protocols.MessageBuilder;
41 import org.iotivity.cloud.base.protocols.coap.CoapMessage;
42 import org.iotivity.cloud.base.protocols.coap.CoapRequest;
43 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
44 import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
45 import org.iotivity.cloud.base.resource.ResourceManager;
46 import org.iotivity.cloud.base.server.CoapServer;
47 import org.iotivity.cloud.base.server.HttpServer;
48 import org.iotivity.cloud.base.server.Server;
49 import org.iotivity.cloud.base.server.WebSocketServer;
50 import org.iotivity.cloud.util.Log;
51
52 import io.netty.channel.ChannelHandler.Sharable;
53 import io.netty.channel.ChannelHandlerContext;
54 import io.netty.channel.SimpleChannelInboundHandler;
55 import io.netty.util.AttributeKey;
56
57 public class ServerSystem extends ResourceManager {
58     private List<Server>               mServerList = new ArrayList<>();
59     public static AttributeKey<Device> keyDevice   = AttributeKey
60             .newInstance("device");
61
62     @Sharable
63     public class PersistentPacketReceiver
64             extends SimpleChannelInboundHandler<CoapMessage> {
65         @Override
66         public void channelActive(ChannelHandlerContext ctx) {
67             StringBuilder deviceId = new StringBuilder(
68                     ctx.channel().id().asLongText().substring(26));
69             deviceId.deleteCharAt(25);
70             deviceId.insert(13, '-');
71             deviceId.insert(18, '-');
72             deviceId.insert(23, '-');
73             CoapDevice device = new CoapDevice(ctx);
74             device.updateDevice(deviceId.toString(), null, null);
75             ctx.channel().attr(ServerSystem.keyDevice).set(device);
76
77             device.onConnected();
78         }
79
80         @Override
81         protected void channelRead0(ChannelHandlerContext ctx,
82                 CoapMessage msg) {
83             try {
84                 // Find proper device and raise event.
85                 Device targetDevice = ctx.channel().attr(ServerSystem.keyDevice)
86                         .get();
87
88                 if (targetDevice == null) {
89                     throw new InternalServerErrorException(
90                             "Unable to find device");
91                 }
92
93                 if (msg instanceof CoapRequest) {
94                     onRequestReceived(targetDevice, (CoapRequest) msg);
95                 } else if (msg instanceof CoapResponse) {
96                     // TODO: Re-architecturing required
97                     IRequestChannel reqChannel = ((CoapDevice) targetDevice)
98                             .getRequestChannel();
99                     CoapClient coapClient = (CoapClient) reqChannel;
100                     coapClient.onResponseReceived(msg);
101                 }
102
103             } catch (ServerException e) {
104                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
105                         e.getErrorResponse()));
106                 Log.f(ctx.channel(), e);
107             } catch (ClientException e) {
108                 Log.f(ctx.channel(), e);
109             } catch (Throwable t) {
110                 Log.f(ctx.channel(), t);
111                 if (msg instanceof CoapRequest) {
112                     ctx.writeAndFlush(MessageBuilder.createResponse(msg,
113                             ResponseStatus.INTERNAL_SERVER_ERROR));
114                 }
115             }
116         }
117
118         @Override
119         public void channelInactive(ChannelHandlerContext ctx)
120                 throws Exception {
121             Device device = ctx.channel().attr(ServerSystem.keyDevice).get();
122             device.onDisconnected();
123             ctx.channel().attr(ServerSystem.keyDevice).remove();
124         }
125     }
126
127     @Sharable
128     public class NonPersistentPacketReceiver
129             extends SimpleChannelInboundHandler<IRequest> {
130
131         @Override
132         public void channelRead0(ChannelHandlerContext ctx, IRequest msg)
133                 throws Exception {
134
135             try {
136                 // Find proper device and raise event.
137                 Device targetDevice = ctx.channel().attr(ServerSystem.keyDevice)
138                         .get();
139
140                 onRequestReceived(targetDevice, msg);
141
142             } catch (ServerException e) {
143                 Log.f(ctx.channel(), e);
144                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
145                         e.getErrorResponse()));
146             } catch (Throwable t) {
147                 Log.f(ctx.channel(), t);
148                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
149                         ResponseStatus.INTERNAL_SERVER_ERROR));
150             }
151         }
152     }
153
154     public void addServer(Server server) {
155         if (server instanceof CoapServer || server instanceof WebSocketServer) {
156             server.addHandler(new PersistentPacketReceiver());
157         } else if (server instanceof HttpServer) {
158             server.addHandler(new NonPersistentPacketReceiver());
159         }
160
161         mServerList.add(server);
162     }
163
164     public void startSystem(boolean tlsMode) throws Exception {
165         for (Server server : mServerList) {
166             server.startServer(tlsMode);
167         }
168     }
169
170     public void stopSystem() throws Exception {
171         for (Server server : mServerList) {
172             server.stopServer();
173         }
174     }
175 }