/* * Copyright 2012 Eric F. Savage, code@efsavage.com * * 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.ajah.util.net; import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.net.MalformedURLException; import java.net.URL; import java.net.URLEncoder; import java.util.logging.Level; import lombok.Data; import lombok.experimental.Accessors; import lombok.extern.java.Log; import com.ajah.lang.ListMap; import com.ajah.util.AjahUtils; import com.ajah.util.StringUtils; /** * This class builds a URL to avoid error-prone string concatenation, especially * regarding adding/removing/editing parameters, which the built-in {@link URL} * class does not handle. * * @author <a href="http://efsavage.com">Eric F. Savage</a>, <a * href="mailto:code@efsavage.com">code@efsavage.com</a>. */ @Data @Accessors(chain = true) @Log public class HttpURLBuilder { private String host; private String path; private int port = 0; private boolean secure; private ListMap<String, String> parameters; /** * Constructs an empty URLBuilder. */ public HttpURLBuilder() { // Empty } /** * Returns the port. If the port is not set, will return default port based * on {@link #isSecure()}. * * @return The port number. */ public int getPort() { if (this.port == 0) { if (isSecure()) { return 443; } return 80; } return this.port; } /** * Sets/replaces a single-value parameter. A null value will not be included * in the URL. * * @param name * The parameter name. * @param value * The parameter value. * @return The current instance, for chaining. */ public HttpURLBuilder setParam(final String name, final String value) { AjahUtils.requireParam(name, "name"); if (StringUtils.isBlank(value)) { return this; } if (this.parameters == null) { this.parameters = new ListMap<String, String>(); } this.parameters.putValue(name, value); return this; } /** * Creates a complete "external" URL. * * @see java.lang.Object#toString() * @throws IllegalArgumentException * If the URL could not be constructed. */ @Override public String toString() { final StringBuilder string = new StringBuilder(); if (isSecure()) { string.append("https://"); } else { string.append("http://"); } string.append(this.host); if ((!isSecure() && getPort() != 80) || (isSecure() && getPort() != 443)) { string.append(":" + this.port); } if (this.path != null && !this.path.startsWith("/")) { string.append("/"); } string.append(this.path == null ? "" : this.path); boolean params = false; if (this.parameters != null && this.parameters.size() > 0) { for (final String name : this.parameters.keySet()) { for (final String value : this.parameters.get(name)) { if (this.parameters.get(name) == null) { // Skip null values continue; } if (params) { string.append("&"); } else { string.append("?"); params = true; } string.append(name); string.append("="); try { string.append(URLEncoder.encode(value, "UTF-8")); } catch (UnsupportedEncodingException e) { log.log(Level.SEVERE, e.getMessage(), e); } } } } return string.toString(); } /** * Returns a URL object. If the source URL is malformed ( * {@link MalformedURLException}) will wrap in an * {@link IllegalArgumentException}. * * @return A URL. * @throws IllegalArgumentException * If the URL could not be constructed. */ public URL toURL() { try { return new URL(toString()); } catch (final MalformedURLException e) { throw new IllegalArgumentException(e); } } /** * Parses a URL into the component parts. * * @param url * The URL to parse. */ public void setUrl(String url) { if (StringUtils.isBlank(url)) { return; } int startPos = 0; if (url.startsWith("http://")) { startPos = 7; setSecure(false); } else if (url.startsWith("https://")) { startPos = 8; setSecure(true); } int slashPos = url.substring(startPos).indexOf('/'); int queryPos = url.indexOf('?'); if (slashPos > 0) { host = url.substring(startPos, startPos + slashPos); if (queryPos > 0) { path = url.substring(startPos + slashPos, queryPos); } else { path = url.substring(startPos + slashPos); } } if (queryPos > 0) { String[] params = url.substring(queryPos + 1).split("&"); for (String param : params) { String[] paramSplit = param.split("="); setParam(paramSplit[0], paramSplit[1]); } } } public void setParam(String name, int value) { setParam(name, String.valueOf(value)); } public void setParam(String name, BigDecimal value) { setParam(name, value.toString()); } }