|  |  | @@ -8,6 +8,7 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | package com.facebook.openwifirrm.ucentral; |  |  |  | package com.facebook.openwifirrm.ucentral; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import java.time.Instant; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.util.Collections; |  |  |  | import java.util.Collections; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.util.HashMap; |  |  |  | import java.util.HashMap; | 
			
		
	
		
		
			
				
					
					|  |  |  | import java.util.List; |  |  |  | import java.util.List; | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -30,6 +31,8 @@ import com.facebook.openwifirrm.ucentral.gw.models.ServiceEvent; | 
			
		
	
		
		
			
				
					
					|  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.StatisticsRecords; |  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.StatisticsRecords; | 
			
		
	
		
		
			
				
					
					|  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.SystemInfoResults; |  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.SystemInfoResults; | 
			
		
	
		
		
			
				
					
					|  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.TokenValidationResult; |  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.TokenValidationResult; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.WebTokenRefreshRequest; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.WebTokenResult; | 
			
		
	
		
		
			
				
					
					|  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.WifiScanRequest; |  |  |  | import com.facebook.openwifirrm.ucentral.gw.models.WifiScanRequest; | 
			
		
	
		
		
			
				
					
					|  |  |  | import com.facebook.openwifirrm.ucentral.prov.models.EntityList; |  |  |  | import com.facebook.openwifirrm.ucentral.prov.models.EntityList; | 
			
		
	
		
		
			
				
					
					|  |  |  | import com.facebook.openwifirrm.ucentral.prov.models.InventoryTagList; |  |  |  | import com.facebook.openwifirrm.ucentral.prov.models.InventoryTagList; | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -137,7 +140,18 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * The access token obtained from uCentralSec, needed only when using public |  |  |  | 	 * The access token obtained from uCentralSec, needed only when using public | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * endpoints. |  |  |  | 	 * endpoints. | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 */ |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	private String accessToken; |  |  |  | 	private WebTokenResult accessToken; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * The unix timestamp (in seconds) keeps track of when the accessToken is created. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	private long created; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * The unix timestamp (in seconds) keeps track of last time when the accessToken  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * is accessed. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	private long lastAccess; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/** |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  | 	 * Constructor. |  |  |  | 	 * Constructor. | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -184,7 +198,8 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		Map<String, Object> body = new HashMap<>(); |  |  |  | 		Map<String, Object> body = new HashMap<>(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		body.put("userId", username); |  |  |  | 		body.put("userId", username); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		body.put("password", password); |  |  |  | 		body.put("password", password); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		HttpResponse<String> response = httpPost("oauth2", OWSEC_SERVICE, body); |  |  |  | 		HttpResponse<String> response = | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			httpPost("oauth2", OWSEC_SERVICE, body, null); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (!response.isSuccess()) { |  |  |  | 		if (!response.isSuccess()) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			logger.error( |  |  |  | 			logger.error( | 
			
		
	
		
		
			
				
					
					|  |  |  | 				"Login failed: Response code {}, body: {}", |  |  |  | 				"Login failed: Response code {}, body: {}", | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -195,27 +210,146 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		// Parse access token from response |  |  |  | 		// Parse access token from response | 
			
		
	
		
		
			
				
					
					|  |  |  | 		JSONObject respBody; |  |  |  | 		WebTokenResult token; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		try { |  |  |  | 		try { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			respBody = new JSONObject(response.getBody()); |  |  |  | 			token = gson.fromJson(response.getBody(), WebTokenResult.class); | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		} catch (JSONException e) { |  |  |  | 		} catch (JsonSyntaxException e) { | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			logger.error("Login failed: Unexpected response", e); |  |  |  | 			logger.error("Login failed: Unexpected response", e); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			logger.debug("Response body: {}", response.getBody()); |  |  |  | 			logger.debug("Response body: {}", response.getBody()); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			return false; |  |  |  | 			return false; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (!respBody.has("access_token")) { |  |  |  | 		if ( | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			token == null || token.access_token == null || | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				token.access_token.isEmpty() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			logger.error("Login failed: Missing access token"); |  |  |  | 			logger.error("Login failed: Missing access token"); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			logger.debug("Response body: {}", respBody.toString()); |  |  |  | 			logger.debug("Response body: {}", response.getBody()); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 			return false; |  |  |  | 			return false; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		this.accessToken = respBody.getString("access_token"); |  |  |  | 		this.accessToken = token; | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		this.created = accessToken.created; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		this.lastAccess = accessToken.created; | 
			
		
	
		
		
			
				
					
					|  |  |  | 		logger.info("Login successful as user: {}", username); |  |  |  | 		logger.info("Login successful as user: {}", username); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		logger.debug("Access token: {}", accessToken); |  |  |  | 		logger.debug("Access token: {}", accessToken.access_token); | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		logger.debug("Refresh token: {}", accessToken.refresh_token); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 		// Load system endpoints |  |  |  | 		// Load system endpoints | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return loadSystemEndpoints(); |  |  |  | 		return loadSystemEndpoints(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * when using public endpoints, refresh the access token if it's expired. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	public synchronized void refreshAccessToken() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (usePublicEndpoints) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			refreshAccessTokenImpl(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * Check if the token is completely expired even if | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * for a token refresh request | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @return true if the refresh token is expired | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	private boolean isAccessTokenExpired() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (accessToken == null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		return created + accessToken.expires_in < | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			Instant.now().getEpochSecond(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * Check if an access token is expired. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @return true if the access token is expired | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	private boolean isAccessTokenTimedOut() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (accessToken == null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return true; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		return lastAccess + accessToken.idle_timeout < | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			Instant.now().getEpochSecond(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * Refresh the access toke when time out. If the refresh token is expired, login again. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * If the access token is expired, POST a WebTokenRefreshRequest to refresh token. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	private void refreshAccessTokenImpl() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (!usePublicEndpoints) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (isAccessTokenExpired()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			synchronized (this) {			 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				if (isAccessTokenExpired()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					logger.info("Token is expired, login again"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					login(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} else if (isAccessTokenTimedOut()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			synchronized (this) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				if (isAccessTokenTimedOut()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					logger.debug("Access token timed out, refreshing the token"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					accessToken = refreshToken(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					created = Instant.now().getEpochSecond(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					lastAccess = created; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					if (accessToken != null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 						logger.debug("Successfully refresh token."); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					}else{ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 						logger.error( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 							"Fail to refresh token with access token: {}", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 							accessToken.access_token | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 						); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	/** | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * POST a WebTokenRefreshRequest to refresh the access token. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 * @return valid access token if success, otherwise return null. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	 */ | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	private WebTokenResult refreshToken() { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (accessToken == null) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return null; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		WebTokenRefreshRequest refreshRequest = new WebTokenRefreshRequest(); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		refreshRequest.userId = username; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		refreshRequest.refreshToken = accessToken.refresh_token; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		logger.debug("refresh token: {}", accessToken.refresh_token); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		Map<String, Object> parameters = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			Collections.singletonMap("grant_type", "refresh_token"); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		HttpResponse<String> response = | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			httpPost( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				"oauth2", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				OWSEC_SERVICE, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				refreshRequest, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				parameters | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (!response.isSuccess()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			logger.error( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				"Failed to refresh token: Response code {}, body: {}", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				response.getStatus(), | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				response.getBody() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return null; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		try { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return gson.fromJson(response.getBody(), WebTokenResult.class); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} catch (JsonSyntaxException e) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			logger.error( | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				"Failed to serialize WebTokenResult: Unexpected response:", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				e | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			logger.debug("Response body: {}", response.getBody()); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			return null; | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/** Read system endpoint URLs from uCentralSec. */ |  |  |  | 	/** Read system endpoint URLs from uCentralSec. */ | 
			
		
	
		
		
			
				
					
					|  |  |  | 	private boolean loadSystemEndpoints() { |  |  |  | 	private boolean loadSystemEndpoints() { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		// Make request |  |  |  | 		// Make request | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -324,8 +458,12 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			.connectTimeout(connectTimeoutMs) |  |  |  | 			.connectTimeout(connectTimeoutMs) | 
			
		
	
		
		
			
				
					
					|  |  |  | 			.socketTimeout(socketTimeoutMs); |  |  |  | 			.socketTimeout(socketTimeoutMs); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (usePublicEndpoints) { |  |  |  | 		if (usePublicEndpoints) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (accessToken != null) { |  |  |  | 			if (!isAccessTokenExpired()) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				req.header("Authorization", "Bearer " + accessToken); |  |  |  | 				req.header( | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					"Authorization", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					"Bearer " + accessToken.access_token | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				lastAccess = Instant.now().getEpochSecond(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} else { |  |  |  | 		} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			req |  |  |  | 			req | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -339,26 +477,29 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/** Send a POST request with a JSON body. */ |  |  |  | 	/** Send a POST request with a JSON body and query params. */ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	private HttpResponse<String> httpPost( |  |  |  | 	private HttpResponse<String> httpPost( | 
			
		
	
		
		
			
				
					
					|  |  |  | 		String endpoint, |  |  |  | 		String endpoint, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		String service, |  |  |  | 		String service, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		Object body |  |  |  | 		Object body, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		Map<String, Object> parameters | 
			
		
	
		
		
			
				
					
					|  |  |  | 	) { |  |  |  | 	) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return httpPost( |  |  |  | 		return httpPost( | 
			
		
	
		
		
			
				
					
					|  |  |  | 			endpoint, |  |  |  | 			endpoint, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			service, |  |  |  | 			service, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			body, |  |  |  | 			body, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			parameters, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			socketParams.connectTimeoutMs, |  |  |  | 			socketParams.connectTimeoutMs, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			socketParams.socketTimeoutMs |  |  |  | 			socketParams.socketTimeoutMs | 
			
		
	
		
		
			
				
					
					|  |  |  | 		); |  |  |  | 		); | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	/** Send a POST request with a JSON body using given timeout values. */ |  |  |  | 	/** Send a POST request with a JSON body and query params using given timeout values. */ | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	private HttpResponse<String> httpPost( |  |  |  | 	private HttpResponse<String> httpPost( | 
			
		
	
		
		
			
				
					
					|  |  |  | 		String endpoint, |  |  |  | 		String endpoint, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		String service, |  |  |  | 		String service, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		Object body, |  |  |  | 		Object body, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		Map<String, Object> parameters, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		int connectTimeoutMs, |  |  |  | 		int connectTimeoutMs, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		int socketTimeoutMs |  |  |  | 		int socketTimeoutMs | 
			
		
	
		
		
			
				
					
					|  |  |  | 	) { |  |  |  | 	) { | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -367,9 +508,16 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			.header("accept", "application/json") |  |  |  | 			.header("accept", "application/json") | 
			
		
	
		
		
			
				
					
					|  |  |  | 			.connectTimeout(connectTimeoutMs) |  |  |  | 			.connectTimeout(connectTimeoutMs) | 
			
		
	
		
		
			
				
					
					|  |  |  | 			.socketTimeout(socketTimeoutMs); |  |  |  | 			.socketTimeout(socketTimeoutMs); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		if (parameters != null && !parameters.isEmpty()) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			req.queryString(parameters); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 		} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (usePublicEndpoints) { |  |  |  | 		if (usePublicEndpoints) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			if (accessToken != null) { |  |  |  | 			if (!isAccessTokenExpired()) { | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 				req.header("Authorization", "Bearer " + accessToken); |  |  |  | 				req.header( | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					"Authorization", | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 					"Bearer " + accessToken.access_token | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				); | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 				lastAccess = Instant.now().getEpochSecond(); | 
			
		
	
		
		
			
				
					
					|  |  |  | 			} |  |  |  | 			} | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} else { |  |  |  | 		} else { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			req |  |  |  | 			req | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -454,6 +602,7 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			String.format("device/%s/wifiscan", serialNumber), |  |  |  | 			String.format("device/%s/wifiscan", serialNumber), | 
			
		
	
		
		
			
				
					
					|  |  |  | 			OWGW_SERVICE, |  |  |  | 			OWGW_SERVICE, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			req, |  |  |  | 			req, | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			null, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			socketParams.connectTimeoutMs, |  |  |  | 			socketParams.connectTimeoutMs, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			socketParams.wifiScanTimeoutMs |  |  |  | 			socketParams.wifiScanTimeoutMs | 
			
		
	
		
		
			
				
					
					|  |  |  | 		); |  |  |  | 		); | 
			
		
	
	
		
		
			
				
					
					|  |  | @@ -482,7 +631,8 @@ public class UCentralClient { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		HttpResponse<String> response = httpPost( |  |  |  | 		HttpResponse<String> response = httpPost( | 
			
		
	
		
		
			
				
					
					|  |  |  | 			String.format("device/%s/configure", serialNumber), |  |  |  | 			String.format("device/%s/configure", serialNumber), | 
			
		
	
		
		
			
				
					
					|  |  |  | 			OWGW_SERVICE, |  |  |  | 			OWGW_SERVICE, | 
			
		
	
		
		
			
				
					
					|  |  |  | 			req |  |  |  | 			req, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 			null | 
			
		
	
		
		
			
				
					
					|  |  |  | 		); |  |  |  | 		); | 
			
		
	
		
		
			
				
					
					|  |  |  | 		if (!response.isSuccess()) { |  |  |  | 		if (!response.isSuccess()) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			logger.error("Error: {}", response.getBody()); |  |  |  | 			logger.error("Error: {}", response.getBody()); | 
			
		
	
	
		
		
			
				
					
					|  |  |   |