All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.ocpsoft.rewrite.servlet.util.URLBuilder Maven / Gradle / Ivy

/*
 * Copyright 2010 Lincoln Baxter, III
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *     http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.ocpsoft.rewrite.servlet.util;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import com.ocpsoft.common.util.Strings;

public class URLBuilder
{

   private Metadata metadata = new Metadata();

   private final List segments = new ArrayList();

   private QueryStringBuilder query = QueryStringBuilder.begin();

   /**
    * Return a new instance of {@link URLBuilder}
    */
   public static URLBuilder begin()
   {
      return new URLBuilder();
   }

   public static URLBuilder build(final List segments, final Metadata metadata)
   {
      return URLBuilder.begin().addPathSegments(segments).setMetadata(metadata);
   }

   public static URLBuilder build(final String url)
   {
      if (url == null)
      {
         throw new IllegalArgumentException("URL cannot be null.");
      }
      if (url.contains("?"))
      {
         String[] parts = url.split("\\?");
         String path = parts[0];
         String query = parts[1];
         if (parts.length > 2)
         {
            query = Strings.join(Arrays.asList(Arrays.copyOfRange(parts, 1, parts.length)), "?");
         }
         return new URLBuilder().addPathSegments(path).addQueryParameters(query);
      }
      return new URLBuilder().addPathSegments(url);
   }

   /*
    * Constructors
    */
   private URLBuilder()
   {}

   public URLBuilder(final List encodedSegments, final Metadata metadata, final QueryStringBuilder query)
   {
      this.segments.addAll(encodedSegments);
      this.metadata = metadata.copy();
      this.query = query;
   }

   /*
    * End Constructors
    */

   public URLBuilder addPathSegments(final List segments)
   {
      this.segments.addAll(segments);
      return this;
   }

   public URLBuilder addPathSegments(final String path)
   {
      if (path != null)
      {
         String temp = path.trim();
         if (temp.endsWith("/"))
         {
            metadata.setTrailingSlash(true);
         }
         if (temp.startsWith("/") && segments.isEmpty())
         {
            metadata.setLeadingSlash(true);
         }

         String trimmedUrl = trimSurroundingSlashes(path);
         String[] newSegments = trimmedUrl.split("/");

         this.segments.addAll(Arrays.asList(newSegments));
      }
      else
      {
         throw new IllegalArgumentException("URL cannot be null.");
      }
      return this;
   }

   public URLBuilder addQueryParameters(final String query)
   {
      this.query.addParameters(query);
      return this;
   }

   /**
    * Return a decoded form of this URL.
    */
   public URLBuilder decode()
   {
      return new URLBuilder(getDecodedSegments(), metadata, query.decode());
   }

   /**
    * Decodes a segment using the {@link URI} class.
    * 
    * @param segment The segment to decode
    * @return the decoded segment
    */
   private String decodeSegment(final String segment)
   {
      try
      {
         String prepared = ("http://localhost/" + segment)
                  .replaceAll(" ", "%20")
                  .replaceAll("\\+", "%20");
         final URI uri = new URI(prepared);
         return uri.getPath().substring(1);
      }
      catch (URISyntaxException e)
      {
         throw new IllegalArgumentException(e);
      }
   }

   /**
    * Return an encoded form of this URL.
    */
   public URLBuilder encode()
   {
      return new URLBuilder(getEncodedSegments(), metadata, query.encode());
   }

   /**
    * Encodes a segment using the {@link URI} class.
    * 
    * @param segment The segment to encode
    * @return the encoded segment
    */
   private String encodeSegment(final String segment)
   {
      try
      {
         final URI uri = new URI("http", "localhost", "/" + segment, null);
         return uri.toASCIIString().substring(17);
      }
      catch (URISyntaxException e)
      {
         throw new IllegalArgumentException(e);
      }
   }

   private List getDecodedSegments()
   {
      List result = new ArrayList();
      for (String segment : segments)
      {
         result.add(decodeSegment(segment));
      }
      return result;
   }

   private List getEncodedSegments()
   {
      List resultSegments = new ArrayList();
      for (String segment : segments)
      {
         resultSegments.add(encodeSegment(segment));
      }
      return resultSegments;
   }

   /**
    * Get the character encoding of this URL (default UTF-8)
    */
   public String getEncoding()
   {
      return metadata.getEncoding();
   }

   /*
    * Getters & Setters
    */

   /**
    * Get the {@link Metadata} object for this URL
    */
   public Metadata getMetadata()
   {
      return metadata;
   }

   public QueryStringBuilder getQueryStringBuilder()
   {
      return query;
   }

   /**
    * Return all segments (separated by '/') in this URL
    * 
    * @return
    */
   public List getSegments()
   {
      return Collections.unmodifiableList(segments);
   }

   /**
    * Return true if this URL begins with '/'
    */
   public boolean hasLeadingSlash()
   {
      return metadata.hasLeadingSlash();
   }

   /**
    * Return true if this URL ends with '/'
    */
   public boolean hasTrailingSlash()
   {
      return metadata.hasTrailingSlash();
   }

   /**
    * Get the number of segments (separated by '/') in this URL
    */
   public int numSegments()
   {
      return segments.size();
   }

   /**
    * Set the character encoding of this URL (default UTF-8)
    */
   public void setEncoding(final String encoding)
   {
      metadata.setEncoding(encoding);
   }

   /**
    * Set the {@link Metadata} object for this URL
    * 
    * @return
    */
   public URLBuilder setMetadata(final Metadata metadata)
   {
      this.metadata = metadata;
      return this;
   }

   public String toPath()
   {
      return metadata.buildURLFromSegments(segments);
   }

   /**
    * Return a String representation of this URL
    */
   @Override
   public String toString()
   {
      return toURL();
   }

   /**
    * Return a URI representation of this URL including path and query string
    */
   public URI toURI()
   {
      try {
         URI uri = new URI(toURL());
         return uri;
      }
      catch (URISyntaxException e) {
         throw new IllegalStateException("URL cannot be parsed.", e);
      }
   }

   /**
    * Return a String representation of this URL including path and query string
    */
   public String toURL()
   {
      return toPath() + query.toQueryString();
   }

   /*
    * Helpers
    */
   private String trimSurroundingSlashes(final String url)
   {
      String result = null;
      if (url != null)
      {
         result = url.trim();
         if (result.startsWith("/"))
         {
            result = result.substring(1);
         }
         if (result.endsWith("/"))
         {
            result = result.substring(0, result.length() - 1);
         }
      }
      return result;
   }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy