IOT-3143
[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, e.getErrorResponse()));
102                 if (e instanceof ServerException.ServiceUnavailableException)
103                     Log.warn(e.getMessage());
104                 else
105                     Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), e);
106             } catch (ClientException e) {
107                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), e);
108             } catch (Throwable t) {
109                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), t);
110                 if (msg instanceof CoapRequest) {
111                     ctx.writeAndFlush(MessageBuilder.createResponse(msg, ResponseStatus.INTERNAL_SERVER_ERROR));
112                 }
113             }
114         }
115
116         @Override
117         public void channelInactive(ChannelHandlerContext ctx)
118                 throws Exception {
119             Device device = ctx.channel().attr(ServerSystem.keyDevice).get();
120             device.onDisconnected();
121             ctx.channel().attr(ServerSystem.keyDevice).remove();
122         }
123     }
124
125     @Sharable
126     public class NonPersistentPacketReceiver
127             extends SimpleChannelInboundHandler<IRequest> {
128
129         @Override
130         public void channelRead0(ChannelHandlerContext ctx, IRequest msg)
131                 throws Exception {
132
133             try {
134                 // Find proper device and raise event.
135                 Device targetDevice = ctx.channel().attr(ServerSystem.keyDevice)
136                         .get();
137
138                 onRequestReceived(targetDevice, msg);
139
140             } catch (ServerException e) {
141                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), e);
142                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
143                         e.getErrorResponse()));
144             } catch (Throwable t) {
145                 Log.error("[{}] channel error", ctx.channel().id().asLongText().substring(26), t);
146                 ctx.writeAndFlush(MessageBuilder.createResponse(msg,
147                         ResponseStatus.INTERNAL_SERVER_ERROR));
148             }
149         }
150     }
151
152     public void addServer(Server server) {
153         if (server instanceof CoapServer || server instanceof WebSocketServer) {
154             server.addHandler(new PersistentPacketReceiver());
155         } else if (server instanceof HttpServer) {
156             server.addHandler(new NonPersistentPacketReceiver());
157         }
158
159         mServerList.add(server);
160     }
161
162     public void startSystem(boolean tlsMode) throws Exception {
163         for (Server server : mServerList) {
164             server.startServer(tlsMode);
165         }
166     }
167
168     public void stopSystem() throws Exception {
169         for (Server server : mServerList) {
170             server.stopServer();
171         }
172     }
173 }