001/**
002 *
003 * Copyright 2003-2007 Jive Software.
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jivesoftware.smackx.workgroup.util;
018
019import java.util.ArrayList;
020import java.util.Iterator;
021import java.util.List;
022import java.util.ListIterator;
023
024/**
025 * Utility methods frequently used by data classes and design-time
026 * classes.
027 */
028public final class ModelUtil {
029    private ModelUtil() {
030        //  Prevents instantiation.
031    }
032
033    /**
034     * This is a utility method that compares two objects when one or
035     * both of the objects might be <CODE>null</CODE>  The result of
036     * this method is determined as follows:
037     * <OL>
038     * <LI>If <CODE>o1</CODE> and <CODE>o2</CODE> are the same object
039     * according to the <CODE>==</CODE> operator, return
040     * <CODE>true</CODE>.
041     * <LI>Otherwise, if either <CODE>o1</CODE> or <CODE>o2</CODE> is
042     * <CODE>null</CODE>, return <CODE>false</CODE>.
043     * <LI>Otherwise, return <CODE>o1.equals(o2)</CODE>.
044     * </OL>
045     * <p/>
046     * This method produces the exact logically inverted result as the
047     * {@link #areDifferent(Object, Object)} method.<P>
048     * <p/>
049     * For array types, one of the <CODE>equals</CODE> methods in
050     * {@link java.util.Arrays} should be used instead of this method.
051     * Note that arrays with more than one dimension will require some
052     * custom code in order to implement <CODE>equals</CODE> properly.
053     */
054    public static final boolean areEqual(Object o1, Object o2) {
055        if (o1 == o2) {
056            return true;
057        }
058        else if (o1 == null || o2 == null) {
059            return false;
060        }
061        else {
062            return o1.equals(o2);
063        }
064    }
065
066    /**
067     * This is a utility method that compares two Booleans when one or
068     * both of the objects might be <CODE>null</CODE>  The result of
069     * this method is determined as follows:
070     * <OL>
071     * <LI>If <CODE>b1</CODE> and <CODE>b2</CODE> are both TRUE or
072     * neither <CODE>b1</CODE> nor <CODE>b2</CODE> is TRUE,
073     * return <CODE>true</CODE>.
074     * <LI>Otherwise, return <CODE>false</CODE>.
075     * </OL>
076     * <p/>
077     */
078    public static final boolean areBooleansEqual(Boolean b1, Boolean b2) {
079        // !jwetherb treat NULL the same as Boolean.FALSE
080        return (b1 == Boolean.TRUE && b2 == Boolean.TRUE) ||
081                (b1 != Boolean.TRUE && b2 != Boolean.TRUE);
082    }
083
084    /**
085     * This is a utility method that compares two objects when one or
086     * both of the objects might be <CODE>null</CODE>.  The result
087     * returned by this method is determined as follows:
088     * <OL>
089     * <LI>If <CODE>o1</CODE> and <CODE>o2</CODE> are the same object
090     * according to the <CODE>==</CODE> operator, return
091     * <CODE>false</CODE>.
092     * <LI>Otherwise, if either <CODE>o1</CODE> or <CODE>o2</CODE> is
093     * <CODE>null</CODE>, return <CODE>true</CODE>.
094     * <LI>Otherwise, return <CODE>!o1.equals(o2)</CODE>.
095     * </OL>
096     * <p/>
097     * This method produces the exact logically inverted result as the
098     * {@link #areEqual(Object, Object)} method.<P>
099     * <p/>
100     * For array types, one of the <CODE>equals</CODE> methods in
101     * {@link java.util.Arrays} should be used instead of this method.
102     * Note that arrays with more than one dimension will require some
103     * custom code in order to implement <CODE>equals</CODE> properly.
104     */
105    public static final boolean areDifferent(Object o1, Object o2) {
106        return !areEqual(o1, o2);
107    }
108
109
110    /**
111     * This is a utility method that compares two Booleans when one or
112     * both of the objects might be <CODE>null</CODE>  The result of
113     * this method is determined as follows:
114     * <OL>
115     * <LI>If <CODE>b1</CODE> and <CODE>b2</CODE> are both TRUE or
116     * neither <CODE>b1</CODE> nor <CODE>b2</CODE> is TRUE,
117     * return <CODE>false</CODE>.
118     * <LI>Otherwise, return <CODE>true</CODE>.
119     * </OL>
120     * <p/>
121     * This method produces the exact logically inverted result as the
122     * {@link #areBooleansEqual(Boolean, Boolean)} method.<P>
123     */
124    public static final boolean areBooleansDifferent(Boolean b1, Boolean b2) {
125        return !areBooleansEqual(b1, b2);
126    }
127
128
129    /**
130     * Returns <CODE>true</CODE> if the specified array is not null
131     * and contains a non-null element.  Returns <CODE>false</CODE>
132     * if the array is null or if all the array elements are null.
133     */
134    public static final boolean hasNonNullElement(Object[] array) {
135        if (array != null) {
136            final int n = array.length;
137            for (int i = 0; i < n; i++) {
138                if (array[i] != null) {
139                    return true;
140                }
141            }
142        }
143        return false;
144    }
145
146    /**
147     * Returns a single string that is the concatenation of all the
148     * strings in the specified string array.  A single space is
149     * put between each string array element.  Null array elements
150     * are skipped.  If the array itself is null, the empty string
151     * is returned.  This method is guaranteed to return a non-null
152     * value, if no expections are thrown.
153     */
154    public static final String concat(String[] strs) {
155        return concat(strs, " ");  //NOTRANS
156    }
157
158    /**
159     * Returns a single string that is the concatenation of all the
160     * strings in the specified string array.  The strings are separated
161     * by the specified delimiter.  Null array elements are skipped.  If
162     * the array itself is null, the empty string is returned.  This
163     * method is guaranteed to return a non-null value, if no expections
164     * are thrown.
165     */
166    public static final String concat(String[] strs, String delim) {
167        if (strs != null) {
168            final StringBuilder buf = new StringBuilder();
169            final int n = strs.length;
170            for (int i = 0; i < n; i++) {
171                final String str = strs[i];
172                if (str != null) {
173                    buf.append(str).append(delim);
174                }
175            }
176            final int length = buf.length();
177            if (length > 0) {
178                //  Trim trailing space.
179                buf.setLength(length - 1);
180            }
181            return buf.toString();
182        }
183        else {
184            return ""; // NOTRANS
185        }
186    }
187
188    /**
189     * Returns <CODE>true</CODE> if the specified {@link String} is not
190     * <CODE>null</CODE> and has a length greater than zero.  This is
191     * a very frequently occurring check.
192     */
193    public static final boolean hasLength(String s) {
194        return (s != null && s.length() > 0);
195    }
196
197
198    /**
199     * Returns <CODE>null</CODE> if the specified string is empty or
200     * <CODE>null</CODE>.  Otherwise the string itself is returned.
201     */
202    public static final String nullifyIfEmpty(String s) {
203        return ModelUtil.hasLength(s) ? s : null;
204    }
205
206    /**
207     * Returns <CODE>null</CODE> if the specified object is null
208     * or if its <CODE>toString()</CODE> representation is empty.
209     * Otherwise, the <CODE>toString()</CODE> representation of the
210     * object itself is returned.
211     */
212    public static final String nullifyingToString(Object o) {
213        return o != null ? nullifyIfEmpty(o.toString()) : null;
214    }
215
216    /**
217     * Determines if a string has been changed.
218     *
219     * @param oldString is the initial value of the String
220     * @param newString is the new value of the String
221     * @return true If both oldString and newString are null or if they are
222     *         both not null and equal to each other.  Otherwise returns false.
223     */
224    public static boolean hasStringChanged(String oldString, String newString) {
225        if (oldString == null && newString == null) {
226            return false;
227        }
228        else if ((oldString == null && newString != null)
229                || (oldString != null && newString == null)) {
230            return true;
231        }
232        else {
233            return !oldString.equals(newString);
234        }
235    }
236
237    public static String getTimeFromLong(long diff) {
238        final String HOURS = "h";
239        final String MINUTES = "min";
240        final String SECONDS = "sec";
241
242        final long MS_IN_A_DAY = 1000 * 60 * 60 * 24;
243        final long MS_IN_AN_HOUR = 1000 * 60 * 60;
244        final long MS_IN_A_MINUTE = 1000 * 60;
245        final long MS_IN_A_SECOND = 1000;
246        diff = diff % MS_IN_A_DAY;
247        long numHours = diff / MS_IN_AN_HOUR;
248        diff = diff % MS_IN_AN_HOUR;
249        long numMinutes = diff / MS_IN_A_MINUTE;
250        diff = diff % MS_IN_A_MINUTE;
251        long numSeconds = diff / MS_IN_A_SECOND;
252        diff = diff % MS_IN_A_SECOND;
253
254        StringBuilder buf = new StringBuilder();
255        if (numHours > 0) {
256            buf.append(numHours + " " + HOURS + ", ");
257        }
258
259        if (numMinutes > 0) {
260            buf.append(numMinutes + " " + MINUTES + ", ");
261        }
262
263        buf.append(numSeconds + " " + SECONDS);
264
265        String result = buf.toString();
266        return result;
267    }
268
269
270    /**
271     * Build a List of all elements in an Iterator.
272     */
273    public static <T> List<T> iteratorAsList(Iterator<T> i) {
274        ArrayList<T> list = new ArrayList<T>(10);
275        while (i.hasNext()) {
276            list.add(i.next());
277        }
278        return list;
279    }
280
281    /**
282     * Creates an Iterator that is the reverse of a ListIterator.
283     */
284    public static <T> Iterator<T> reverseListIterator(ListIterator<T> i) {
285        return new ReverseListIterator<T>(i);
286    }
287}
288
289/**
290 * An Iterator that is the reverse of a ListIterator.
291 */
292class ReverseListIterator<T> implements Iterator<T> {
293    private ListIterator<T> _i;
294
295    ReverseListIterator(ListIterator<T> i) {
296        _i = i;
297        while (_i.hasNext())
298            _i.next();
299    }
300
301    public boolean hasNext() {
302        return _i.hasPrevious();
303    }
304
305    public T next() {
306        return _i.previous();
307    }
308
309    public void remove() {
310        _i.remove();
311    }
312
313}
314
315
316
317
318
319
320
321
322
323
324