Package org.vfny.geoserver.wms.requests

Source Code of org.vfny.geoserver.wms.requests.GetLegendGraphicKvpReader

/* Copyright (c) 2001, 2003 TOPP - www.openplans.org.  All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.wms.requests;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.logging.Logger;

import javax.servlet.http.HttpServletRequest;

import org.geotools.feature.FeatureType;
import org.geotools.styling.FeatureTypeStyle;
import org.geotools.styling.Rule;
import org.geotools.styling.SLDParser;
import org.geotools.styling.Style;
import org.geotools.styling.StyleFactory;
import org.vfny.geoserver.Request;
import org.vfny.geoserver.ServiceException;
import org.vfny.geoserver.global.Data;
import org.vfny.geoserver.global.FeatureTypeInfo;
import org.vfny.geoserver.global.WMS;
import org.vfny.geoserver.wms.WmsException;

/**
* Key/Value pair set parsed for a GetLegendGraphic request. When calling
* <code>getRequest</code> produces a {@linkPlain
* org.vfny.geoserver.requests.wms.GetLegendGraphicRequest}
* <p>
* See {@linkplain org.vfny.geoserver.wms.requests.GetLegendGraphicRequest} for
* a complete list of expected request parameters.
* </p>
*
* @author Gabriel Roldan, Axios Engineering
* @version $Id$
* @see org.vfny.geoserver.wms.requests.GetLegendGraphicRequest
*/
public class GetLegendGraphicKvpReader extends WmsKvpRequestReader {
  /** DOCUMENT ME! */
  private static final Logger LOGGER = Logger
      .getLogger(GetLegendGraphicKvpReader.class.getPackage().getName());

  /**
   * Factory to create styles from inline or remote SLD documents (aka, from
   * SLD_BODY or SLD parameters).
   */
  private static final StyleFactory styleFactory = StyleFactory
      .createStyleFactory();

  /**
   * Creates a new GetLegendGraphicKvpReader object.
   *
   * @param params
   *            map of key/value pairs with the parameters for a
   *            GetLegendGraphic request
   */
  public GetLegendGraphicKvpReader(Map params) {
    super(params);
  }

  /**
   * DOCUMENT ME!
   *
   * @param httpRequest
   *            DOCUMENT ME!
   *
   * @return DOCUMENT ME!
   *
   * @throws ServiceException
   *             see <code>throws WmsException</code>
   * @throws WmsException
   *             if some invalid parameter was passed.
   */
  public Request getRequest(HttpServletRequest httpRequest)
      throws ServiceException {
    GetLegendGraphicRequest request = new GetLegendGraphicRequest();
    // TODO: we should really get rid of the HttpServletRequest dependency
    // beyond the HTTP facade. Neither the request readers should depend on
    // it
    request.setHttpServletRequest(httpRequest);

    String version = super.getRequestVersion();

    if (!GetLegendGraphicRequest.SLD_VERSION.equals(version)) {
      throw new WmsException("Invalid SLD version number \"" + version
          + "\"");
    }

    String layer = getValue("LAYER");
    FeatureTypeInfo fti;
    FeatureType ft;

    try {
      WMS wms = request.getWMS();
      Data catalog = wms.getData();
      fti = catalog.getFeatureTypeInfo(layer);
      ft = fti.getFeatureType();
    } catch (NoSuchElementException e) {
      throw new WmsException(layer + " layer does not exists.",
          "LayerNotDefined");
    } catch (IOException e) {
      throw new WmsException(
          "Can't obtain the schema for the required layer.");
    }

    request.setLayer(ft);

    String format = getValue("FORMAT");

    if (!org.vfny.geoserver.wms.responses.GetLegendGraphicResponse
        .supportsFormat(format)) {
      throw new WmsException("Invalid graphic format: " + format,
          "InvalidFormat");
    }

    request.setFormat(format);

    parseOptionalParameters(request, fti);

    return request;
  }

  /**
   * DOCUMENT ME!
   *
   * @param req
   *            DOCUMENT ME!
   * @param ft
   *            DOCUMENT ME!
   *
   * @throws WmsException
   *             DOCUMENT ME!
   *
   * @task TODO: validate EXCEPTIONS parameter
   */
  private void parseOptionalParameters(GetLegendGraphicRequest req,
      FeatureTypeInfo ft) throws WmsException {
    parseStyleAndRule(req, ft);

    // not used by now, since we don't support nested layers yet
    String featureType = getValue("FEATURETYPE");

    String scale = getValue("SCALE");

    if ((scale != null) && !"".equals(scale)) {
      double scaleFactor = Double.valueOf(scale).doubleValue();
      req.setScale(scaleFactor);
    }

    String width = getValue("WIDTH");

    if ((width != null) && !"".equals(width)) {
      int legendW = Integer.valueOf(width).intValue();
      req.setWidth(legendW);
    }

    String height = getValue("HEIGHT");

    if ((height != null) && !"".equals(height)) {
      int legendH = Integer.valueOf(height).intValue();
      req.setHeight(legendH);
    }

    String exceptions = getValue("EXCEPTIONS");

    if (exceptions != null) {
      req.setExceptionsFormat(exceptions);
    }
  }

  /**
   * Parses the STYLE, SLD and SLD_BODY parameters, as well as RULE.
   *
   * <p>
   * STYLE, SLD and SLD_BODY are mutually exclusive. STYLE refers to a named
   * style known by the server and applicable to the requested layer (i.e., it
   * is exposed as one of the layer's styles in the Capabilities document).
   * SLD is a URL to an externally available SLD document, and SLD_BODY is a
   * string containing the SLD document itself.
   * </p>
   *
   * <p>
   * As I don't completelly understand which takes priority over which from
   * the spec, I assume the precedence order as follow: SLD, SLD_BODY, STYLE,
   * in decrecent order of precedence.
   * </p>
   *
   * @param req
   * @param ftype
   *
   * @throws WmsException
   */
  private void parseStyleAndRule(GetLegendGraphicRequest req,
      FeatureTypeInfo ftype) throws WmsException {
    String styleName = getValue("STYLE");
    String sldUrl = getValue("SLD");
    String sldBody = getValue("SLD_BODY");

    LOGGER.fine("looking for style " + styleName);

    Style sldStyle = null;

    if (sldUrl != null) {
      LOGGER.finer("taking style from SLD parameter");
      Style[] styles = loadRemoteStyle(sldUrl); // may throw an
      // exception
      sldStyle = findStyle(styleName, styles);
    } else if (sldBody != null) {
      LOGGER.finer("taking style from SLD_BODY parameter");
      Style[] styles = parseSldBody(sldBody); // may throw an exception
      sldStyle = findStyle(styleName, styles);
    } else if ((styleName != null) && !"".equals(styleName)) {
      LOGGER.finer("taking style from STYLE parameter");
      sldStyle = req.getWMS().getData().getStyle(styleName);
    } else {
      sldStyle = ftype.getDefaultStyle();
    }

    req.setStyle(sldStyle);

    String rule = getValue("RULE");
    Rule sldRule = extractRule(sldStyle, rule);

    if (sldRule != null) {
      req.setRule(sldRule);
    }
  }

  /**
   * Finds the Style named <code>styleName</code> in <code>styles</code>.
   *
   * @param styleName
   *            name of style to search for in the list of styles. If
   *            <code>null</code>, it is assumed the request is made in
   *            literal mode and the user has requested the first style.
   * @param styles non null, non empty, list of styles
   * @return
   * @throws NoSuchElementException
   *             if no style named <code>styleName</code> is found in
   *             <code>styles</code>
   */
  private Style findStyle(String styleName, Style[] styles)
      throws NoSuchElementException {
    if (styles == null || styles.length == 0) {
      throw new NoSuchElementException(
          "No styles have been provided to search for " + styleName);
    }
    if(styleName == null){
      LOGGER.finer("styleName is null, request in literal mode, returning first style");
      return styles[0];
    }
    LOGGER.finer("request in library mode, looking for style " + styleName);
    StringBuffer noMatchNames = new StringBuffer();
    for (int i = 0; i < styles.length; i++) {
      if (styles[i] != null && styleName.equals(styles[i].getName())) {
        return styles[i];
      }
      noMatchNames.append(styles[i].getName());
      if (i < styles.length)
        noMatchNames.append(", ");
    }
    throw new NoSuchElementException(styleName
        + " not found. Provided style names: " + noMatchNames);
  }

  /**
   * Loads a remote SLD document and parses it to a Style object
   *
   * @param sldUrl
   *            an URL to a SLD document
   *
   * @return the document parsed to a Style object
   *
   * @throws WmsException
   *             if <code>sldUrl</code> is not a valid URL, a stream can't
   *             be opened or a parsing error occurs
   */
  private Style[] loadRemoteStyle(String sldUrl) throws WmsException {
    InputStream in;

    try {
      URL url = new URL(sldUrl);
      in = url.openStream();
    } catch (MalformedURLException e) {
      throw new WmsException(e, "Not a valid URL to an SLD document "
          + sldUrl, "loadRemoteStyle");
    } catch (IOException e) {
      throw new WmsException(e, "Can't open the SLD URL " + sldUrl,
          "loadRemoteStyle");
    }

    return parseSld(new InputStreamReader(in));
  }

  /**
   * Parses a SLD Style from a xml string
   *
   * @param sldBody
   *            the string containing the SLD document
   *
   * @return the SLD document string parsed to a Style object
   *
   * @throws WmsException
   *             if a parsing error occurs.
   */
  private Style[] parseSldBody(String sldBody) throws WmsException {
    // return parseSld(new StringBufferInputStream(sldBody));
    return parseSld(new StringReader(sldBody));
  }

  /**
   * Parses the content of the given input stream to an SLD Style, provided
   * that a valid SLD document can be read from <code>xmlIn</code>.
   *
   * @param xmlIn
   *            where to read the SLD document from.
   *
   * @return the parsed Style
   *
   * @throws WmsException
   *             if a parsing error occurs
   */
  private Style[] parseSld(Reader xmlIn) throws WmsException {
    SLDParser parser = new SLDParser(styleFactory, xmlIn);
    Style[] styles = null;

    try {
      styles = parser.readXML();
    } catch (RuntimeException e) {
      throw new WmsException(e);
    }

    if ((styles == null) || (styles.length == 0)) {
      throw new WmsException("Document contains no styles");
    }

    return styles;
  }

  /**
   * DOCUMENT ME!
   *
   * @param sldStyle
   * @param rule
   *
   * @return DOCUMENT ME!
   *
   * @throws WmsException
   */
  private Rule extractRule(Style sldStyle, String rule) throws WmsException {
    Rule sldRule = null;

    if ((rule != null) && !"".equals(rule)) {
      FeatureTypeStyle[] fts = sldStyle.getFeatureTypeStyles();

      for (int i = 0; i < fts.length; i++) {
        Rule[] rules = fts[i].getRules();

        for (int r = 0; r < rules.length; r++) {
          if (rule.equalsIgnoreCase(rules[r].getName())) {
            sldRule = rules[r];
            LOGGER.fine("found requested rule: " + rule);

            break;
          }
        }
      }

      if (sldRule == null) {
        throw new WmsException("Style " + sldStyle.getName()
            + " does not contains a rule named " + rule);
      }
    }

    return sldRule;
  }
}
TOP

Related Classes of org.vfny.geoserver.wms.requests.GetLegendGraphicKvpReader

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.