/*
* Copyright (c) 2001-2007 Sun Microsystems, Inc. All rights reserved.
*
* The Sun Project JXTA(TM) Software License
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. The end-user documentation included with the redistribution, if any, must
* include the following acknowledgment: "This product includes software
* developed by Sun Microsystems, Inc. for JXTA(TM) technology."
* Alternately, this acknowledgment may appear in the software itself, if
* and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Sun", "Sun Microsystems, Inc.", "JXTA" and "Project JXTA" must
* not be used to endorse or promote products derived from this software
* without prior written permission. For written permission, please contact
* Project JXTA at http://www.jxta.org.
*
* 5. Products derived from this software may not be called "JXTA", nor may
* "JXTA" appear in their name, without prior written permission of Sun.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SUN
* MICROSYSTEMS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* JXTA is a registered trademark of Sun Microsystems, Inc. in the United
* States and other countries.
*
* Please see the license information page at :
* <http://www.jxta.org/project/www/license.html> for instructions on use of
* the license in source files.
*
* ====================================================================
*
* This software consists of voluntary contributions made by many individuals
* on behalf of Project JXTA. For more information on Project JXTA, please see
* http://www.jxta.org.
*
* This license is based on the BSD license adopted by the Apache Foundation.
*/
package net.jxta.impl.util.ternary.wild;
import net.jxta.impl.util.ternary.DoublyLinkedList;
import net.jxta.impl.util.ternary.TernarySearchTree;
import net.jxta.impl.util.ternary.TernarySearchTreeImpl;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
public class WildcardTernarySearchTreeImpl<T> implements WildcardTernarySearchTree<T> {
private static final Logger LOG = Logger.getLogger( WildcardTernarySearchTreeImpl.class.getName( ) );
private static final String WILDCARD = "*";
private TernarySearchTree prefix = new TernarySearchTreeImpl( );
private TernarySearchTree suffix = new TernarySearchTreeImpl( );
private long size = 0;
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernaryTree#contains(java.lang.String)
*/
public boolean contains( String key ) {
prefix.setNumReturnValues( 1 );
return ( null != prefix.get( key ) );
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernaryTree#delete(java.lang.String)
*/
public boolean delete( String key ) {
prefix.remove( key );
suffix.remove( new StringBuffer( key ).reverse( ).toString( ) );
size--;
return true;
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernarySearchTree#deleteTree()
*/
public void deleteTree( ) {
prefix.deleteTree( );
suffix.deleteTree( );
size = 0;
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernaryTree#find(java.lang.String)
*/
@SuppressWarnings( "unchecked" )
public T find( String key ) {
return (T) prefix.get( key );
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernaryTree#getSize()
*/
public long getSize( ) {
return size;
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernaryTree#insert(java.lang.String, java.lang.Object)
*/
public void insert( String key, Object value ) throws IllegalStateException {
prefix.put( key, value );
suffix.put( new StringBuffer( key ).reverse( ).toString( ), value );
size++;
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernaryTree#search(java.lang.String)
*/
public List<String> search( String term, int threshold )
throws IllegalArgumentException {
if ( ( term.length( ) - term.replace( WILDCARD, "" ).length( ) ) != 1 ) {
throw new IllegalArgumentException( "" );
}
if ( term.endsWith( WILDCARD ) ) {
this.prefix.setNumReturnValues( threshold );
return toList( prefix.matchPrefix( term.substring( 0, term.length( ) - 1 ) ), false );
} else if ( term.startsWith( WILDCARD ) ) {
String revTerm = new StringBuffer( term.substring( 1 ) ).reverse( ).toString( );
this.suffix.setNumReturnValues( threshold );
return toList( suffix.matchPrefix( revTerm ), true );
} else {
int idx = term.indexOf( WILDCARD );
return (List<String>) intersection( search( term.substring( 0, idx + 1 ), threshold ),
search( term.substring( idx ), threshold ) );
}
}
private List<String> toList( DoublyLinkedList dll, boolean reverse ) {
if ( LOG.isLoggable( Level.FINEST ) ) {
LOG.finest( "Building result list... linked list size: " + dll.size( ) );
}
ArrayList<String> al = new ArrayList<String>( );
Iterator<Object> it = dll.iterator( );
String key;
while ( it.hasNext( ) ) {
key = (String) it.next( );
if ( reverse ) {
key = new StringBuffer( key ).reverse( ).toString( );
}
al.add( key );
}
return al;
}
private Collection<String> intersection( Collection<String> coll1, Collection<String> coll2 ) {
if ( LOG.isLoggable( Level.FINEST ) ) {
LOG.finest( "Result intersection. Collection sizes: " + coll1.size( ) + " " + coll2.size( ) );
}
Set<String> intersection = new HashSet<String>( coll1 );
intersection.retainAll( coll2 );
return new ArrayList<String>( intersection );
}
/* (non-Javadoc)
* @see net.jxta.impl.util.ternary.wild.WildcardTernarySearchTree#matchPrefix(java.lang.String)
*/
public List<String> matchPrefix( String prefix, int threshold ) {
this.prefix.setNumReturnValues( threshold );
DoublyLinkedList dll = this.prefix.matchPrefix( prefix );
return toList( dll, false );
}
}