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