View Javadoc

1   package org.mortbay.cometd;
2   
3   import java.nio.ByteBuffer;
4   import java.util.Collections;
5   import java.util.HashMap;
6   import java.util.Iterator;
7   import java.util.Map;
8   import java.util.Set;
9   import java.util.concurrent.atomic.AtomicInteger;
10  
11  import org.cometd.Bayeux;
12  import org.cometd.Message;
13  import org.mortbay.util.ajax.JSON;
14  
15  public class MessageImpl extends HashMap<String,Object> implements Message, org.mortbay.util.ajax.JSON.Generator
16  {
17      Message _associated;
18      ByteBuffer _buffer;
19      String _channel;
20      String _clientId;
21      Object _data;
22      Object _ext;
23      String _id;
24      String _json;
25      boolean _lazy=false;
26      final MessagePool _pool;
27      AtomicInteger _refs=new AtomicInteger();
28  
29      /* ------------------------------------------------------------ */
30      public MessageImpl()
31      {
32          super(8);
33          _pool=null;
34      }
35  
36      /* ------------------------------------------------------------ */
37      public MessageImpl(MessagePool bayeux)
38      {
39          super(8);
40          _pool=bayeux;
41      }
42  
43      /* ------------------------------------------------------------ */
44      public void addJSON(StringBuffer buffer)
45      {
46          buffer.append(getJSON());
47      }
48  
49      /* ------------------------------------------------------------ */
50      /*
51       * (non-Javadoc)
52       * 
53       * @see java.util.HashMap#clear()
54       */
55      @Override
56      public void clear()
57      {
58          setAssociated(null);
59          _buffer=null;
60          _channel=null;
61          _clientId=null;
62          _data=null;
63          _ext=null;
64          _id=null;
65          _json=null;
66          _lazy=false;
67          _ext=null; // TODO recycle
68          _refs.set(0);
69  
70          Iterator<Map.Entry<String,Object>> iterator=super.entrySet().iterator();
71          while(iterator.hasNext())
72          {
73              Map.Entry<String,Object> entry=iterator.next();
74              String key=entry.getKey();
75              if (Bayeux.CHANNEL_FIELD.equals(key))
76                  entry.setValue(null);
77              else if (Bayeux.ID_FIELD.equals(key))
78                  entry.setValue(null);
79              else if (Bayeux.TIMESTAMP_FIELD.equals(key))
80                  entry.setValue(null);
81              else if (Bayeux.DATA_FIELD.equals(key))
82                  entry.setValue(null);
83              else if (Bayeux.EXT_FIELD.equals(key))
84                  entry.setValue(null);
85              else
86                  iterator.remove();
87          }
88          super.clear();
89      }
90  
91      /* ------------------------------------------------------------ */
92      public Object clone()
93      {
94          MessageImpl msg=new MessageImpl();
95          msg.putAll(this);
96          msg._channel=_channel;
97          msg._clientId=_clientId;
98          msg._id=_id;
99          return msg;
100     }
101 
102     /* ------------------------------------------------------------ */
103     public void decRef()
104     {
105         int r=_refs.decrementAndGet();
106         if (r == 0 && _pool != null)
107         {
108             setAssociated(null);
109             _pool.recycleMessage(this);
110         }
111         else if (r < 0)
112             throw new IllegalStateException();
113     }
114 
115     /* ------------------------------------------------------------ */
116     /*
117      * (non-Javadoc)
118      * 
119      * @see java.util.HashMap#entrySet()
120      */
121     @Override
122     public Set<java.util.Map.Entry<String,Object>> entrySet()
123     {
124         return Collections.unmodifiableSet(super.entrySet());
125     }
126 
127     /* ------------------------------------------------------------ */
128     public Message getAssociated()
129     {
130         return _associated;
131     }
132 
133     /* ------------------------------------------------------------ */
134     public ByteBuffer getBuffer()
135     {
136         return _buffer;
137     }
138 
139     /* ------------------------------------------------------------ */
140     public String getChannel()
141     {
142         return _channel;
143     }
144 
145     /* ------------------------------------------------------------ */
146     public String getClientId()
147     {
148         if (_clientId == null)
149             _clientId=(String)get(Bayeux.CLIENT_FIELD);
150         return _clientId;
151     }
152 
153     /* ------------------------------------------------------------ */
154     public Object getData()
155     {
156         return _data;
157     }
158 
159     /* ------------------------------------------------------------ */
160     public Map<String,Object> getExt(boolean create)
161     {
162         Object ext=_ext == null?get(Bayeux.EXT_FIELD):_ext;
163         if (ext instanceof Map)
164             return (Map<String,Object>)ext;
165         if (ext instanceof JSON.Literal)
166         {
167             JSON json=_pool == null?JSON.getDefault():_pool.getMsgJSON();
168             _ext=ext=json.fromJSON(ext.toString());
169             super.put(Bayeux.EXT_FIELD,ext);
170             return (Map<String,Object>)ext;
171         }
172 
173         if (!create)
174             return null;
175 
176         _ext=ext=new HashMap<String,Object>();
177         super.put(Bayeux.EXT_FIELD,ext);
178         return (Map<String,Object>)ext;
179 
180     }
181 
182     /* ------------------------------------------------------------ */
183     public String getId()
184     {
185         return _id;
186     }
187 
188     /* ------------------------------------------------------------ */
189     public String getJSON()
190     {
191         if (_json == null)
192         {
193             JSON json=_pool == null?JSON.getDefault():_pool.getMsgJSON();
194             StringBuffer buf=new StringBuffer(json.getStringBufferSize());
195             synchronized(buf)
196             {
197                 json.appendMap(buf,this);
198                 _json=buf.toString();
199             }
200         }
201         return _json;
202     }
203 
204     /* ------------------------------------------------------------ */
205     public int getRefs()
206     {
207         return _refs.get();
208     }
209 
210     /* ------------------------------------------------------------ */
211     public void incRef()
212     {
213         _refs.incrementAndGet();
214     }
215 
216     /* ------------------------------------------------------------ */
217     /**
218      * Lazy messages are queued but do not wake up waiting clients.
219      * 
220      * @return true if message is lazy
221      */
222     public boolean isLazy()
223     {
224         return _lazy;
225     }
226 
227     /* ------------------------------------------------------------ */
228     public boolean isSuccessful()
229     {
230         Boolean bool=(Boolean)get(Bayeux.SUCCESSFUL_FIELD);
231         return bool != null && bool.booleanValue();
232     }
233 
234     /* ------------------------------------------------------------ */
235     /*
236      * (non-Javadoc)
237      * 
238      * @see java.util.HashMap#keySet()
239      */
240     @Override
241     public Set<String> keySet()
242     {
243         return Collections.unmodifiableSet(super.keySet());
244     }
245 
246     /* ------------------------------------------------------------ */
247     /*
248      * (non-Javadoc)
249      * 
250      * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
251      */
252     @Override
253     public Object put(String key, Object value)
254     {
255         _json=null;
256         _buffer=null;
257         if (Bayeux.CHANNEL_FIELD.equals(key))
258             _channel=(String)value;
259         else if (Bayeux.ID_FIELD.equals(key))
260             _id=value.toString();
261         else if (Bayeux.CLIENT_FIELD.equals(key))
262             _clientId=(String)value;
263         else if (Bayeux.DATA_FIELD.equals(key))
264             _data=value;
265         else if (Bayeux.EXT_FIELD.equals(key))
266             _ext=value;
267         return super.put(key,value);
268     }
269 
270     /* ------------------------------------------------------------ */
271     /*
272      * (non-Javadoc)
273      * 
274      * @see java.util.HashMap#putAll(java.util.Map)
275      */
276     @Override
277     public void putAll(Map<? extends String,? extends Object> m)
278     {
279         _json=null;
280         _buffer=null;
281         super.putAll(m);
282         _channel=(String)get(Bayeux.CHANNEL_FIELD);
283         Object id=get(Bayeux.ID_FIELD);
284         _id=id == null?null:id.toString();
285         _data=get(Bayeux.DATA_FIELD);
286     }
287 
288     /* ------------------------------------------------------------ */
289     /*
290      * (non-Javadoc)
291      * 
292      * @see java.util.HashMap#remove(java.lang.Object)
293      */
294     @Override
295     public Object remove(Object key)
296     {
297         _json=null;
298         _buffer=null;
299         if (Bayeux.CHANNEL_FIELD.equals(key))
300             _channel=null;
301         else if (Bayeux.ID_FIELD.equals(key))
302             _id=null;
303         else if (Bayeux.DATA_FIELD.equals(key))
304             _data=null;
305         else if (Bayeux.EXT_FIELD.equals(key))
306             _ext=null;
307         return super.remove(key);
308     }
309 
310     /* ------------------------------------------------------------ */
311     public void setAssociated(Message associated)
312     {
313         if (_associated != associated)
314         {
315             if (_associated != null)
316                 ((MessageImpl)_associated).decRef();
317             _associated=associated;
318             if (_associated != null)
319                 ((MessageImpl)_associated).incRef();
320         }
321     }
322 
323     /* ------------------------------------------------------------ */
324     /**
325      * @param buffer
326      *            A cached buffer containing HTTP response headers and message
327      *            content, to be reused when sending one message to multiple
328      *            clients
329      */
330     public void setBuffer(ByteBuffer buffer)
331     {
332         _buffer=buffer;
333     }
334 
335     /* ------------------------------------------------------------ */
336     /**
337      * Lazy messages are queued but do not wake up waiting clients.
338      * 
339      * @param lazy
340      *            true if message is lazy
341      */
342     public void setLazy(boolean lazy)
343     {
344         _lazy=lazy;
345     }
346 
347     /* ------------------------------------------------------------ */
348     public String toString()
349     {
350         return getJSON();
351     }
352 }