Java tutorial
/** * This file is part of JEMMA - http://jemma.energy-home.org * (C) Copyright 2013 Telecom Italia (http://www.telecomitalia.it) * * JEMMA is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License (LGPL) version 3 * or later as published by the Free Software Foundation, which accompanies * this distribution and is available at http://www.gnu.org/licenses/lgpl.html * * JEMMA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License (LGPL) for more details. * */ package org.energy_home.jemma.internal.shapi; import org.energy_home.jemma.ah.cluster.ah.ConfigServer; import org.energy_home.jemma.ah.hac.ApplianceException; import org.energy_home.jemma.ah.hac.HacException; import org.energy_home.jemma.ah.hac.IAppliance; import org.energy_home.jemma.ah.hac.IApplicationEndPoint; import org.energy_home.jemma.ah.hac.IApplicationService; import org.energy_home.jemma.ah.hac.IAttributeValue; import org.energy_home.jemma.ah.hac.IEndPoint; import org.energy_home.jemma.ah.hac.IServiceCluster; import org.energy_home.jemma.ah.hac.ServiceClusterException; import org.energy_home.jemma.ah.hac.lib.ext.IApplianceConfiguration; import org.energy_home.jemma.ah.hac.lib.ext.IAppliancesProxy; import org.energy_home.jemma.ah.hac.lib.ext.INetworkManager; import org.energy_home.jemma.ah.hap.client.AHContainerAddress; import org.energy_home.jemma.ah.hap.client.AHContainers; import org.energy_home.jemma.ah.hap.client.EHContainers; import org.energy_home.jemma.ah.hap.client.IM2MHapService; import org.energy_home.jemma.ah.m2m.device.M2MContainerAddress; import org.energy_home.jemma.ah.m2m.device.M2MNetworkScl; import org.energy_home.jemma.internal.ah.hap.client.AHM2MContainerAddress; import org.energy_home.jemma.internal.ah.hap.client.AHM2MHapService; import org.energy_home.jemma.m2m.ContentInstance; import org.energy_home.jemma.m2m.ContentInstanceItemStatus; import org.energy_home.jemma.m2m.ContentInstanceItems; import org.energy_home.jemma.m2m.ContentInstanceItemsStatus; import org.energy_home.jemma.m2m.ContentInstancesBatchRequest; import org.energy_home.jemma.m2m.ContentInstancesBatchResponse; import org.energy_home.jemma.m2m.SubscriptionItems; import org.energy_home.jemma.m2m.Subscription; import org.energy_home.jemma.m2m.M2MConstants; import org.energy_home.jemma.m2m.M2MXmlConverter; import org.energy_home.jemma.m2m.M2MXmlObject; import org.energy_home.jemma.m2m.Scl; import org.energy_home.jemma.m2m.SclItems; import org.energy_home.jemma.m2m.SclStatusEnumeration; import org.energy_home.jemma.utils.rest.RestClient; import org.energy_home.jemma.utils.thread.ExecutorService; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.entity.ByteArrayEntity; import org.apache.http.util.EntityUtils; import org.osgi.service.http.HttpService; import org.osgi.service.http.NamespaceException; //import org.apache.http.client.ClientProtocolException; public class HapProxy extends HttpServlet implements IApplicationService, ISubscriptionManager { private static final Log log = LogFactory.getLog(HapProxy.class); private static final long PERIODIC_TASK_TIMEOUT = 117000; private static final String servletUri = "/HAP"; private static final String sclsListUri = M2MConstants.URL_HAG_SCL_BASE + M2MConstants.URL_SCLS + M2MConstants.URL_SLASH + M2MContainerAddress.ALL_ID_FILTER; public static final String START_INSTANCE_ID_REQUEST_PARAM = "startInstanceId"; public static final String END_INSTANCE_ID_REQUEST_PARAM = "endInstanceId"; public static final String ALL_FILTER = "/" + AHContainerAddress.ALL_ID_FILTER; public static final String APPLIANCE_FILTER = "/APPLIANCE"; public static final String APPLIANCE_FILTER_VALUE = M2MConstants.URL_SLASH + AHM2MContainerAddress.DEFAULT_APPLIANCE_PREFIX; public static final String DEVICES_EP_FILTER = "/DEVICE"; public static final String DEVICES_EP_FILTER_VALUE = "/POS"; public static final String NODES_EP_FILTER = "/NODE"; public static final String NODES_EP_FILTER_VALUE = "/0"; public static final String CONFIG_ATTR_FILTER = "/CONFIG"; public static final String CONFIG_ATTR_FILTER_VALUE = "/ah.core.config."; public static final String STATUS_ATTR_FILTER = "/STATUS"; public static final String STATUS_ATTR_FILTER_VALUE = "/ah.cluster."; public static final String EH_STATUS_ATTR_FILTER = "/EHSTATUS"; public static final String EH_STATUS_ATTR_FILTER_VALUE = "/ah.eh.esp."; public static final String AAL_STATUS_ATTR_FILTER = "/AALSTATUS"; public static final String AAL_STATUS_ATTR_FILTER_VALUE = "/ah.aal."; public static final String SH_STATUS_ATTR_FILTER = "/SHSTATUS"; public static final String SH_STATUS_ATTR_FILTER_VALUE = "/ah.sh."; public static final String HTTP_RESPONSE_TYPE = "application/xml; charset=UTF-8"; public static final int HTTP_RESPONSE_BUFFER_SIZE = 16 * 1024; public static final String HTTP_ENTITY_CONTENT_TYPE = "application/xml"; public static boolean isAnUnconfirmedCommand(AHContainerAddress containerAddress) { String containerName = containerAddress.getContainerName(); return containerName.equals(AHContainers.attrId_ah_zigbee_network_status) || ServiceClusterProxy.isAnUnconfirmedCommand(containerAddress); } class NotificationTask implements Runnable { ContentInstanceItems cisItems; NotificationTask(ContentInstanceItems cisItems) { this.cisItems = cisItems; } void releaseRequestResources(HttpResponse response) { try { if (response != null) restClient.consume(response); } catch (Exception e) { log.error("releaseRequestResources: error while consuming rest client response", e); } } public HttpEntity getEntity(ContentInstanceItems cisItems) { ByteArrayEntity entity = null; try { byte[] b = xmlConverter.getByteArray(cisItems); entity = new ByteArrayEntity(b); entity.setContentType(HTTP_ENTITY_CONTENT_TYPE); } catch (Exception e) { log.error("Error while creating http entity from " + cisItems.toXmlString()); return null; } return entity; } public void run() { HttpEntity entity = getEntity(cisItems); if (entity != null) { synchronized (subscriptionInfos) { for (Iterator iterator = subscriptionInfos.iterator(); iterator.hasNext();) { SubscriptionInfo subscriptionInfo = (SubscriptionInfo) iterator.next(); HttpResponse response = null; try { response = restClient.post(subscriptionInfo.uri, entity); if (!RestClient.isOkOrCreatedStatus(response)) { log.warn("Removing subscriber: error " + response.getStatusLine().getStatusCode() + " while contacting " + subscriptionInfo.subscription.getContact()); iterator.remove(); } } catch (Exception e) { log.error("Error while sending request to subscriber " + subscriptionInfo.subscription.getContact(), e); iterator.remove(); } finally { releaseRequestResources(response); } } } } } } private static RestClient restClient; private IAppliancesProxy appliancesProxy; private ApplianceProxyList applianceProxyList = new ApplianceProxyList(); private M2MNetworkScl networkScl; private AHM2MHapService hapService; private ExecutorService executorService = null; private IServiceCluster[] serviceClusterProxies = new IServiceCluster[] {}; private OnOffClusterProxy onOffClusterProxy; private MeteringClusterProxy meteringClusterProxy; private ApplianceControlClusterProxy applianceControlClusterProxy; private INetworkManager zbNetworkManager; private SclItems sclItems = null; private Scl scl = null; List<SubscriptionInfo> subscriptionInfos; String subscriptionItemsAddressedId; private String indexPage = null; private M2MXmlConverter xmlConverter; private Map<String, IApplianceConfiguration> applianceConfigurationUpdatesMap = new HashMap(); private IApplianceConfiguration getApplianceConfiguration(String appliancePid, int endPoint) { IApplianceConfiguration applianceConfig = null; synchronized (applianceConfigurationUpdatesMap) { applianceConfig = applianceConfigurationUpdatesMap.get(appliancePid); if (applianceConfig == null) { IAppliance appliance = appliancesProxy.getAppliance(appliancePid); if (appliance == null) appliancesProxy.getInstallingAppliance(appliancePid); applianceConfig = appliancesProxy.getApplianceConfiguration(appliancePid); applianceConfigurationUpdatesMap.put(appliancePid, applianceConfig); } } return applianceConfig; } private boolean commitApplianceConfigurationUpdates() { boolean result = true; synchronized (applianceConfigurationUpdatesMap) { for (Iterator<IApplianceConfiguration> iterator = applianceConfigurationUpdatesMap.values() .iterator(); iterator.hasNext();) { IApplianceConfiguration config = iterator.next(); result = result & appliancesProxy.updateApplianceConfiguration(config); iterator.remove(); } } return result; } private static void initResponse(HttpServletResponse response) { response.setContentType(HTTP_RESPONSE_TYPE); response.setBufferSize(HTTP_RESPONSE_BUFFER_SIZE); } private String replaceFilters(String requestUri, boolean isProxy) { if (!isProxy) { requestUri = requestUri.replace(APPLIANCE_FILTER, APPLIANCE_FILTER_VALUE); requestUri = requestUri.replace(DEVICES_EP_FILTER, DEVICES_EP_FILTER_VALUE); } else { requestUri = requestUri.replace(APPLIANCE_FILTER, ALL_FILTER); requestUri = requestUri.replace(DEVICES_EP_FILTER, ALL_FILTER); } requestUri = requestUri.replace(CONFIG_ATTR_FILTER, CONFIG_ATTR_FILTER_VALUE); requestUri = requestUri.replace(NODES_EP_FILTER, NODES_EP_FILTER_VALUE); requestUri = requestUri.replace(STATUS_ATTR_FILTER, STATUS_ATTR_FILTER_VALUE); requestUri = requestUri.replace(EH_STATUS_ATTR_FILTER, EH_STATUS_ATTR_FILTER_VALUE); requestUri = requestUri.replace(AAL_STATUS_ATTR_FILTER, AAL_STATUS_ATTR_FILTER_VALUE); requestUri = requestUri.replace(SH_STATUS_ATTR_FILTER, SH_STATUS_ATTR_FILTER_VALUE); return requestUri; } private void copyResponseEntity(HttpResponse proxyResponse, HttpServletResponse servletResponse) throws IOException { HttpEntity entity = proxyResponse.getEntity(); if (entity != null) { OutputStream servletOutputStream = servletResponse.getOutputStream(); try { entity.writeTo(servletOutputStream); } finally { try { EntityUtils.consume(entity); } catch (IOException e) { e.printStackTrace(); } try { if (servletOutputStream != null) servletOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void writeXmlObject(HttpServletResponse servletResponse, M2MXmlObject object) throws IOException { OutputStream servletOutputStream = servletResponse.getOutputStream(); try { xmlConverter.writeObject(object, servletOutputStream); } finally { try { if (servletOutputStream != null) servletOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } private Object readXmlObject(HttpServletRequest servletRequest) throws IOException { InputStream servletInputStream = servletRequest.getInputStream(); try { return xmlConverter.readObject(servletInputStream); } finally { try { if (servletInputStream != null) servletInputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } private void writeStringObject(HttpServletResponse servletResponse, String object) throws IOException { PrintWriter pw = servletResponse.getWriter(); try { if (indexPage != null) pw.append(object); } finally { if (pw != null) pw.close(); } } private ContentInstance getZigBeeNetworkContentInstance() { if (zbNetworkManager == null) return null; try { boolean isOpen = zbNetworkManager.isNetworkOpen(); ContentInstance ci = new ContentInstance(); ci.setId(System.currentTimeMillis()); if (isOpen) ci.setContent(new Integer(1)); else ci.setContent(new Integer(0)); return ci; } catch (Exception e) { log.error("Error while opening zigbee network", e); return null; } } private ContentInstance openZigBeeNetwork() { if (zbNetworkManager == null) return null; try { zbNetworkManager.openNetwork(); } catch (Exception e) { log.error("Error while opening zigbee network", e); } return getZigBeeNetworkContentInstance(); } private ContentInstance closeZigBeeNetwork() { if (zbNetworkManager == null) return null; try { zbNetworkManager.closeNetwork(); } catch (Exception e) { log.error("Error while closing zigbee network", e); } return getZigBeeNetworkContentInstance(); } private void initServiceClusters(ApplianceProxy applianceProxy) { for (int i = 0; i < serviceClusterProxies.length; i++) { ServiceClusterProxy proxy = (ServiceClusterProxy) serviceClusterProxies[i]; proxy.initServiceCluster(applianceProxy); } } private void checkServiceClusters(ApplianceProxy applianceProxy) { for (int i = 0; i < serviceClusterProxies.length; i++) { ServiceClusterProxy proxy = (ServiceClusterProxy) serviceClusterProxies[i]; proxy.checkServiceCluster(applianceProxy); } } private void periodicTask() { try { long startTime = System.currentTimeMillis(); log.info(String.format("Periodic task execution -> START %s", startTime)); ApplianceProxy[] applianceProxyArray = applianceProxyList.getApplianceProxyArray(); for (int i = 0; i < applianceProxyArray.length; i++) { ApplianceProxy applianceProxy = applianceProxyArray[i]; if (applianceProxy.getAppliance().isAvailable()) checkServiceClusters(applianceProxy); } } catch (Exception e) { log.error("Error during periodic task execution", e); } } public HapProxy() { log.info("HapProxy constructor"); } public void addNetworkManager(INetworkManager s, Map properties) { String key = (String) properties.get("network.type"); if (key == null) log.error("addNetworkManager: eceived invalid network type property"); else if (key.equals("ZigBee")) { zbNetworkManager = s; } } public void removeNetworkManager(INetworkManager s, Map properties) { String key = (String) properties.get("network.type"); if (key == null) log.error("removeNetworkManager: eceived invalid network type property"); else if (key.equals("ZigBee")) { zbNetworkManager = s; } } public void setHttpService(HttpService httpService) { log.debug("setHttpService"); try { httpService.registerServlet(servletUri, this, null, null); } catch (ServletException e) { log.error("setHttpService", e); } catch (NamespaceException e) { log.error("setHttpService", e); } } public void unsetHttpService(HttpService httpService) { log.debug("unsetHttpService"); httpService.unregister(servletUri); } public void setExecutorService(ExecutorService executorService) { this.executorService = executorService; log.info("Executor Service registered"); } public void unsetExecutorService(ExecutorService executorService) { this.executorService = null; log.info("Executor Service unregistered"); } private void initResources(String sclId) { StringBuilder sb = new StringBuilder("<html><body><h1>M2M Resources</h1>"); if (sclId == null) { sb.append("<h2>Resources not available (gateway identifier not yet configured)</h2>"); } else { scl = new Scl(); scl.setId(sclId); scl.setCreationTime(System.currentTimeMillis()); scl.setLastModifiedTime(System.currentTimeMillis()); scl.setSclBaseId( M2MConstants.URL_HAG_SCL_BASE + M2MConstants.URL_SCLS + M2MConstants.URL_SLASH + scl.getId()); sclItems = new SclItems(); sclItems.setAddressedId(M2MConstants.URL_HAG_SCL_BASE + M2MConstants.URL_SCLS); List<Scl> sclList = sclItems.getScls(); sclList.add(scl); long now = System.currentTimeMillis(); subscriptionInfos = new ArrayList<SubscriptionInfo>(1); subscriptionItemsAddressedId = scl.getSclBaseId() + M2MConstants.URL_SUBSCRIPTIONS; sb.append("<h2>Gateway Resources (HAG)</h2>"); sb.append("<h3>Core resources</h3>"); sb.append("<a href=").append(M2MConstants.URL_HAG_SCL_BASE).append(M2MConstants.URL_SCLS); sb.append(M2MConstants.URL_SLASH).append(M2MContainerAddress.ALL_ID_FILTER) .append(">Gateway description</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(M2MConstants.URL_SLASH).append(AHContainers.attrId_ah_zigbee_network_status); sb.append(M2MConstants.URL_CONTENT_INSTANCES) .append(">ZigBee network status (0=closed, 1=open)</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(M2MConstants.URL_CONTENT_INSTANCES) .append(">Appliance type list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(NODES_EP_FILTER).append(CONFIG_ATTR_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">Appliance configuration list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(NODES_EP_FILTER).append(M2MConstants.URL_SLASH) .append(AHContainers.attrId_ah_core_appliance_events); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">Appliance events list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(DEVICES_EP_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">Device type list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(DEVICES_EP_FILTER).append(CONFIG_ATTR_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">Device configuration list</a><br>"); sb.append("<h3>Application resources</h3>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(DEVICES_EP_FILTER).append(STATUS_ATTR_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">AH device status list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(DEVICES_EP_FILTER).append(EH_STATUS_ATTR_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">Energy@home device status list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(DEVICES_EP_FILTER).append(AAL_STATUS_ATTR_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">AAL device status list</a><br>"); sb.append("<a href=").append(scl.getSclBaseId()).append(M2MConstants.URL_CONTAINERS); sb.append(APPLIANCE_FILTER).append(DEVICES_EP_FILTER).append(SH_STATUS_ATTR_FILTER); sb.append(M2MConstants.URL_CONTENT_INSTANCES).append(">SmartHome device status list</a><br>"); sb = sb.append("<h2>Cloud Resources (HAP)</h2>"); String hapScl = scl.getSclBaseId().replace("HAG", "SB"); long time = System.currentTimeMillis(); String queryString = "?startInstanceId=" + (time - 86400000) + "&endInstanceId=" + time; sb.append("<h3>Application resources</h3>"); // Currently works only with default end point id (1) used in Energy@home trial sb.append("<a href=").append(hapScl).append(M2MConstants.URL_CONTAINERS); sb.append(M2MConstants.URL_SLASH).append(M2MContainerAddress.ALL_ID_FILTER).append("/1/"); sb.append(EHContainers.attrId_ah_eh_esp_deliveredEnergySum).append(M2MConstants.URL_CONTENT_INSTANCES); sb.append(queryString).append(">Delivered energy sum data</a><br>"); sb.append("<a href=").append(hapScl).append(M2MConstants.URL_CONTAINERS); sb.append(M2MConstants.URL_SLASH).append(M2MContainerAddress.ALL_ID_FILTER).append("/1/"); sb.append(EHContainers.attrId_ah_eh_esp_receivedEnergySum).append(M2MConstants.URL_CONTENT_INSTANCES); sb.append(queryString).append(">Received energy sum data</a><br>"); // Currently works only with default end point id (1) used in Energy@home trial sb.append("<a href=").append(hapScl).append(M2MConstants.URL_CONTAINERS); sb.append(M2MConstants.URL_SLASH).append(M2MContainerAddress.ALL_ID_FILTER).append("/1/"); sb.append(EHContainers.attrId_ah_eh_esp_hourlyEnergy).append(M2MConstants.URL_CONTENT_INSTANCES); sb.append(queryString).append(">Hourly energy consumption data</a><br>"); sb.append("<a href=").append(hapScl).append(M2MConstants.URL_CONTAINERS); sb.append(M2MConstants.URL_SLASH).append(M2MContainerAddress.ALL_ID_FILTER).append("/1/"); sb.append(EHContainers.attrId_ah_eh_esp_hourlyDeliveredEnergy) .append(M2MConstants.URL_CONTENT_INSTANCES); sb.append(queryString).append(">Delivered hourly energy data</a><br>"); sb.append("<a href=").append(hapScl).append(M2MConstants.URL_CONTAINERS); sb.append(M2MConstants.URL_SLASH).append(M2MContainerAddress.ALL_ID_FILTER).append("/1/"); sb.append(EHContainers.attrId_ah_eh_esp_hourlyReceivedEnergy) .append(M2MConstants.URL_CONTENT_INSTANCES); sb.append(queryString).append(">Received hourly energy data</a><br>"); } sb.append("</body></html>"); indexPage = sb.toString(); } public void setM2MHapService(IM2MHapService hapService) { log.debug("setM2MHapService"); this.hapService = new AHM2MHapService(hapService); try { onOffClusterProxy = new OnOffClusterProxy(applianceProxyList, this.hapService, this); meteringClusterProxy = new MeteringClusterProxy(applianceProxyList, this.hapService, this); applianceControlClusterProxy = new ApplianceControlClusterProxy(applianceProxyList, this.hapService, this); serviceClusterProxies = new IServiceCluster[] { onOffClusterProxy, meteringClusterProxy, applianceControlClusterProxy }; } catch (Exception e) { log.error("Error while creating appliance cluster proxies", e); } initResources(hapService.getLocalHagId()); } public void unsetM2MHapService(IM2MHapService hapService) { log.debug("unsetM2MHapService"); onOffClusterProxy = null; meteringClusterProxy = null; applianceControlClusterProxy = null; serviceClusterProxies = new IServiceCluster[] {}; this.hapService = null; sclItems = null; scl = null; } public void setAppliancesProxy(IAppliancesProxy appProxy) { log.debug("setAppliancesProxy"); this.appliancesProxy = appProxy; } public void unsetAppliancesProxy(IAppliancesProxy appProxy) { log.debug("unsetAppliancesProxy"); this.appliancesProxy = null; } public void setM2MNetworkScl(M2MNetworkScl networkScl) { log.debug("setM2MNetworkScl"); this.networkScl = networkScl; } public void unsetM2MNetworkScl(M2MNetworkScl httpService) { log.debug("unsetM2MNetworkScl"); this.networkScl = null; } public void start() { log.debug("start"); xmlConverter = M2MXmlConverter.getCoreConverter(); restClient = RestClient.get(); executorService.scheduleTask(new Runnable() { public void run() { try { periodicTask(); } catch (Exception e) { log.error("ESP periodic task error", e); } } }, PERIODIC_TASK_TIMEOUT, PERIODIC_TASK_TIMEOUT); } public void stop() { log.debug("stop"); restClient.release(); applianceProxyList.clear(); xmlConverter = null; } private ContentInstance postContentInstance(AHContainerAddress containerAddress, ContentInstance ci) throws ApplianceException, ServiceClusterException { String containerName = containerAddress.getContainerName(); if (containerName == null) return null; String appliancePid = containerAddress.getAppliancePid(); String endPointIdStr = containerAddress.getEndPointId(); if (containerName.equals(AHContainers.attrId_ah_zigbee_network_status)) { Integer open = (Integer) ci.getContent(); if (open.intValue() > 0) { ci = openZigBeeNetwork(); } else { ci = closeZigBeeNetwork(); } } else if (appliancePid != null && endPointIdStr != null) { Integer endPointId; try { endPointId = new Integer(endPointIdStr); } catch (Exception e) { log.error("Error while parsing endPointId"); return null; } if (containerName.equals(AHContainers.attrId_ah_cluster_ah_ConfigServer_Name) || containerName.equals(AHContainers.attrId_ah_core_config_name)) { String name = (String) ci.getContent(); try { IApplianceConfiguration config = getApplianceConfiguration(appliancePid, endPointId.intValue()); if (!config.updateName(endPointId, name)) ci = null; } catch (Exception e) { log.error("Error while trying to modify appliance name", e); ci = null; } } else if (containerName.equals(AHContainers.attrId_ah_cluster_ah_ConfigServer_CategoryPid) || containerName.equals(AHContainers.attrId_ah_core_config_category)) { Integer categoryPid = (Integer) ci.getContent(); try { IApplianceConfiguration config = getApplianceConfiguration(appliancePid, endPointId.intValue()); if (!config.updateCategoryPid(endPointId, categoryPid.toString())) ci = null; } catch (Exception e) { log.error("Error while trying to modify appliance category", e); ci = null; } } else if (containerName.equals(AHContainers.attrId_ah_cluster_ah_ConfigServer_LocationPid) || containerName.equals(AHContainers.attrId_ah_core_config_location)) { Integer locationPid = (Integer) ci.getContent(); try { IApplianceConfiguration config = getApplianceConfiguration(appliancePid, endPointId.intValue()); if (!config.updateLocationPid(endPointId, locationPid.toString())) ci = null; } catch (Exception e) { log.error("Error while trying to modify appliance location", e); ci = null; } } else { if (containerName.startsWith(AHContainers.attrId_ah_cluster_onoff_prexif)) onOffClusterProxy.execCommand(appliancePid, endPointId, containerName, ci); else if (containerName.startsWith(AHContainers.attrId_ah_cluster_applctrl_prexif)) applianceControlClusterProxy.execCommand(appliancePid, endPointId, containerName, ci); } } if (ci != null) ci.setId(new Long(System.currentTimeMillis())); return ci; } private ContentInstancesBatchResponse postBatchRequest(ContentInstancesBatchRequest batchRequest) { ContentInstancesBatchResponse batchResponse = new ContentInstancesBatchResponse(); List<ContentInstanceItemsStatus> responseStatusList = batchResponse.getContentInstanceItemsStatuses(); List<ContentInstanceItems> itemsList = batchRequest.getContentInstanceItems(); for (Iterator iterator = itemsList.iterator(); iterator.hasNext();) { ContentInstanceItems contentInstanceItems = (ContentInstanceItems) iterator.next(); ContentInstanceItemsStatus itemsStatus = new ContentInstanceItemsStatus(); itemsStatus.setAddressedId(contentInstanceItems.getAddressedId()); responseStatusList.add(itemsStatus); for (Iterator iterator2 = contentInstanceItems.getContentInstances().iterator(); iterator2.hasNext();) { ContentInstance ci = (ContentInstance) iterator2.next(); ContentInstanceItemStatus itemStatus = new ContentInstanceItemStatus(); itemStatus.setResourceId(new Long(System.currentTimeMillis())); itemsStatus.getContentInstanceItemStatuses().add(itemStatus); try { AHContainerAddress itemContainerAddress = new AHM2MContainerAddress( contentInstanceItems.getAddressedId()); if (!isValidLocalHagId(itemContainerAddress.getHagId())) { itemStatus.setBatchStatus(HttpServletResponse.SC_NOT_FOUND); } else { ci = postContentInstance(itemContainerAddress, ci); if (ci == null) itemStatus.setBatchStatus(HttpServletResponse.SC_NOT_FOUND); else if (ServiceClusterProxy.isAnUnconfirmedCommand(itemContainerAddress)) itemStatus.setBatchStatus(HttpServletResponse.SC_ACCEPTED); else itemStatus.setBatchStatus(HttpServletResponse.SC_OK); } } catch (Exception e) { log.error("", e); itemStatus.setBatchStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } } } return batchResponse; } private ContentInstanceItems getSingleContentInstanceItems(String uri, ContentInstance ci, long startInstanceId, long endInstanceId) { ContentInstanceItems ciItems = new ContentInstanceItems(); ciItems.setAddressedId(uri); boolean addContentInstance = true; if (startInstanceId != M2MNetworkScl.CONTENT_INSTANCE_OLDEST_ID && ci.getId() < startInstanceId) addContentInstance = false; else if (endInstanceId != M2MNetworkScl.CONTENT_INSTANCE_LATEST_ID && ci.getId() > endInstanceId) addContentInstance = false; if (addContentInstance) ciItems.getContentInstances().add(ci); return ciItems; } private boolean isValidLocalHagId(String hagId) { return (hagId != null && hagId.equals(hapService.getM2MHapService().getLocalHagId())); } protected void doGet(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { String requestUri = servletRequest.getRequestURI(); String method = servletRequest.getParameter("method"); if (requestUri.endsWith(servletUri)) { writeStringObject(servletResponse, indexPage); return; } initResponse(servletResponse); if (requestUri.endsWith(M2MConstants.URL_SLASH)) requestUri = requestUri.substring(0, requestUri.length() - 1); if (requestUri.startsWith(M2MConstants.URL_SCL_BASE)) { if (networkScl == null) { servletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } requestUri = replaceFilters(requestUri, true); HttpResponse proxyResponse = null; OutputStream out = null; try { String queryString = servletRequest.getQueryString(); proxyResponse = networkScl.httpGet(requestUri + "?" + queryString); int statusCode = proxyResponse.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_OK) { copyResponseEntity(proxyResponse, servletResponse); } else { // TODO check status code mapping servletResponse.sendError(statusCode); } } catch (Exception e) { log.error("service: error while sending request to hap service", e); servletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } } else if (requestUri.startsWith(M2MConstants.URL_HAG_SCL_BASE)) { requestUri = replaceFilters(requestUri, false); try { M2MXmlObject xmlObject = null; if (requestUri.startsWith(subscriptionItemsAddressedId)) { if (requestUri.endsWith(M2MContainerAddress.ALL_ID_FILTER)) { SubscriptionItems subscriptionItems = new SubscriptionItems(); for (Iterator iterator = subscriptionInfos.iterator(); iterator.hasNext();) { SubscriptionInfo subscriptionInfo = (SubscriptionInfo) iterator.next(); subscriptionItems.getSubscriptions().add(subscriptionInfo.subscription); } writeXmlObject(servletResponse, subscriptionItems); } else { String subscriptionId = requestUri.substring(subscriptionItemsAddressedId.length() + 1, requestUri.length()); SubscriptionInfo subscriptionInfo = null; for (Iterator iterator = subscriptionInfos.iterator(); iterator.hasNext();) { subscriptionInfo = (SubscriptionInfo) iterator.next(); if (subscriptionInfo.subscription.getId().equals(subscriptionId)) { break; } else subscriptionInfo = null; } if (subscriptionInfo != null) writeXmlObject(servletResponse, subscriptionInfo.subscription); else servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } } else if (requestUri.endsWith(sclsListUri)) { scl.setOnLineStatus(hapService.getM2MHapService().isConnected() ? SclStatusEnumeration.ONLINE : SclStatusEnumeration.DISCONNECTED); if (sclItems != null) writeXmlObject(servletResponse, sclItems); else servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } else if (scl != null && requestUri.endsWith(scl.getSclBaseId())) { writeXmlObject(servletResponse, scl); } else if (scl != null && requestUri.startsWith(scl.getSclBaseId() + M2MConstants.URL_SLASH)) { long startInstanceId = M2MNetworkScl.CONTENT_INSTANCE_OLDEST_ID; String startInstanceIdStr = servletRequest.getParameter(START_INSTANCE_ID_REQUEST_PARAM); if (startInstanceIdStr != null && startInstanceIdStr.length() > 0) { try { startInstanceId = Long.parseLong(startInstanceIdStr); } catch (Exception e) { log.error("Error while parsing stratInstanceId parameter"); } } long endInstanceId = M2MNetworkScl.CONTENT_INSTANCE_LATEST_ID; String endInstanceIdStr = servletRequest.getParameter(END_INSTANCE_ID_REQUEST_PARAM); if (endInstanceIdStr != null && endInstanceIdStr.length() > 0) { try { endInstanceId = Long.parseLong(endInstanceIdStr); } catch (Exception e) { log.error("Error while parsing stratInstanceId parameter"); } } String contentInstanceId = null; if (requestUri.endsWith(M2MConstants.URL_CIS_ID_LATEST_ALIAS)) { contentInstanceId = M2MConstants.URL_CIS_ID_LATEST_ALIAS; requestUri = requestUri.replace(M2MConstants.URL_CIS_ID_LATEST_ALIAS, ""); } if (requestUri.endsWith(M2MConstants.URL_CIS_ID_OLDEST_ALIAS)) { contentInstanceId = M2MConstants.URL_CIS_ID_OLDEST_ALIAS; requestUri = requestUri.replace(M2MConstants.URL_CIS_ID_OLDEST_ALIAS, ""); } // TODO:!!! manage uri with a specific timestamp used for content instance id AHContainerAddress containerAddress = new AHM2MContainerAddress(requestUri); if (!isValidLocalHagId(containerAddress.getHagId())) servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); boolean isFilter = containerAddress.isFilterAddress(); String containerName = containerAddress.getContainerName(); if (containerName != null && containerName.equals(AHContainers.attrId_ah_zigbee_network_status)) { xmlObject = getZigBeeNetworkContentInstance(); // If latest or oldest is specified a ContentInstance is returned, otherwise a ContentInstanceItems // with a single item is built if (xmlObject != null && contentInstanceId == null) { xmlObject = getSingleContentInstanceItems(requestUri, (ContentInstance) xmlObject, startInstanceId, endInstanceId); } } else if (!isFilter) { String[] clusterAndAttributeNames = ServiceClusterProxy .getClusterAndAttributeNamesForNotCachedAttributes(containerAddress); if (clusterAndAttributeNames == null) { xmlObject = hapService.getM2MHapService().getLocalContentInstance(containerAddress); } else { // A request is sent to the device ApplianceProxy applianceProxy = applianceProxyList .getApplianceProxy(containerAddress.getAppliancePid()); IServiceCluster serviceCluster = applianceProxy.getServiceCluster( new Integer(containerAddress.getEndPointId()).intValue(), clusterAndAttributeNames[0]); IAttributeValue av = serviceCluster.getAttributeValue(clusterAndAttributeNames[1], applianceProxy.getApplicationRequestContext()); ContentInstance ci = new ContentInstance(); ci.setId(av.getTimestamp()); ci.setContent(av.getValue()); xmlObject = ci; } if (xmlObject != null && contentInstanceId == null) { // If latest or oldest is specified a ContentInstance is returned, otherwise a ContentInstanceItems // with a single item is built xmlObject = getSingleContentInstanceItems(requestUri, (ContentInstance) xmlObject, startInstanceId, endInstanceId); } } else { xmlObject = hapService.getM2MHapService().getLocalContentInstanceItemsList(containerAddress, startInstanceId, endInstanceId); } if (xmlObject == null) { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } else { writeXmlObject(servletResponse, xmlObject); } } else { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } } catch (Exception e) { log.error("service: error while parsing local request", e); servletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } } else { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } } protected void doPost(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { String requestUri = servletRequest.getRequestURI(); initResponse(servletResponse); requestUri = replaceFilters(requestUri, false); if (requestUri.startsWith(M2MConstants.URL_HAG_SCL_BASE)) { try { if (requestUri.equals(subscriptionItemsAddressedId)) { long now = System.currentTimeMillis(); Subscription subscription = (Subscription) readXmlObject(servletRequest); if (subscription.getId() != null || subscription.getContact() == null) { servletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); } else { for (Iterator iterator = subscriptionInfos.iterator(); iterator.hasNext();) { // Only one subscription for each contact uri is allowed (last subscription overwrite a previous existing one) if (subscription.getContact() .equals(((SubscriptionInfo) iterator.next()).subscription.getContact())) { iterator.remove(); break; } } subscription.setCreationTime(now); subscription.setLastModifiedTime(now); subscription.setId(UUID.randomUUID().toString()); writeXmlObject(servletResponse, subscription); subscriptionInfos.add(new SubscriptionInfo(subscription)); } } else if (requestUri.endsWith(M2MConstants.URL_CIS_BATCH_REQUEST)) { ContentInstancesBatchRequest batchRequest = (ContentInstancesBatchRequest) readXmlObject( servletRequest); ContentInstancesBatchResponse batchResponse = postBatchRequest(batchRequest); writeXmlObject(servletResponse, batchResponse); } else { AHContainerAddress containerAddress = new AHM2MContainerAddress(requestUri); if (!isValidLocalHagId(containerAddress.getHagId())) servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); String containerName = containerAddress.getContainerName(); if (containerName != null) { ContentInstance ci = (ContentInstance) readXmlObject(servletRequest); ci = postContentInstance(containerAddress, ci); if (ci == null) servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); else if (ServiceClusterProxy.isAnUnconfirmedCommand(containerAddress)) servletResponse.setStatus(HttpServletResponse.SC_ACCEPTED); else servletResponse.setStatus(HttpServletResponse.SC_OK); writeXmlObject(servletResponse, ci); } else { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } } commitApplianceConfigurationUpdates(); } catch (Exception e) { log.error("service: error while parsing local request", e); servletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } } else { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } } protected void doDelete(HttpServletRequest servletRequest, HttpServletResponse servletResponse) throws ServletException, IOException { String requestUri = servletRequest.getRequestURI(); initResponse(servletResponse); requestUri = replaceFilters(requestUri, false); if (requestUri.startsWith(M2MConstants.URL_HAG_SCL_BASE)) { try { if (requestUri.startsWith(subscriptionItemsAddressedId)) { if (requestUri.endsWith(M2MContainerAddress.ALL_ID_FILTER)) servletResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); else { String subscriptionId = requestUri.substring(subscriptionItemsAddressedId.length() + 1, requestUri.length()); SubscriptionInfo subscriptionInfo = null; synchronized (subscriptionInfos) { for (Iterator iterator = subscriptionInfos.iterator(); iterator.hasNext();) { subscriptionInfo = (SubscriptionInfo) iterator.next(); if (subscriptionInfo.subscription.getId().equals(subscriptionId)) { iterator.remove(); break; } } } } } else { AHContainerAddress containerAddress = new AHM2MContainerAddress(requestUri); if (!isValidLocalHagId(containerAddress.getHagId())) servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); String appliancePid = containerAddress.getAppliancePid(); if (containerAddress.getAppliancePid() != null && containerAddress.getEndPointId() == null && containerAddress.getContainerName() == null) { ContentInstance ci = hapService.getM2MHapService() .getLocalContentInstance(containerAddress); boolean result = false; // Only existing resources are deleted if (ci != null) { result = appliancesProxy.deleteAppliance(appliancePid); if (!result) { servletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return; } } else { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); return; } } else { servletResponse.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED); } ContentInstance ci = new ContentInstance(); ci.setId(System.currentTimeMillis()); writeXmlObject(servletResponse, ci); } } catch (Exception e) { log.error("service: error while parsing local request", e); servletResponse.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE); } } else { servletResponse.sendError(HttpServletResponse.SC_NOT_FOUND); } } // ****************** private void applianceAndEndPointTypesUpdated(IAppliance appliance, long timestamp) { try { String appliancePid = appliance.getPid(); String applianceType = appliance.getDescriptor().getType(); try { hapService.storeAttributeValue(appliancePid, null, null, null, timestamp, applianceType, true); } catch (HacException e) { log.error("applianceAndEndPointTypesUpdated: exception while storing appliance type", e); } IEndPoint[] endPoints = appliance.getEndPoints(); IEndPoint endPoint = null; for (int i = 0; i < endPoints.length; i++) { try { endPoint = endPoints[i]; hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), null, null, timestamp, endPoint.getType(), true); } catch (HacException e) { log.error("applianceAndEndPointTypesUpdated: exception while storing appliance type", e); } } } catch (Exception e) { log.error("applianceAndEndPointTypesUpdated", e); } } private void applianceStatusUpdated(ApplianceProxy applianceProxy, int appStatus, long timestamp) { try { IAppliance appliance = applianceProxy.getAppliance(); String appliancePid = appliance.getPid(); hapService.storeAttributeValue(appliancePid, IEndPoint.COMMON_END_POINT_ID, null, AHContainers.attrId_ah_core_appliance_events, timestamp, new Integer(appStatus), false); } catch (Exception e) { log.error("applianceStatusUpdated", e); } } private void endPointConfigurationUpdated(ApplianceProxy applianceProxy, IEndPoint endPoint, long timestamp) { try { IAppliance appliance = applianceProxy.getAppliance(); String appliancePid = appliance.getPid(); String clusterName = ConfigServer.class.getName(); ConfigServer configServer = (ConfigServer) endPoint.getServiceCluster(clusterName); String categoryPid = configServer.getCategoryPid(applianceProxy.getApplicationRequestContext()); String locationPid = configServer.getLocationPid(applianceProxy.getApplicationRequestContext()); // hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), clusterName, ConfigServer.ATTR_NAME_NAME, timestamp, configServer.getName(confirmationRequestContext), true); hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), null, AHContainers.attrId_ah_core_config_name, timestamp, configServer.getName(applianceProxy.getApplicationRequestContext()), true); // hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), clusterName, ConfigServer.ATTR_NAME_LOCATION_PID, timestamp, locationPid != null ? new Integer(locationPid) : null, true); hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), null, AHContainers.attrId_ah_core_config_location, timestamp, locationPid != null ? new Integer(locationPid) : null, true); // hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), clusterName, ConfigServer.ATTR_NAME_CATEGORY_PID, timestamp, categoryPid != null ? new Integer(categoryPid) : null, true); hapService.storeAttributeValue(appliancePid, new Integer(endPoint.getId()), null, AHContainers.attrId_ah_core_config_category, timestamp, categoryPid != null ? new Integer(categoryPid) : null, true); } catch (Exception e) { log.error("endPointConfigurationUpdated", e); } } private void configurationUpdated(ApplianceProxy applianceProxy, long timestamp) { try { IAppliance appliance = applianceProxy.getAppliance(); IEndPoint[] endPoints = appliance.getEndPoints(); for (int i = 0; i < endPoints.length; i++) { endPointConfigurationUpdated(applianceProxy, endPoints[i], timestamp); } } catch (Exception e) { log.error("configurationUpdated", e); } } // IApplicationService Interface public IServiceCluster[] getServiceClusters() { return serviceClusterProxies; } public void notifyApplianceAdded(IApplicationEndPoint endPoint, IAppliance appliance) { try { String appliancePid = appliance.getPid(); if (appliance.isSingleton()) { log.info("applianceConnected - singleton appliance " + appliancePid); return; } ApplianceProxy applianceProxy = new ApplianceProxy(endPoint, appliance); applianceProxyList.addApplianceProxy(applianceProxy); boolean isAvailable = appliance.isAvailable(); long timestamp = System.currentTimeMillis(); applianceAndEndPointTypesUpdated(appliance, timestamp); applianceStatusUpdated(applianceProxy, AHContainers.APPLIANCE_EVENT_STARTED, timestamp); timestamp++; if (isAvailable) { applianceStatusUpdated(applianceProxy, AHContainers.APPLIANCE_EVENT_AVAILABLE, timestamp); initServiceClusters(applianceProxy); } else { applianceStatusUpdated(applianceProxy, AHContainers.APPLIANCE_EVENT_UNAVAILABLE, timestamp); } configurationUpdated(applianceProxy, timestamp); } catch (Exception e) { log.error("notifyApplianceAdded error", e); } } public void notifyApplianceRemoved(IAppliance appliance) { try { String appliancePid = appliance.getPid(); ApplianceProxy applianceProxy = applianceProxyList.getApplianceProxy(appliancePid); if (applianceProxy == null) return; applianceStatusUpdated(applianceProxy, AHContainers.APPLIANCE_EVENT_STOPPED, System.currentTimeMillis()); applianceProxyList.removeApplianceProxy(appliance.getPid()); } catch (Exception e) { log.error("notifyApplianceRemoved error", e); } } public void notifyApplianceAvailabilityUpdated(IAppliance appliance) { try { String appliancePid = appliance.getPid(); ApplianceProxy applianceProxy = applianceProxyList.getApplianceProxy(appliancePid); if (applianceProxy == null) return; boolean isAvailable = appliance.isAvailable(); long timestamp = System.currentTimeMillis(); if (isAvailable) { applianceStatusUpdated(applianceProxy, AHContainers.APPLIANCE_EVENT_AVAILABLE, timestamp); initServiceClusters(applianceProxy); } else { applianceStatusUpdated(applianceProxy, AHContainers.APPLIANCE_EVENT_UNAVAILABLE, timestamp); } } catch (Exception e) { log.error("notifyApplianceAvailabilityUpdated error", e); } } public void notifyInstallingApplianceAdded(IAppliance appliance) { // Currently not used } public void notifyInstallingApplianceRemoved(IAppliance appliance) { // Currently not used } public void notifyInstallingApplianceAvailabilityUpdated(IAppliance appliance) { // Currently not used } // Subscription manager interface public boolean checkActiveSubscriptions() { return subscriptionInfos.size() > 0; } public void notifyContentInstanceItems(ContentInstanceItems cisItems) { executorService.addNearRealTimeOrderedTask(new HapProxy.NotificationTask(cisItems)); } }