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

cat.inspiracio.url.URL Maven / Gradle / Ivy

There is a newer version: 0.0.1
Show newest version
/*
Copyright 2015 Alexander Bunkenburg 

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 cat.inspiracio.url;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cat.inspiracio.lang.NotImplementedException;

/** A proper java bean for a URL of the http protocol. 
 * 
 * Has getters and setters for Java bean style.
 * Also has methods for fluid style.
 * 
 * Intended to implement https://url.spec.whatwg.org/.
 * */
public class URL implements Serializable, URLUtils{
	private static final long serialVersionUID = -2542102834410732299L;

	// constants --------------------------
	
	/** The MIME types that we can guess from the extension. */
	private static final Maptypes=new HashMap();static{
		types.put("css", "text/css");
		types.put("csv", "text/csv");
		types.put("gif", "image/gif");
		types.put("html", "text/html");
		types.put("jpeg", "image/jpeg");
		types.put("jpg", "image/jpeg");
		types.put("js", "application/javascript");
		types.put("png", "image/png");
		types.put("txt", "text/plain");		
		types.put("xml", "application/xml");		
	}
	
	// state ------------------------------

	/** A URL’s scheme is an ASCII string that identifies the type of URL and 
	 * can be used to dispatch a URL for further processing after parsing. 
	 * 
	 * [spec: It is initially the empty string.] */
	private String scheme=null;

	/** A URL’s username is an ASCII string identifying a user. 
	 * [spec: It is initially the empty string.] */
	private String username=null;
	
	/** A URL’s password is either null or an ASCII string identifying a user’s 
	 * credentials. It is initially null.*/
	private String password=null;
	
	/** A URL’s host is either null or a host. It is initially null. 
	 * A host is a domain, an IPv4, or an IPv6. Not implemented: IPv4 and [IPv6]. */
	private String host=null;
	
	/** A URL’s port is either null or a 16-bit integer that identifies a 
	 * networking port. It is initially null. */
	private int port=0;//int is 32 bit. short is 16 bit. But I'll use int anyway.
	
	/** A URL’s path is a list of zero or more ASCII string holding data, usually 
	 * identifying a location in hierarchical form. It is initially the empty list. */
	private String path=null;//The concatenation, with initial '/'.
	
	/** A URL’s query is either null or an ASCII string holding data. It is initially null. */
	private URLParameters query=null;//null means no parameters
	
	/** A URL’s fragment is either null or a string holding data that can be used 
	 * for further processing on the resource the URL’s other components identify. 
	 * It is initially null. */
	private String fragment=null;
	
	/** A URL also has an associated non-relative flag. It is initially unset. */
	private boolean nonRelative=false;
	
	/** A URL also has an associated object that is either null or a Blob object. 
	 * It is initially null. Not implemented. */
	//private Object object;
	
	// construction -----------------------
	
	/** Extracts the URL from a request. 
	 * 
	 * Does not parse fragment, which is not sent to the server. */
//Very useful, but introduces dependency on javax.servlet.http.HttpServletRequest.
//	public URL(HttpServletRequest request){
//		scheme=request.getScheme();
//		server=request.getServerName();
//		port=request.getServerPort();
//		path=request.getRequestURI();
//		parameters=URLParameters.from(request);
//		fragment=null;//Not sent to the server.
//	}

	/** Makes a new URL, initially empty. */
	public URL(){}

	/** Parses a URL from a string.
	 * Null is like empty string. */
	public URL(String url){
	    URLParser p=new URLParser();
        p.basic(url, null, null, this, null);
	}

	/** http://www.w3.org/TR/url/#dom-url
	 * 
	 *  Not implemented. */
	public URL(String url, String base){throw new NotImplementedException();}

	/** Deep clone of the URL. */
	@Override public URL clone(){
		URL clone=new URL();
		clone.nonRelative=nonRelative;
		clone.scheme=scheme;
		clone.username=username;
		clone.password=password;
		clone.host=host;
		clone.port=port;
		clone.path=path;
		clone.query=clone(query);
		clone.fragment=fragment;
		return clone;
	}

	// accessors ---------------------------
	
	public String getScheme(){return scheme;}
	public void setScheme(String s){scheme=s;}
	public String scheme(){return scheme;}
	public URL scheme(String s){scheme=s;return this;}
	
    private boolean isSpecialScheme(String scheme){
        if(scheme==null)return false;
        switch(scheme){
        case"ftp":
        case"file":
        case"gopher":
        case"http":
        case"https":
        case"ws":
        case"wss":return true;
        }
        return false;
    }
    boolean isSpecial(){return isSpecialScheme(scheme);}
    
    private boolean isLocalScheme(String scheme){
        if(scheme==null)return false;
        switch(scheme){
        case"about":
        case"blob":
        case"data":
        case"filesystem":return true;//Not "file"
        }
        return false;
    }
    boolean isLocal(){return isLocalScheme(scheme);}
    
    /** https://url.spec.whatwg.org/#syntax-url-absolute */
    boolean isAbsolute(){
        //simplifying: has a scheme
        return scheme!=null && 0 getParameters(String key){return parameters(key);}
	public List parameters(String key){
		if(query==null)return Collections.emptyList();
		return query.getValues(key);
	}
	
	/** Adds a parameter.
	 * Setting a parameter to null removes it. */
	public void addParameter(String key, String value){
		if(value==null){
			removeParameter(key);
			return;
		}
		if(query==null)query=new URLParameters();
		query.add(key, value);
	}

	/** Sets a parameter.
	 * Overwrites the parameter if it is already set.
	 * Setting a parameter to null removes it. */
	public void setParameter(String key, String value){
		if(value==null)removeParameter(key);
		else parameter(key, value);
	}
	public URL parameter(String key, String value){
		if(query==null && value==null)return this;
		if(query==null)query=new URLParameters();
		query.set(key, value);
		return this;
	}

	/** May return empty parameters, but never null. */
	public URLParameters getParameters(){return parameters();}
	public URLParameters parameters(){
		if(query==null)query=new URLParameters();
		return query;
	}
	
	/** Sets all parameters. Passing null removes all parameters. */
	public void setParameters(URLParameters ps){parameters(ps);}
	
	/** Sets all parameters. Passing null removes all parameters. */
	public URL parameters(URLParameters ps){query=ps;return this;}

	public URL removeParameter(String key){parameter(key, null);return this;}
	public URL removeParameters(){query=null;return this;}
	
	public void setSearchParams(URLSearchParams ps){query=ps;}
	public URLSearchParams getSearchParams(){
	    if(query==null)return null;
	    if(query instanceof URLSearchParams)return (URLSearchParams)query;
	    query=new URLSearchParams(query);
	    return (URLSearchParams)query;
	}

	public void setSearch(String s){
	    if(null==s || 0==s.length()){
	        removeParameters();
	        return;
	    }
	    if(s.startsWith("?"))
	        s=s.substring(1);
	    query=new URLParameters(s);
	}
	
	/** Gets the query string, with initial "?", or null.
	 * http://www.w3.org/TR/url/#dom-urlutils-search 
	 * ?key=value&key=value */
	public String getSearch(){
	    if(query==null || query.empty())return "";
	    return "?" + query.toString();
	}
	
	/** Does the path end with this suffix? */
	public boolean endsWith(String suffix){
		if(path==null)return suffix==null;
		return path.endsWith(suffix);
	}

	public String fragment(){return fragment;}
	public String getFragment(){return fragment();}
	public void setFragment(String f){fragment=f;}
	public URL fragment(String f){fragment=f;return this;}
	public URL removeFragment(){return fragment(null);}

	/** Sets the fragment. Setting it to empty string or null
	 * removes the fragment.
	 * @param h New fragment. If it doesn't start with "#", 
	 * 	the initial "#" is assumed. */
	public void setHash(String h){
	    if("javascript".equals(scheme))return;
	    if(h==null || "".equals(h)){
	        fragment=null;
	        return;
	    }
	    if(h.startsWith("#"))
	        h=h.substring(1);
	    fragment=h;
	}
	public URL hash(String h){setHash(h);return this;}
	
	/** Gets the fragment, with initial "#", or empty string. */
	public String getHash(){
	    if(fragment==null)return "";
	    return "#" + fragment;
	}
	public String hash(){return getHash();}
	
	/** The complete URL as String.
	 *  
	 * Username and password are shown, encoded.
	 * 
	 * If the port is standard, it will not appear.
	 * The parameters appear in the order they were inserted. 
	 **/
	@Override public String toString(){
		
		StringBuilder builder=new StringBuilder();
		
		if(scheme!=null && 0
	 * 	
  • if there is no port, uses default port for the scheme *
  • ignores parameter order * * */ @Override public boolean equals(Object o){ if(o==null)return false; if(this==o)return true; if(!(o instanceof URL))return false; URL a=(URL)o; URL b=this; return equals(a.scheme, b.scheme) && equals(a.username, b.username) && equals(a.password, b.password) && equals(a.host, b.host) && a.port()==b.port() && equals(a.path, b.path) && equals(a.query, b.query) && equals(a.fragment, b.fragment); } // static API methods ------------------------------------ /** Not implemented */ public static String domainToASCII(String domain){throw new NotImplementedException();} /** Not implemented */ public static String domainToUnicode(String domain){throw new NotImplementedException();} // helpers ----------------------------------------------- /** Cloning parameters without stumbling over null. */ private URLParameters clone(URLParameters ps){ if(ps==null || ps.isEmpty()) return null; return ps.clone(); } /** Equality without stumbling over null. */ private boolean equals(Object a, Object b){ if(a==null)return b==null; return a.equals(b); } boolean isNonRelative(){return nonRelative;} void setNonRelative(boolean nonRelative){this.nonRelative=nonRelative;} private boolean isASCIIAlpha(char c){return ('A'<=c && c<='Z') || ('a'<=c && c<='z');} /** A normalized Windows drive letter is a Windows drive letter of which * the second code point is ":". */ private boolean isNormalizedWindowsDriveLetter(String s){ return isWindowsDriveLetter(s) && s.charAt(1)==':'; } /** A Windows drive letter is two code points, of which the first is an * ASCII alpha and the second is either ":" or "|".*/ private boolean isWindowsDriveLetter(String s){ if(s==null || 2!=s.length()) return false; return isWindowsDriveLetter(s.charAt(0), s.charAt(1)); } /** A Windows drive letter is two code points, of which the first is an * ASCII alpha and the second is either ":" or "|".*/ private boolean isWindowsDriveLetter(char a, char b){ return isASCIIAlpha(a) && (b==':' || b=='|'); } /** utf-8 percent encode codePoint using the user info encode set. * Spec: https://url.spec.whatwg.org/#utf-8-percent-encode */ private String encode(String s){ //The simple encode set are C0 controls and all code points greater than U+007E. //The default encode set is the simple encode set and code points U+0020, '"', "#", "<", ">", "?", "`", "{", and "}". //The user info encode set is the default encode set and code points "/", ":", ";", "=", "@", "[", "\", "]", "^", and "|". //approximate implementation try{ return URLEncoder.encode(s, "UTF-8");//UnsupportedEncodingException }catch(UnsupportedEncodingException e){throw new RuntimeException(e);} } /** utf-8 percent decode codePoint using the user info encode set. * Spec: https://url.spec.whatwg.org/#utf-8-percent-encode */ @SuppressWarnings("unused") private String decode(String s){ try{ return URLDecoder.decode(s, "UTF-8");//UnsupportedEncodingException }catch(UnsupportedEncodingException e){throw new RuntimeException(e);} } }




  • © 2015 - 2025 Weber Informatics LLC | Privacy Policy