1   //========================================================================
2   //Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
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   //http://www.apache.org/licenses/LICENSE-2.0
8   //Unless required by applicable law or agreed to in writing, software
9   //distributed under the License is distributed on an "AS IS" BASIS,
10  //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  //See the License for the specific language governing permissions and
12  //limitations under the License.
13  //========================================================================
14  
15  package org.mortbay.cometd;
16  
17  import java.nio.ByteBuffer;
18  import java.util.Collections;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  import java.util.Set;
23  import java.util.concurrent.atomic.AtomicInteger;
24  
25  import org.cometd.Bayeux;
26  import org.cometd.Message;
27  import org.mortbay.util.ajax.JSON;
28  
29  
30  public class MessageImpl extends HashMap<String, Object> implements Message, org.mortbay.util.ajax.JSON.Generator
31  {
32      MessagePool _pool;
33      String _clientId;
34      String _json;
35      String _channel;
36      String _id;
37      Object _data;
38      Message _associated;
39      AtomicInteger _refs=new AtomicInteger();
40      
41      private ByteBuffer _buffer;
42  
43      /* ------------------------------------------------------------ */
44      public MessageImpl()
45      {
46          super(8);
47      }
48      
49      /* ------------------------------------------------------------ */
50      public MessageImpl(MessagePool bayeux)
51      {
52          super(8);
53          _pool=bayeux;
54      }
55      
56      /* ------------------------------------------------------------ */
57      public int getRefs()
58      {
59          return _refs.get();
60      }
61      
62      /* ------------------------------------------------------------ */
63      public void incRef()
64      {
65          _refs.getAndIncrement();
66      }
67  
68      /* ------------------------------------------------------------ */
69      public void decRef()
70      {
71          int r= _refs.decrementAndGet();
72          if (r==0 && _pool!=null)
73              _pool.recycleMessage(this);
74          else if (r<0)
75              throw new IllegalStateException();
76      }
77  
78      /* ------------------------------------------------------------ */
79      public String getChannel()
80      {
81          return _channel;
82      }
83      
84      /* ------------------------------------------------------------ */
85      public String getClientId()
86      {
87          if (_clientId==null)
88              _clientId=(String)get(Bayeux.CLIENT_FIELD);
89          return _clientId;
90      }
91  
92      /* ------------------------------------------------------------ */
93      public String getId()
94      {
95          return _id;
96      }
97  
98      /* ------------------------------------------------------------ */
99      public Object getData()
100     {
101         return _data;
102     }
103     
104     /* ------------------------------------------------------------ */
105     public void addJSON(StringBuffer buffer)
106     {
107         buffer.append(getJSON());
108     }
109 
110     /* ------------------------------------------------------------ */
111     public String getJSON()
112     {
113         if (_json==null)
114         {
115             JSON json=_pool==null?JSON.getDefault():_pool.getMsgJSON();
116             StringBuffer buf = new StringBuffer(json.getStringBufferSize());
117             synchronized(buf)
118             {
119                 json.appendMap(buf,this);
120                 _json=buf.toString();
121             }
122         }
123         return _json;
124     }
125     
126     /* ------------------------------------------------------------ */
127     /* (non-Javadoc)
128      * @see java.util.HashMap#clear()
129      */
130     @Override
131     public void clear()
132     {
133         _json=null;
134         _buffer=null;
135         _id=null;
136         _channel=null;
137         _clientId=null;
138         setAssociated(null);
139         _refs.set(0);
140         Iterator<Map.Entry<String,Object>> iterator=super.entrySet().iterator();
141         while(iterator.hasNext())
142         {
143             Map.Entry<String, Object> entry=iterator.next();
144             String key=entry.getKey();
145             if (Bayeux.CHANNEL_FIELD.equals(key))
146                 entry.setValue(null);
147             else if (Bayeux.ID_FIELD.equals(key))
148                 entry.setValue(null);
149             else if (Bayeux.TIMESTAMP_FIELD.equals(key))
150                 entry.setValue(null);
151             else if (Bayeux.DATA_FIELD.equals(key))
152                 entry.setValue(null);
153             else
154                 iterator.remove();
155         }
156         super.clear();
157     }
158 
159     /* ------------------------------------------------------------ */
160     /* (non-Javadoc)
161      * @see java.util.HashMap#put(java.lang.Object, java.lang.Object)
162      */
163     @Override
164     public Object put(String key, Object value)
165     {
166         _json=null;
167         _buffer=null;
168         if (Bayeux.CHANNEL_FIELD.equals(key))
169             _channel=(String)value;
170         else if (Bayeux.ID_FIELD.equals(key))
171             _id=value.toString();
172         else if (Bayeux.CLIENT_FIELD.equals(key))
173             _clientId=(String)value;
174         else if (Bayeux.DATA_FIELD.equals(key))
175             _data=value;
176         return super.put(key,value);
177     }
178 
179     /* ------------------------------------------------------------ */
180     /* (non-Javadoc)
181      * @see java.util.HashMap#putAll(java.util.Map)
182      */
183     @Override
184     public void putAll(Map<? extends String, ? extends Object> m)
185     {
186         _json=null;
187         _buffer=null;
188         super.putAll(m);
189         _channel=(String)get(Bayeux.CHANNEL_FIELD);
190         Object id=get(Bayeux.ID_FIELD);
191         _id=id==null?null:id.toString();
192         _data=get(Bayeux.DATA_FIELD);
193     }
194 
195     /* ------------------------------------------------------------ */
196     /* (non-Javadoc)
197      * @see java.util.HashMap#remove(java.lang.Object)
198      */
199     @Override
200     public Object remove(Object key)
201     {
202         _json=null;
203         _buffer=null;
204         if (Bayeux.CHANNEL_FIELD.equals(key))
205             _channel=null;
206         else if (Bayeux.ID_FIELD.equals(key))
207             _id=null;
208         else if (Bayeux.DATA_FIELD.equals(key))
209             _data=null;
210         return super.remove(key);
211     }
212 
213     /* ------------------------------------------------------------ */
214     /* (non-Javadoc)
215      * @see java.util.HashMap#entrySet()
216      */
217     @Override
218     public Set<java.util.Map.Entry<String, Object>> entrySet()
219     {
220         return Collections.unmodifiableSet(super.entrySet());
221     }
222 
223     /* ------------------------------------------------------------ */
224     /* (non-Javadoc)
225      * @see java.util.HashMap#keySet()
226      */
227     @Override
228     public Set<String> keySet()
229     {
230         return Collections.unmodifiableSet(super.keySet());
231     }
232 
233     /* ------------------------------------------------------------ */
234     public Message getAssociated()
235     {
236         return _associated;
237     }
238 
239     /* ------------------------------------------------------------ */
240     public void setAssociated(Message associated)
241     {
242         if (_associated!=associated)
243         {
244             if (_associated!=null)
245                 ((MessageImpl)_associated).decRef();
246             _associated=associated;
247             if (_associated!=null)
248                 ((MessageImpl)_associated).incRef();
249         }
250     }
251         
252     /* ------------------------------------------------------------ */
253     /**
254      * @param buffer A cached buffer containing HTTP response headers 
255      * and message content, to be reused when sending one message
256      * to multiple clients 
257      */
258     public void setBuffer(ByteBuffer buffer)
259     {
260         _buffer = buffer;
261     }
262     
263     /* ------------------------------------------------------------ */
264     public ByteBuffer getBuffer()
265     {
266         return _buffer;
267     }
268  }