/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.kml.icons; import java.io.File; import java.io.UnsupportedEncodingException; import java.net.URL; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Collections; import java.util.Map; import org.geoserver.config.GeoServerDataDirectory; import org.geoserver.ows.URLMangler.URLType; import org.geoserver.ows.util.ResponseUtils; import org.geoserver.platform.GeoServerExtensions; import org.geotools.data.DataUtilities; import org.geotools.styling.Style; /** * Stores the values of dynamic style properties needed to generate an icon for a particular * feature. * * @author David Winslow, OpenGeo * @author Kevin Smith, OpenGeo * */ public abstract class IconProperties { private IconProperties() { } public abstract Double getOpacity(); public abstract Double getScale(); public abstract Double getHeading(); public abstract String href(String baseURL, String workspace, String styleName); public abstract Style inject(Style base); public abstract Map<String, String> getProperties(); public abstract String getIconName(Style style); public abstract boolean isExternal(); public static IconProperties generator(final Double opacity, final Double scale, final Double heading, final Map<String, String> styleProperties) { return new IconProperties() { @Override public Double getOpacity() { return opacity; } @Override public Double getScale() { return scale; } @Override public Double getHeading() { return heading; } @Override public boolean isExternal() { return false; } @Override public String href(String baseURL, String workspace, String styleName) { if(workspace!=null) { styleName=workspace+"/"+styleName; } return ResponseUtils.buildURL(baseURL, "kml/icon/" + styleName, styleProperties, URLType.RESOURCE); } @Override public Style inject(Style base) { return IconPropertyInjector.injectProperties(base, styleProperties); } @Override public Map<String, String> getProperties() { return styleProperties; } @Override public String getIconName(Style style) { try { final MessageDigest digest = MessageDigest.getInstance("MD5"); digest.update(style.getName().getBytes("UTF-8")); for (Map.Entry<String, String> property : styleProperties.entrySet()) { digest.update(property.getKey().getBytes("UTF-8")); digest.update(property.getValue().getBytes("UTF-8")); } final byte[] hash = digest.digest(); final StringBuilder builder = new StringBuilder(); for (byte b : hash) { builder.append(String.format("%02x", b)); } return builder.toString(); } catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } }; } public static IconProperties externalReference(final Double opacity, final Double scale, final Double heading, final String url) { return new IconProperties() { @Override public Double getOpacity() { return opacity; } @Override public Double getScale() { return scale; } @Override public Double getHeading() { return heading; } @Override public String href(String baseURL, String workspace, String styleName) { try { URL target = new URL(url); String graphicProtocol = target.getProtocol(); if("file".equals(graphicProtocol)) { File file = DataUtilities.urlToFile(target); File styles = null; File graphicFile = null; if (file.isAbsolute()) { GeoServerDataDirectory dataDir = (GeoServerDataDirectory) GeoServerExtensions .bean("dataDirectory"); // we grab the canonical path to make sure we can compare them, no // relative parts in them and so on styles = dataDir.getStyles().dir().getCanonicalFile(); file = graphicFile = file.getCanonicalFile(); if (file.getAbsolutePath().startsWith(styles.getAbsolutePath())) { // ok, part of the styles directory, extract only the relative path file = new File(file.getAbsolutePath().substring( styles.getAbsolutePath().length() + 1)); } else { // we wont' transform this, other dirs are not published file = null; } // rebuild the icon href accordingly if (file != null && styles != null) { return ResponseUtils.buildURL(baseURL, "styles/" + styles.toURI().relativize(graphicFile.toURI()), null, URLType.RESOURCE); } else { // we don't know how to handle this then... return null; } } return ResponseUtils.buildURL(baseURL, "styles/"+target.getPath(), Collections.<String, String> emptyMap(), URLType.RESOURCE); } else if (!("http".equals(graphicProtocol) || "https".equals(graphicProtocol))) { return null; } //return ResponseUtils.buildURL(baseURL, "rest/render/kml/icon/" + styleName, styleProperties, URLType.RESOURCE); return url; } catch (Exception ex) { throw new IllegalStateException(ex); } } @Override public boolean isExternal() { return true; } @Override public Style inject(Style base) { throw new RuntimeException("An implementation is missing"); } @Override public Map<String, String> getProperties() { throw new RuntimeException("An implementation is missing"); } @Override public String getIconName(Style style) { throw new RuntimeException("An implementation is missing"); } }; } }