org.cruk.genologics.api.jaxb.URIAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.cruk.genologics.api.jaxb.URIAdapter.java

Source

/*
 * CRUK-CI Genologics REST API Java Client.
 * Copyright (C) 2013 Cancer Research UK Cambridge Institute.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.cruk.genologics.api.jaxb;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.xml.bind.annotation.adapters.XmlAdapter;

import org.apache.commons.lang3.StringUtils;
import org.apache.http.NameValuePair;
import org.apache.http.client.utils.URLEncodedUtils;

/**
 * Convert to and from URI objects, correctly encoding the query string.
 * Can also remove the "state" parameter from the query part of a URI string
 * before converting to a URI object, or when converting back.
 * Turns out this is probably a bad idea after all, so it has been disabled.
 */
public class URIAdapter extends XmlAdapter<String, URI> {
    /**
     * UTF-8 character set for URL encoding.
     */
    private static final Charset UTF8 = Charset.forName("UTF-8");

    /**
     * Pattern for removing "state=" terms in the query string.
     */
    private static final Pattern STATE_PATTERN = Pattern.compile("([\\?&]?)state=\\d+(&?)");

    /**
     * Flag indicating whether the state removing behaviour should be used.
     */
    private static final boolean REMOVE_STATE = false;

    public URIAdapter() {
    }

    /**
     * Convert a string into a URI.
     *
     * @param v The string to convert.
     *
     * @return A {@code URI} object for the string, or null if {@code v} is null.
     *
     * @throws URISyntaxException if the string cannot be parsed.
     */
    @Override
    public URI unmarshal(String v) throws URISyntaxException {
        return v == null ? null : new URI(escapeString(v));
    }

    /**
     * Convert the given URI into its string format.
     *
     * @param v The URI to print.
     *
     * @return The URI as a string, or null if {@code v} is null.
     */
    @Override
    public String marshal(URI v) {
        String s = null;
        if (v != null) {
            s = v.toString();
            if (REMOVE_STATE) {
                s = removeStateParameter(s);
            }
        }
        return s;
    }

    /**
     * Escape a string before conversion to a URI and, according to setting,
     * remove the state parameter.
     *
     * @param v The URI in string form.
     *
     * @return The encoded URI.
     */
    private String escapeString(String v) {
        if (v != null) {
            int queryStart = v.indexOf('?');
            if (queryStart >= 0) {
                List<NameValuePair> queryParts = URLEncodedUtils.parse(v.substring(queryStart + 1), UTF8);
                removeStateParameter(queryParts);

                v = v.substring(0, queryStart);
                if (!queryParts.isEmpty()) {
                    v += '?' + URLEncodedUtils.format(queryParts, UTF8);
                }
            }
        }
        return v;
    }

    /**
     * Look for a parameter called "state" and remove it from the list if
     * it is found.
     *
     * @param terms The name value pair terms.
     */
    private void removeStateParameter(List<NameValuePair> terms) {
        if (REMOVE_STATE) {
            Iterator<NameValuePair> iter = terms.iterator();
            while (iter.hasNext()) {
                if ("state".equals(iter.next().getName())) {
                    iter.remove();
                }
            }
        }
    }

    /**
     * Remove any "state=" parameter from the given URI.
     *
     * @param uri The URI to modify.
     *
     * @return A new URI which is {@code uri} without the state information.
     */
    public static URI removeStateParameter(URI uri) {
        if (uri != null) {
            try {
                uri = new URI(removeStateParameter(uri.toString()));
            } catch (URISyntaxException e) {
                throw new AssertionError(
                        "Removing state information from URI " + uri + " failed: " + e.getMessage());
            }
        }
        return uri;
    }

    /**
     * Remove any "state=" parameter from the given URI.
     *
     * @param uri The URI to modify.
     *
     * @return A string which is {@code uri} without the state information.
     */
    public static String removeStateParameter(String uri) {
        if (uri != null) {
            StringBuffer builder = new StringBuffer();

            Matcher m = STATE_PATTERN.matcher(uri);
            while (m.find()) {
                String replacement = "";

                if (StringUtils.isNotEmpty(m.group(2))) {
                    // There are more options after the state parameter.
                    // Need to put the first question mark or ampersand back.
                    replacement = m.group(1);
                }

                m.appendReplacement(builder, replacement);
            }
            m.appendTail(builder);

            uri = builder.toString();
        }

        return uri;
    }
}