com.mg.framework.utils.MiscUtils.java Source code

Java tutorial

Introduction

Here is the source code for com.mg.framework.utils.MiscUtils.java

Source

/*
 * MiscUtils.java
 *
 * Copyright (c) 1998 - 2006 BusinessTechnology, Ltd.
 * All rights reserved
 *
 * This program is the proprietary and confidential information
 * of BusinessTechnology, Ltd. and may be used and disclosed only
 * as authorized in a license agreement authorizing and
 * controlling such use and disclosure
 *
 * Millennium ERP system.
 *
 */
package com.mg.framework.utils;

import com.mg.framework.api.Logger;
import com.mg.framework.api.annotations.EnumConstantText;
import com.mg.framework.api.metadata.BuiltInType;
import com.mg.framework.api.metadata.ui.FieldMetadata;
import com.mg.framework.api.orm.PersistentObject;
import com.mg.framework.support.Messages;
import com.mg.framework.support.ui.UIUtils;

import java.lang.reflect.Field;
import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.IllegalFormatException;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;

/**
 * Misc Utility Functions
 *
 * @author Oleg V. Safonov
 * @version $Id: MiscUtils.java,v 1.13 2008/12/23 09:06:45 safonov Exp $
 */
public class MiscUtils {
    public static List<Locale> availableLocaleList = null;
    private static Logger logger = ServerUtils.getLogger(MiscUtils.class);

    /**
     * ? ??     ?? ?  
     *
     * @param <T>        
     * @param itemClass ??  
     * @param list      ??   
     * @return ?? ?  
     */
    @SuppressWarnings("unchecked") //$NON-NLS-1$
    public static <T> List<T> convertUncheckedList(Class<T> itemClass, List list) {
        return new ArrayList<T>(list);
    }

    /**
     *  ? ?  -??, ???  
     * ?
     */
    public static Object getPropertyTextRepresentation(Object value, FieldMetadata metadata) {
        return getPropertyTextRepresentation(value, metadata, ServerUtils.getUserLocale());
    }

    /**
     *  ? ?  -??
     *
     * @param value     
     * @param metadata 
     * @param locale   
     * @return ? ?  <code>value</code> ?     ?
     *  ??  UI
     */
    @SuppressWarnings("unchecked")
    public static Object getPropertyTextRepresentation(Object value, FieldMetadata metadata, Locale locale) {
        if (metadata != null && metadata.getConversionRoutine() != null) {
            //TODO  ? ? ,      ? ?  
            return metadata.getConversionRoutine().outputConverse(value);
        } else if (value == null)
            return null;
        else if (value instanceof String)
            return org.apache.commons.lang.StringUtils.stripEnd((String) value, null);
        else if (value instanceof Date)
            return MiscUtils.getDateTextRepresentation((Date) value, metadata, locale);
        else if (value instanceof Enum)
            return MiscUtils.getEnumTextRepresentation((Enum) value, locale);
        else if (value instanceof Boolean)
            return MiscUtils.getBooleanTextRepresentation((Boolean) value, locale);
        else if (value instanceof PersistentObject)
            return MiscUtils.getPersistentObjectTextRepresentation((PersistentObject) value, metadata, locale);
        else
            return value;
    }

    /**
     *  ? ? ?? ? 
     *
     * @param value    ??  ? 
     * @param metadata 
     * @return ? ?
     */
    public static String getArrayCustomFieldTextRepresentation(Object[] value, FieldMetadata metadata) {
        return getArrayCustomFieldTextRepresentation(value, metadata, ServerUtils.getUserLocale());
    }

    /**
     *  ? ? ?? ? 
     *
     * @param value    ??  ? 
     * @param metadata 
     * @param locale   
     * @return ? ?
     */
    public static String getArrayCustomFieldTextRepresentation(Object[] value, FieldMetadata metadata,
            Locale locale) {
        if (metadata == null)
            return value == null ? null : Arrays.toString(value);

        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < value.length; i++) {
            Object element = MiscUtils.getPropertyTextRepresentation(value[i], metadata, locale);
            if (element != null) {
                if (i > 0)
                    sb.append(", ");
                sb.append(element);
            }
        }
        return sb.toString();
    }

    /**
     *  ? ? ? ? , ??? 
     *  ?
     *
     * @param value ? ? 
     * @return ? ?
     * @throws NullPointerException ? <code>value == null</code>
     * @see #getEnumTextRepresentation(Enum, Locale)
     */
    public static String getEnumTextRepresentation(Enum<?> value) {
        return getEnumTextRepresentation(value, ServerUtils.getUserLocale());
    }

    /**
     *  ? ? ? ? 
     *
     * @param value  ? ? 
     * @param locale 
     * @return ? ?
     * @throws NullPointerException ? <code>value == null</code>
     */
    public static String getEnumTextRepresentation(Enum<?> value, Locale locale) {
        if (value == null)
            throw new NullPointerException();

        String result;
        EnumConstantText textAnnot = null;
        Field fld = ReflectionUtils.findDeclaredField(value.getClass(), value.name());
        textAnnot = fld.getAnnotation(EnumConstantText.class);
        if (textAnnot != null)
            result = UIUtils.loadL10nText(locale, textAnnot.value());
        else
            result = value.name();
        return result;
    }

    /**
     *  ? ?  ? , ???  
     * ?
     *
     * @param value 
     * @return ? ?
     * @throws NullPointerException ? <code>value == null</code>
     */
    public static String getBooleanTextRepresentation(Boolean value) {
        return getBooleanTextRepresentation(value, ServerUtils.getUserLocale());
    }

    /**
     *  ? ?  ? 
     *
     * @param value  
     * @param locale 
     * @return ? ?
     * @throws NullPointerException ? <code>value == null</code>
     */
    public static String getBooleanTextRepresentation(Boolean value, Locale locale) {
        if (value == null)
            throw new NullPointerException();

        return value ? Messages.getInstance().getMessage(Messages.TRUE_TEXT, locale)
                : Messages.getInstance().getMessage(Messages.FALSE_TEXT, locale);
    }

    /**
     * ? ? ? ??  ??,  ??
     * ????  ? <>
     *
     * @param values ?  ??
     * @return ? ?
     */
    private static String generateDefaultText(Object[] values) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < values.length; i++)
            sb.append(StringUtils.BLANK_STRING).append(values[i]);
        return sb.substring(1);
    }

    /**
     *  ? ?  ??, ???  
     * ?
     *
     * @param persistentObject ??
     * @param metadata         
     * @return ? ?
     * @throws NullPointerException ? <code>persistentObject == null</code>  <code>metadata ==
     *                              null</code>
     * @see #getPersistentObjectTextRepresentation(PersistentObject, FieldMetadata, Locale)
     */
    public static String getPersistentObjectTextRepresentation(PersistentObject persistentObject,
            FieldMetadata metadata) {
        return getPersistentObjectTextRepresentation(persistentObject, metadata, ServerUtils.getUserLocale());
    }

    /**
     *  ? ?  ??
     *
     * @param persistentObject ??
     * @param metadata         
     * @param locale           
     * @return ? ?
     */
    public static String getPersistentObjectTextRepresentation(PersistentObject persistentObject,
            FieldMetadata metadata, Locale locale) {
        if (metadata == null)
            throw new NullPointerException("The metadata must not be null");

        return getPersistentObjectTextRepresentation(persistentObject, metadata.getEntityPropertyText(),
                metadata.getEntityPropertyFormatText(), locale);
    }

    /**
     *  ? ?  ??
     *
     * @param persistentObject         ??
     * @param entityPropertyText       ?? ? ?
     * @param entityPropertyFormatText  ? (  ?? ?  
     *                                 {@link String#format(String, Object[])})
     * @return ? ?
     */
    public static String getPersistentObjectTextRepresentation(PersistentObject persistentObject,
            String[] entityPropertyText, String entityPropertyFormatText) {
        return getPersistentObjectTextRepresentation(persistentObject, entityPropertyText, entityPropertyFormatText,
                ServerUtils.getUserLocale());
    }

    /**
     *  ? ?  ??
     *
     * @param persistentObject         ??
     * @param entityPropertyText       ?? ? ?
     * @param entityPropertyFormatText  ? (  ?? ?  
     *                                 {@link String#format(String, Object[])})
     * @param locale                   
     * @return ? ?
     */
    public static String getPersistentObjectTextRepresentation(PersistentObject persistentObject,
            String[] entityPropertyText, String entityPropertyFormatText, Locale locale) {
        if (persistentObject == null)
            throw new NullPointerException("The persistentObject must not be null");

        String result;
        try {
            if (entityPropertyText != null) {
                Object[] values = new Object[entityPropertyText.length];
                for (int i = 0; i < entityPropertyText.length; i++) {
                    Object attrValue = persistentObject.getAttribute(entityPropertyText[i]);
                    // ?   
                    if (attrValue instanceof String)
                        values[i] = ((String) attrValue).trim();
                    else
                        values[i] = attrValue;
                }
                if (entityPropertyFormatText != null) {
                    try {
                        result = String.format(locale, entityPropertyFormatText, values);
                    } catch (IllegalFormatException e) {
                        logger.error("Illegal format of entity text representation", e);
                        result = generateDefaultText(values);
                    }
                } else {
                    result = generateDefaultText(values);
                }
            } else {
                //legacy implementation
                try {
                    result = (String) persistentObject.getAttribute("Code");
                } catch (Exception e) {
                    try {
                        result = (String) persistentObject.getAttribute("Name");
                    } catch (Exception ee) {
                        logger.error(
                                "The entityPropertyText must be explicit set (Code or Name property is not found)",
                                ee);
                        result = "<unknown>";
                    }
                }
            }
        } catch (Exception e) {
            logger.error("Error during entity text generation", e);
            result = "<invalid text>";
        }
        return result;
    }

    /**
     *  ? ?  ?? ?  <code>DATE, DATETIME, TIME</code>.
     * ???   ?
     *
     * @param value     
     * @param metadata 
     * @return ? ?  ? ? ? <code>value == null</code>
     * @throws NullPointerException ? <code>metadata == null</code>
     * @see #getDateTextRepresentation(Date, FieldMetadata, Locale)
     */
    public static String getDateTextRepresentation(Date value, FieldMetadata metadata) {
        return getDateTextRepresentation(value, metadata, ServerUtils.getUserLocale());
    }

    /**
     *  ? ?  ?? ?  <code>DATE, DATETIME, TIME</code>
     *
     * @param value     
     * @param metadata 
     * @param locale   
     * @return ? ?  ? ? ? <code>value == null</code>
     * @throws NullPointerException ? <code>metadata == null</code>
     */
    public static String getDateTextRepresentation(Date value, FieldMetadata metadata, Locale locale) {
        if (value == null || DateTimeUtils.isBoundDateValue(value))
            return StringUtils.EMPTY_STRING;
        if (metadata == null)
            return value.toString();

        DateFormat df;
        switch (metadata.getBuiltInType()) {
        case DATE:
            df = DateFormat.getDateInstance(DateFormat.MEDIUM, locale);
            break;
        case DATETIME:
            df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
            break;
        case TIME:
            df = DateFormat.getTimeInstance(DateFormat.MEDIUM, locale);
            break;
        default:
            return value.toString();
        }
        return df.format(value);
    }

    public static String[] generateEntityPropertyText(String entityPropertyText) {
        List<String> properties = StringUtils.split(entityPropertyText, ",");
        if (properties != null)
            return properties.toArray(new String[properties.size()]);
        else
            return null;
    }

    /**
     *  ?  ?  ? Java 
     *
     * @param clazz ?? Java 
     * @return ? 
     */
    public static BuiltInType javaTypeToBuiltInType(Class<?> clazz) {
        return BuiltInType.fromJavaClass(clazz);
    }

    /**
     * Get an iterator from a collection, returning null if collection is null
     *
     * @param col The collection to be turned in to an iterator
     * @return The resulting Iterator
     */
    public static <E> Iterator<E> toIterator(Collection<E> col) {
        if (col == null)
            return null;
        else
            return col.iterator();
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(String name1, Object value1) {
        return new MiscUtils.SimpleMap(name1, value1);

        /* Map fields = new HashMap();
           fields.put(name1, value1);
           return fields;*/
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(String name1, Object value1, String name2, Object value2) {
        return new MiscUtils.SimpleMap(name1, value1, name2, value2);

        /* Map fields = new HashMap();
           fields.put(name1, value1);
           fields.put(name2, value2);
           return fields;*/
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(String name1, Object value1, String name2, Object value2, String name3,
            Object value3) {
        return new MiscUtils.SimpleMap(name1, value1, name2, value2, name3, value3);

        /* Map fields = new HashMap();
           fields.put(name1, value1);
           fields.put(name2, value2);
           fields.put(name3, value3);
           return fields;*/
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(String name1, Object value1, String name2, Object value2, String name3,
            Object value3, String name4, Object value4) {
        return new MiscUtils.SimpleMap(name1, value1, name2, value2, name3, value3, name4, value4);

        /* Map fields = new HashMap();
           fields.put(name1, value1);
           fields.put(name2, value2);
           fields.put(name3, value3);
           fields.put(name4, value4);
           return fields;*/
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(String name1, Object value1, String name2, Object value2, String name3,
            Object value3, String name4, Object value4, String name5, Object value5) {
        Map<String, Object> fields = new HashMap<String, Object>();

        fields.put(name1, value1);
        fields.put(name2, value2);
        fields.put(name3, value3);
        fields.put(name4, value4);
        fields.put(name5, value5);
        return fields;
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(String name1, Object value1, String name2, Object value2, String name3,
            Object value3, String name4, Object value4, String name5, Object value5, String name6, Object value6) {
        Map<String, Object> fields = new HashMap<String, Object>();

        fields.put(name1, value1);
        fields.put(name2, value2);
        fields.put(name3, value3);
        fields.put(name4, value4);
        fields.put(name5, value5);
        fields.put(name6, value6);
        return fields;
    }

    /**
     * Create a map from passed nameX, valueX parameters
     *
     * @return The resulting Map
     */
    public static Map<String, Object> toMap(Object[] data) {
        if (data == null) {
            return null;
        }
        if (data.length % 2 == 1) {
            throw new IllegalArgumentException("You must pass an even sized array to the toMap method");
        }
        Map<String, Object> map = new HashMap<String, Object>();
        for (int i = 0; i < data.length;) {
            map.put((String) data[i++], data[i++]);
        }
        return map;
    }

    /**
     * Sort a List of Maps by specified consistent keys.
     *
     * @param listOfMaps List of Map objects to sort.
     * @param sortKeys   List of Map keys to sort by.
     * @return a new List of sorted Maps.
     */
    public static <K, V> List<Map<K, Comparable<V>>> sortMaps(List<Map<K, Comparable<V>>> listOfMaps,
            List<K> sortKeys) {
        if (listOfMaps == null || sortKeys == null)
            return null;
        List<Map<K, Comparable<V>>> toSort = new LinkedList<Map<K, Comparable<V>>>(listOfMaps);
        try {
            MapComparator<K, V> mc = new MapComparator<K, V>(sortKeys);
            Collections.sort(toSort, mc);
        } catch (Exception e) {
            //Debug.logError(e, "Problems sorting list of maps; returning null.", module);
            return null;
        }
        return toSort;
    }

    /**
     * Create a list from passed objX parameters
     *
     * @return The resulting List
     */
    public static <T> List<T> toList(T obj1) {
        List<T> list = new ArrayList<T>(1);

        list.add(obj1);
        return list;
    }

    /**
     * Create a list from passed objX parameters
     *
     * @return The resulting List
     */
    public static <E> List<E> toList(E obj1, E obj2) {
        List<E> list = new ArrayList<E>(2);

        list.add(obj1);
        list.add(obj2);
        return list;
    }

    /**
     * Create a list from passed objX parameters
     *
     * @return The resulting List
     */
    public static <E> List<E> toList(E obj1, E obj2, E obj3) {
        List<E> list = new ArrayList<E>(3);

        list.add(obj1);
        list.add(obj2);
        list.add(obj3);
        return list;
    }

    /**
     * Create a list from passed objX parameters
     *
     * @return The resulting List
     */
    public static <E> List<E> toList(E obj1, E obj2, E obj3, E obj4) {
        List<E> list = new ArrayList<E>(4);

        list.add(obj1);
        list.add(obj2);
        list.add(obj3);
        list.add(obj4);
        return list;
    }

    /**
     * Create a list from passed objX parameters
     *
     * @return The resulting List
     */
    public static <E> List<E> toList(E obj1, E obj2, E obj3, E obj4, E obj5) {
        List<E> list = new ArrayList<E>(5);

        list.add(obj1);
        list.add(obj2);
        list.add(obj3);
        list.add(obj4);
        list.add(obj5);
        return list;
    }

    /**
     * Create a list from passed objX parameters
     *
     * @return The resulting List
     */
    public static <E> List<E> toList(E obj1, E obj2, E obj3, E obj4, E obj5, E obj6) {
        List<E> list = new ArrayList<E>(6);

        list.add(obj1);
        list.add(obj2);
        list.add(obj3);
        list.add(obj4);
        list.add(obj5);
        list.add(obj6);
        return list;
    }

    public static <E> List<E> toList(Collection<E> collection) {
        if (collection == null)
            return null;
        if (collection instanceof List) {
            return (List<E>) collection;
        } else {
            return new ArrayList<E>(collection);
        }
    }

    public static <E> List<E> toListArray(E[] data) {
        if (data == null) {
            return null;
        }
        List<E> list = new ArrayList<E>(data.length);
        for (int i = 0; i < data.length; i++) {
            list.add(data[i]);
        }
        return list;
    }

    /**
     * Parse a locale string Locale object
     *
     * @param localeString The locale string (en_US)
     * @return Locale The new Locale object or null if no valid locale can be interpreted
     */
    public static Locale parseLocale(String localeString) {
        if (localeString == null || localeString.length() == 0) {
            return null;
        }

        Locale locale = null;
        if (localeString.length() == 2) {
            // two letter language code
            locale = new Locale(localeString);
        } else if (localeString.length() == 5) {
            // positions 0-1 language, 3-4 are country
            String language = localeString.substring(0, 2);
            String country = localeString.substring(3, 5);
            locale = new Locale(language, country);
        } else if (localeString.length() > 6) {
            // positions 0-1 language, 3-4 are country, 6 and on are special extensions
            String language = localeString.substring(0, 2);
            String country = localeString.substring(3, 5);
            String extension = localeString.substring(6);
            locale = new Locale(language, country, extension);
        } else {
            //Debug.logWarning("Do not know what to do with the localeString [" + localeString + "], should be length 2, 5, or greater than 6, returning null", module);
        }

        return locale;
    }

    /**
     * The input can be a String, Locale, or even null and a valid Locale will always be returned; if
     * nothing else works, returns the default locale.
     *
     * @param localeObject An Object representing the locale
     */
    public static Locale ensureLocale(Object localeObject) {
        if (localeObject != null && localeObject instanceof String) {
            localeObject = MiscUtils.parseLocale((String) localeObject);
        }
        if (localeObject != null && localeObject instanceof Locale) {
            return (Locale) localeObject;
        } else {
            return Locale.getDefault();
        }
    }

    /**
     * Returns a List of available locales sorted by display name
     */
    public static List<Locale> availableLocales() {
        if (availableLocaleList == null) {
            synchronized (MiscUtils.class) {
                if (availableLocaleList == null) {
                    TreeMap<String, Locale> localeMap = new TreeMap<String, Locale>();
                    Locale[] locales = Locale.getAvailableLocales();
                    for (int i = 0; i < locales.length; i++) {
                        localeMap.put(locales[i].getDisplayName(), locales[i]);
                    }
                    availableLocaleList = new LinkedList<Locale>(localeMap.values());
                }
            }
        }
        return availableLocaleList;
    }

    /**
     * This is meant to be very quick to create and use for small sized maps, perfect for how we
     * usually use UtilMisc.toMap
     */
    protected static class SimpleMap implements Map<String, Object>, java.io.Serializable {
        protected Map<String, Object> realMapIfNeeded = null;

        String[] names;
        Object[] values;

        public SimpleMap() {
            names = new String[0];
            values = new Object[0];
        }

        public SimpleMap(String name1, Object value1) {
            names = new String[1];
            values = new Object[1];
            this.names[0] = name1;
            this.values[0] = value1;
        }

        public SimpleMap(String name1, Object value1, String name2, Object value2) {
            names = new String[2];
            values = new Object[2];
            this.names[0] = name1;
            this.values[0] = value1;
            this.names[1] = name2;
            this.values[1] = value2;
        }

        public SimpleMap(String name1, Object value1, String name2, Object value2, String name3, Object value3) {
            names = new String[3];
            values = new Object[3];
            this.names[0] = name1;
            this.values[0] = value1;
            this.names[1] = name2;
            this.values[1] = value2;
            this.names[2] = name3;
            this.values[2] = value3;
        }

        public SimpleMap(String name1, Object value1, String name2, Object value2, String name3, Object value3,
                String name4, Object value4) {
            names = new String[4];
            values = new Object[4];
            this.names[0] = name1;
            this.values[0] = value1;
            this.names[1] = name2;
            this.values[1] = value2;
            this.names[2] = name3;
            this.values[2] = value3;
            this.names[3] = name4;
            this.values[3] = value4;
        }

        protected void makeRealMap() {
            realMapIfNeeded = new HashMap<String, Object>();
            for (int i = 0; i < names.length; i++) {
                realMapIfNeeded.put(names[i], values[i]);
            }
            this.names = null;
            this.values = null;
        }

        public void clear() {
            if (realMapIfNeeded != null) {
                realMapIfNeeded.clear();
            } else {
                realMapIfNeeded = new HashMap<String, Object>();
                names = null;
                values = null;
            }
        }

        public boolean containsKey(Object obj) {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.containsKey(obj);
            } else {
                for (int i = 0; i < names.length; i++) {
                    if (obj == null && names[i] == null)
                        return true;
                    if (names[i] != null && names[i].equals(obj))
                        return true;
                }
                return false;
            }
        }

        public boolean containsValue(Object obj) {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.containsValue(obj);
            } else {
                for (int i = 0; i < names.length; i++) {
                    if (obj == null && values[i] == null)
                        return true;
                    if (values[i] != null && values[i].equals(obj))
                        return true;
                }
                return false;
            }
        }

        public java.util.Set<Map.Entry<String, Object>> entrySet() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.entrySet();
            } else {
                this.makeRealMap();
                return realMapIfNeeded.entrySet();
            }
        }

        public Object get(Object obj) {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.get(obj);
            } else {
                for (int i = 0; i < names.length; i++) {
                    if (obj == null && names[i] == null)
                        return values[i];
                    if (names[i] != null && names[i].equals(obj))
                        return values[i];
                }
                return null;
            }
        }

        public boolean isEmpty() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.isEmpty();
            } else {
                if (this.names.length == 0)
                    return true;
                return false;
            }
        }

        public java.util.Set<String> keySet() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.keySet();
            } else {
                this.makeRealMap();
                return realMapIfNeeded.keySet();
            }
        }

        public Object put(String obj, Object obj1) {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.put(obj, obj1);
            } else {
                this.makeRealMap();
                return realMapIfNeeded.put(obj, obj1);
            }
        }

        public void putAll(java.util.Map<? extends String, ? extends Object> map) {
            if (realMapIfNeeded != null) {
                realMapIfNeeded.putAll(map);
            } else {
                this.makeRealMap();
                realMapIfNeeded.putAll(map);
            }
        }

        public Object remove(Object obj) {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.remove(obj);
            } else {
                this.makeRealMap();
                return realMapIfNeeded.remove(obj);
            }
        }

        public int size() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.size();
            } else {
                return this.names.length;
            }
        }

        public java.util.Collection<Object> values() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.values();
            } else {
                this.makeRealMap();
                return realMapIfNeeded.values();
            }
        }

        public String toString() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.toString();
            } else {
                StringBuffer outString = new StringBuffer("{");
                for (int i = 0; i < names.length; i++) {
                    if (i > 0)
                        outString.append(',');
                    outString.append('{');
                    outString.append(names[i]);
                    outString.append(',');
                    outString.append(values[i]);
                    outString.append('}');
                }
                outString.append('}');
                return outString.toString();
            }
        }

        public int hashCode() {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.hashCode();
            } else {
                int hashCode = 0;
                for (int i = 0; i < names.length; i++) {
                    //note that this calculation is done based on the calc specified in the Java java.util.Map interface
                    int tempNum = (names[i] == null ? 0 : names[i].hashCode())
                            ^ (values[i] == null ? 0 : values[i].hashCode());
                    hashCode += tempNum;
                }
                return hashCode;
            }
        }

        @SuppressWarnings("unchecked")
        public boolean equals(Object obj) {
            if (realMapIfNeeded != null) {
                return realMapIfNeeded.equals(obj);
            } else {
                Map<String, Object> mapObj = (Map<String, Object>) obj;

                //first check the size
                if (mapObj.size() != names.length)
                    return false;

                //okay, same size, now check each entry
                for (int i = 0; i < names.length; i++) {
                    //first check the name
                    if (!mapObj.containsKey(names[i]))
                        return false;

                    //if that passes, check the value
                    Object mapValue = mapObj.get(names[i]);
                    if (mapValue == null) {
                        if (values[i] != null)
                            return false;
                    } else {
                        if (!mapValue.equals(values[i]))
                            return false;
                    }
                }

                return true;
            }
        }
    }

}