/* * Copyright (C) 2008 Laurent Caillette * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, either * version 3 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.novelang.outfit.xml; import java.util.Arrays; import java.util.Iterator; import com.google.common.collect.ImmutableList; import org.xml.sax.Attributes; /** * An immutable implementation. Doesn't seem to exist elsewhere. * Strongly inspired by JDK's implementation (1.6.0_22). * * @author Laurent Caillette */ public class ImmutableAttributes implements Attributes { private final int length ; private final String[] data ; public ImmutableAttributes() { length = 0 ; data = null ; } public ImmutableAttributes( final Attributes others ) { if( others.getLength() > 0 ) { length = others.getLength() ; data = new String[ length * 5 ] ; for( int i = 0 ; i < length ; i++ ) { data[ i * 5 ] = others.getURI( i ) ; data[ i * 5 + 1 ] = others.getLocalName( i ) ; data[ i * 5 + 2 ] = others.getQName( i ) ; data[ i * 5 + 3 ] = others.getType( i ) ; data[ i * 5 + 4 ] = others.getValue( i ) ; } } else { length = 0 ; data = null ; } } private ImmutableAttributes( final ImmutableList< Attribute > attributes ) { if( attributes.isEmpty() ) { length = 0 ; data = null; } else { length = attributes.size(); data = new String[ length * 5 ] ; final Iterator< Attribute > iterator = attributes.iterator() ; for( int i = 0 ; i < length ; i++ ) { final Attribute attribute = iterator.next() ; data[ i * 5 ] = attribute.uri ; data[ i * 5 + 1 ] = attribute.localName ; data[ i * 5 + 2 ] = attribute.qName ; data[ i * 5 + 3 ] = attribute.type ; data[ i * 5 + 4 ] = attribute.value ; } } } @Override public int getLength() { return length ; } @Override public String getURI( final int index ) { if( index >= 0 && index < length ) { return data[ index * 5 ] ; } else { return null ; } } @Override public String getLocalName( final int index ) { if( index >= 0 && index < length ) { return data[ index * 5 + 1 ]; } else { return null; } } @Override public String getQName( final int index ) { if( index >= 0 && index < length ) { return data[ index * 5 + 2 ]; } else { return null; } } @Override public String getType( final int index ) { if( index >= 0 && index < length ) { return data[ index * 5 + 3 ] ; } else { return null ; } } @Override public String getValue( final int index ) { if( index >= 0 && index < length ) { return data[ index * 5 + 4 ] ; } else { return null; } } @Override public int getIndex( final String uri, final String localName ) { final int max = length * 5 ; for( int i = 0 ; i < max ; i += 5 ) { if( data[ i ].equals( uri ) && data[ i + 1 ].equals( localName ) ) { return i / 5 ; } } return -1 ; } @Override public int getIndex( final String qName ) { final int max = length * 5; for( int i = 0 ; i < max ; i += 5 ) { if( data[ i + 2 ].equals( qName ) ) { return i / 5 ; } } return -1 ; } @Override public String getType( final String uri, final String localName ) { final int max = length * 5 ; for( int i = 0 ; i < max ; i += 5 ) { if( data[ i ].equals( uri ) && data[ i + 1 ].equals( localName ) ) { return data[ i + 3 ] ; } } return null ; } @Override public String getType( final String qName ) { final int max = length * 5 ; for( int i = 0 ; i < max ; i += 5 ) { if( data[ i + 2 ].equals( qName ) ) { return data[ i + 3 ] ; } } return null ; } @Override public String getValue( final String uri, final String localName ) { final int max = length * 5 ; for( int i = 0 ; i < max ; i += 5 ) { if( data[ i ].equals( uri ) && data[ i + 1 ].equals( localName ) ) { return data[ i + 4 ] ; } } return null ; } @Override public String getValue( final String qName ) { final int max = length * 5 ; for( int i = 0 ; i < max ; i += 5 ) { if( data[ i + 2 ].equals( qName ) ) { return data[ i + 4 ] ; } } return null ; } @Override public boolean equals( final Object other ) { if( this == other ) { return true ; } if( other == null || getClass() != other.getClass() ) { return false ; } final ImmutableAttributes that = ( ImmutableAttributes ) other; if( length != that.length ) { return false ; } if( ! Arrays.equals( data, that.data ) ) { return false ; } return true ; } @Override public int hashCode() { int result = length ; result = 31 * result + ( data != null ? Arrays.hashCode( data ) : 0 ) ; return result ; } @Override public String toString() { return getClass().getSimpleName() + "{" + ( data == null ? "" : Arrays.asList( data ) ) + "}" ; } private static final class Attribute { /* data[ i * 5 ] = others.getURI( i ) ; data[ i * 5 + 1 ] = others.getLocalName( i ) ; data[ i * 5 + 2 ] = others.getQName( i ) ; data[ i * 5 + 3 ] = others.getType( i ) ; data[ i * 5 + 4 ] = others.getValue( i ) ; */ public final String uri ; public final String localName ; public final String qName ; public final String type ; public final String value ; private Attribute( final String uri, final String localName, final String qName, final String type, final String value ) { this.uri = uri ; this.localName = localName ; this.qName = qName ; this.type = type ; this.value = value ; } } public static class Builder { private final ImmutableList.Builder< Attribute > attributes = ImmutableList.builder() ; public Builder add( final String uri, final String localName, final String qName, final String type, final String value ) { attributes.add( new Attribute( uri, localName, qName, type, value ) ) ; return this ; } public ImmutableAttributes build() { return new ImmutableAttributes( attributes.build() ) ; } } }