001    /**
002     *   GRANITE DATA SERVICES
003     *   Copyright (C) 2006-2013 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    package org.granite.client.messaging.messages;
021    
022    import java.io.IOException;
023    import java.io.ObjectInput;
024    import java.io.ObjectOutput;
025    import java.util.HashMap;
026    import java.util.Map;
027    
028    import org.granite.util.UUIDUtil;
029    
030    /**
031     * @author Franck WOLFF
032     */
033    public abstract class AbstractMessage implements Message {
034            
035        private String id = UUIDUtil.randomUUID();
036        private String clientId = null;
037    
038            private long timestamp = 0L;
039        private long timeToLive = 0L;
040            
041            private Map<String, Object> headers = new HashMap<String, Object>();
042            
043            public AbstractMessage() {
044            }
045    
046            public AbstractMessage(String clientId) {
047                    this.clientId = clientId;
048            }
049    
050            public AbstractMessage(
051                    String id,
052                    String clientId,
053                    long timestamp,
054                    long timeToLive,
055                    Map<String, Object> headers) {
056    
057                    setId(id);
058                    this.clientId = clientId;
059                    this.timestamp = timestamp;
060                    this.timeToLive = timeToLive;
061                    this.headers = headers;
062            }
063    
064            @Override
065            public String getId() {
066                    return id;
067            }
068    
069            @Override
070            public void setId(String id) {
071                    if (id == null)
072                            throw new NullPointerException("id cannot be null");
073                    this.id = id;
074            }
075    
076            @Override
077            public String getClientId() {
078                    return clientId;
079            }
080    
081            @Override
082            public void setClientId(String clientId) {
083                    this.clientId = clientId;
084            }
085    
086            @Override
087            public long getTimestamp() {
088                    return timestamp;
089            }
090    
091            @Override
092            public void setTimestamp(long timestamp) {
093                    this.timestamp = timestamp;
094            }
095    
096            @Override
097            public long getTimeToLive() {
098                    return timeToLive;
099            }
100    
101            @Override
102            public void setTimeToLive(long timeToLive) {
103                    this.timeToLive = timeToLive;
104            }
105    
106            @Override
107            public Map<String, Object> getHeaders() {
108                    return headers;
109            }
110    
111            @Override
112            public void setHeaders(Map<String, Object> headers) {
113                    if (headers == null)
114                            throw new NullPointerException("headers cannot be null");
115                    this.headers = headers;
116            }
117    
118            @Override
119            public Object getHeader(String name) {
120                    return headers.get(name);
121            }
122    
123            @Override
124            public void setHeader(String name, Object value) {
125                    headers.put(name, value);
126            }
127    
128            @Override
129            public boolean headerExists(String name) {
130                    return headers.containsKey(name);
131            }
132    
133            @Override
134            public boolean isExpired() {
135                    return isExpired(System.currentTimeMillis());
136            }
137    
138            @Override
139            public boolean isExpired(long currentTimeMillis) {
140                    return getRemainingTimeToLive(currentTimeMillis) < 0;
141            }
142    
143            @Override
144            public long getRemainingTimeToLive() {
145                    return getRemainingTimeToLive(System.currentTimeMillis());
146            }
147    
148            @Override
149            public long getRemainingTimeToLive(long currentTimeMillis) {
150                    if (timestamp <= 0L || this.timeToLive <= 0L)
151                            throw new IllegalStateException("Unset timestamp/timeToLive: {timestamp=" + timestamp + ", timeToLive=" + timeToLive + "}");
152                    return timestamp + timeToLive - currentTimeMillis;
153            }
154            
155            protected void copy(AbstractMessage message) {
156                    message.id = id;
157                    message.clientId = clientId;
158                    message.timestamp = timestamp;
159                    message.timeToLive = timeToLive;
160                    message.headers.putAll(headers);
161            }
162    
163            @Override
164            public Message clone() throws CloneNotSupportedException {
165                    return copy();
166            }
167    
168            @Override
169            @SuppressWarnings("unchecked")
170            public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {           
171                String id = in.readUTF();
172                if (id == null)
173                    throw new RuntimeException("Message id cannot be null");
174                this.id = id;
175                
176                clientId = in.readUTF();
177    
178                    timestamp = in.readLong();
179                timeToLive = in.readLong();
180    
181                Map<String, Object> headers = (Map<String, Object>)in.readObject();
182                    if (headers != null)
183                            this.headers = headers;
184            }
185    
186            @Override
187            public void writeExternal(ObjectOutput out) throws IOException {
188                out.writeUTF(id);
189                if (clientId != null)
190                    out.writeUTF(clientId);
191                else
192                    out.writeObject(null);
193    
194                    out.writeLong(timestamp);
195                    out.writeLong(timeToLive);
196                    
197                    if (headers.size() > 0)
198                            out.writeObject(headers);
199                    else
200                            out.writeObject(null);
201            }
202    
203            @Override
204            public boolean equals(Object obj) {
205                    return (obj instanceof AbstractMessage && id.equals(((AbstractMessage)obj).id));
206            }
207    
208            @Override
209            public int hashCode() {
210                    return id.hashCode();
211            }
212            
213            @Override
214            public String toString() {
215                    return toString(new StringBuilder(getClass().getName()).append(" {")).append("\n}").toString();
216            }
217    
218            public StringBuilder toString(StringBuilder sb) {
219                    return sb
220                            .append("\n    id=").append(id)
221                            .append("\n    clientId=").append(clientId)
222                            .append("\n    timestamp=").append(timestamp)
223                            .append("\n    timeToLive=").append(timeToLive)
224                            .append("\n    headers=").append(headers);
225            }
226    }