Package org.geomajas.plugin.caching.service

Source Code of org.geomajas.plugin.caching.service.CacheKeyServiceImpl

/*
* This is part of Geomajas, a GIS framework, http://www.geomajas.org/.
*
* Copyright 2008-2011 Geosparc nv, http://www.geosparc.com/, Belgium.
*
* The program is available in open source according to the GNU Affero
* General Public License. All contributions in this program are covered
* by the Geomajas Contributors License Agreement. For full licensing
* details, see LICENSE.txt in the project root.
*/

package org.geomajas.plugin.caching.service;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.Random;

import org.geomajas.geometry.Crs;
import org.geomajas.global.CacheableObject;
import org.geomajas.service.pipeline.PipelineContext;
import org.jboss.serial.io.JBossObjectOutputStream;
import org.opengis.filter.Filter;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.twmacinta.util.MD5;
import com.vividsolutions.jts.geom.Geometry;

/**
* Implementation of {@link CacheKeyService}.
*
* @author Joachim Van der Auwera
*/
@Component
public class CacheKeyServiceImpl implements CacheKeyService {

  private static final int BASE_KEY_LENGTH = 512;

  private static final char[] CHARACTERS = {
      'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
      'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
      'u', 'v', 'w', 'x', 'y', 'z',
      '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};

  private static final String ENCODING = "UTF-8";

  private final Logger log = LoggerFactory.getLogger(CacheKeyServiceImpl.class);

  private Random random = new Random();

  public String getCacheKey(CacheContext context) {
    try {
      MD5 md5 = new MD5();
      StringBuilder toHash = new StringBuilder(BASE_KEY_LENGTH);
      if (context instanceof CacheContextImpl) {
        CacheContextImpl cci = (CacheContextImpl) context;
        for (Map.Entry<String, Object> entry : cci.entries()) {
          md5.Update(entry.getKey(), ENCODING);
          md5.Update(":");
          if (log.isDebugEnabled()) {
            toHash.append(entry.getKey());
            toHash.append(":");
          }
          Object value = entry.getValue();
          if (null != value) {
            String cid = getCacheId(value);
            md5.Update(cid, ENCODING);
            if (log.isDebugEnabled()) {
              toHash.append(cid);
            }
          }
          md5.Update("-");
          if (log.isDebugEnabled()) {
            toHash.append("-");
          }
        }
      } else {
        String cid = getCacheId(context);
        md5.Update(cid, ENCODING);
        if (log.isDebugEnabled()) {
          toHash.append(cid);
        }
      }
      String key = md5.asHex();
      if (log.isDebugEnabled()) {
        log.debug("key for context {} which is a hash for {}", key, forceAscii(toHash));
      }
      return key;
    } catch (UnsupportedEncodingException uee) {
      log.error("Impossible error, UTF-8 should be supported:" + uee.getMessage(), uee);
      return null;
    }
  }

  private String getCacheId(Object value) {
    if (value instanceof CacheableObject) {
      return ((CacheableObject) value).getCacheId();
    } else if (value instanceof Crs) {
      return ((Crs) value).getId();
    } else if (value instanceof CoordinateReferenceSystem) {
      return ((CoordinateReferenceSystem) value).toWKT();
    } else if (value instanceof Geometry) {
      return ((Geometry) value).toText();
    } else if (value instanceof Filter) {
      return value.toString();
    } else if (value instanceof Integer) {
      return Integer.toString((Integer) value);
    } else if (value instanceof String) {
      return value.toString();
    } else {
      try {
        log.debug("Serializing {} for unique id", value.getClass().getName());
        ByteArrayOutputStream baos = new ByteArrayOutputStream(256);
        JBossObjectOutputStream serialize = new JBossObjectOutputStream(baos);
        serialize.writeObject(value);
        serialize.flush();
        serialize.close();
        return baos.toString("UTF-8");
      } catch (IOException ioe) {
        String fallback = value.toString();
        log.error("Could not serialize " + value + ", falling back to toString() which may cause problems.",
            ioe);
        return fallback;
      }
    }
  }

  public CacheContext getCacheContext(PipelineContext pipelineContext, String[] keys) {
    CacheContext res = new CacheContextImpl();
    for (String key : keys) {
      Object value = pipelineContext.getOptional(key);
      if (null != value) {
        res.put(key, value);
      } else {
        log.warn("No value for context key " + key);
      }
    }
    return res;
  }

  public String makeUnique(String duplicateKey) {
    log.debug("Need to make key {} unique.", duplicateKey);
    return duplicateKey + CHARACTERS[random.nextInt(CHARACTERS.length)];
  }

  /**
   * Convert StringBuilder output to a string while escaping characters. This prevents outputting control characters
   * and unreadable characters. It seems both cause problems for certain editors.
   * <p/>
   * The ASCII characters (excluding controls characters) are copied to the result as is, other characters are
   * escaped using \\uxxxx notation. Note that string comparisons on this result may be inaccurate as both (Java
   * strings) "\\u1234" and "\u1234" will produce the same converted string!
   *
   * @param source StringBuilder to convert
   * @return String representation using only ASCI characters
   */
  private String forceAscii(StringBuilder source) {
    int length = source.length();
    StringBuilder res = new StringBuilder(length);
    for (int i = 0; i < length; i++) {
      char c = source.charAt(i);
      if ((c >= 32 && c <= 127) || Character.isSpaceChar(c)) {
        res.append(c);
      } else {
        res.append("\\u");
        String scode = Integer.toHexString(i);
        while (scode.length() < 4) {
          scode = "0" + scode;
        }
        res.append(scode);
      }
    }
    return res.toString();
  }

}
TOP

Related Classes of org.geomajas.plugin.caching.service.CacheKeyServiceImpl

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.