]> git.basschouten.com Git - openhab-addons.git/blob
2e8e418be07a50d8f40bde1c0c209a675ace53b4
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2020 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.io.neeo.internal.serialization;
14
15 import java.lang.reflect.Type;
16 import java.util.ArrayList;
17 import java.util.List;
18 import java.util.Objects;
19
20 import org.apache.commons.lang.StringUtils;
21 import org.eclipse.jdt.annotation.NonNullByDefault;
22 import org.eclipse.jdt.annotation.Nullable;
23 import org.openhab.core.items.Item;
24 import org.openhab.core.items.ItemNotFoundException;
25 import org.openhab.core.thing.Channel;
26 import org.openhab.core.thing.ChannelUID;
27 import org.openhab.core.thing.type.ChannelType;
28 import org.openhab.core.types.Command;
29 import org.openhab.io.neeo.internal.NeeoUtil;
30 import org.openhab.io.neeo.internal.ServiceContext;
31 import org.openhab.io.neeo.internal.models.ItemSubType;
32 import org.openhab.io.neeo.internal.models.NeeoCapabilityType;
33 import org.openhab.io.neeo.internal.models.NeeoDeviceChannel;
34 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelDirectory;
35 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelDirectoryListItem;
36 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelKind;
37 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelRange;
38 import org.openhab.io.neeo.internal.models.NeeoDeviceChannelText;
39
40 import com.google.gson.JsonDeserializationContext;
41 import com.google.gson.JsonDeserializer;
42 import com.google.gson.JsonElement;
43 import com.google.gson.JsonObject;
44 import com.google.gson.JsonParseException;
45 import com.google.gson.JsonSerializationContext;
46 import com.google.gson.JsonSerializer;
47
48 /**
49  * Implementation of {@link JsonSerializer} and {@link JsonDeserializer} to serialize/deserial
50  * {@link NeeoDeviceChannel}
51  *
52  * @author Tim Roberts - Initial Contribution
53  */
54 @NonNullByDefault
55 public class NeeoDeviceChannelSerializer
56         implements JsonSerializer<NeeoDeviceChannel>, JsonDeserializer<NeeoDeviceChannel> {
57
58     /** The service context */
59     @Nullable
60     private final ServiceContext context;
61
62     /**
63      * Creates the serializer with no context
64      */
65     public NeeoDeviceChannelSerializer() {
66         this(null);
67     }
68
69     /**
70      * Creates the serializer using the given context. A null context will suppress certain values on the returned
71      * object
72      *
73      * @param context the possibly null context
74      */
75     public NeeoDeviceChannelSerializer(@Nullable ServiceContext context) {
76         this.context = context;
77     }
78
79     @Override
80     public JsonElement serialize(NeeoDeviceChannel chnl, @Nullable Type type,
81             @Nullable JsonSerializationContext jsonContext) {
82         Objects.requireNonNull(chnl, "chnl cannot be null");
83         Objects.requireNonNull(type, "type cannot be null");
84         Objects.requireNonNull(jsonContext, "jsonContext cannot be null");
85
86         final JsonObject jo = new JsonObject();
87
88         jo.add("kind", jsonContext.serialize(chnl.getKind()));
89         jo.addProperty("itemName", chnl.getItemName());
90         jo.addProperty("label", chnl.getLabel());
91         jo.addProperty("value", chnl.getValue());
92         jo.addProperty("channelNbr", chnl.getChannelNbr());
93         jo.add("type", jsonContext.serialize(chnl.getType()));
94         jo.add("subType", jsonContext.serialize(chnl.getSubType()));
95         jo.add("range", jsonContext.serialize(chnl.getRange()));
96
97         final ServiceContext localContext = context;
98         if (localContext != null) {
99             final List<String> commandTypes = new ArrayList<>();
100             boolean isReadOnly = false;
101             String itemLabel = chnl.getLabel();
102             String itemType = null;
103
104             try {
105                 final Item item = localContext.getItemRegistry().getItem(chnl.getItemName());
106                 itemType = item.getType();
107
108                 if (StringUtils.isNotEmpty(item.getLabel())) {
109                     itemLabel = item.getLabel();
110                 }
111
112                 for (Class<? extends Command> cmd : item.getAcceptedCommandTypes()) {
113                     if (!StringUtils.equalsIgnoreCase(cmd.getSimpleName(), "refreshtype")) {
114                         commandTypes.add(cmd.getSimpleName().toLowerCase());
115                     }
116                 }
117
118                 for (ChannelUID channelUid : localContext.getItemChannelLinkRegistry()
119                         .getBoundChannels(chnl.getItemName())) {
120                     if (channelUid != null) {
121                         jo.addProperty("groupId", channelUid.getGroupId());
122                         final Channel channel = localContext.getThingRegistry().getChannel(channelUid);
123                         if (channel != null) {
124                             final ChannelType channelType = localContext.getChannelTypeRegistry()
125                                     .getChannelType(channel.getChannelTypeUID());
126                             if (channelType != null && channelType.getState() != null) {
127                                 isReadOnly = channelType.getState().isReadOnly();
128                             }
129                         }
130                     }
131                 }
132             } catch (ItemNotFoundException e) {
133                 itemType = "N/A";
134             }
135
136             if (StringUtils.isNotEmpty(itemLabel)) {
137                 switch (chnl.getSubType()) {
138                     case HUE:
139                         itemType += " (Hue)";
140                         break;
141
142                     case SATURATION:
143                         itemType += " (Sat)";
144                         break;
145
146                     case BRIGHTNESS:
147                         itemType += " (Bri)";
148                         break;
149
150                     default:
151                         break;
152                 }
153             }
154
155             jo.addProperty("itemType", itemType);
156             jo.addProperty("itemLabel", itemLabel);
157             jo.add("acceptedCommandTypes", jsonContext.serialize(commandTypes));
158             jo.addProperty("isReadOnly", isReadOnly);
159
160         }
161
162         if (chnl instanceof NeeoDeviceChannelText) {
163             jo.addProperty("labelVisible", ((NeeoDeviceChannelText) chnl).isLabelVisible());
164         } else if (chnl instanceof NeeoDeviceChannelDirectory) {
165             jo.add("listItems", jsonContext.serialize(((NeeoDeviceChannelDirectory) chnl).getListItems()));
166         }
167
168         return jo;
169     }
170
171     @Override
172     public NeeoDeviceChannel deserialize(@Nullable JsonElement elm, @Nullable Type type,
173             @Nullable JsonDeserializationContext context) throws JsonParseException {
174         Objects.requireNonNull(elm, "elm cannot be null");
175         Objects.requireNonNull(type, "type cannot be null");
176         Objects.requireNonNull(context, "context cannot be null");
177
178         if (!(elm instanceof JsonObject)) {
179             throw new JsonParseException("Element not an instance of JsonObject: " + elm);
180         }
181
182         final JsonObject jo = (JsonObject) elm;
183         final String itemName = NeeoUtil.getString(jo, "itemName");
184
185         if (itemName == null || StringUtils.isEmpty(itemName)) {
186             throw new JsonParseException("Element requires an itemName attribute: " + elm);
187         }
188
189         final ItemSubType itemSubType = jo.has("subType") ? context.deserialize(jo.get("subType"), ItemSubType.class)
190                 : ItemSubType.NONE;
191
192         final String label = NeeoUtil.getString(jo, "label");
193         final String value = NeeoUtil.getString(jo, "value");
194         final Integer channelNbr = NeeoUtil.getInt(jo, "channelNbr");
195
196         if (channelNbr == null) {
197             throw new JsonParseException("Channel Number is not a valid integer");
198         }
199         final NeeoCapabilityType capType = context.deserialize(jo.get("type"), NeeoCapabilityType.class);
200
201         final NeeoDeviceChannelRange range = jo.has("range")
202                 ? context.deserialize(jo.get("range"), NeeoDeviceChannelRange.class)
203                 : null;
204
205         final NeeoDeviceChannelKind kind = jo.has("kind")
206                 ? context.deserialize(jo.get("kind"), NeeoDeviceChannelKind.class)
207                 : NeeoDeviceChannelKind.ITEM;
208
209         try {
210             if (capType == NeeoCapabilityType.TEXTLABEL) {
211                 final boolean labelVisible = jo.has("labelVisible") ? jo.get("labelVisible").getAsBoolean() : true;
212
213                 return new NeeoDeviceChannelText(kind, itemName, channelNbr, capType, itemSubType,
214                         label == null || StringUtils.isEmpty(label) ? NeeoUtil.NOTAVAILABLE : label, value, range,
215                         labelVisible);
216             } else if (capType == NeeoCapabilityType.DIRECTORY) {
217                 final NeeoDeviceChannelDirectoryListItem[] listItems = jo.has("listItems")
218                         ? context.deserialize(jo.get("listItems"), NeeoDeviceChannelDirectoryListItem[].class)
219                         : new NeeoDeviceChannelDirectoryListItem[0];
220
221                 return new NeeoDeviceChannelDirectory(kind, itemName, channelNbr, capType, itemSubType,
222                         label == null || StringUtils.isEmpty(label) ? NeeoUtil.NOTAVAILABLE : label, value, range,
223                         listItems);
224             } else {
225                 return new NeeoDeviceChannel(kind, itemName, channelNbr, capType, itemSubType,
226                         label == null || StringUtils.isEmpty(label) ? NeeoUtil.NOTAVAILABLE : label, value, range);
227             }
228         } catch (NullPointerException | IllegalArgumentException e) {
229             throw new JsonParseException(e);
230         }
231     }
232 }