001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     * 
010     * http://www.apache.org/licenses/LICENSE-2.0
011     * 
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     * 
019     */
020    package org.apache.directory.server.dhcp.messages;
021    
022    
023    import java.text.ParseException;
024    import java.util.Arrays;
025    import java.util.regex.Matcher;
026    import java.util.regex.Pattern;
027    
028    import org.apache.directory.server.i18n.I18n;
029    
030    
031    /**
032     * A representation of a DHCP hardware address.
033     * 
034     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
035     * @version $Rev: 551805 $, $Date: 2007-06-29 00:57:04 -0500 (Fr, 29 Jun 2007) $
036     */
037    public final class HardwareAddress
038    {
039        /**
040         * [htype] Hardware address type, see ARP section in "Assigned Numbers" RFC;
041         * e.g., '1' = 10mb ethernet.
042         */
043        private final short type;
044    
045        /**
046         * [hlen] Hardware address length (e.g. '6' for 10mb ethernet).
047         */
048        private final short length;
049    
050        /**
051         * [chaddr] Client hardware address.
052         */
053        private final byte[] address;
054    
055    
056        /**
057         * @param type
058         * @param length
059         * @param address
060         */
061        public HardwareAddress(short type, short length, byte[] address)
062        {
063            this.type = type;
064            this.length = length;
065            this.address = address;
066        }
067    
068    
069        public byte[] getAddress()
070        {
071            return address;
072        }
073    
074    
075        public short getLength()
076        {
077            return length;
078        }
079    
080    
081        public short getType()
082        {
083            return type;
084        }
085    
086    
087        /**
088         * @see java.lang.Object#hashCode()
089         * @return the instance's hash code 
090         */
091        public int hashCode()
092        {
093            int hashCode = 98643532 ^ type ^ length;
094            for ( int i = 0; i < length; i++ )
095                hashCode ^= address[i];
096    
097            return hashCode;
098        }
099    
100    
101        /*
102         * @see java.lang.Object#equals(java.lang.Object)
103         */
104        public boolean equals( Object obj )
105        {
106            if ( null == obj || !( obj.getClass().equals( HardwareAddress.class ) ) )
107                return false;
108    
109            HardwareAddress hw = ( HardwareAddress ) obj;
110    
111            return length == hw.length && type == hw.type && Arrays.equals( address, hw.address );
112        }
113    
114    
115        /**
116         * Create the string representation of the hardware address native to the
117         * corresponding address type. This method currently supports only type
118         * 1==ethernet with the representation <code>a1:a2:a3:a4:a5:a6</code>.<br>
119         * For all other types, this method falls back to the representation created
120         * by toString().
121         * 
122         * @see java.lang.Object#toString()
123         */
124        public String getNativeRepresentation()
125        {
126            StringBuffer sb = new StringBuffer();
127            switch ( type )
128            {
129                case 1:
130                    for ( int i = 0; i < length; i++ )
131                    {
132                        if ( i > 0 )
133                            sb.append( ":" );
134                        String hex = Integer.toHexString( address[i] & 0xff );
135                        if ( hex.length() < 2 )
136                            sb.append( '0' );
137                        sb.append( hex );
138                    }
139                    break;
140                default:
141                    sb.append( toString() );
142            }
143    
144            return sb.toString();
145        }
146    
147    
148        /**
149         * Create a string representation of the hardware address. The string
150         * representation is in the format<br>
151         * <code>t/a1:a2:a3...</code><br>
152         * Where <code>t</code> represents the address type (decimal) and
153         * <code>a<sub>n</sub></code> represent the address bytes (hexadecimal).
154         * 
155         * @see java.lang.Object#toString()
156         */
157        public String toString()
158        {
159            StringBuffer sb = new StringBuffer();
160            sb.append( type );
161            sb.append( "/" );
162            for ( int i = 0; i < length; i++ )
163            {
164                if ( i > 0 )
165                    sb.append( ":" );
166                String hex = Integer.toHexString( address[i] & 0xff );
167                if ( hex.length() < 2 )
168                    sb.append( '0' );
169                sb.append( hex );
170            }
171    
172            return sb.toString();
173        }
174    
175        private static final Pattern PARSE_PATTERN = Pattern
176            .compile( "(\\d+)\\s+(?:(\\p{XDigit}{1,2}):)*(\\p{XDigit}{1,2})?" );
177    
178    
179        /**
180         * Parses a string representation of a hardware address according to the
181         * specification given in {@link #toString()}.
182         * 
183         * @param s
184         * @return HardwareAddress
185         * @throws ParseException
186         */
187        public static HardwareAddress valueOf( String s )
188        {
189            if ( null == s || s.length() == 0 )
190                return null;
191    
192            Matcher m = PARSE_PATTERN.matcher( s );
193            if ( !m.matches() )
194                throw new IllegalArgumentException( I18n.err( I18n.ERR_637, s ) );
195    
196            int type = Integer.parseInt( m.group( 1 ) );
197            int len = m.groupCount() - 1;
198    
199            byte addr[] = new byte[len];
200            for ( int i = 0; i < addr.length; i++ )
201                addr[i] = ( byte ) Integer.parseInt( m.group( i + 2 ), 16 );
202    
203            return new HardwareAddress( ( short ) type, ( short ) len, addr );
204        }
205    }