/* * Copyright (C) 2000 - 2008 TagServlet Ltd * * This file is part of Open BlueDragon (OpenBD) CFML Server Engine. * * OpenBD is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * Free Software Foundation,version 3. * * OpenBD is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with OpenBD. If not, see http://www.gnu.org/licenses/ * * Additional permission under GNU GPL version 3 section 7 * * If you modify this Program, or any covered work, by linking or combining * it with any of the JARS listed in the README.txt (or a modified version of * (that library), containing parts covered by the terms of that JAR, the * licensors of this Program grant you additional permission to convey the * resulting work. * README.txt @ http://www.openbluedragon.org/license/README.txt * * http://www.openbluedragon.org/ */ package com.naryx.tagfusion.cfm.engine; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.Map; import java.util.Set; import com.nary.util.FastMap; import com.naryx.tagfusion.cfm.tag.cfDUMP; import com.naryx.tagfusion.cfm.tag.tagUtils; /** * This class extends the regular cfStructData with the purpose of giving * access to java.util.Map instances (and subclasses of). * This will give us the ability to call methods of a subclass of Map * that aren't in the declared Map methods. * * This differs from cfStructData in that it stores its values in Java "natural" * form and converts to cfData as needed, the opposite of cfStructData. */ public class cfJavaStructData extends cfStructData implements java.io.Serializable{ static final long serialVersionUID = 1; private Map theMap; /** * The original case-sensitive keys are stored in "theMap". A mapping from the * lowercased version of the key to the original key is stored in "keyMap". This * allows us to do case-insensitive key lookup via the getMappedKey() method. */ private Map keyMap; public cfJavaStructData( java.util.Map _map ){ super( _map ); theMap = _map; setInstance( theMap ); // initialize keyMap for case-insensitive key lookups keyMap = new FastMap(); Iterator iter = theMap.keySet().iterator(); while ( iter.hasNext() ) { setMappedKey( iter.next().toString() ); } } public void dump( java.io.PrintWriter out ) { dump( out, false, "", cfDUMP.TOP_DEFAULT ); } public void dump( java.io.PrintWriter out, String _lbl, int _top ) { dump( out, false, _lbl, _top ); } public void dumpLong( java.io.PrintWriter out ) { dump( out, true, "", cfDUMP.TOP_DEFAULT ); } public void dumpLong( java.io.PrintWriter out, String _lbl, int _top ) { dump( out, true, _lbl, _top ); } protected void dump( java.io.PrintWriter out, boolean longVersion, String _lbl, int _top ) { out.write( "<table class='cfdump_table_struct'>" ); Object[] keys = keys(); if ( keys.length > 0 ) { out.write( "<th class='cfdump_th_struct' colspan='2'>" ); if ( _lbl.length() > 0 ) out.write( _lbl + " - " ); out.write( "struct</th>" ); try{ Arrays.sort( keys ); }catch( ClassCastException e ){} // we can't guarantee the key types, but we'll try and sort them for ( int i = 0; i < keys.length; i ++ ) { String key = keys[ i ].toString(); // again we can't guarantee the key type so use toString() out.write( "<tr><td class='cfdump_td_struct'>" ); out.write( key ); out.write( "</td><td class='cfdump_td_value'>" ); if ( _top > 0 ){ cfData dd = getForDump( key ); if ( dd != null ) { int newTop = (dd.getDataType() == cfData.CFSTRUCTDATA ? _top - 1 : _top); if (longVersion) dd.dumpLong( out, "", newTop ); else dd.dump( out, "", newTop ); } else { out.write( "[null]" ); } } out.write( "</td></tr>" ); } } else { out.write( "<th class='cfdump_th_struct' colspan='2'>struct [empty]</th>" ); } out.write( "</table>" ); } // don't ever return null from this method private String getMappedKey( String key ) { Object realKey = keyMap.get( key.toLowerCase() ); return ( realKey != null ? realKey.toString() : key ); } private String setMappedKey( String key ) { String lowerKey = key.toLowerCase(); if ( keyMap.containsKey( lowerKey ) ) { return (String)keyMap.get( lowerKey ); } keyMap.put( lowerKey, key ); return key; } public void clear() { theMap.clear(); } public boolean containsKey(String _key) { return theMap.containsKey( getMappedKey( _key ) ); } public boolean containsValue(cfData _data) { return theMap.containsValue( tagUtils.getNatural( _data ) ); } public boolean containsValue(Object value) { return theMap.containsValue(value); } public Map copy() { FastMap copy = new FastMap(); Object[] keys = keys(); for ( int i = 0; i < keys.length; i ++ ) { String key = (String)keys[ i ]; Object val = getData( key ); copy.put( key, val ); } return copy; } public void deleteData(String _key) { theMap.remove( getMappedKey( _key ) ); keyMap.remove( _key.toLowerCase() ); } public cfData duplicate() { java.util.Map duplicateMap = null; try{ duplicateMap = (java.util.Map)theMap.getClass().newInstance(); }catch( InstantiationException e ){ duplicateMap = new java.util.HashMap(); }catch( IllegalAccessException i ){ duplicateMap = new java.util.HashMap(); } duplicateMap.putAll( theMap ); return new cfJavaStructData( duplicateMap ); } public Set entrySet() { return theMap.entrySet(); } // Map interface method, key is case-sensitive public Object get(Object key) { return theMap.get( key ); } public cfData getData(String _key) { cfData data = tagUtils.convertToCfData( theMap.get( getMappedKey( _key ) ) ); return ( data.getDataType() == cfData.CFNULLDATA ? null : data ); } private cfData getForDump(String _key) { return tagUtils.convertToCfData( theMap.get( getMappedKey( _key ) ) ); } public boolean equals( Object o ) { if ( o instanceof cfJavaStructData ) { return theMap.equals( ((cfJavaStructData)o).theMap ); } return false; } public int hashCode() { return theMap.hashCode(); } public boolean isEmpty() { return theMap.isEmpty(); } public Object[] keys() { return theMap.keySet().toArray(); } public Set keySet() { return theMap.keySet(); } public Object put(Object key, Object value) { return theMap.put( key, value); // key is case-sensitive } public void putAll(Map m) { Iterator iter = m.keySet().iterator(); while ( iter.hasNext() ) { Object key = iter.next(); put( key, m.get( key ) ); } } // Map interface method, key is case-sensitive public Object remove(Object key) { Object obj = theMap.remove(key); if ( obj != null ) { keyMap.remove( key.toString().toLowerCase() ); } return obj; } public void setData(String _key, cfData _data) { theMap.put( setMappedKey( _key ), tagUtils.getNatural(_data ) ); } public int size() { return theMap.size(); } public String toString() { return theMap.toString(); } public Collection values() { return theMap.values(); } }