ed1ea16e0e907bb94c89738de495c9c8fee8d703
[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.slf4j.Logger;
33 import org.slf4j.LoggerFactory;
34 import org.iotivity.cloud.base.connector.CoapClient;
35 import org.iotivity.cloud.base.device.CoapDevice;
36 import org.iotivity.cloud.base.device.Device;
37 import org.iotivity.cloud.base.device.IRequestChannel;
38 import org.iotivity.cloud.base.exception.ClientException;
39 import org.iotivity.cloud.base.exception.ServerException;
40 import org.iotivity.cloud.base.exception.ServerException.InternalServerErrorException;
41 import org.iotivity.cloud.base.protocols.IRequest;
42 import org.iotivity.cloud.base.protocols.MessageBuilder;
43 import org.iotivity.cloud.base.protocols.coap.CoapMessage;
44 import org.iotivity.cloud.base.protocols.coap.CoapRequest;
45 import org.iotivity.cloud.base.protocols.coap.CoapResponse;
46 import org.iotivity.cloud.base.protocols.enums.ResponseStatus;
47 import org.iotivity.cloud.base.resource.ResourceManager;
48 import org.iotivity.cloud.base.server.CoapServer;
49 import org.iotivity.cloud.base.server.HttpServer;
50 import org.iotivity.cloud.base.server.Server;
51 import org.iotivity.cloud.base.server.WebSocketServer;
52
53 public class ServerSystem extends ResourceManager {
54     private final static Logger         Log          = LoggerFactory.getLogger(ServerSystem.class);
55     private List<Server>                mServerList  = new ArrayList<>();
56     public static AttributeKey<Device>  keyDevice    = AttributeKey
57             .newInstance("device");
58
59     @Sharable
60     public class PersistentPacketReceiver
61             extends SimpleChannelInboundHandler<CoapMessage> {
62         @Override
63         public void channelActive(ChannelHandlerContext ctx) {
64             StringBuilder deviceId = new StringBuilder(
65                     ctx.channel().id().asLongText().substring(26));
66             deviceId.deleteCharAt(25);
67             deviceId.insert(13, '-');
68             deviceId.insert(18, '-');
69             deviceId.insert(23, '-');
70             CoapDevice device = new CoapDevice(ctx);
71             device.updateDevice(deviceId.toString(), null, null);
72             ctx.channel().attr(ServerSystem.keyDevice).set(device);
73
74             device.onConnected();
75         }
76
77         @Override
78         protected void channelRead0(ChannelHandlerContext ctx,
79                 CoapMessage msg) {
80             try {
81                 // Find proper device and raise event.
82                 Device targetDevice = ctx.channel().attr(ServerSystem.keyDevice)
83                         .get();
84
85                 if (targetDevice == null) {
86                     throw new InternalServerErrorException(
87                             "Unable to find device");
88                 }
89
90                 if (msg instanceof CoapRequest) {
91                     onRequestReceived(targetDevice, (CoapRequest) msg);
92                 } else if (msg instanceof CoapResponse) {
93                     // TODO: Re-architecturing required
94                     IRequestChannel reqChannel = ((CoapDevice) targetDevice)
95                             .getRequestChannel();
96                     CoapClient coapClient = (CoapClient) reqChannel;
97                     coapClient.onResponseReceived(msg);
98                 }
99
100             } catch (ServerException e) {
101                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
102                         e.getErrorResponse()));
103                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), e);
104             } catch (ClientException e) {
105                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), e);
106             } catch (Throwable t) {
107                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), t);
108                 if (msg instanceof CoapRequest) {
109                     ctx.writeAndFlush(MessageBuilder.createResponse(msg,
110                             ResponseStatus.INTERNAL_SERVER_ERROR));
111                 }
112             }
113         }
114
115         @Override
116         public void channelInactive(ChannelHandlerContext ctx)
117                 throws Exception {
118             Device device = ctx.channel().attr(ServerSystem.keyDevice).get();
119             device.onDisconnected();
120             ctx.channel().attr(ServerSystem.keyDevice).remove();
121         }
122     }
123
124     @Sharable
125     public class NonPersistentPacketReceiver
126             extends SimpleChannelInboundHandler<IRequest> {
127
128         @Override
129         public void channelRead0(ChannelHandlerContext ctx, IRequest msg)
130                 throws Exception {
131
132             try {
133                 // Find proper device and raise event.
134                 Device targetDevice = ctx.channel().attr(ServerSystem.keyDevice)
135                         .get();
136
137                 onRequestReceived(targetDevice, msg);
138
139             } catch (ServerException e) {
140                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), e);
141                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
142                         e.getErrorResponse()));
143             } catch (Throwable t) {
144                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), t);
145                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
146                         ResponseStatus.INTERNAL_SERVER_ERROR));
147             }
148         }
149     }
150
151     public void addServer(Server server) {
152         if (server instanceof CoapServer || server instanceof WebSocketServer) {
153             server.addHandler(new PersistentPacketReceiver());
154         } else if (server instanceof HttpServer) {
155             server.addHandler(new NonPersistentPacketReceiver());
156         }
157
158         mServerList.add(server);
159     }
160
161     public void startSystem(boolean tlsMode) throws Exception {
162         for (Server server : mServerList) {
163             server.startServer(tlsMode);
164         }
165     }
166
167     public void stopSystem() throws Exception {
168         for (Server server : mServerList) {
169             server.stopServer();
170         }
171     }
172 }