All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cloudhopper.sxmp.OptionalParamMap Maven / Gradle / Ivy

package com.cloudhopper.sxmp;

/*
 * #%L
 * ch-sxmp
 * %%
 * Copyright (C) 2012 - 2013 Cloudhopper by Twitter
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

import com.cloudhopper.commons.charset.CharsetUtil;
import com.cloudhopper.commons.charset.ModifiedUTF8Charset;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

/**
 * Map for StratusRequest optional params.
 * Keys are limited to 255 UTF8 bytes max.
 * Objects can be: short, int, long, double, string (32767 UTF8 bytes max)
 *
 * @author dhoffman
 */
public class OptionalParamMap implements Map {

    static public final int HASH_MAP = 1;
    static public final int TREE_MAP = 2;

    static private final ModifiedUTF8Charset MODIFIED_UTF8_CHARSET = (ModifiedUTF8Charset)CharsetUtil.CHARSET_MODIFIED_UTF8;

    private final Map map;

    /**
     * Create an optional param map based on the specified map type
     * @param type
     * @throws IllegalArgumentException
     */
    public OptionalParamMap(int type) throws IllegalArgumentException {
        switch (type) {
            case HASH_MAP:
                map = new HashMap();
                break;
            case TREE_MAP:
                map = new TreeMap();
                break;
            default:
                throw new IllegalArgumentException("Invalid map type");
        }
    }

    @Override
    public Object put(String key, Object value) {
        if (map.size() + 1 > 255)
            throw new IllegalArgumentException("more than 255 entries");

        validateEntry(key, value);
        return map.put(key, value);
    }

    @Override
    public void putAll(Map map) {
        if (this.map.size() + map.size() > 255)
            throw new IllegalArgumentException("more than 255 entries");

        for (Object s : map.keySet()) {
            if (!(s instanceof String)) {
                throw new IllegalArgumentException("keys must be strings");
            }
            put((String) s, map.get(s));
        }
    }

    @Override
    public Object get(Object key) {
        return map.get(key);
    }

    public String getString(String key, String defaultValue) {
        Object o = get(key);
        if (o != null && o instanceof String)
            return (String) o;
        return defaultValue;
    }

    public Integer getInteger(String key, Integer defaultValue) {
        Object o = get(key);
        if (o != null && o instanceof Integer)
            return (Integer) o;
        return defaultValue;
    }

    /*
     * getLong will successfully return for both Long values and Integer values
     * it will convert the Integer to a Long
     */
    public Long getLong(String key, Long defaultValue) {
        Object o = get(key);
        if (o != null) {
            if (o instanceof Long) {
                return (Long) o;
            } else if (o instanceof Integer) {
                return new Long((Integer)o);
            }
        }
        return defaultValue;
    }

    public Double getDouble(String key, Double defaultValue) {
        Object o = get(key);
        if (o != null && o instanceof Double)
            return (Double) o;
        return defaultValue;
    }

    @Override
    public Set keySet() {
        return map.keySet();
    }

    @Override
    public Collection values() {
        return map.values();
    }

    @Override
    public int size() {
        return map.size();
    }

    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    @Override
    public boolean containsKey(Object o) {
        return map.containsKey(o);
    }

    @Override
    public boolean containsValue(Object o) {
        return map.containsValue(o);
    }

    @Override
    public Object remove(Object o) {
        return map.remove(o);
    }

    @Override
    public void clear() {
        map.clear();
    }

    @Override
    public Set> entrySet() {
        return map.entrySet();
    }

    @Override
    public String toString() {
        StringBuffer sb = new StringBuffer();
        sb.append("{");
        for (String key : keySet()) {
            sb.append(key).append("=");
            Object o = get(key);
            if (o instanceof Integer)
                sb.append("i");
            else if (o instanceof Long)
                sb.append("l");
            else if (o instanceof Double)
                sb.append("d");
            sb.append(o).append(", ");
        }
        sb.append("}");
        return sb.toString();
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof OptionalParamMap)
            return map.equals(((OptionalParamMap) o).map);
        return false;
    }

    /**
     * validation:
     * enforces key length less than 256 UTF8 bytes
     * enforces valid value type (cannot be null)
     * enforces valid String value length less than 32767 UTF8 bytes
     */
    private void validateEntry(String key, Object value) {
        if (isBlank(key)) {
            throw new IllegalArgumentException("key cannot be null/blank");
        }
        if (ModifiedUTF8Charset.calculateByteLength(key) > 255) {
            throw new IllegalArgumentException("key length > 255 bytes");
        }
        else if (value == null) {
            throw new IllegalArgumentException("value cannot be null");
        }
        else if (value instanceof String) {
            if (ModifiedUTF8Charset.calculateByteLength((String) value) > 32767) {
                throw new IllegalArgumentException("string value length > 34767 bytes");
            }
        }
        else if (value instanceof Integer ||
                 value instanceof Long ||
                 value instanceof Double) {
            // valid
        } else {
            throw new IllegalArgumentException("Illegal value type: "+value.getClass().toString());
        }
    }

    // Replaces org.apache.commons.lang.StringUtils.isBlank
    private static boolean isBlank(String str) {
	int strLen;
	if (str == null || (strLen = str.length()) == 0) {
	    return true;
	}
	for (int i = 0; i < strLen; i++) {
	    if ((Character.isWhitespace(str.charAt(i)) == false)) {
		return false;
	    }
	}
	return true;
    }

}