001/*
002 *  jDTAUS Core API
003 *  Copyright (C) 2005 Christian Schulte
004 *  <cs@schulte.it>
005 *
006 *  This library is free software; you can redistribute it and/or
007 *  modify it under the terms of the GNU Lesser General Public
008 *  License as published by the Free Software Foundation; either
009 *  version 2.1 of the License, or any later version.
010 *
011 *  This library is distributed in the hope that it will be useful,
012 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
013 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 *  Lesser General Public License for more details.
015 *
016 *  You should have received a copy of the GNU Lesser General Public
017 *  License along with this library; if not, write to the Free Software
018 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
019 *
020 */
021package org.jdtaus.core.text;
022
023import java.io.Serializable;
024import java.rmi.server.UID;
025import java.util.Comparator;
026import java.util.Locale;
027
028/**
029 * Application message.
030 * <p>Application messages consist of at least the two properties
031 * {@code timestamp} and {@code formatArguments}. The {@code timestamp} property
032 * will be initialized during instantiation to hold the timestamp of instance
033 * creation. Property {@code formatArguments} holds the arguments to use
034 * for formatting message text. It is recommended that subclasses of this class
035 * are declared {@code final} so that calling {@code getClass()} on a message
036 * instance always returns a type uniquely identifying a message type in the
037 * system.</p>
038 *
039 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
040 * @version $JDTAUS: Message.java 8743 2012-10-07 03:06:20Z schulte $
041 *
042 * @see MessageEvent
043 */
044public abstract class Message implements Cloneable, Serializable
045{
046    //--Constants---------------------------------------------------------------
047
048    /**
049     * Comparator for sorting messages in ascending order of occurence.
050     * <p><b>Note:</b><br/>
051     * This comparator imposes orderings that are inconsistent with equals.</p>
052     */
053    public static final Comparator ASCENDING =
054        new AscendingMessageComparator();
055
056    /**
057     * Comparator for sorting messages in descending order of occurence.
058     * <p><b>Note:</b><br/>
059     * This comparator imposes orderings that are inconsistent with equals.</p>
060     */
061    public static final Comparator DESCENDING =
062        new DescendingMessageComparator();
063
064    /** Serial version UID for backwards compatibility with 1.0.x classes. */
065    private static final long serialVersionUID = -5747726994506247015L;
066
067    //---------------------------------------------------------------Constants--
068    //--Constructors------------------------------------------------------------
069
070    /** Creates a new {@code Message} instance. */
071    public Message()
072    {
073        super();
074        this.timestamp = System.currentTimeMillis();
075        this.uid = new UID();
076    }
077
078    //------------------------------------------------------------Constructors--
079    //--Message-----------------------------------------------------------------
080
081    /**
082     * Unique message identifier.
083     * @serial
084     */
085    private UID uid;
086
087    /**
088     * The timestamp this message got created.
089     * @serial
090     */
091    private long timestamp;
092
093    /**
094     * Getter for property {@code timestamp}.
095     *
096     * @return the timestamp this message got created.
097     */
098    public final long getTimestamp()
099    {
100        return this.timestamp;
101    }
102
103    /**
104     * Getter for property {@code formatArguments}.
105     *
106     * @param locale the locale to be used for the arguments to return.
107     *
108     * @return the arguments to use when formatting the message text.
109     */
110    public abstract Object[] getFormatArguments( Locale locale );
111
112    /**
113     * Gets the formatted message text.
114     *
115     * @param locale the locale to be used for the text to return.
116     *
117     * @return the text of the message for {@code locale}.
118     */
119    public abstract String getText( Locale locale );
120
121    /**
122     * Creates a string representing the properties of the instance.
123     *
124     * @return a string representing the properties of the instance.
125     */
126    private String internalString()
127    {
128        final StringBuffer buf = new StringBuffer( 500 );
129
130        buf.append( "\n\ttimestamp=" ).append( this.timestamp ).
131            append( "\n\tuid=" ).append( this.uid ).
132            append( "\n\ttext=" ).append( this.getText( Locale.getDefault() ) );
133
134        final Object[] args = this.getFormatArguments( Locale.getDefault() );
135        for ( int i = 0; i < args.length; i++ )
136        {
137            buf.append( "\n\tformatArguments[" ).append( i ).append( "]=" ).
138                append( args[i] );
139
140        }
141
142        return buf.toString();
143    }
144
145    //-----------------------------------------------------------------Message--
146    //--Object------------------------------------------------------------------
147
148    /**
149     * Returns a string representation of the object.
150     *
151     * @return a string representation of the object.
152     */
153    public String toString()
154    {
155        return super.toString() + this.internalString();
156    }
157
158    /**
159     * Returns a hash code value for this object.
160     *
161     * @return a hash code value for this object.
162     */
163    public final int hashCode()
164    {
165        return this.uid.hashCode();
166    }
167
168    /**
169     * Indicates whether some other object is equal to this one.
170     * <p>Messages internally cary a UID which is created during instantiation.
171     * This UID is used for comparing {@code o} with the instance.</p>
172     *
173     * @param o the reference object with which to compare.
174     *
175     * @return {@code true} if this object is the same as {@code o};
176     * {@code false} otherwise.
177     *
178     * @see UID
179     */
180    public final boolean equals( final Object o )
181    {
182        return o == this || ( o instanceof Message &&
183            ( ( Message ) o ).uid.equals( this.uid ) );
184
185    }
186
187    /**
188     * Creates and returns a copy of this object.
189     *
190     * @return a clone of this instance.
191     */
192    public Object clone()
193    {
194        try
195        {
196            return super.clone();
197        }
198        catch ( final CloneNotSupportedException e )
199        {
200            throw new AssertionError( e );
201        }
202    }
203
204    //------------------------------------------------------------------Object--
205}
206
207/**
208 * Comparator for sorting messages in ascending order of occurence.
209 * <p><b>Note:</b><br/>
210 * This comparator imposes orderings that are inconsistent with equals.</p>
211 *
212 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
213 * @version $JDTAUS: Message.java 8743 2012-10-07 03:06:20Z schulte $
214 */
215class AscendingMessageComparator implements Comparator, Serializable
216{
217
218    /** Creates a new {@code AscendingMessageComparator} instance. */
219    AscendingMessageComparator()
220    {
221        super();
222    }
223
224    //--Comparator--------------------------------------------------------------
225
226    /**
227     * {@inheritDoc}
228     *
229     * @throws NullPointerException if either {@code o1} or {@code o2} is
230     * {@code null}.
231     * @throws ClassCastException if either {@code o1} or {@code o2} is
232     * not an instance of {@code Message}.
233     */
234    public int compare( final Object o1, final Object o2 )
235    {
236        if ( o1 == null )
237        {
238            throw new NullPointerException( "o1" );
239        }
240        if ( o2 == null )
241        {
242            throw new NullPointerException( "o2" );
243        }
244        if ( !( o1 instanceof Message ) )
245        {
246            throw new ClassCastException( o1.getClass().getName() );
247        }
248        if ( !( o2 instanceof Message ) )
249        {
250            throw new ClassCastException( o2.getClass().getName() );
251        }
252
253        // TODO JDK 1.5 Long.valueOf(long)
254        final Long l1 = new Long( ( ( Message ) o1 ).getTimestamp() );
255        final Long l2 = new Long( ( ( Message ) o2 ).getTimestamp() );
256        return l1.compareTo( l2 );
257    }
258
259    //--------------------------------------------------------------Comparator--
260}
261
262/**
263 * Comparator for sorting messages in descending order of occurence.
264 * <p><b>Note:</b><br/>
265 * This comparator imposes orderings that are inconsistent with equals.</p>
266 *
267 * @author <a href="mailto:cs@schulte.it">Christian Schulte</a>
268 * @version $JDTAUS: Message.java 8743 2012-10-07 03:06:20Z schulte $
269 */
270class DescendingMessageComparator
271    extends AscendingMessageComparator
272{
273
274    /** Creates a new {@code DescendingMessageComparator} instance. */
275    DescendingMessageComparator()
276    {
277        super();
278    }
279
280    //--Comparator--------------------------------------------------------------
281
282    /**
283     * {@inheritDoc}
284     *
285     * @throws NullPointerException if either {@code o1} or {@code o2} is
286     * {@code null}.
287     * @throws ClassCastException if either {@code o1} or {@code o2} is
288     * not an instance of {@code Message}.
289     */
290    public int compare( final Object o1, final Object o2 )
291    {
292        return super.compare( o2, o1 );
293    }
294
295    //--------------------------------------------------------------Comparator--
296}