Coverage Report - org.apache.maven.doxia.site.decoration.inheritance.URIPathDescriptor
 
Classes in this File Line Coverage Branch Coverage Complexity
URIPathDescriptor
100%
48/48
100%
38/38
2,846
 
 1  
 package org.apache.maven.doxia.site.decoration.inheritance;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.net.URI;
 23  
 import java.net.URISyntaxException;
 24  
 
 25  
 import org.codehaus.plexus.util.PathTool;
 26  
 
 27  
 /**
 28  
  * Describes a link that may be absolute or relative, and that is anchored to an absolute URI.
 29  
  *
 30  
  * @author ltheussl
 31  
  *
 32  
  * @since 1.2
 33  
  */
 34  
 public class URIPathDescriptor
 35  
 {
 36  
     private final URI baseURI;
 37  
     private final URI link;
 38  
 
 39  
     /**
 40  
      * A URIPathDescriptor consists of a base URI and a link.
 41  
      * Both arguments to this constructor have to be parsable to URIs.
 42  
      * The baseURI parameter has to be absolute in the sense of {@link URI#isAbsolute()}.
 43  
      *
 44  
      * Before being parsed to {@link URI}s, the arguments are modified to catch
 45  
      * some common bad practices: first all Windows-style backslashes '\' are replaced by
 46  
      * forward slashes '/'.
 47  
      * If the baseURI does not end with '/', a slash is appended.
 48  
      * If the link starts with a '/', the first character is stripped.
 49  
      *
 50  
      * @param baseURI The base URI. Has to be a valid absolute URI.
 51  
      *      In addition, the path of the URI should not have any file part,
 52  
      *      ie <code>http://maven.apache.org/</code> is valid,
 53  
      *      <code>http://maven.apache.org/index.html</code> is not.
 54  
      *      Even though the latter form is accepted without warning,
 55  
      *      the methods in this class will not return what is probably expected,
 56  
      *      because a slash is appended during construction, as noted above.
 57  
      * @param link the link. This may be a relative link or an absolute link.
 58  
      *      Note that URIs that start with a "/", ie don't specify a scheme, are considered relative.
 59  
      *
 60  
      * @throws IllegalArgumentException if either argument is not parsable as a URI,
 61  
      *      or if baseURI is not absolute.
 62  
      */
 63  
     public URIPathDescriptor( final String baseURI, final String link )
 64  1770
     {
 65  1770
         final String llink = sanitizeLink( link );
 66  1770
         final String bbase = sanitizeBase( baseURI );
 67  
 
 68  1770
         this.baseURI = URI.create( bbase ).normalize();
 69  1764
         this.link = URI.create( llink ).normalize();
 70  
 
 71  1758
         if ( !this.baseURI.isAbsolute() )
 72  
         {
 73  6
             throw new IllegalArgumentException( "Base URI is not absolute: " + baseURI );
 74  
         }
 75  1752
     }
 76  
 
 77  
     /**
 78  
      * Return the base of this URIPathDescriptor as a URI.
 79  
      * This is always {@link URI#normalize() normalized}.
 80  
      *
 81  
      * @return the normalized base URI.
 82  
      */
 83  
     public URI getBaseURI()
 84  
     {
 85  12
         return baseURI;
 86  
     }
 87  
 
 88  
     /**
 89  
      * Return the link of this URIPathDescriptor as a URI.
 90  
      * This is always {@link URI#normalize() normalized}.
 91  
      *
 92  
      * @return the normalized link URI.
 93  
      */
 94  
     public URI getLink()
 95  
     {
 96  6
         return link;
 97  
     }
 98  
 
 99  
     /**
 100  
      * Resolve the link to the base.
 101  
      * This always returns an absolute URI. If link is absolute, link is returned.
 102  
      *
 103  
      * @return the resolved link. This is equivalent to calling
 104  
      *      {@link #getBaseURI()}.{@link URI#resolve(java.net.URI) resolve}( {@link #getLink()} ).
 105  
      */
 106  
     public URI resolveLink()
 107  
     {
 108  252
         return baseURI.resolve( link );
 109  
     }
 110  
 
 111  
     /**
 112  
      * Calculate the relative link with respect to the base.
 113  
      * The original link is returned if either
 114  
      *      link is relative;
 115  
      *      or link and base do not share the {@link #sameSite(java.net.URI) same site}.
 116  
      *
 117  
      * @return the link as a relative URI.
 118  
      */
 119  
     public URI relativizeLink()
 120  
     {
 121  462
         return relativizeLink( baseURI.toString(), link );
 122  
     }
 123  
 
 124  
     // NOTE: URI.relativize does not work as expected, see
 125  
     // http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6226081
 126  
     private static URI relativizeLink( final String base, final URI link )
 127  
     {
 128  462
         if ( !link.isAbsolute() )
 129  
         {
 130  168
             return link;
 131  
         }
 132  
 
 133  294
         final URI newBaseURI = URI.create( base );
 134  
 
 135  294
         if ( !sameSite( link, newBaseURI ) )
 136  
         {
 137  66
             return link;
 138  
         }
 139  
 
 140  228
         final String relativePath = PathTool.getRelativeWebPath( newBaseURI.toString(), link.toString() );
 141  
 
 142  228
         return URI.create( correctRelativePath( relativePath ) );
 143  
     }
 144  
 
 145  
     /**
 146  
      * Calculate the link as viewed from a different base.
 147  
      * This returns the original link if link is absolute.
 148  
      * This returns {@link #resolveLink()} if either
 149  
      *      newBase == null,
 150  
      *      or newBase is not parsable as a URI,
 151  
      *      or newBase and this {@link #getBaseURI()} do not share the
 152  
      *      {@link #sameSite(java.net.URI) same site}.
 153  
      *
 154  
      * @param newBase the new base URI. Has to be parsable as a URI.
 155  
      *.
 156  
      * @return a new relative link or the original link {@link #resolveLink() resolved},
 157  
      *      i.e. as an absolute link, if the link cannot be re-based.
 158  
      */
 159  
     public URI rebaseLink( final String newBase )
 160  
     {
 161  1164
         if ( link.isAbsolute() )
 162  
         {
 163  420
             return link;
 164  
         }
 165  
 
 166  744
         if ( newBase == null )
 167  
         {
 168  6
             return resolveLink();
 169  
         }
 170  
 
 171  
         final URI newBaseURI;
 172  
 
 173  
         try
 174  
         {
 175  738
             newBaseURI = new URI( newBase );
 176  
         }
 177  6
         catch ( URISyntaxException ex )
 178  
         {
 179  6
             return resolveLink();
 180  732
         }
 181  
 
 182  732
         if ( !sameSite( newBaseURI ) )
 183  
         {
 184  114
             return resolveLink();
 185  
         }
 186  
 
 187  618
         final String relativeBasePath = PathTool.getRelativeWebPath( newBaseURI.getPath(), baseURI.getPath() );
 188  
 
 189  618
         return URI.create( correctRelativePath( relativeBasePath ) ).resolve( link );
 190  
     }
 191  
 
 192  
     private static String correctRelativePath( final String relativePath )
 193  
     {
 194  846
         if ( "".equals( relativePath ) || "/".equals( relativePath ) )
 195  
         {
 196  42
             return "./";
 197  
         }
 198  
         else
 199  
         {
 200  804
             return relativePath;
 201  
         }
 202  
     }
 203  
 
 204  
     /**
 205  
      * Check if this URIPathDescriptor lives on the same site as the given URI.
 206  
      *
 207  
      * @param uri a URI to compare with.
 208  
      *      May be null, in which case false is returned.
 209  
      *
 210  
      * @return true if {@link #getBaseURI()} shares the same scheme, host and port with the given URI
 211  
      *      where null values are allowed.
 212  
      */
 213  
     public boolean sameSite( final URI uri )
 214  
     {
 215  828
         return ( uri != null ) && sameSite( this.baseURI, uri );
 216  
     }
 217  
 
 218  
     private static boolean sameSite( final URI baseURI, final URI newBaseURI )
 219  
     {
 220  1116
         final boolean sameScheme =
 221  
             ( newBaseURI.getScheme() == null ? false : baseURI.getScheme().equalsIgnoreCase( newBaseURI.getScheme() ) );
 222  1116
         final boolean sameHost =
 223  
             ( baseURI.getHost() == null ? newBaseURI.getHost() == null
 224  
                             : baseURI.getHost().equalsIgnoreCase( newBaseURI.getHost() ) );
 225  1116
         final boolean samePort = ( baseURI.getPort() == newBaseURI.getPort() );
 226  
 
 227  1116
         return ( sameScheme && samePort && sameHost );
 228  
     }
 229  
 
 230  
     /**
 231  
      * Construct a string representation of this URIPathDescriptor.
 232  
      * This is equivalent to calling {@link #resolveLink()}.toString().
 233  
      *
 234  
      * @return this URIPathDescriptor as a String.
 235  
      */
 236  
     public String toString()
 237  
     {
 238  66
         return resolveLink().toString();
 239  
     }
 240  
 
 241  
     private static String sanitizeBase( final String base )
 242  
     {
 243  1770
         String sane = base.replace( '\\', '/' );
 244  
 
 245  1770
         if ( !sane.endsWith( "/" ) )
 246  
         {
 247  1098
             sane += "/";
 248  
         }
 249  
 
 250  1770
         return sane;
 251  
     }
 252  
 
 253  
     private static String sanitizeLink( final String link )
 254  
     {
 255  1770
         String sane = link.replace( '\\', '/' );
 256  
 
 257  1770
         if ( sane.startsWith( "/" ) )
 258  
         {
 259  390
             sane = sane.substring( 1 );
 260  
         }
 261  
 
 262  1770
         return sane;
 263  
     }
 264  
 }