package org.mortbay.cometd; import java.nio.ByteBuffer; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import org.cometd.Bayeux; import org.cometd.Message; import org.mortbay.util.ajax.JSON; public class MessageImpl extends HashMap implements Message, org.mortbay.util.ajax.JSON.Generator { Message _associated; ByteBuffer _buffer; String _channel; String _clientId; Object _data; Object _ext; String _id; String _json; boolean _lazy=false; final MessagePool _pool; AtomicInteger _refs=new AtomicInteger(); /* ------------------------------------------------------------ */ public MessageImpl() { super(8); _pool=null; } /* ------------------------------------------------------------ */ public MessageImpl(MessagePool bayeux) { super(8); _pool=bayeux; } /* ------------------------------------------------------------ */ public void addJSON(StringBuffer buffer) { buffer.append(getJSON()); } /* ------------------------------------------------------------ */ /* * (non-Javadoc) * * @see java.util.HashMap#clear() */ @Override public void clear() { setAssociated(null); _buffer=null; _channel=null; _clientId=null; _data=null; _ext=null; _id=null; _json=null; _lazy=false; _ext=null; // TODO recycle _refs.set(0); Iterator> iterator=super.entrySet().iterator(); while(iterator.hasNext()) { Map.Entry entry=iterator.next(); String key=entry.getKey(); if (Bayeux.CHANNEL_FIELD.equals(key)) entry.setValue(null); else if (Bayeux.ID_FIELD.equals(key)) entry.setValue(null); else if (Bayeux.TIMESTAMP_FIELD.equals(key)) entry.setValue(null); else if (Bayeux.DATA_FIELD.equals(key)) entry.setValue(null); else if (Bayeux.EXT_FIELD.equals(key)) entry.setValue(null); else iterator.remove(); } super.clear(); } /* ------------------------------------------------------------ */ public Object clone() { MessageImpl msg=new MessageImpl(); msg.putAll(this); msg._channel=_channel; msg._clientId=_clientId; msg._id=_id; return msg; } /* ------------------------------------------------------------ */ public void decRef() { int r=_refs.decrementAndGet(); if (r == 0 && _pool != null) { setAssociated(null); _pool.recycleMessage(this); } else if (r < 0) throw new IllegalStateException(); } /* ------------------------------------------------------------ */ /* * (non-Javadoc) * * @see java.util.HashMap#entrySet() */ @Override public Set> entrySet() { return Collections.unmodifiableSet(super.entrySet()); } /* ------------------------------------------------------------ */ public Message getAssociated() { return _associated; } /* ------------------------------------------------------------ */ public ByteBuffer getBuffer() { return _buffer; } /* ------------------------------------------------------------ */ public String getChannel() { return _channel; } /* ------------------------------------------------------------ */ public String getClientId() { if (_clientId == null) _clientId=(String)get(Bayeux.CLIENT_FIELD); return _clientId; } /* ------------------------------------------------------------ */ public Object getData() { return _data; } /* ------------------------------------------------------------ */ public Map getExt(boolean create) { Object ext=_ext == null?get(Bayeux.EXT_FIELD):_ext; if (ext instanceof Map) return (Map)ext; if (ext instanceof JSON.Literal) { JSON json=_pool == null?JSON.getDefault():_pool.getMsgJSON(); _ext=ext=json.fromJSON(ext.toString()); super.put(Bayeux.EXT_FIELD,ext); return (Map)ext; } if (!create) return null; _ext=ext=new HashMap(); super.put(Bayeux.EXT_FIELD,ext); return (Map)ext; } /* ------------------------------------------------------------ */ public String getId() { return _id; } /* ------------------------------------------------------------ */ public String getJSON() { if (_json == null) { JSON json=_pool == null?JSON.getDefault():_pool.getMsgJSON(); StringBuffer buf=new StringBuffer(json.getStringBufferSize()); synchronized(buf) { json.appendMap(buf,this); _json=buf.toString(); } } return _json; } /* ------------------------------------------------------------ */ public int getRefs() { return _refs.get(); } /* ------------------------------------------------------------ */ public void incRef() { _refs.incrementAndGet(); } /* ------------------------------------------------------------ */ /** * Lazy messages are queued but do not wake up waiting clients. * * @return true if message is lazy */ public boolean isLazy() { return _lazy; } /* ------------------------------------------------------------ */ public boolean isSuccessful() { Boolean bool=(Boolean)get(Bayeux.SUCCESSFUL_FIELD); return bool != null && bool.booleanValue(); } /* ------------------------------------------------------------ */ /* * (non-Javadoc) * * @see java.util.HashMap#keySet() */ @Override public Set keySet() { return Collections.unmodifiableSet(super.keySet()); } /* ------------------------------------------------------------ */ /* * (non-Javadoc) * * @see java.util.HashMap#put(java.lang.Object, java.lang.Object) */ @Override public Object put(String key, Object value) { _json=null; _buffer=null; if (Bayeux.CHANNEL_FIELD.equals(key)) _channel=(String)value; else if (Bayeux.ID_FIELD.equals(key)) _id=value.toString(); else if (Bayeux.CLIENT_FIELD.equals(key)) _clientId=(String)value; else if (Bayeux.DATA_FIELD.equals(key)) _data=value; else if (Bayeux.EXT_FIELD.equals(key)) _ext=value; return super.put(key,value); } /* ------------------------------------------------------------ */ /* * (non-Javadoc) * * @see java.util.HashMap#putAll(java.util.Map) */ @Override public void putAll(Map m) { _json=null; _buffer=null; super.putAll(m); _channel=(String)get(Bayeux.CHANNEL_FIELD); Object id=get(Bayeux.ID_FIELD); _id=id == null?null:id.toString(); _data=get(Bayeux.DATA_FIELD); } /* ------------------------------------------------------------ */ /* * (non-Javadoc) * * @see java.util.HashMap#remove(java.lang.Object) */ @Override public Object remove(Object key) { _json=null; _buffer=null; if (Bayeux.CHANNEL_FIELD.equals(key)) _channel=null; else if (Bayeux.ID_FIELD.equals(key)) _id=null; else if (Bayeux.DATA_FIELD.equals(key)) _data=null; else if (Bayeux.EXT_FIELD.equals(key)) _ext=null; return super.remove(key); } /* ------------------------------------------------------------ */ public void setAssociated(Message associated) { if (_associated != associated) { if (_associated != null) ((MessageImpl)_associated).decRef(); _associated=associated; if (_associated != null) ((MessageImpl)_associated).incRef(); } } /* ------------------------------------------------------------ */ /** * @param buffer * A cached buffer containing HTTP response headers and message * content, to be reused when sending one message to multiple * clients */ public void setBuffer(ByteBuffer buffer) { _buffer=buffer; } /* ------------------------------------------------------------ */ /** * Lazy messages are queued but do not wake up waiting clients. * * @param lazy * true if message is lazy */ public void setLazy(boolean lazy) { _lazy=lazy; } /* ------------------------------------------------------------ */ public String toString() { return getJSON(); } }