@Override
    public Feature decorate(Feature feature, KmlEncodingContext context) {
      Placemark pm = (Placemark) feature;
      // while it's possible to have more than one style object, GE will only paint
      // the first one
      Style style = pm.createAndAddStyle();
      List<Symbolizer> symbolizers = context.getCurrentSymbolizers();
      SimpleFeature sf = context.getCurrentFeature();
      if (symbolizers.size() > 0 && sf.getDefaultGeometry() != null) {
        // sort by point, text, line and polygon
        Map<Class, List<Symbolizer>> classified = classifySymbolizers(symbolizers);

        // if no point symbolizers, create a default one
        List<Symbolizer> points = classified.get(PointSymbolizer.class);
        if (points.size() == 0) {
          if (context.isDescriptionEnabled()) {
            setDefaultIconStyle(style, sf, context);
          }
        } else {
          org.geotools.styling.Style wholeStyle = context.getCurrentLayer().getStyle();
          IconProperties properties = IconPropertyExtractor.extractProperties(wholeStyle, sf);
          setIconStyle(style, wholeStyle, properties, context);
        }

        // handle label styles
        List<Symbolizer> texts = classified.get(TextSymbolizer.class);
        if (texts.size() == 0) {
          if (context.isDescriptionEnabled()) {
            setDefaultLabelStyle(style);
          }
        } else {
          // the XML schema allows only one text style, follow painter's model
          // and set the last one
          TextSymbolizer lastTextSymbolizer = (TextSymbolizer) texts.get(texts.size() - 1);
          setLabelStyle(style, sf, lastTextSymbolizer);
        }

        // handle line styles
        List<Symbolizer> lines = classified.get(LineSymbolizer.class);
        // the XML schema allows only one line style, follow painter's model
        // and set the last one
        if (lines.size() > 0) {
          LineSymbolizer lastLineSymbolizer = (LineSymbolizer) lines.get(lines.size() - 1);
          setLineStyle(style, sf, lastLineSymbolizer.getStroke());
        }

        // handle polygon styles
        boolean forceOutiline = lines.size() == 0;
        List<Symbolizer> polygons = classified.get(PolygonSymbolizer.class);
        if (polygons.size() > 0) {
          // the XML schema allows only one polygon style, follow painter's model
          // and set the last one
          PolygonSymbolizer lastPolygonSymbolizer =
              (PolygonSymbolizer) polygons.get(polygons.size() - 1);
          setPolygonStyle(style, sf, lastPolygonSymbolizer, forceOutiline);
        }
      }

      return feature;
    }
    protected void setLiveIconStyle(
        Style style,
        org.geotools.styling.Style sld,
        IconProperties properties,
        KmlEncodingContext context) {
      final Double opacity = properties.getOpacity();
      final Double scale = properties.getScale();
      final Double heading = properties.getHeading();

      IconStyle is = style.createAndSetIconStyle();

      if (opacity != null) {
        is.setColor(colorToHex(Color.WHITE, opacity));
      }

      if (scale != null) {
        is.setScale(scale);
      }

      if (heading != null) {
        is.setHeading(heading);
      }

      // Get the name of the workspace

      WorkspaceInfo ws = context.getWms().getCatalog().getStyleByName(sld.getName()).getWorkspace();
      String wsName = null;
      if (ws != null) wsName = ws.getName();

      Icon icon = is.createAndSetIcon();
      icon.setHref(
          properties.href(
              context.getMapContent().getRequest().getBaseUrl(), wsName, sld.getName()));
    }
    protected void setInlineIconStyle(
        Style style,
        org.geotools.styling.Style sld,
        IconProperties properties,
        KmlEncodingContext context) {
      final String name = properties.getIconName(sld);

      Map<String, org.geotools.styling.Style> iconStyles = context.getIconStyles();
      if (!iconStyles.containsKey(name)) {
        final org.geotools.styling.Style injectedStyle =
            IconPropertyInjector.injectProperties(sld, properties.getProperties());

        iconStyles.put(name, injectedStyle);
      }
      final Double scale = properties.getScale();
      final String path = "icons/" + name + ".png";

      IconStyle is = style.createAndSetIconStyle();
      if (properties.getHeading() != null) {
        is.setHeading(0.0);
      }
      if (scale != null) {
        is.setScale(scale);
      }

      Icon icon = is.createAndSetIcon();
      icon.setHref(path);
    }
 @Override
 public KmlDecorator getDecorator(
     Class<? extends Feature> featureClass, KmlEncodingContext context) {
   if (Placemark.class.isAssignableFrom(featureClass) && context.isDescriptionEnabled()) {
     return new PlacemarkNameDecorator();
   } else {
     return null;
   }
 }
 /** Encodes a KML IconStyle from a point style and symbolizer. */
 protected void setIconStyle(
     Style style,
     org.geotools.styling.Style sld,
     IconProperties properties,
     KmlEncodingContext context) {
   if (context.isLiveIcons() || properties.isExternal()) {
     setLiveIconStyle(style, sld, properties, context);
   } else {
     setInlineIconStyle(style, sld, properties, context);
   }
 }
  public KmlDecorator getDecorator(
      Class<? extends Feature> featureClass, KmlEncodingContext context) {
    // this decorator makes sense only for WMS
    if (!(context.getService() instanceof WMSInfo)) {
      return null;
    }

    if (Placemark.class.isAssignableFrom(featureClass)) {
      return new PlacemarkStyleDecorator();
    } else {
      return null;
    }
  }
    @Override
    public Feature decorate(Feature feature, KmlEncodingContext context) {
      Placemark pm = (Placemark) feature;

      // try with the template
      SimpleFeature sf = context.getCurrentFeature();
      String title = null;
      try {
        title = context.getTemplate().title(sf);
      } catch (IOException e) {
        String msg = "Error occured processing 'title' template.";
        LOGGER.log(Level.WARNING, msg, e);
      }

      // if we got nothing, set the title to the ID, but also try the text symbolizers
      if (title == null || "".equals(title)) {
        title = sf.getID();
        StringBuffer label = new StringBuffer();

        for (Symbolizer sym : context.getCurrentSymbolizers()) {
          if (sym instanceof TextSymbolizer) {
            Expression e = SLD.textLabel((TextSymbolizer) sym);
            String value = e.evaluate(feature, String.class);

            if ((value != null) && !"".equals(value.trim())) {
              label.append(value);
            }
          }
        }

        if (label.length() > 0) {
          title = label.toString();
        }
      }

      pm.setName(title);
      return pm;
    }
    protected void setDefaultIconStyle(
        Style style, SimpleFeature feature, KmlEncodingContext context) {
      // figure out if line or polygon
      boolean line =
          feature.getDefaultGeometry() != null
              && (feature.getDefaultGeometry() instanceof LineString
                  || feature.getDefaultGeometry() instanceof MultiLineString);
      boolean poly =
          feature.getDefaultGeometry() != null
              && (feature.getDefaultGeometry() instanceof Polygon
                  || feature.getDefaultGeometry() instanceof MultiPolygon);

      // Final pre-flight check
      if (!line && !poly) {
        LOGGER.log(
            Level.FINER,
            "Unexpectedly entered encodeDefaultIconStyle() "
                + "with something that does not have a multipoint geometry.");
        return;
      }

      IconStyle is = style.createAndSetIconStyle();
      // make transparent if they ask for attributes, since we'll have a label
      if (context.isDescriptionEnabled()) {
        is.setColor("00ffffff");
      }
      // if line or polygon scale the label
      if (line || poly) {
        is.setScale(0.4);
      }
      String imageURL =
          "http://icons.opengeo.org/markers/icon-" + (poly ? "poly.1" : "line.1") + ".png";
      Icon icon = is.createAndSetIcon();
      icon.setHref(imageURL);
      icon.setViewBoundScale(1);
    }