Package org.openhab.io.rest.internal.resources

Source Code of org.openhab.io.rest.internal.resources.SitemapResource

/**
* Copyright (c) 2010-2014, openHAB.org and others.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*/
package org.openhab.io.rest.internal.resources;

import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URLEncoder;
import java.util.Collection;
import java.util.LinkedList;
import java.util.concurrent.TimeUnit;

import javax.ws.rs.DefaultValue;
import javax.ws.rs.GET;
import javax.ws.rs.HeaderParam;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;

import org.apache.commons.lang.StringUtils;
import org.atmosphere.annotation.Suspend.SCOPE;
import org.atmosphere.cpr.AtmosphereRequest;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.Broadcaster;
import org.atmosphere.cpr.BroadcasterFactory;
import org.atmosphere.cpr.HeaderConfig;
import org.atmosphere.jersey.SuspendResponse;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.ecore.EObject;
import org.openhab.core.items.Item;
import org.openhab.io.rest.RESTApplication;
import org.openhab.io.rest.internal.broadcaster.GeneralBroadcaster;
import org.openhab.io.rest.internal.listeners.SitemapStateChangeListener;
import org.openhab.io.rest.internal.resources.beans.MappingBean;
import org.openhab.io.rest.internal.resources.beans.PageBean;
import org.openhab.io.rest.internal.resources.beans.SitemapBean;
import org.openhab.io.rest.internal.resources.beans.SitemapListBean;
import org.openhab.io.rest.internal.resources.beans.WidgetBean;
import org.openhab.model.core.ModelRepository;
import org.openhab.model.sitemap.Chart;
import org.openhab.model.sitemap.Frame;
import org.openhab.model.sitemap.Image;
import org.openhab.model.sitemap.LinkableWidget;
import org.openhab.model.sitemap.List;
import org.openhab.model.sitemap.Mapping;
import org.openhab.model.sitemap.Selection;
import org.openhab.model.sitemap.Setpoint;
import org.openhab.model.sitemap.Sitemap;
import org.openhab.model.sitemap.Slider;
import org.openhab.model.sitemap.Switch;
import org.openhab.model.sitemap.Video;
import org.openhab.model.sitemap.Webview;
import org.openhab.model.sitemap.Widget;
import org.openhab.ui.items.ItemUIRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.sun.jersey.api.json.JSONWithPadding;

/**
* <p>This class acts as a REST resource for sitemaps and provides different methods to interact with them,
* like retrieving a list of all available sitemaps or just getting the widgets of a single page.</p>
*
* <p>The typical content types are XML or JSON.</p>
*
* <p>This resource is registered with the Jersey servlet.</p>
*
* @author Kai Kreuzer
* @author Chris Jackson
* @since 0.8.0
*/
@Path(SitemapResource.PATH_SITEMAPS)
public class SitemapResource {

  private static final Logger logger = LoggerFactory.getLogger(SitemapResource.class);

    protected static final String SITEMAP_FILEEXT = ".sitemap";

  public static final String PATH_SITEMAPS = "sitemaps";
 
  public static final String ATMOS_TIMEOUT_HEADER = "X-Atmosphere-Timeout";
 
  public static final int DEFAULT_TIMEOUT_SECS = 300;
 
  @Context UriInfo uriInfo;
  @Context Broadcaster sitemapBroadcaster;

  @GET
    @Produces( { MediaType.WILDCARD })
    public Response getSitemaps(
        @Context HttpHeaders headers,
        @QueryParam("type") String type,
        @QueryParam("jsoncallback") @DefaultValue("callback") String callback) {
    logger.debug("Received HTTP GET request at '{}' for media type '{}'.", new String[] { uriInfo.getPath(), type });
    String responseType = MediaTypeHelper.getResponseMediaType(headers.getAcceptableMediaTypes(), type);
    if(responseType!=null) {
        Object responseObject = responseType.equals(MediaTypeHelper.APPLICATION_X_JAVASCRIPT) ?
            new JSONWithPadding(new SitemapListBean(getSitemapBeans(uriInfo.getAbsolutePathBuilder().build())), callback) : new SitemapListBean(getSitemapBeans(uriInfo.getAbsolutePathBuilder().build()));
        return Response.ok(responseObject, responseType).build();
    } else {
      return Response.notAcceptable(null).build();
    }
    }

  @GET @Path("/{sitemapname: [a-zA-Z_0-9]*}")
    @Produces( { MediaType.WILDCARD })
    public Response getSitemapData(
        @Context HttpHeaders headers,
        @PathParam("sitemapname") String sitemapname,
        @QueryParam("type") String type,
        @QueryParam("jsoncallback") @DefaultValue("callback") String callback) {
    logger.debug("Received HTTP GET request at '{}' for media type '{}'.", new String[] { uriInfo.getPath(), type });
    String responseType = MediaTypeHelper.getResponseMediaType(headers.getAcceptableMediaTypes(), type);
    if(responseType!=null) {
        Object responseObject = responseType.equals(MediaTypeHelper.APPLICATION_X_JAVASCRIPT) ?
            new JSONWithPadding(getSitemapBean(sitemapname, uriInfo.getBaseUriBuilder().build()), callback) : getSitemapBean(sitemapname, uriInfo.getBaseUriBuilder().build());
        return Response.ok(responseObject, responseType).build();
    } else {
      return Response.notAcceptable(null).build();
    }
    }

    @GET @Path("/{sitemapname: [a-zA-Z_0-9]*}/{pageid: [a-zA-Z_0-9]*}")
  @Produces( { MediaType.WILDCARD })
    public SuspendResponse<Response> getPageData(
        @Context HttpHeaders headers,
        @PathParam("sitemapname") String sitemapname,
        @PathParam("pageid") String pageId,
        @QueryParam("type") String type,
        @QueryParam("jsoncallback") @DefaultValue("callback") String callback,
        @HeaderParam(HeaderConfig.X_ATMOSPHERE_TRANSPORT) String atmosphereTransport,
        @Context AtmosphereResource resource) {
    logger.debug("Received HTTP GET request at '{}' for media type '{}'.", new String[] { uriInfo.getPath(), type });
    if(atmosphereTransport==null || atmosphereTransport.isEmpty()) {
      String responseType = MediaTypeHelper.getResponseMediaType(headers.getAcceptableMediaTypes(), type);
      if(responseType!=null) {
          Object responseObject = responseType.equals(MediaTypeHelper.APPLICATION_X_JAVASCRIPT) ?
              new JSONWithPadding(getPageBean(sitemapname, pageId, uriInfo.getBaseUriBuilder().build()), callback) : getPageBean(sitemapname, pageId, uriInfo.getBaseUriBuilder().build());
          throw new WebApplicationException(Response.ok(responseObject, responseType).header(ATMOS_TIMEOUT_HEADER, DEFAULT_TIMEOUT_SECS + "").build());
      } else {
        throw new WebApplicationException(Response.notAcceptable(null).build());
      }
    }
   
    GeneralBroadcaster sitemapBroadcaster = BroadcasterFactory.getDefault().lookup(GeneralBroadcaster.class, resource.getRequest().getPathInfo(), true);
    sitemapBroadcaster.addStateChangeListener(new SitemapStateChangeListener());
   
    boolean resume = false;
    try {
    AtmosphereRequest request = resource.getRequest();
    resume = !ResponseTypeHelper.isStreamingTransport(request);
    } catch (Exception e) {
      logger.debug(e.getMessage());
    }

    return new SuspendResponse.SuspendResponseBuilder<Response>()
      .scope(SCOPE.REQUEST)
      .resumeOnBroadcast(resume)
      .broadcaster(sitemapBroadcaster)
      .period(DEFAULT_TIMEOUT_SECS, TimeUnit.SECONDS)
      .outputComments(true).build();
    }
 
    static public PageBean getPageBean(String sitemapName, String pageId, URI uri) {
    ItemUIRegistry itemUIRegistry = RESTApplication.getItemUIRegistry();
    Sitemap sitemap = getSitemap(sitemapName);
    if(sitemap!=null) {
      if(pageId.equals(sitemap.getName())) {
        return createPageBean(sitemapName, sitemap.getLabel(), sitemap.getIcon(), sitemap.getName(), sitemap.getChildren(), false, isLeaf(sitemap.getChildren()), uri);
      } else {
        Widget pageWidget = itemUIRegistry.getWidget(sitemap, pageId);
        if(pageWidget instanceof LinkableWidget) {
          EList<Widget> children = itemUIRegistry.getChildren((LinkableWidget) pageWidget);
          PageBean pageBean = createPageBean(sitemapName, itemUIRegistry.getLabel(pageWidget), itemUIRegistry.getIcon(pageWidget),
              pageId, children, false, isLeaf(children), uri);
          EObject parentPage = pageWidget.eContainer();
          while(parentPage instanceof Frame) {
            parentPage = parentPage.eContainer();
          }
          if(parentPage instanceof Widget) {
            String parentId = itemUIRegistry.getWidgetId((Widget) parentPage);
            pageBean.parent = getPageBean(sitemapName, parentId, uri);
            pageBean.parent.widgets = null;
            pageBean.parent.parent = null;
          } else if(parentPage instanceof Sitemap) {
            pageBean.parent = getPageBean(sitemapName, sitemap.getName(), uri);
            pageBean.parent.widgets = null;
          }
          return pageBean;
        } else {
          if(logger.isDebugEnabled()) {
            if(pageWidget==null) {
                logger.debug("Received HTTP GET request at '{}' for the unknown page id '{}'.", uri, pageId);
            } else {
                logger.debug("Received HTTP GET request at '{}' for the page id '{}'. " +
                    "This id refers to a non-linkable widget and is therefore no valid page id.", uri, pageId);
            }
          }
            throw new WebApplicationException(404);
        }
      }
    } else {
      logger.info("Received HTTP GET request at '{}' for the unknown sitemap '{}'.", uri, sitemapName);
      throw new WebApplicationException(404);
    }
  }

  public Collection<SitemapBean> getSitemapBeans(URI uri) {
    Collection<SitemapBean> beans = new LinkedList<SitemapBean>();
    logger.debug("Received HTTP GET request at '{}'.", UriBuilder.fromUri(uri).build().toASCIIString());
    ModelRepository modelRepository = RESTApplication.getModelRepository();
    for(String modelName : modelRepository.getAllModelNamesOfType("sitemap")) {
      Sitemap sitemap = (Sitemap) modelRepository.getModel(modelName);
      if(sitemap!=null) {
        SitemapBean bean = new SitemapBean();
        bean.name = StringUtils.removeEnd(modelName, SITEMAP_FILEEXT);
        bean.icon = sitemap.getIcon();
        bean.label = sitemap.getLabel();
        bean.link = UriBuilder.fromUri(uri).path(bean.name).build().toASCIIString();
        bean.homepage = new PageBean();
        bean.homepage.link = bean.link + "/" + sitemap.getName();
        beans.add(bean);
      }
    }
    return beans;
  }

  public SitemapBean getSitemapBean(String sitemapname, URI uri) {
    Sitemap sitemap = getSitemap(sitemapname);
    if(sitemap!=null) {
      return createSitemapBean(sitemapname, sitemap, uri);
    } else {
      logger.info("Received HTTP GET request at '{}' for the unknown sitemap '{}'.", uriInfo.getPath(), sitemapname);
      throw new WebApplicationException(404);
    }
  }

  private SitemapBean createSitemapBean(String sitemapName, Sitemap sitemap, URI uri) {
      SitemapBean bean = new SitemapBean();
   
      bean.name = sitemapName;
    bean.icon = sitemap.getIcon();
    bean.label = sitemap.getLabel();

      bean.link = UriBuilder.fromUri(uri).path(SitemapResource.PATH_SITEMAPS).path(bean.name).build().toASCIIString();
      bean.homepage = createPageBean(sitemap.getName(), sitemap.getLabel(), sitemap.getIcon(), sitemap.getName(), sitemap.getChildren(), true, false, uri);
      return bean;
    }
   
    static private PageBean createPageBean(String sitemapName, String title, String icon, String pageId, EList<Widget> children, boolean drillDown, boolean isLeaf, URI uri) {
      PageBean bean = new PageBean();
      bean.id = pageId;
      bean.title = title;
      bean.icon = icon;
    bean.leaf = isLeaf;
      bean.link = UriBuilder.fromUri(uri).path(PATH_SITEMAPS).path(sitemapName).path(pageId).build().toASCIIString();
      if(children!=null) {
        int cntWidget = 0;
        for(Widget widget : children) {
          String widgetId = pageId + "_" + cntWidget;
          WidgetBean subWidget = createWidgetBean(sitemapName, widget, drillDown, uri, widgetId);
        if(subWidget != null)
          bean.widgets.add(subWidget);
          cntWidget++;
        }
      } else {
        bean.widgets = null;
      }
    return bean;
  }

  static private WidgetBean createWidgetBean(String sitemapName, Widget widget, boolean drillDown, URI uri, String widgetId) {
    ItemUIRegistry itemUIRegistry = RESTApplication.getItemUIRegistry();

    // Test visibility
    if(itemUIRegistry.getVisiblity(widget) == false)
      return null;

      WidgetBean bean = new WidgetBean();
      if(widget.getItem()!=null) {
        Item item = ItemResource.getItem(widget.getItem());
          if(item!=null) {
            bean.item = ItemResource.createItemBean(item, false, UriBuilder.fromUri(uri).build().toASCIIString());
          }
      }
      bean.widgetId = widgetId;
      bean.icon = itemUIRegistry.getIcon(widget);
    bean.labelcolor = itemUIRegistry.getLabelColor(widget);
    bean.valuecolor = itemUIRegistry.getValueColor(widget);
      bean.label = itemUIRegistry.getLabel(widget);
      bean.type = widget.eClass().getName();
      if (widget instanceof LinkableWidget) {
      LinkableWidget linkableWidget = (LinkableWidget) widget;
      EList<Widget> children = itemUIRegistry.getChildren(linkableWidget);
        if(widget instanceof Frame) {
          int cntWidget=0;
          for(Widget child : children) {
            widgetId += "_" + cntWidget;
          WidgetBean subWidget = createWidgetBean(sitemapName, child, drillDown, uri, widgetId);
          if(subWidget != null) {
            bean.widgets.add(subWidget);
              cntWidget++;
          }
        }
        } else if(children.size()>0)  {
        String pageName = itemUIRegistry.getWidgetId(linkableWidget);
        bean.linkedPage = createPageBean(sitemapName, itemUIRegistry.getLabel(widget), itemUIRegistry.getIcon(widget), pageName,
            drillDown ? children : null, drillDown, isLeaf(children), uri);
        }
    }
      if(widget instanceof Switch) {
        Switch switchWidget = (Switch) widget;
        for(Mapping mapping : switchWidget.getMappings()) {
          MappingBean mappingBean = new MappingBean();
        // Remove quotes - if they exist
        if(mapping.getCmd() != null) {
          if(mapping.getCmd().startsWith("\"") && mapping.getCmd().endsWith("\"")) {
            mappingBean.command = mapping.getCmd().substring(1, mapping.getCmd().length()-1);
          }
          else {
            mappingBean.command = mapping.getCmd();
          }
        }
        else {
          mappingBean.command = mapping.getCmd();
        }
        mappingBean.label = mapping.getLabel();
        bean.mappings.add(mappingBean);
      }
    }
    if (widget instanceof Selection) {
      Selection selectionWidget = (Selection) widget;
      for (Mapping mapping : selectionWidget.getMappings()) {
        MappingBean mappingBean = new MappingBean();
        // Remove quotes - if they exist
        if(mapping.getCmd() != null) {
          if(mapping.getCmd().startsWith("\"") && mapping.getCmd().endsWith("\"")) {
            mappingBean.command = mapping.getCmd().substring(1, mapping.getCmd().length()-1);
          }
          else {
            mappingBean.command = mapping.getCmd();
          }       
        }
        else {
          mappingBean.command = mapping.getCmd();
        }
          mappingBean.label = mapping.getLabel();
          bean.mappings.add(mappingBean);
        }
      }
      if(widget instanceof Slider) {
        Slider sliderWidget = (Slider) widget;
        bean.sendFrequency = sliderWidget.getFrequency();
        bean.switchSupport = sliderWidget.isSwitchEnabled();
      }
      if(widget instanceof List) {
        List listWidget = (List) widget;
        bean.separator = listWidget.getSeparator();
      }
      if (widget instanceof Image ||
        widget instanceof Video ||
        widget instanceof Webview) {

          if(widget instanceof Image) {
            Image imageWidget = (Image) widget;
            if(imageWidget.getRefresh() > 0) {
              bean.refresh = imageWidget.getRefresh();
            }
            bean.url = imageWidget.getUrl();
          }
          else if (widget instanceof Video) {
            Video videoWidget = (Video) widget;
            if(videoWidget.getEncoding() != null) {
              bean.encoding = videoWidget.getEncoding();
            }
            bean.url = videoWidget.getUrl();
          }
          else {
        Webview webViewWidget = (Webview) widget;
        bean.height = webViewWidget.getHeight();
        bean.url = webViewWidget.getUrl();
          }

      String wId = itemUIRegistry.getWidgetId(widget);

      StringBuilder sbBaseUrl = new StringBuilder();
      sbBaseUrl.append(uri.getScheme()).append("://").append(uri.getHost());
      if (uri.getPort() >= 0 && uri.getPort() != 80) {
        sbBaseUrl.append(":").append(uri.getPort());
      }
      StringBuilder sb = new StringBuilder();
      sb.append("/proxy?");
      sb.append("sitemap=").append(sitemapName).append(".sitemap&");
      sb.append("widgetId=").append(wId);
      if (bean.url != null && bean.url.startsWith("/")) {
            try {
              sb.append("&").append("baseUrl=").append(URLEncoder.encode(sbBaseUrl.toString(), "UTF-8"));
            }
        catch (UnsupportedEncodingException ex) {
          throw new RuntimeException(ex.getMessage(), ex);
        }
      }
      sbBaseUrl.append(sb.toString());
      bean.url = sbBaseUrl.toString();
      }
      if(widget instanceof Chart) {
        Chart chartWidget = (Chart) widget;
        bean.service = chartWidget.getService();
        bean.period = chartWidget.getPeriod();
        if(chartWidget.getRefresh()>0) {
          bean.refresh = chartWidget.getRefresh();
        }
      }
      if(widget instanceof Setpoint) {
        Setpoint setpointWidget = (Setpoint) widget;
        bean.minValue = setpointWidget.getMinValue();
        bean.maxValue = setpointWidget.getMaxValue();
        bean.step = setpointWidget.getStep();
      }
    return bean;
  }

  private static boolean isLeaf(EList<Widget> children) {
    for(Widget w : children) {
      if(w instanceof Frame) {
        if(isLeaf(((Frame) w).getChildren())) {
          return false;
        }
      } else if(w instanceof LinkableWidget) {
        LinkableWidget linkableWidget = (LinkableWidget) w;
        ItemUIRegistry itemUIRegistry = RESTApplication.getItemUIRegistry();
        if(itemUIRegistry.getChildren(linkableWidget).size() > 0) {
          return false;
        }
      }
    }
    return true;
  }

  static public Sitemap getSitemap(String sitemapname) {
        ModelRepository repo = RESTApplication.getModelRepository();
        if(repo!=null) {
      Sitemap sitemap = (Sitemap) repo.getModel(sitemapname + SITEMAP_FILEEXT);
      return sitemap;
        }
        return null;
    }
}
TOP

Related Classes of org.openhab.io.rest.internal.resources.SitemapResource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.