001: /*
002: * $Id: Hex.java,v 1.12 2007/08/27 11:18:20 agoubard Exp $
003: *
004: * Copyright 2003-2007 Orange Nederland Breedband B.V.
005: * See the COPYRIGHT file for redistribution and use restrictions.
006: */
007: package org.xins.common.types.standard;
008:
009: import org.xins.common.types.Type;
010: import org.xins.common.types.TypeValueException;
011: import org.xins.common.MandatoryArgumentChecker;
012: import org.xins.common.text.HexConverter;
013:
014: /**
015: * Standard type <em>_hex</em>.
016: *
017: * @version $Revision: 1.12 $ $Date: 2007/08/27 11:18:20 $
018: * @author gveiog
019: *
020: * @since XINS 1.5.0.
021: */
022: public class Hex extends Type {
023:
024: /**
025: * The only instance of this class. This field is never <code>null</code>.
026: */
027: public static final Hex SINGLETON = new Hex();
028:
029: /**
030: * The minimum number of bytes this Hex can have.
031: */
032: private final int _minimum;
033:
034: /**
035: * The maximum number of bytes this Hex can have.
036: */
037: private final int _maximum;
038:
039: /**
040: * Constructs a new <code>Hex</code>.
041: * This constructor is private, the field {@link #SINGLETON} should be
042: * used.
043: */
044: private Hex() {
045: this ("_hex", 0, Integer.MAX_VALUE);
046: }
047:
048: /**
049: * Constructs a new <code>Hex</code> object (constructor for
050: * subclasses).
051: *
052: * @param name
053: * the name of this type, cannot be <code>null</code>.
054: *
055: * @param minimum
056: * the minimum for the value.# minimum number of bytes this Hex can have
057: *
058: * @param maximum
059: * the maximum for the value.# maximum number of bytes this Hex can have
060: */
061: protected Hex(String name, int minimum, int maximum) {
062: super (name, byte[].class);
063:
064: _minimum = minimum;
065: _maximum = maximum;
066: }
067:
068: /**
069: * Converts the specified non-<code>null</code> string value to a
070: * <code>byte[]</code> value.
071: *
072: * @param string
073: * the hexadecimal string to convert, cannot be <code>null</code>.
074: *
075: * @return
076: * the <code>byte[]</code> value.
077: *
078: * @throws IllegalArgumentException
079: * if <code>string == null</code>.
080: *
081: * @throws TypeValueException
082: * if the specified string does not represent a valid value for this
083: * type.If the string does not have a hexadecimal value or have a character
084: * that is not hexadecimal digit.
085: */
086: public static byte[] fromStringForRequired(String string)
087: throws IllegalArgumentException, TypeValueException {
088: int index = 0;
089: if (string == null) {
090: throw new IllegalArgumentException("string == null");
091: } else {
092: try {
093:
094: // this method converts the string to byte and also checks if the string has hex digits
095: return HexConverter.parseHexBytes(string, index, string
096: .length());
097:
098: } catch (Exception ex) {
099: throw new TypeValueException(SINGLETON, string);
100: }
101: }
102: }
103:
104: /**
105: * Converts the specified string value to a <code>byte[]</code> value.
106: *
107: * @param string
108: * the hexadecimal string to convert, can be <code>null</code>.
109: *
110: * @return
111: * the byte[], or <code>null</code> if
112: * <code>string == null</code>.
113: *
114: * @throws TypeValueException
115: * if the specified string does not represent a valid value for this
116: * type.If the string does not have a hexadecimal value or
117: * have a character that is not hexadecimal digit.
118: */
119: public static byte[] fromStringForOptional(String string)
120: throws TypeValueException {
121: int index = 0;
122: if (string == null) {
123: return null;
124: }
125: try {
126: return HexConverter.parseHexBytes(string, index, string
127: .length());
128:
129: } catch (Exception e) {
130: throw new TypeValueException(SINGLETON, string);
131: }
132: }
133:
134: /**
135: * Converts the specified <code>byte[]</code> to a hexadecimal string.
136: *
137: * @param value
138: * the value to convert, can be <code>null</code>.
139: *
140: * @return
141: * the textual representation of the value, or <code>null</code> if and
142: * only if <code>value == null</code>.
143: */
144: public static String toString(byte[] value) {
145: if (value == null) {
146: return null;
147: } else {
148: return HexConverter.toHexString(value);
149: }
150: }
151:
152: /**
153: * Determines if the specified <code>String</code> value is considered
154: * valid for this type (implementation method).
155: *
156: * <p>This method is called from {@link #isValidValue(String)}. When
157: * called from that method, it is guaranteed that the argument is not
158: * <code>null</code>.
159: * # 1.check if the string has hex digits
160: * # 2. if the byte[] created from that string has minimum < byte[].length < maximum
161: * @param string
162: * the <code>String</code> value that should be checked for validity,
163: * never <code>null</code>.
164: *
165: * @return
166: * <code>true</code> if and only if the specified <code>String</code>
167: * value is valid, <code>false</code> otherwise.
168: */
169: protected boolean isValidValueImpl(String string) {
170: try {
171: for (int i = 0; i < string.length(); i++) {
172: if (!HexConverter.isHexDigit(string.charAt(i))) {
173: return false;
174: }
175: }
176: byte[] number = HexConverter.parseHexBytes(string, 0,
177: string.length());
178: if (number.length < _minimum || number.length > _maximum) {
179: return false;
180: }
181: return true;
182: } catch (Exception ex) {
183: // TODO: Log
184: return false;
185: }
186: }
187:
188: /**
189: * Converts from a <code>String</code> to an instance of the value class
190: * for this type (implementation method).
191: *
192: * <p>This method is not required to check the validity of the specified
193: * value (since {@link #isValidValueImpl(String)} should have been called
194: * before) but if it does, then it may throw a {@link TypeValueException}.
195: *
196: * @param string
197: * the string to convert to an instance of the value class, guaranteed
198: * to be not <code>null</code> and guaranteed to have been passed to
199: * {@link #isValidValueImpl(String)} without getting an exception.
200: *
201: * @return
202: * an instance of the value class, cannot be <code>null</code>.
203: *
204: * @throws TypeValueException
205: * if <code>string</code> is considered to be an invalid value for this
206: * type.
207: */
208: protected Object fromStringImpl(String string)
209: throws TypeValueException {
210: try {
211: return HexConverter.parseHexBytes(string, 0, string
212: .length());
213: } catch (Exception ex) {
214: throw new TypeValueException(SINGLETON, string, ex
215: .getMessage());
216: }
217: }
218:
219: /**
220: * Generates a string representation of the specified value for this type.
221: * The specified value must be an instance of the value class for this type
222: * (see {@link #getValueClass()}). Also, it may have to fall within a
223: * certain range of valid values, depending on the type.
224: *
225: * @param value
226: * the value, cannot be <code>null</code>.
227: *
228: * @return
229: * the string representation of the specified value for this type,
230: * cannot be <code>null</code>.
231: *
232: * @throws IllegalArgumentException
233: * if <code>value == null</code>.
234: *
235: * @throws ClassCastException
236: * if <code>getValueClass().isInstance(value) == false</code>.
237: *
238: * @throws TypeValueException
239: * if the specified value is not in the allowed range.
240: * #Maybe this is redundant because i dont think that there is any possibility to be out of range
241: * but since it exists also to other standard types i left it.
242: *
243: */
244: public final String toString(Object value)
245: throws IllegalArgumentException, ClassCastException,
246: TypeValueException {
247:
248: // Check preconditions
249: MandatoryArgumentChecker.check("value", value);
250:
251: // Convert the argument to a byte array (may throw ClassCastException)
252: byte[] b = (byte[]) value;
253:
254: // Try converting the byte array as a Hex string
255: try {
256: return HexConverter.toHexString(b);
257: } catch (Exception e) {
258:
259: throw new TypeValueException(SINGLETON, new String(b), e
260: .getMessage());
261: }
262: }
263:
264: public String getDescription() {
265: return "Binary data where each byte is represented by its hexadecimal value.";
266: }
267: }
|