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

com.cemiltokatli.jurl.HttpURL Maven / Gradle / Ivy

package com.cemiltokatli.jurl;

import com.cemiltokatli.jurl.exception.HttpURLParseError;
import com.cemiltokatli.jurl.exception.MalformedHttpURLException;
import com.cemiltokatli.jurl.exception.URLBuildException;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Represents a URL with http or https protocol.
 * An object of this class can only be instantiated by the JURL.build method.
 */
public class HttpURL extends URL {
    private String host;
    private int port;
    private boolean shownWWW;
    private LinkedList routeParameters;
    private LinkedHashMap queryFields;
    private String fragment;
    private String urlString;

    /**
     * Creates a new HttpURL object with the given protocol.
     *
     * @param protocol Protocol of the URL.
     */
    HttpURL(String protocol){
        super(protocol);
        this.port = -1;
        this.routeParameters = new LinkedList<>();
        this.queryFields = new LinkedHashMap<>();
    }

    /**
     * Returns the host name.
     *
     * @return the host name of the URL.
     */
    public String getHost(){
        return host;
    }

    /**
     * Returns the port number.
     *
     * @return the port number of the URL.
     */
    public int getPort(){
        return port;
    }

    /**
     * Returns a boolean value indicating that if the host name starts with "www".
     *
     * @return a boolean indicating that if the host name starts with "www".
     */
    public boolean isWWWShown(){
        return shownWWW;
    }

    /**
     * Returns the segments of the path field (route parameters) of the url.
     *
     * @return the route parameters of the URL.
     */
    public List getRouteParams(){
        return routeParameters;
    }

    /**
     * Returns the query fields.
     *
     * @return the query fields of the URL.
     */
    public LinkedHashMap getQueryFields(){
        return queryFields;
    }

    /**
     * Returns the fragment (hash).
     *
     * @return the fragment of the URL.
     */
    public String getFragment(){
        return fragment;
    }


    /**
     * Sets the given value as the host name of the URL.
     *
     * @param host the host name
     * @return the HttpURL object
     */
    public HttpURL setHost(String host){
        if(host != null){
            this.host = host.replaceAll("/","");
        }

        return this;
    }

    /**
     * Sets the given value as the port number of the URL.
     *
     * @param port the port number
     * @return the HttpURL object
     */
    public HttpURL setPort(int port){
        this.port = port;
        return this;
    }

    /**
     * Shows or hides WWW in the beginning of the host name.
     *
     * @param status true to show, false to hide
     * @return the HttpURL object
     */
    public HttpURL showWWW(boolean status){
        this.shownWWW = status;
        return this;
    }

    /**
     * Adds a new route parameter.
     *
     * @param param parameter to be added.
     * @return the HttpURL object
     */
    public HttpURL addRouteParam(String param){
        if(param.contains("/")){
            String[] pieces = param.replaceFirst("^/", "").split("/");
            for(String piece : pieces){
                if(!piece.isEmpty()){
                    this.routeParameters.add(piece.trim());
                }
            }
        }
        else
            this.routeParameters.add(param);

        return this;
    }

    /**
     * Removes the given route parameter.
     *
     * @param param parameter to be removed.
     * @return the HttpURL object
     */
    public HttpURL removeRouteParam(String param){
        this.routeParameters.remove(param);
        return this;
    }

    /**
     * It is possible to add placeholders in the URL that you send to the "setString" method and
     * replace these placeholders with real values later. This approach allows you to add route parameters dynamically
     * even if you are building the URL on a pre-defined structure.
     * This method allows you to replace those placeholders with real values.
     *
     * @param name name of the placeholder
     * @param value value to be replaced with the name
     * @return the HttpURL object
     */
    public HttpURL setRouteParam(String name, String value){
        for(int i = 0; i < routeParameters.size(); i++){
            if(routeParameters.get(i).equals("{"+name+"}")){
                routeParameters.set(i, value);
            }
        }

        return this;
    }

    /**
     * Adds a new query field.
     *
     * @param name the name of the field.
     * @param value the value of the field.
     * @return the HttpURL object
     */
    public HttpURL addQueryField(String name, String value){
        this.queryFields.put(name, value);
        return this;
    }

    /**
     * Removes the query field whose name is given.
     *
     * @param name the name of the field to be removed.
     * @return the HttpURL object
     */
    public HttpURL removeQueryField(String name){
        this.queryFields.remove(name);
        return this;
    }

    /**
     * Sets the given value as the fragment of the URL.
     *
     * @param fragment the fragment of the URL.
     * @return the HttpURL object
     */
    public HttpURL setFragment(String fragment){
        this.fragment = fragment;
        return this;
    }

    /**
     * Removes the fragment of the URL.
     *
     * @return the HttpURL object
     */
    public HttpURL clearFragment(){
        this.fragment = null;
        return this;
    }

    /**
     * Parses the given url.
     * This method must be called before all of the others in this class.
     *
     * @param url url to be parsed
     * @return the HttpURL object
     * @throws MalformedHttpURLException If the given URL is malformed.
     * @throws HttpURLParseError If the building of the URL has already been started.
     */
    public HttpURL setString(String url) throws MalformedHttpURLException, HttpURLParseError{
        //Check if the building of the URL has been started before this method is called
        if(host != null || port >= 0 || routeParameters.size() > 0 || queryFields.size() > 0 || fragment != null || urlString != null){
            throw new HttpURLParseError("URL cannot be parsed if it is already being built");
        }

        this.urlString = url;
        String cleanURL = url;

        //Clean protocol
        cleanURL = cleanURL.replaceFirst("^https://|http://","");

        //Extraction
        java.net.URL urlObj;

        try{
            urlObj = new java.net.URL("http://"+cleanURL);
        }
        catch(java.net.MalformedURLException e){
            throw new MalformedHttpURLException(e.getMessage());
        }

        //Extract Host
        host = urlObj.getHost();

        //Extract port
        port = urlObj.getPort();

        //Extract WWW Status
        String[] hostPieces = host.split("\\.");
        if(hostPieces.length >= 3 && host.startsWith("www")) {
            shownWWW = true;
            host = host.replaceFirst("www\\.","");
        }

        //Extract Route Parameters
        if(urlObj.getPath() != null) {
            String[] pieces = urlObj.getPath().replaceFirst("^/", "").split("/");
            for(String piece : pieces){
                if(!piece.trim().isEmpty())
                    routeParameters.add(piece);
            }
        }

        //Extract Query Fields
        if(urlObj.getQuery() != null) {
            queryFields = new LinkedHashMap<>();
            String[] variables = urlObj.getQuery().split("&");
            for(String variable : variables){
                String[] pieces = variable.split("=");
                queryFields.put(pieces[0], pieces[1]);
            }
        }

        //Extract Fragment
        Pattern fragmentPattern = Pattern.compile("#.+");
        Matcher fragmentMatcher = fragmentPattern.matcher(cleanURL);
        if(fragmentMatcher.find()){
            fragment = fragmentMatcher.group(0).replaceFirst("#", "");
        }

        return this;
    }


    /**
     * Builds the URL and returns it as a string.
     * If the encode argument is true, it also encodes the URL.
     *
     * @param encode true to encode the URL.
     * @return the built URL
     */
    public String toString(boolean encode){
        StringBuilder url = new StringBuilder();
        boolean addSlash = true;

        //Protocol
        url.append(super.getProtocol());

        //Host
            //# Throw an error if the host name is null or empty
            if(host == null || host.isEmpty())
                throw new URLBuildException("Host name is null or empty. A host name must be set to build a http or https url.");

        String hostPrepared = host.replaceFirst("^https://|http://|https:|http:","");

        if(shownWWW)
            url.append("www.");

        if(shownWWW && hostPrepared.split("\\.").length >= 3 && hostPrepared.startsWith("www"))
            hostPrepared = hostPrepared.replaceFirst("www\\.","");

        url.append(hostPrepared);

        //Port
        if(port > -1){
            url.append(":").append(port);
        }

        //Route Parameters
        if(routeParameters.size() > 0) {
            url.append("/");

            String param="";
            for(int i = 0; i < routeParameters.size(); i++){
                param = routeParameters.get(i);

                if (encode)
                    param = encode(param, true);


                if(i > 0)
                    url.append("/");

                url.append(param);
            }

            //# If the latest param is a directory, add a slash (/) at the end
            if(!param.contains(".")) {
                url.append("/");
            }

            addSlash = false;
        }

        //Query Fields
        if(queryFields.size() > 0) {
            if(addSlash) {
                url.append("/");
                addSlash = false;
            }

            url.append("?");

            boolean addDelimiter = false;
            String value;
            for (String key : queryFields.keySet()) {
                if (addDelimiter)
                    url.append("&");
                else
                    addDelimiter = true;

                value = queryFields.get(key);

                if(encode){
                    key = encode(key, true);
                    value = encode(value, true);
                }

                url.append(key).append("=").append(value);
            }
        }

        //Fragment
        if(fragment != null) {
            String fragmentPrepared = fragment;

            if(encode)
                fragmentPrepared = encode(fragmentPrepared, true);

            if(addSlash)
                url.append("/");

            url.append("#").append(fragmentPrepared);
        }

        return url.toString();
    }

    /**
     * Builds the URL and returns it as a string.
     *
     * @return the built URL
     */
    @Override
    public String toString(){
        return toString(false);
    }

    /**
     * Builds the URL and returns it as a java.net.URL object.
     * If the encode argument is true, it also encodes the URL.
     *
     * @param encode true to encode the URL.
     * @return The built URL
     * @throws java.net.MalformedURLException If the built URL is malformed
     */
    public java.net.URL toURL(boolean encode) throws java.net.MalformedURLException{
        return new java.net.URL(toString(encode));
    }

    /**
     * Builds the URL and returns it as a java.net.URL object.
     *
     * @return the build URL
     * @throws java.net.MalformedURLException  If the built URL is malformed
     */
    public java.net.URL toURL() throws java.net.MalformedURLException{
        return new java.net.URL(toString(false));
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy