001: /*
002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/util/CmsUUID.java,v $
003: * Date : $Date: 2008-02-27 12:05:36 $
004: * Version: $Revision: 1.30 $
005: *
006: * This library is part of OpenCms -
007: * the Open Source Content Management System
008: *
009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010: *
011: * This library is free software; you can redistribute it and/or
012: * modify it under the terms of the GNU Lesser General Public
013: * License as published by the Free Software Foundation; either
014: * version 2.1 of the License, or (at your option) any later version.
015: *
016: * This library is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: * Lesser General Public License for more details.
020: *
021: * For further information about Alkacon Software GmbH, please see the
022: * company website: http://www.alkacon.com
023: *
024: * For further information about OpenCms, please see the
025: * project website: http://www.opencms.org
026: *
027: * You should have received a copy of the GNU Lesser General Public
028: * License along with this library; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031:
032: package org.opencms.util;
033:
034: import org.opencms.main.CmsIllegalArgumentException;
035: import org.opencms.main.CmsInitException;
036: import org.opencms.main.CmsLog;
037:
038: import java.io.Externalizable;
039: import java.io.IOException;
040: import java.io.ObjectInput;
041: import java.io.ObjectOutput;
042: import java.io.Serializable;
043:
044: import org.apache.commons.logging.Log;
045:
046: import org.safehaus.uuid.EthernetAddress;
047: import org.safehaus.uuid.UUID;
048: import org.safehaus.uuid.UUIDGenerator;
049:
050: /**
051: * Generates a UUID using spatial and temporal uniqueness.<p>
052: *
053: * Spatial uniqueness is derived from
054: * ethernet address (MAC, 802.1); temporal from system clock.<p>
055: *
056: * For more information about the algorithm used, please see
057: * <a href="http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt">
058: * draft-leach-uuids-guids-01.txt</a>.<p>
059: *
060: * Because Java is unable to read the MAC address of the machine
061: * (without using JNI), the MAC address has to be provided first
062: * by using the static {@link #init(String)} method.<p>
063: *
064: * This class is just a facade wrapper for the "real" UUID implementation.<p>
065: *
066: * @author Alexander Kandzior
067: *
068: * @version $Revision: 1.30 $
069: *
070: * @since 6.0.0
071: */
072: public final class CmsUUID extends Object implements Serializable,
073: Cloneable, Comparable, Externalizable {
074:
075: /** The log object for this class. */
076: private static final Log LOG = CmsLog.getLog(CmsUUID.class);
077:
078: /** Ethernet address of the server machine. */
079: private static EthernetAddress m_ethernetAddress;
080:
081: /** OpenCms UUID (name based uuid of "www.opencms.org" in the dns name space). */
082: private static UUID m_opencmsUUID = UUIDGenerator.getInstance()
083: .generateNameBasedUUID(new UUID(UUID.NAMESPACE_DNS),
084: "www.opencms.org");
085:
086: /** Constant for the null UUID. */
087: private static final CmsUUID NULL_UUID = new CmsUUID(UUID
088: .getNullUUID());
089:
090: /** Serial version UID required for safe serialization. */
091: private static final long serialVersionUID = 1736324454709298676L;
092:
093: /** Internal UUID implementation. */
094: private transient UUID m_uuid;
095:
096: /**
097: * Creates a new UUID.<p>
098: *
099: * Please note that the static init() method has to be called first to initialize the
100: * internet address of the machine.<p>
101: */
102: public CmsUUID() {
103:
104: if (m_ethernetAddress == null) {
105: // if no ethernet address is available, generate a dummy
106: // this is required because otherwise we can't ever de-serialize a CmsUUID outside of OpenCms,
107: // since the empty constructor is called when the de-serialization takes place
108: init(getDummyEthernetAddress());
109: }
110: m_uuid = UUIDGenerator.getInstance().generateTimeBasedUUID(
111: m_ethernetAddress);
112: }
113:
114: /**
115: * Create a UUID based on a binary data array.<p>
116: *
117: * @param data a binary data array representing a UUID
118: */
119: public CmsUUID(byte[] data) {
120:
121: m_uuid = new UUID(data);
122: }
123:
124: /**
125: * Create a UUID based on a String.<p>
126: *
127: * @param uuid a String representing a UUID
128: * @throws NumberFormatException in case uuid is not a valid UUID
129: */
130: public CmsUUID(String uuid) throws NumberFormatException {
131:
132: m_uuid = new UUID(uuid);
133: }
134:
135: /**
136: * Create a new UUID based on another one (used internal for cloning).<p>
137: *
138: * @param uuid the UUID to clone
139: */
140: private CmsUUID(UUID uuid) {
141:
142: m_uuid = uuid;
143: }
144:
145: /**
146: * Check that the given id is not the null id.<p>
147: *
148: * @param id the id to check
149: * @param canBeNull only if flag is set, <code>null</code> is accepted
150: *
151: * @see #isNullUUID()
152: */
153: public static void checkId(CmsUUID id, boolean canBeNull) {
154:
155: if (canBeNull && (id == null)) {
156: return;
157: }
158: if ((!canBeNull && (id == null)) || id.isNullUUID()) {
159: throw new CmsIllegalArgumentException(Messages.get()
160: .container(Messages.ERR_INVALID_UUID_1, id));
161: }
162: }
163:
164: /**
165: * Returns a constant (name based) UUID,
166: * based on the given name in the OpenCms name space.
167: *
168: * @param name the name to derive the uuid from
169: * @return name based UUID of the given name
170: */
171: public static CmsUUID getConstantUUID(String name) {
172:
173: return new CmsUUID(UUIDGenerator.getInstance()
174: .generateNameBasedUUID(m_opencmsUUID, name));
175: }
176:
177: /**
178: * Returns a String representing a dummy (random based) ethernet address.<p>
179: *
180: * @return a String representing a dummy (random based) ethernet address
181: */
182: public static String getDummyEthernetAddress() {
183:
184: return UUIDGenerator.getInstance().getDummyAddress().toString();
185: }
186:
187: /**
188: * Returns a null UUID,
189: * use this null UUID to check if a UUID has been initialized or not.<p>
190: *
191: * @return a null UUID
192: */
193: public static CmsUUID getNullUUID() {
194:
195: return NULL_UUID;
196: }
197:
198: /**
199: * Returns a constant (name based) UUID for OpenCms,
200: * based on "www.opencms.org" in the dns name space.
201: *
202: * @return name based UUID of OpenCms
203: */
204: public static CmsUUID getOpenCmsUUID() {
205:
206: return new CmsUUID(m_opencmsUUID);
207: }
208:
209: /**
210: * Initialize the UUID generator with the ethernet address of the server machine.<p>
211: *
212: * The ethernetAddress parameter must represent a 'standard' ethernet MAC address string
213: * (e.g. '00:C0:F0:3D:5B:7C').
214: *
215: * @param ethernetAddress the ethernet address of the server machine
216: * @throws CmsInitException in case the ethernetAddress String is not a valid ethernet address
217: */
218: public static void init(String ethernetAddress)
219: throws CmsInitException {
220:
221: try {
222: m_ethernetAddress = new EthernetAddress(ethernetAddress);
223: } catch (Exception e) {
224: throw new CmsInitException(Messages.get().container(
225: Messages.ERR_INVALID_ETHERNET_ADDRESS_1,
226: ethernetAddress));
227: }
228: }
229:
230: /**
231: * Returns <code>true</code> if the given UUID is valid.<p>
232: *
233: * @param uuid the UUID to check
234: *
235: * @return <code>true</code> if the given UUID is valid
236: */
237: public static boolean isValidUUID(String uuid) {
238:
239: try {
240: return (null != uuid) && (null != UUID.valueOf(uuid));
241: } catch (NumberFormatException e) {
242: // return false
243: }
244: return false;
245: }
246:
247: /**
248: * Returns the given String transformed to a UUID in case the String is a valid UUID.<p>
249: *
250: * @param uuid the String to transform to a UUID
251: *
252: * @return the given String transformed to a UUID in case the String is a valid UUID
253: *
254: * @throws NumberFormatException in case the String is no valid UUID
255: */
256: public static CmsUUID valueOf(String uuid)
257: throws NumberFormatException {
258:
259: return new CmsUUID(UUID.valueOf(uuid));
260: }
261:
262: /**
263: * Creates a clone of this CmsUUID.<p>
264: *
265: * @return a clone of this CmsUUID
266: */
267: public Object clone() {
268:
269: if (this == NULL_UUID) {
270: return NULL_UUID;
271: }
272: return new CmsUUID((UUID) m_uuid.clone());
273: }
274:
275: /**
276: * @see java.lang.Comparable#compareTo(java.lang.Object)
277: */
278: public int compareTo(Object obj) {
279:
280: if (obj instanceof CmsUUID) {
281: return m_uuid.compareTo(((CmsUUID) obj).m_uuid);
282: }
283: return 0;
284: }
285:
286: /**
287: * @see java.lang.Object#equals(java.lang.Object)
288: */
289: public boolean equals(Object obj) {
290:
291: if (obj == this ) {
292: return true;
293: }
294: if (obj instanceof CmsUUID) {
295: return ((CmsUUID) obj).m_uuid.equals(m_uuid);
296: }
297: return false;
298: }
299:
300: /**
301: * Returns the String representation of this UUID, same as {@link #toString()}.<p>
302: *
303: * This method is useful if bean like access to the UUID String is required.<p>
304: *
305: * @return the String representation of this UUID
306: */
307: public String getStringValue() {
308:
309: return toString();
310: }
311:
312: /**
313: * Optimized hashCode implementation for UUID's.<p>
314: *
315: * @see java.lang.Object#hashCode()
316: */
317: public int hashCode() {
318:
319: return m_uuid.hashCode();
320: }
321:
322: /**
323: * Returns true if this UUID is equal to the null UUID.<p>
324: *
325: * @return true if this UUID is equal to the null UUID
326: */
327: public boolean isNullUUID() {
328:
329: if (this == NULL_UUID) {
330: return true;
331: }
332: return m_uuid.equals(UUID.getNullUUID());
333: }
334:
335: /**
336: * @see java.io.Externalizable#readExternal(java.io.ObjectInput)
337: */
338: public void readExternal(ObjectInput in) {
339:
340: Object o = null;
341: try {
342: o = in.readObject();
343: } catch (Throwable e) {
344: // there are 2 development version of OpenCms (6.1.7 and 6.1.8) which had a different format,
345: // here the Object was preceded by a Long
346: try {
347: // first read the long, we don't really need it but it must be removed from the stream
348: in.readLong();
349: o = in.readObject();
350: } catch (Throwable t) {
351: if (LOG.isDebugEnabled()) {
352: LOG.debug(Messages.get().getBundle().key(
353: Messages.LOG_READ_UUID_OLD_1, o), t);
354: }
355: }
356: }
357:
358: if (o instanceof String) {
359: // this UUID has been serialized using the new method
360: if (LOG.isDebugEnabled()) {
361: LOG.debug(Messages.get().getBundle().key(
362: Messages.LOG_READ_UUID_1, o));
363: }
364: m_uuid = new UUID((String) o);
365: }
366:
367: // log an error if the uuid could not be deserialized
368: if (m_uuid == null) {
369: // UUID cannot be deserialized
370: if (LOG.isDebugEnabled()) {
371: LOG.debug(Messages.get().getBundle().key(
372: Messages.LOG_ERR_READ_UUID_0));
373: }
374: }
375: }
376:
377: /**
378: * Returns the UUID as a 16-byte byte array.<p>
379: *
380: * @return 16-byte byte array that contains the UUID's bytes in the network byte order
381: */
382: public byte[] toByteArray() {
383:
384: return m_uuid.toByteArray();
385: }
386:
387: /**
388: * @see java.lang.Object#toString()
389: */
390: public String toString() {
391:
392: return m_uuid.toString();
393: }
394:
395: /**
396: *
397: * @see java.io.Externalizable#writeExternal(java.io.ObjectOutput)
398: */
399: public void writeExternal(ObjectOutput out) throws IOException {
400:
401: if (LOG.isDebugEnabled()) {
402: LOG.debug(Messages.get().getBundle().key(
403: Messages.LOG_WRITE_UUID_1, toString()));
404: }
405: out.writeObject(toString());
406: }
407: }
|