KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > directwebremoting > convert > MapConverter


1 /*
2  * Copyright 2005 Joe Walker
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.directwebremoting.convert;
17
18 import java.lang.reflect.Modifier JavaDoc;
19 import java.util.HashMap JavaDoc;
20 import java.util.Iterator JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.StringTokenizer JavaDoc;
23
24 import org.directwebremoting.dwrp.ParseUtil;
25 import org.directwebremoting.dwrp.ProtocolConstants;
26 import org.directwebremoting.dwrp.ObjectOutboundVariable;
27 import org.directwebremoting.extend.Converter;
28 import org.directwebremoting.extend.ConverterManager;
29 import org.directwebremoting.extend.InboundContext;
30 import org.directwebremoting.extend.InboundVariable;
31 import org.directwebremoting.extend.MarshallException;
32 import org.directwebremoting.extend.OutboundContext;
33 import org.directwebremoting.extend.OutboundVariable;
34 import org.directwebremoting.extend.TypeHintContext;
35 import org.directwebremoting.util.JavascriptUtil;
36 import org.directwebremoting.util.LocalUtil;
37 import org.directwebremoting.util.Logger;
38 import org.directwebremoting.util.Messages;
39
40 /**
41  * An implementation of Converter for Maps.
42  * @author Joe Walker [joe at eireneh dot com]
43  * @version $Id: StringConverter.java,v 1.2 2004/11/04 15:54:07 joe_walker Exp $
44  */

45 public class MapConverter implements Converter
46 {
47     /* (non-Javadoc)
48      * @see org.directwebremoting.Converter#setConverterManager(org.directwebremoting.ConverterManager)
49      */

50     public void setConverterManager(ConverterManager newConfig)
51     {
52         this.config = newConfig;
53     }
54
55     /* (non-Javadoc)
56      * @see org.directwebremoting.Converter#convertInbound(java.lang.Class, org.directwebremoting.InboundVariable, org.directwebremoting.InboundContext)
57      */

58     public Object JavaDoc convertInbound(Class JavaDoc paramType, InboundVariable iv, InboundContext inctx) throws MarshallException
59     {
60         String JavaDoc value = iv.getValue();
61
62         // If the text is null then the whole bean is null
63
if (value.trim().equals(ProtocolConstants.INBOUND_NULL))
64         {
65             return null;
66         }
67
68         if (!value.startsWith(ProtocolConstants.INBOUND_MAP_START))
69         {
70             throw new IllegalArgumentException JavaDoc(Messages.getString("MapConverter.FormatError", ProtocolConstants.INBOUND_MAP_START));
71         }
72
73         if (!value.endsWith(ProtocolConstants.INBOUND_MAP_END))
74         {
75             throw new IllegalArgumentException JavaDoc(Messages.getString("MapConverter.FormatError", ProtocolConstants.INBOUND_MAP_END));
76         }
77
78         value = value.substring(1, value.length() - 1);
79
80         try
81         {
82             // Maybe we ought to check that the paramType isn't expecting a more
83
// distinct type of Map and attempt to create that?
84
Map JavaDoc map;
85
86             // If paramType is concrete then just use whatever we've got.
87
if (!paramType.isInterface() && !Modifier.isAbstract(paramType.getModifiers()))
88             {
89                 // If there is a problem creating the type then we have no way
90
// of completing this - they asked for a specific type and we
91
// can't create that type. I don't know of a way of finding
92
// subclasses that might be instaniable so we accept failure.
93
map = (Map JavaDoc) paramType.newInstance();
94             }
95             else
96             {
97                 map = new HashMap JavaDoc();
98             }
99
100             // Get the extra type info
101
TypeHintContext thc = inctx.getCurrentTypeHintContext();
102
103             TypeHintContext keyThc = thc.createChildContext(0);
104             Class JavaDoc keyType = keyThc.getExtraTypeInfo();
105
106             TypeHintContext valThc = thc.createChildContext(1);
107             Class JavaDoc valType = valThc.getExtraTypeInfo();
108
109             // We should put the new object into the working map in case it
110
// is referenced later nested down in the conversion process.
111
inctx.addConverted(iv, paramType, map);
112             InboundContext incx = iv.getLookup();
113
114             // Loop through the property declarations
115
StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(value, ",");
116             int size = st.countTokens();
117             for (int i = 0; i < size; i++)
118             {
119                 String JavaDoc token = st.nextToken();
120                 if (token.trim().length() == 0)
121                 {
122                     continue;
123                 }
124
125                 int colonpos = token.indexOf(ProtocolConstants.INBOUND_MAP_ENTRY);
126                 if (colonpos == -1)
127                 {
128                     throw new MarshallException(paramType, Messages.getString("MapConverter.MissingSeparator", ProtocolConstants.INBOUND_MAP_ENTRY, token));
129                 }
130
131                 // Convert the value part of the token by splitting it into the
132
// type and value (as passed in by Javascript)
133
String JavaDoc valStr = token.substring(colonpos + 1).trim();
134                 String JavaDoc[] splitIv = ParseUtil.splitInbound(valStr);
135                 String JavaDoc splitIvValue = splitIv[LocalUtil.INBOUND_INDEX_VALUE];
136                 String JavaDoc splitIvType = splitIv[LocalUtil.INBOUND_INDEX_TYPE];
137                 InboundVariable valIv = new InboundVariable(incx, null, splitIvType, splitIvValue);
138                 Object JavaDoc val = config.convertInbound(valType, valIv, inctx, valThc);
139
140                 // Keys (unlike values) do not have type info passed with them
141
// Could we have recurrsive key? - I don't think so because keys
142
// must be strings in Javascript
143
String JavaDoc keyStr = token.substring(0, colonpos).trim();
144                 //String[] keySplit = LocalUtil.splitInbound(keyStr);
145
//InboundVariable keyIv = new InboundVariable(incx, splitIv[LocalUtil.INBOUND_INDEX_TYPE], splitIv[LocalUtil.INBOUND_INDEX_VALUE]);
146
InboundVariable keyIv = new InboundVariable(incx, null, ProtocolConstants.TYPE_STRING, keyStr);
147                 Object JavaDoc key = config.convertInbound(keyType, keyIv, inctx, keyThc);
148
149                 map.put(key, val);
150             }
151
152             return map;
153         }
154         catch (MarshallException ex)
155         {
156             throw ex;
157         }
158         catch (Exception JavaDoc ex)
159         {
160             throw new MarshallException(paramType, ex);
161         }
162     }
163
164     /* (non-Javadoc)
165      * @see org.directwebremoting.Converter#convertOutbound(java.lang.Object, org.directwebremoting.OutboundContext)
166      */

167     public OutboundVariable convertOutbound(Object JavaDoc data, OutboundContext outctx) throws MarshallException
168     {
169         // First we just collect our converted children
170
Map JavaDoc ovs = (Map JavaDoc) LocalUtil.classNewInstance("OrderedConvertOutbound", "java.util.LinkedHashMap", Map JavaDoc.class);
171         if (ovs == null)
172         {
173             ovs = new HashMap JavaDoc();
174         }
175
176         ObjectOutboundVariable ov = new ObjectOutboundVariable(outctx);
177         outctx.put(data, ov);
178
179         // Loop through the map outputting any init code and collecting
180
// converted outbound variables into the ovs map
181
Map JavaDoc map = (Map JavaDoc) data;
182         for (Iterator JavaDoc it = map.entrySet().iterator(); it.hasNext();)
183         {
184             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
185             Object JavaDoc key = entry.getKey();
186             Object JavaDoc value = entry.getValue();
187
188             // It would be nice to check for Enums here
189
if (!(key instanceof String JavaDoc) && !sentNonStringWarning)
190             {
191                 log.warn("--Javascript does not support non string keys. Converting '" + key.getClass().getName() + "' using toString()");
192                 sentNonStringWarning = true;
193             }
194
195             String JavaDoc outkey = JavascriptUtil.escapeJavaScript(key.toString());
196
197             // OutboundVariable ovkey = config.convertOutbound(key, outctx);
198
// buffer.append(ovkey.getInitCode());
199
// outkey = ovkey.getAssignCode();
200

201             OutboundVariable nested = config.convertOutbound(value, outctx);
202
203             ovs.put(outkey, nested);
204         }
205
206         ov.init(ovs, null);
207
208         return ov;
209     }
210
211     /**
212      * We don't want to give the non-string warning too many times.
213      */

214     private static boolean sentNonStringWarning = false;
215
216     /**
217      * To forward marshalling requests
218      */

219     private ConverterManager config = null;
220
221     /**
222      * The log stream
223      */

224     private static final Logger log = Logger.getLogger(MapConverter.class);
225 }
226
Popular Tags