001/*
002 * Copyright 2005 Stephen J. McConnell
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package net.dpml.cli.validation;
017
018import java.net.URISyntaxException;
019import java.net.URI;
020
021import java.util.List;
022import java.util.ListIterator;
023
024/**
025 * The <code>URIValidator</code> validates the string argument
026 * values are valid URIs.  If the value is a URI, the string value in
027 * the {@link java.util.List} of values is replaced with the
028 * {@link java.net.URI} instance.
029 *
030 * The following example shows how to limit the valid values
031 * for the site argument to 'artifact' URIs.
032 *
033 * <pre>
034 * ...
035 * ArgumentBuilder builder = new ArgumentBuilder();
036 * Argument plugin =
037 *   builder
038 *     .withName("plugin");
039 *     .withValidator( new URIValidator( "artifact", "link" ) );
040 * </pre>
041 *
042 * @author <a href="@PUBLISHER-URL@">@PUBLISHER-NAME@</a>
043 * @version @PROJECT-VERSION@
044 */
045public class URIValidator implements Validator 
046{
047    private final String[] m_schemes;
048
049   /**
050    * Creates a UriValidator.
051    */
052    public URIValidator() 
053    {
054        m_schemes = new String[0];
055    }
056
057   /**
058    * Creates a UriValidator for the specified scheme.
059    * @param scheme the uri scheme
060    */
061    public URIValidator( final String scheme ) 
062    {
063        m_schemes = new String[]{scheme};
064    }
065    
066   /**
067    * Creates a UriValidator for the specified schemes.
068    * @param schemes an array of schemes
069    */
070    public URIValidator( final String[] schemes ) 
071    {
072        m_schemes = schemes;
073    }
074    
075   /**
076    * Validate the list of values against the list of permitted values.
077    * If a value is valid, replace the string in the <code>values</code>
078    * {@link java.util.List} with the {@link java.net.URI} instance.
079    *
080    * @param values the list of values to validate 
081    * @exception InvalidArgumentException if a value is invalid
082    * @see net.dpml.cli.validation.Validator#validate(java.util.List)
083    */
084    public void validate( final List values )
085        throws InvalidArgumentException 
086    {
087        for( final ListIterator i = values.listIterator(); i.hasNext();) 
088        {
089            final Object object = i.next();
090            if( object instanceof URI )
091            {
092                break;
093            }
094            final String name = (String) object;
095            try 
096            {
097                final URI uri = new URI( name );
098                if( m_schemes.length == 0 )
099                {
100                    i.set( uri );
101                }
102                else 
103                {
104                    if( match( uri ) )
105                    {
106                        i.set( uri );
107                    }
108                    else
109                    {
110                        throw new InvalidArgumentException( name );
111                    }
112                }
113            } 
114            catch( final URISyntaxException e )
115            {
116                final String error =
117                  "Bad uri syntax in value [" + name + "].";
118                throw new InvalidArgumentException( error );
119            }
120        }
121    }
122    
123    private boolean match( URI uri )
124    {
125        String scheme = uri.getScheme();
126        for( int i=0; i<m_schemes.length; i++ )
127        {
128            if( scheme.startsWith( m_schemes[i] ) )
129            {
130                return true;
131            }
132        }
133        return false;
134    }
135}