001    /*
002      GRANITE DATA SERVICES
003      Copyright (C) 2012 GRANITE DATA SERVICES S.A.S.
004    
005      This file is part of Granite Data Services.
006    
007      Granite Data Services is free software; you can redistribute it and/or modify
008      it under the terms of the GNU Library General Public License as published by
009      the Free Software Foundation; either version 2 of the License, or (at your
010      option) any later version.
011    
012      Granite Data Services is distributed in the hope that it will be useful, but
013      WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
014      FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License
015      for more details.
016    
017      You should have received a copy of the GNU Library General Public License
018      along with this library; if not, see <http://www.gnu.org/licenses/>.
019    */
020    
021    package org.granite.client.messaging.messages;
022    
023    import java.io.IOException;
024    import java.io.ObjectInput;
025    import java.io.ObjectOutput;
026    import java.util.HashMap;
027    import java.util.Map;
028    
029    import org.granite.util.UUIDUtil;
030    
031    /**
032     * @author Franck WOLFF
033     */
034    public abstract class AbstractMessage implements Message {
035            
036        private String id = UUIDUtil.randomUUID();
037        private String clientId = null;
038    
039            private long timestamp = 0L;
040        private long timeToLive = 0L;
041            
042            private Map<String, Object> headers = new HashMap<String, Object>();
043            
044            public AbstractMessage() {
045            }
046    
047            public AbstractMessage(String clientId) {
048                    this.clientId = clientId;
049            }
050    
051            public AbstractMessage(
052                    String id,
053                    String clientId,
054                    long timestamp,
055                    long timeToLive,
056                    Map<String, Object> headers) {
057    
058                    setId(id);
059                    this.clientId = clientId;
060                    this.timestamp = timestamp;
061                    this.timeToLive = timeToLive;
062                    this.headers = headers;
063            }
064    
065            @Override
066            public String getId() {
067                    return id;
068            }
069    
070            @Override
071            public void setId(String id) {
072                    if (id == null)
073                            throw new NullPointerException("id cannot be null");
074                    this.id = id;
075            }
076    
077            @Override
078            public String getClientId() {
079                    return clientId;
080            }
081    
082            @Override
083            public void setClientId(String clientId) {
084                    this.clientId = clientId;
085            }
086    
087            @Override
088            public long getTimestamp() {
089                    return timestamp;
090            }
091    
092            @Override
093            public void setTimestamp(long timestamp) {
094                    this.timestamp = timestamp;
095            }
096    
097            @Override
098            public long getTimeToLive() {
099                    return timeToLive;
100            }
101    
102            @Override
103            public void setTimeToLive(long timeToLive) {
104                    this.timeToLive = timeToLive;
105            }
106    
107            @Override
108            public Map<String, Object> getHeaders() {
109                    return headers;
110            }
111    
112            @Override
113            public void setHeaders(Map<String, Object> headers) {
114                    if (headers == null)
115                            throw new NullPointerException("headers cannot be null");
116                    this.headers = headers;
117            }
118    
119            @Override
120            public Object getHeader(String name) {
121                    return headers.get(name);
122            }
123    
124            @Override
125            public void setHeader(String name, Object value) {
126                    headers.put(name, value);
127            }
128    
129            @Override
130            public boolean headerExists(String name) {
131                    return headers.containsKey(name);
132            }
133    
134            @Override
135            public boolean isExpired() {
136                    return isExpired(System.currentTimeMillis());
137            }
138    
139            @Override
140            public boolean isExpired(long currentTimeMillis) {
141                    return getRemainingTimeToLive(currentTimeMillis) < 0;
142            }
143    
144            @Override
145            public long getRemainingTimeToLive() {
146                    return getRemainingTimeToLive(System.currentTimeMillis());
147            }
148    
149            @Override
150            public long getRemainingTimeToLive(long currentTimeMillis) {
151                    if (timestamp <= 0L || this.timeToLive <= 0L)
152                            throw new IllegalStateException("Unset timestamp/timeToLive: {timestamp=" + timestamp + ", timeToLive=" + timeToLive + "}");
153                    return timestamp + timeToLive - currentTimeMillis;
154            }
155            
156            protected void copy(AbstractMessage message) {
157                    message.id = id;
158                    message.clientId = clientId;
159                    message.timestamp = timestamp;
160                    message.timeToLive = timeToLive;
161                    message.headers.putAll(headers);
162            }
163    
164            @Override
165            public Message clone() throws CloneNotSupportedException {
166                    return copy();
167            }
168    
169            @Override
170            @SuppressWarnings("unchecked")
171            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {           
172                String id = in.readUTF();
173                if (id == null)
174                    throw new RuntimeException("Message id cannot be null");
175                this.id = id;
176                
177                clientId = in.readUTF();
178    
179                    timestamp = in.readLong();
180                timeToLive = in.readLong();
181    
182                Map<String, Object> headers = (Map<String, Object>)in.readObject();
183                    if (headers != null)
184                            this.headers = headers;
185            }
186    
187            @Override
188            public void writeExternal(ObjectOutput out) throws IOException {
189                out.writeUTF(id);
190                if (clientId != null)
191                    out.writeUTF(clientId);
192                else
193                    out.writeObject(null);
194    
195                    out.writeLong(timestamp);
196                    out.writeLong(timeToLive);
197                    
198                    if (headers.size() > 0)
199                            out.writeObject(headers);
200                    else
201                            out.writeObject(null);
202            }
203    
204            @Override
205            public boolean equals(Object obj) {
206                    return (obj instanceof AbstractMessage && id.equals(((AbstractMessage)obj).id));
207            }
208    
209            @Override
210            public int hashCode() {
211                    return id.hashCode();
212            }
213            
214            @Override
215            public String toString() {
216                    return toString(new StringBuilder(getClass().getName()).append(" {")).append("\n}").toString();
217            }
218    
219            public StringBuilder toString(StringBuilder sb) {
220                    return sb
221                            .append("\n    id=").append(id)
222                            .append("\n    clientId=").append(clientId)
223                            .append("\n    timestamp=").append(timestamp)
224                            .append("\n    timeToLive=").append(timeToLive)
225                            .append("\n    headers=").append(headers);
226            }
227    }