2 * Copyright 2017 Gregory Moyer
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.openhab.binding.sleepiq.api.impl;
18 import java.io.IOException;
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.List;
23 import java.util.logging.Logger;
24 import java.util.stream.Collectors;
26 import javax.ws.rs.client.Client;
27 import javax.ws.rs.client.ClientBuilder;
28 import javax.ws.rs.client.ClientRequestContext;
29 import javax.ws.rs.client.ClientRequestFilter;
30 import javax.ws.rs.client.Entity;
31 import javax.ws.rs.core.MediaType;
32 import javax.ws.rs.core.Response;
33 import javax.ws.rs.core.Response.Status;
35 import org.openhab.binding.sleepiq.api.BedNotFoundException;
36 import org.openhab.binding.sleepiq.api.Configuration;
37 import org.openhab.binding.sleepiq.api.LoginException;
38 import org.openhab.binding.sleepiq.api.SleepIQ;
39 import org.openhab.binding.sleepiq.api.UnauthorizedException;
40 import org.openhab.binding.sleepiq.api.filter.LoggingFilter;
41 import org.openhab.binding.sleepiq.api.model.Bed;
42 import org.openhab.binding.sleepiq.api.model.BedsResponse;
43 import org.openhab.binding.sleepiq.api.model.Failure;
44 import org.openhab.binding.sleepiq.api.model.FamilyStatus;
45 import org.openhab.binding.sleepiq.api.model.LoginInfo;
46 import org.openhab.binding.sleepiq.api.model.LoginRequest;
47 import org.openhab.binding.sleepiq.api.model.PauseMode;
48 import org.openhab.binding.sleepiq.api.model.Sleeper;
49 import org.openhab.binding.sleepiq.api.model.SleepersResponse;
50 import org.openhab.binding.sleepiq.internal.GsonProvider;
52 public class SleepIQImpl extends AbstractClient implements SleepIQ
54 protected static final String PARAM_KEY = "_k";
56 protected static final String DATA_BED_ID = "bedId";
58 protected final Configuration config;
60 private volatile LoginInfo loginInfo;
62 public SleepIQImpl(Configuration config)
68 public LoginInfo login() throws LoginException
70 if (loginInfo == null)
74 if (loginInfo == null)
76 Response response = getClient().target(config.getBaseUri())
77 .path(Endpoints.login())
78 .request(MediaType.APPLICATION_JSON_TYPE)
79 .put(Entity.json(new LoginRequest().withLogin(config.getUsername())
80 .withPassword(config.getPassword())));
82 if (isUnauthorized(response))
84 throw new UnauthorizedException(response.readEntity(Failure.class));
87 if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily()))
89 throw new LoginException(response.readEntity(Failure.class));
92 // add the received cookies to all future requests
93 getClient().register(new ClientRequestFilter()
96 public void filter(ClientRequestContext requestContext) throws IOException
98 List<Object> cookies = response.getCookies()
101 .map(newCookie -> newCookie.toCookie())
102 .collect(Collectors.toList());
103 requestContext.getHeaders().put("Cookie", cookies);
107 loginInfo = response.readEntity(LoginInfo.class);
116 public List<Bed> getBeds()
118 return getSessionResponse(this::getBedsResponse).readEntity(BedsResponse.class).getBeds();
121 protected Response getBedsResponse(Map<String, Object> data) throws LoginException
123 LoginInfo login = login();
124 return getClient().target(config.getBaseUri())
125 .path(Endpoints.bed())
126 .queryParam(PARAM_KEY, login.getKey())
127 .request(MediaType.APPLICATION_JSON_TYPE)
132 public List<Sleeper> getSleepers()
134 return getSessionResponse(this::getSleepersResponse).readEntity(SleepersResponse.class)
138 protected Response getSleepersResponse(Map<String, Object> data) throws LoginException
140 LoginInfo login = login();
141 return getClient().target(config.getBaseUri())
142 .path(Endpoints.sleeper())
143 .queryParam(PARAM_KEY, login.getKey())
144 .request(MediaType.APPLICATION_JSON_TYPE)
149 public FamilyStatus getFamilyStatus()
151 return getSessionResponse(this::getFamilyStatusResponse).readEntity(FamilyStatus.class);
154 protected Response getFamilyStatusResponse(Map<String, Object> data) throws LoginException
156 LoginInfo login = login();
157 return getClient().target(config.getBaseUri())
158 .path(Endpoints.bed())
159 .path(Endpoints.familyStatus())
160 .queryParam(PARAM_KEY, login.getKey())
161 .request(MediaType.APPLICATION_JSON_TYPE)
166 public PauseMode getPauseMode(String bedId) throws BedNotFoundException
168 Map<String, Object> data = new HashMap<>();
169 data.put(DATA_BED_ID, bedId);
171 Response response = getSessionResponse(this::getPauseModeResponse, data);
173 if (!Status.Family.SUCCESSFUL.equals(response.getStatusInfo().getFamily()))
175 throw new BedNotFoundException(response.readEntity(Failure.class));
178 return response.readEntity(PauseMode.class);
181 protected Response getPauseModeResponse(Map<String, Object> data) throws LoginException
183 LoginInfo login = login();
184 return getClient().target(config.getBaseUri())
185 .path(Endpoints.bed())
186 .path(data.get(DATA_BED_ID).toString())
187 .path(Endpoints.pauseMode())
188 .queryParam(PARAM_KEY, login.getKey())
189 .request(MediaType.APPLICATION_JSON_TYPE)
193 protected boolean isUnauthorized(Response response)
195 return Status.UNAUTHORIZED.getStatusCode() == response.getStatusInfo().getStatusCode();
198 protected synchronized void resetLogin()
203 protected Response getSessionResponse(Request request)
205 return getSessionResponse(request, Collections.emptyMap());
208 protected Response getSessionResponse(Request request, Map<String, Object> data)
212 Response response = request.execute(data);
214 if (isUnauthorized(response))
219 response = request.execute(data);
224 catch (LoginException e)
226 throw new RuntimeException(e.getMessage(), e);
231 protected Client createClient()
233 ClientBuilder builder = ClientBuilder.newBuilder();
235 // setup Gson (de)serialization
236 GsonProvider<Object> gsonProvider = new GsonProvider<>(getGson());
237 builder.register(gsonProvider);
239 // turn on logging if requested
240 if (config.isLogging())
242 builder.register(new LoggingFilter(Logger.getLogger(SleepIQImpl.class.getName()),
246 return builder.build();
250 public static interface Request
252 public Response execute(Map<String, Object> data) throws LoginException;