Coverage report

  %line %branch
org.apache.jetspeed.util.Path
0% 
0% 

 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  * 
 9  
  *      http://www.apache.org/licenses/LICENSE-2.0
 10  
  * 
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.jetspeed.util;
 18  
 
 19  
 import java.io.Serializable;
 20  
 import java.util.Arrays;
 21  
 import java.util.HashMap;
 22  
 
 23  
 /**
 24  
  * <h2>Overview</h2>
 25  
  * <p>
 26  
  * The Path object is used to standard used to standardize the creation of
 27  
  * mutation of path-like structures. For: example /foo/bar/index.html.
 28  
  * </p>
 29  
  * <h2>Rules for Interperting Pathes</h2>
 30  
  * <p>
 31  
  * Below are the rules for how the constructor interprets literal paths.
 32  
  * <strong>NOTE</strong> the {@link addSegment(String)} interprets string
 33  
  * pathes in a somewhat different manner. <table>
 34  
  * <tr>
 35  
  * <th>Literal Path</th>
 36  
  * <th>Interpretation</th>
 37  
  * </tr>
 38  
  * <td> <i>/foo/bar/index.html</i> </td>
 39  
  * <td> <code>foo</code> and <code>bar</code> will be considered directory
 40  
  * segments while <code>index.html</code> will be considered a file segment.
 41  
  * This means that the <code>baseName</code> will be set to <i>index</i> and
 42  
  * the <code>fileExtension</code> will be set to <i>.html</i> </td>
 43  
  * <tr>
 44  
  * <td> <i>/foo/bar/</i>, <i>/foo/bar</i>, <i>foo/bar/</i> <i>foo/bar</i>
 45  
  * </td>
 46  
  * <td>
 47  
  * <p>
 48  
  * <code>foo</code> and <code>bar</code> will be considered directory
 49  
  * segments. <code>baseName</code> and <code>fileExtension</code> will be
 50  
  * left as <code>null</code>.
 51  
  * <p>
 52  
  * I cases where a file has no extension you must use the
 53  
  * {@link setFileSegment(String))} to manually set the file. This causes the
 54  
  * <code>baseName</code> to be set to the file name specified and the
 55  
  * <code>fileExtension</code> will be set to the empty string ("").
 56  
  * </p>
 57  
  * </td>
 58  
  * </tr>
 59  
  * </table>
 60  
  * 
 61  
  * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
 62  
  */
 63  
 public class Path implements Serializable, Cloneable
 64  
 {
 65  
     /** The serial version uid. */
 66  
     private static final long serialVersionUID = 6890966283704092945L;
 67  
 
 68  
     public static final String PATH_SEPERATOR = "/";
 69  
     
 70  0
     private static final String[] EMPTY_SEGMENTS = new String[0];
 71  
     
 72  0
     private static HashMap childrenMap = new HashMap();
 73  
     
 74  
     private final String path;
 75  
     private final String[] segments;
 76  
 
 77  
     private final String fileName;
 78  
 
 79  
     private final String baseName;
 80  
 
 81  
     private final String fileExtension;
 82  
 
 83  
     private final String queryString;
 84  
     
 85  
     private final int hashCode;
 86  
 
 87  
     public Path()
 88  0
     {
 89  0
         segments = EMPTY_SEGMENTS;
 90  0
         fileName = null;
 91  0
         baseName = null;
 92  0
         fileExtension = null;
 93  0
         queryString = null;
 94  0
         hashCode = 0;
 95  0
         path = "";
 96  0
     }
 97  
     
 98  
     private Path(Path parent, String childSegment, boolean pathOnly)
 99  
     {
 100  0
         this(parent, splitPath(childSegment), pathOnly);
 101  0
     }
 102  
             
 103  
     private Path(Path parent, String[] children, boolean pathOnly)
 104  0
     {
 105  0
         int code = 0;
 106  0
         if (!pathOnly)
 107  
         {
 108  0
             this.fileName = parent.fileName;
 109  0
             this.baseName = parent.baseName;
 110  0
             this.fileExtension = parent.fileExtension;
 111  0
             this.queryString = parent.queryString;
 112  0
             if (queryString != null)
 113  
             {
 114  0
                 code += queryString.hashCode();
 115  
             }
 116  
         }
 117  
         else
 118  
         {
 119  0
             fileName = null;
 120  0
             baseName = null;
 121  0
             fileExtension = null;
 122  0
             queryString = null;
 123  
         }
 124  
         
 125  0
         int size = parent.segments.length;
 126  0
         if (pathOnly && parent.fileName != null)
 127  
         {
 128  0
             size--;
 129  
         }
 130  
 
 131  0
         int index = 0;
 132  
         
 133  0
         segments = new String[size+children.length];
 134  0
         for (index = 0; index < size; index++)
 135  
         {
 136  0
             segments[index] = parent.segments[index];
 137  0
             code += segments[index].hashCode();
 138  
         }
 139  0
         for (int i = 0; i < children.length; i++, index++)
 140  
         {
 141  0
             segments[index] = children[i];
 142  0
             code += segments[index].hashCode();
 143  
         }
 144  0
         if (fileName != null && !pathOnly)
 145  
         {
 146  0
             segments[index] = fileName;
 147  0
             code += segments[index].hashCode();
 148  
         }
 149  0
         hashCode = code;
 150  0
         path = buildPath();
 151  0
     }
 152  
             
 153  
     private Path(Path parent)
 154  0
     {
 155  0
         this.fileName = parent.fileName;
 156  0
         this.baseName = parent.baseName;
 157  0
         this.fileExtension = parent.fileExtension;
 158  0
         this.queryString = parent.queryString;
 159  0
         segments = new String[parent.segments.length-1];
 160  0
         int code = 0;
 161  0
         for (int i = 0; i < parent.segments.length-2; i++)
 162  
         {
 163  0
             segments[i] = parent.segments[i];
 164  0
             code += segments.hashCode();
 165  
         }
 166  0
         if (fileName != null)
 167  
         {
 168  0
             segments[segments.length-1] = fileName;
 169  
         }
 170  0
         else if (parent.segments.length > 1)
 171  
         {
 172  0
             segments[segments.length-1] = parent.segments[parent.segments.length-2];
 173  
         }
 174  0
         if ( segments.length > 0)
 175  
         {
 176  0
             code += segments[segments.length-1].hashCode();
 177  
         }
 178  0
         if (queryString != null)
 179  
         {
 180  0
             code += queryString.hashCode();
 181  
         }
 182  0
         hashCode = code;
 183  0
         path = buildPath();
 184  0
     }
 185  
             
 186  
     private Path(String[] segments, int offset, class="keyword">int count)
 187  0
     {
 188  0
         this.segments = new String[count];
 189  0
         int code = 0;
 190  0
         for (int i = 0; i < count; i++)
 191  
         {
 192  0
             this.segments[i] = segments[offset+i];
 193  0
             code+=segments[offset+i].hashCode();
 194  
         }
 195  0
         hashCode = code;
 196  0
         if (count > 0)
 197  
         {
 198  0
             fileName = this.segments[count-1];
 199  0
             int extIndex = fileName.lastIndexOf('.');
 200  0
             if (extIndex > -1)
 201  
             {
 202  0
                 baseName = fileName.substring(0, extIndex);
 203  0
                 fileExtension = fileName.substring(extIndex);
 204  
             }
 205  
             else
 206  
             {
 207  0
                 baseName = fileName;
 208  0
                 fileExtension = "";
 209  
             }
 210  0
         }
 211  
         else
 212  
         {
 213  0
             fileName = null;
 214  0
             baseName = null;
 215  0
             fileExtension = null;
 216  
         }
 217  0
         queryString = null;
 218  0
         path = buildPath();
 219  0
     }
 220  
             
 221  
     public Path(String path)
 222  0
     {
 223  
         
 224  0
         String tmp = path.replace('\\', '/');
 225  
 
 226  0
         if (!tmp.startsWith("/"))
 227  
         {
 228  0
             tmp = "/" + tmp;
 229  
         }
 230  
 
 231  0
         this.path = tmp;
 232  
         
 233  0
         if (path.equals("/"))
 234  
         {
 235  0
             segments = new String[]{""};
 236  0
             fileName = null;
 237  0
             baseName = null;
 238  0
             fileExtension = null;
 239  0
             queryString = null;
 240  0
             hashCode = 0;
 241  
         }
 242  
         else
 243  
         {
 244  0
             int queryStart = path.indexOf('?');
 245  0
             int len = queryStart > -1 ? queryStart : path.length();
 246  0
             segments = split(path, 0, len, '/');
 247  0
             int code  = 0;
 248  0
             for (int i = 0; i < segments.length; i++)
 249  
             {
 250  0
                 code += segments[i].hashCode();
 251  
             }
 252  0
             String tmpFileName = null;
 253  
             
 254  0
             if (queryStart > 1 && path.length() > queryStart+1)
 255  
             {
 256  0
                 queryString = path.substring(queryStart+1);
 257  0
                 code += queryString.hashCode();
 258  
             }
 259  
             else
 260  
             {
 261  0
                 queryString = null;
 262  
             }
 263  0
             hashCode = code;
 264  0
             int extIndex = -1;
 265  0
             if (segments.length > 0)
 266  
             {
 267  0
                 tmpFileName = segments[segments.length-1];
 268  0
                 extIndex = tmpFileName.lastIndexOf('.');
 269  
             }
 270  0
             if (extIndex > -1)
 271  
             {
 272  0
                 fileName = tmpFileName;
 273  0
                 baseName = tmpFileName.substring(0, extIndex);
 274  0
                 fileExtension = tmpFileName.substring(extIndex);
 275  
             }
 276  
             else
 277  
             {
 278  0
                 fileName = null;
 279  0
                 baseName = null;
 280  0
                 fileExtension = null;
 281  
             }
 282  
         }
 283  0
     }
 284  
 
 285  
     private static String[] splitPath(String path)
 286  
     {
 287  0
         String[] children = null;
 288  0
         path = path.replace('\\', '/');
 289  
 
 290  0
         if (path.startsWith("/"))
 291  
         {
 292  0
             path = "/" + path;
 293  
         }
 294  
 
 295  0
         if (path.equals("/"))
 296  
         {
 297  0
             children = new String[]{""};
 298  
         }
 299  
         else
 300  
         {
 301  0
             int index = path.indexOf('?');
 302  0
             int len = index > -1 ? index : path.length();
 303  0
             children = split(path, 0, len, '/');
 304  
         }
 305  0
         return children;
 306  
     }
 307  
     
 308  
     /**
 309  
      * Returns the segement of the path at the specified index <code>i</code>.
 310  
      * 
 311  
      * @param i
 312  
      *            index containing the segment to return.
 313  
      * @return Segment at index <code>i</code>
 314  
      * @throws ArrayIndexOutOfBoundsException
 315  
      *             if the index is not within the bounds of this Path.
 316  
      */
 317  
     public String getSegment(int i)
 318  
     {
 319  0
         return segments[i];
 320  
     }
 321  
 
 322  
     /**
 323  
      * <p>
 324  
      * Adds this segment to the end of the path but before the current file
 325  
      * segment, if one exists. For consistency Segments added via this method
 326  
      * are <strong>ALWAYS</strong> considered directories even when matching a
 327  
      * standrad file pattern i.e. <i>index.html</i>
 328  
      * </p>
 329  
      * <p>
 330  
      * If you need to set the file segment, please use the setFileSegment()
 331  
      * method.
 332  
      * </p>
 333  
      * 
 334  
      * @param segment
 335  
      * @return
 336  
      */
 337  
     public Path addSegment(String segment)
 338  
     {
 339  0
         return new Path(this, segment, false);
 340  
     }
 341  
 
 342  
     public Path getSubPath(int beginAtSegment)
 343  
     {
 344  0
         return new Path(segments, beginAtSegment, segments.length-beginAtSegment);
 345  
     }
 346  
 
 347  
     public Path getSubPath(int beginAtSegment, class="keyword">int endSegment)
 348  
     {
 349  0
         return new Path(segments, beginAtSegment, endSegment-beginAtSegment);
 350  
     }
 351  
 
 352  
     public String getBaseName()
 353  
     {
 354  0
         return baseName;
 355  
     }
 356  
 
 357  
     public String getFileExtension()
 358  
     {
 359  0
         return fileExtension;
 360  
     }
 361  
 
 362  
     public String getFileName()
 363  
     {
 364  0
         return fileName;
 365  
     }
 366  
 
 367  
     public String getQueryString()
 368  
     {
 369  0
         return queryString;
 370  
     }
 371  
 
 372  
     public int length()
 373  
     {
 374  0
         return segments.length;
 375  
     }
 376  
     
 377  
     public String toString()
 378  
     {
 379  0
         return path;
 380  
     }
 381  
 
 382  
     private String buildPath()
 383  
     {
 384  0
         int len = 0;
 385  0
         for (int i = 0; i < segments.length; i++)
 386  
         {
 387  0
             len+=segments[i].length()+1;
 388  
         }
 389  0
         if (queryString!=null)
 390  
         {
 391  0
             len+=queryString.length()+1;
 392  
         }
 393  0
         char[] buffer = new class="keyword">char[len];
 394  0
         int index = 0;
 395  0
         for (int i = 0; i < segments.length; i++ )
 396  
         {
 397  0
             buffer[index++] = '/';
 398  0
             len = segments[i].length();
 399  0
             segments[i].getChars(0, len, buffer, index);
 400  0
             index+= len;
 401  
         }
 402  0
         if (queryString != null)
 403  
         {                
 404  0
             buffer[index++] = '?';
 405  0
             len = queryString.length();
 406  0
             queryString.getChars(0, len, buffer, index);
 407  
         }
 408  0
         return new String(buffer);
 409  
     }
 410  
 
 411  
     public boolean equals(Object obj)
 412  
     {
 413  0
         if (obj instanceof Path)
 414  
         {
 415  0
             Path other = (Path)obj;
 416  0
             if ( (other.queryString != null && other.queryString.equals(queryString)) ||
 417  
                     (other.queryString == null && queryString == class="keyword">null) )
 418  
             {
 419  0
                 return Arrays.equals(other.segments,segments);
 420  
             }
 421  
         }
 422  0
         return false;
 423  
     }
 424  
 
 425  
     public int hashCode()
 426  
     {
 427  0
         return hashCode;
 428  
     }
 429  
 
 430  
     /**
 431  
      * Removes the last directory segment in this path. This method <strong>WILL
 432  
      * NOT</strong> remove the fileSegment, but path segment immediately before
 433  
      * it.
 434  
      * 
 435  
      * @return segment removed.
 436  
      */
 437  
     public Path removeLastPathSegment()
 438  
     {
 439  0
         if ((fileName != null && segments.length == 1) || segments.length == 0)
 440  
         {
 441  0
             return this;
 442  
         }
 443  0
         return new Path(this);
 444  
     }
 445  
 
 446  
     public Path getChild(String childPath)
 447  
     {
 448  0
         synchronized (childrenMap)
 449  
         {
 450  0
             Path child = null;
 451  0
             HashMap children = (HashMap)childrenMap.get(path);
 452  0
             if (children == null)
 453  
             {
 454  0
                 children = new HashMap();
 455  0
                 childrenMap.put(path, children);
 456  
             }
 457  
             else
 458  
             {
 459  0
                 child = (Path)children.get(childPath);
 460  
             }
 461  0
             if ( child == null )
 462  
             {
 463  0
                 if (segments.length == 0)
 464  
                 {
 465  0
                     child = new Path(childPath);
 466  
                 }
 467  
                 else
 468  
                 {
 469  0
                     child = new Path(this, childPath, true);
 470  
                 }
 471  0
                 children.put(childPath, child);
 472  
             }
 473  0
             return child;
 474  0
         }
 475  
     }
 476  
 
 477  
     public Path getChild(Path childPath)
 478  
     {
 479  0
         return getChild(childPath.path);
 480  
     }
 481  
     
 482  
     private static String[] split(String str, int start, class="keyword">int length, char separator)
 483  
     {
 484  
         String[] result;
 485  0
         char[] buffer = str.toCharArray();
 486  0
         int tokens = 0;
 487  0
         boolean token = false;
 488  0
         for (int i = start; i < length; i++)
 489  
         {
 490  0
             if (buffer[i]==separator)
 491  
             {
 492  0
                 token = false;
 493  
             }
 494  0
             else if (!token)
 495  
             {
 496  0
                 tokens++;
 497  0
                 token = true;
 498  
             }
 499  
         }
 500  0
         result = new String[tokens];
 501  0
         if (tokens > 0)
 502  
         {
 503  0
             int begin = start;
 504  0
             int end = start;
 505  0
             token = false;
 506  0
             tokens = 0;
 507  0
             for (int i = start; i < length; i++)
 508  
             {
 509  0
                 if (buffer[i]==separator)
 510  
                 {
 511  0
                     if (token)
 512  
                     {
 513  0
                        result[tokens++] = new String(buffer,begin,end);
 514  0
                        token = false;
 515  
                     }
 516  
                 }
 517  0
                 else if (!token)
 518  
                 {
 519  0
                     token = true;
 520  0
                     begin = i;
 521  0
                     end = 1;
 522  
                 }
 523  
                 else
 524  
                 {
 525  0
                     end++;
 526  
                 }
 527  
             }
 528  0
             if (token)
 529  
             {
 530  0
                 result[tokens] = new String(buffer,begin, end);
 531  
             }
 532  
         }
 533  0
         return result;
 534  
     }
 535  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.