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.io.IOException;
18  import java.io.Reader;
19  import java.util.HashSet;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.cometd.Bayeux;
24  import org.cometd.Message;
25  import org.mortbay.util.ArrayQueue;
26  import org.mortbay.util.StringMap;
27  import org.mortbay.util.ajax.JSON;
28  
29  
30  public class MessagePool 
31  {
32      final private ArrayQueue<MessageImpl> _messagePool;
33      final private ArrayQueue<JSON.ReaderSource> _readerPool;
34  
35      /* ------------------------------------------------------------ */
36      public MessagePool()
37      {
38          this(50);
39      }
40  
41      /* ------------------------------------------------------------ */
42      public MessagePool(int capacity)
43      {
44          _messagePool=new ArrayQueue<MessageImpl>(capacity);
45          _readerPool=new ArrayQueue<JSON.ReaderSource>(capacity);
46      }
47      
48      /* ------------------------------------------------------------ */
49      /**
50       * @return the {@link JSON} instance used to convert data and ext fields
51       */
52      public JSON getJSON()
53      {
54          return _json;
55      }
56  
57      /* ------------------------------------------------------------ */
58      /**
59       * @param json the {@link JSON} instance used to convert data and ext fields
60       */
61      public void setJSON(JSON json)
62      {
63          _json=json;
64      }
65  
66      /* ------------------------------------------------------------ */
67      /**
68       * @return the {@link JSON} instance used to convert bayeux messages
69       */
70      public JSON getMsgJSON()
71      {
72          return _msgJSON;
73      }
74  
75      /* ------------------------------------------------------------ */
76      /**
77       * @param msgJSON the {@link JSON} instance used to convert bayeux messages
78       */
79      public void setMsgJSON(JSON msgJSON)
80      {
81          _msgJSON=msgJSON;
82      }
83  
84      /* ------------------------------------------------------------ */
85      /**
86       * @return the {@link JSON} instance used to convert batches of bayeux messages
87       */
88      public JSON getBatchJSON()
89      {
90          return _batchJSON;
91      }
92  
93      /* ------------------------------------------------------------ */
94      /**
95       * @param batchJSON the {@link JSON} instance used to convert batches of bayeux messages
96       */
97      public void setBatchJSON(JSON batchJSON)
98      {
99          _batchJSON=batchJSON;
100     }
101 
102 
103     /* ------------------------------------------------------------ */
104     public MessageImpl newMessage()
105     {
106         MessageImpl message=_messagePool.poll();
107         if (message==null)
108             message=new MessageImpl(this);
109         message.incRef();
110         return message;
111     }
112 
113     /* ------------------------------------------------------------ */
114     public MessageImpl newMessage(Message associated)
115     {
116         MessageImpl message=_messagePool.poll();
117         if (message==null)
118             message=new MessageImpl(this);
119         message.incRef();
120         if (associated!=null)
121             message.setAssociated(associated);
122         return message;
123     }
124 
125     /* ------------------------------------------------------------ */
126     public void recycleMessage(MessageImpl message)
127     {
128         message.clear();
129         _messagePool.offer(message);
130     }
131 
132     /* ------------------------------------------------------------ */
133     public Message[] parse(Reader reader) throws IOException
134     {
135         JSON.ReaderSource source =_readerPool.poll();
136         if (source==null)
137             source=new JSON.ReaderSource(reader);
138         else
139             source.setReader(reader);
140         
141         Object batch=_batchJSON.parse(source);
142         _readerPool.offer(source);
143 
144         if (batch==null)
145             return new Message[0]; 
146         if (batch.getClass().isArray())
147             return (Message[])batch;
148         return new Message[]{(Message)batch};
149     }
150 
151     /* ------------------------------------------------------------ */
152     public Message[] parse(String s) throws IOException
153     {
154         Object batch=_batchJSON.parse(new JSON.StringSource(s));
155         if (batch==null)
156             return new Message[0]; 
157         if (batch.getClass().isArray())
158             return (Message[])batch;
159         return new Message[]{(Message)batch};
160     }
161 
162     /* ------------------------------------------------------------ */
163     public void parseTo(String fodder, List<Message> messages)
164     {
165         Object batch=_batchJSON.parse(new JSON.StringSource(fodder));
166         if (batch==null)
167             return;
168         if (batch.getClass().isArray())
169         {
170             Message[] msgs=(Message[])batch;
171             for (int m=0;m<msgs.length;m++)
172                 messages.add(msgs[m]);
173         }
174         else
175             messages.add((Message)batch);
176     }
177 
178     /* ------------------------------------------------------------ */
179     /* ------------------------------------------------------------ */
180     private StringMap _fieldStrings = new StringMap();
181     private StringMap _valueStrings = new StringMap();
182     {
183         _fieldStrings.put(Bayeux.ADVICE_FIELD,Bayeux.ADVICE_FIELD);
184         _fieldStrings.put(Bayeux.CHANNEL_FIELD,Bayeux.CHANNEL_FIELD);
185         _fieldStrings.put(Bayeux.CLIENT_FIELD,Bayeux.CLIENT_FIELD);
186         _fieldStrings.put("connectionType","connectionType");
187         _fieldStrings.put(Bayeux.DATA_FIELD,Bayeux.DATA_FIELD);
188         _fieldStrings.put(Bayeux.ERROR_FIELD,Bayeux.ERROR_FIELD);
189         _fieldStrings.put(Bayeux.EXT_FIELD,Bayeux.EXT_FIELD);
190         _fieldStrings.put(Bayeux.ID_FIELD,Bayeux.ID_FIELD);
191         _fieldStrings.put(Bayeux.SUBSCRIPTION_FIELD,Bayeux.SUBSCRIPTION_FIELD);
192         _fieldStrings.put(Bayeux.SUCCESSFUL_FIELD,Bayeux.SUCCESSFUL_FIELD);
193         _fieldStrings.put(Bayeux.TIMESTAMP_FIELD,Bayeux.TIMESTAMP_FIELD);
194         _fieldStrings.put(Bayeux.TRANSPORT_FIELD,Bayeux.TRANSPORT_FIELD);
195         
196         _valueStrings.put(Bayeux.META_CLIENT,Bayeux.META_CLIENT);
197         _valueStrings.put(Bayeux.META_CONNECT,Bayeux.META_CONNECT);
198         _valueStrings.put(Bayeux.META_DISCONNECT,Bayeux.META_DISCONNECT);
199         _valueStrings.put(Bayeux.META_HANDSHAKE,Bayeux.META_HANDSHAKE);
200         _valueStrings.put(Bayeux.META_SUBSCRIBE,Bayeux.META_SUBSCRIBE);
201         _valueStrings.put(Bayeux.META_UNSUBSCRIBE,Bayeux.META_UNSUBSCRIBE);
202     }
203     
204 
205     /* ------------------------------------------------------------ */
206     /* ------------------------------------------------------------ */
207     private JSON _json = new JSON()
208     {
209         @Override
210         protected String toString(char[] buffer, int offset, int length)
211         {
212             Map.Entry entry = _valueStrings.getEntry(buffer,offset,length);
213             if (entry!=null)
214                 return (String)entry.getValue();
215             String s= new String(buffer,offset,length);
216             return s;
217         }
218     };
219 
220     /* ------------------------------------------------------------ */
221     /* ------------------------------------------------------------ */
222     private JSON _msgJSON = new JSON()
223     {
224         @Override
225         protected Map newMap()
226         {
227             return newMessage();
228         }
229 
230         @Override
231         protected String toString(char[] buffer, int offset, int length)
232         {
233             Map.Entry entry = _fieldStrings.getEntry(buffer,offset,length);
234             if (entry!=null)
235                 return (String)entry.getValue();
236             String s= new String(buffer,offset,length);
237             return s;
238         }
239 
240         @Override
241         protected JSON contextFor(String field)
242         {
243             return _json;
244         }
245     };
246 
247     /* ------------------------------------------------------------ */
248     /* ------------------------------------------------------------ */
249     private JSON _batchJSON = new JSON()
250     {
251         @Override
252         protected Map newMap()
253         {
254             return newMessage();
255         }
256 
257         @Override
258         protected Object[] newArray(int size)
259         {
260             return new Message[size]; // todo recycle
261         }
262 
263         @Override
264         protected JSON contextFor(String field)
265         {
266             return _json;
267         }
268 
269         @Override
270         protected JSON contextForArray()
271         {
272             return _msgJSON;
273         }
274     };
275 
276 }