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