/**
* Copyright Microsoft Corporation
*
* 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.microsoft.azure.storage.core;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import com.microsoft.azure.storage.StorageException;
/**
* RESERVED FOR INTERNAL USE. A helper class to help modify the query string of a URI
*/
public final class UriQueryBuilder {
/**
* Stores the one to one key/ value collection of query parameters.
*/
private final HashMap<String, ArrayList<String>> parameters = new HashMap<String, ArrayList<String>>();
/**
* Adds a value to the URI with escaping.
*
* @param name
* the query key name.
* @param value
* the query value.
* @throws StorageException
*/
public void add(final String name, final String value) throws StorageException {
if (Utility.isNullOrEmpty(name)) {
throw new IllegalArgumentException(SR.QUERY_PARAMETER_NULL_OR_EMPTY);
}
this.insertKeyValue(name, value);
}
/**
* Add query parameter to an existing Uri. This takes care of any existing query parameters in the Uri.
*
* @param uri
* the original uri.
* @return the appended uri
* @throws URISyntaxException
* if the resulting uri is invalid.
* @throws StorageException
*/
public URI addToURI(final URI uri) throws URISyntaxException, StorageException {
final String origRawQuery = uri.getRawQuery();
final String rawFragment = uri.getRawFragment();
final String uriString = uri.resolve(uri).toASCIIString();
final HashMap<String, String[]> origQueryMap = PathUtility.parseQueryString(origRawQuery);
// Try/Insert original queries to map
for (final Entry<String, String[]> entry : origQueryMap.entrySet()) {
for (final String val : entry.getValue()) {
this.insertKeyValue(entry.getKey(), val);
}
}
final StringBuilder retBuilder = new StringBuilder();
// has a fragment
if (Utility.isNullOrEmpty(origRawQuery) && !Utility.isNullOrEmpty(rawFragment)) {
final int bangDex = uriString.indexOf('#');
retBuilder.append(uriString.substring(0, bangDex));
}
else if (!Utility.isNullOrEmpty(origRawQuery)) {
// has a query
final int queryDex = uriString.indexOf('?');
retBuilder.append(uriString.substring(0, queryDex));
}
else {
// no fragment or query
retBuilder.append(uriString);
if (uri.getRawPath().length() <= 0) {
retBuilder.append("/");
}
}
final String finalQuery = this.toString();
if (finalQuery.length() > 0) {
retBuilder.append("?");
retBuilder.append(finalQuery);
}
if (!Utility.isNullOrEmpty(rawFragment)) {
retBuilder.append("#");
retBuilder.append(rawFragment);
}
return new URI(retBuilder.toString());
}
/**
* Inserts a key / value in the Hashmap, assumes the value is already utf-8 encoded.
*
* @param key
* the key to insert
* @param value
* the value to insert
* @throws StorageException
*/
private void insertKeyValue(String key, String value) throws StorageException {
if (value != null) {
value = Utility.safeEncode(value);
}
if (!key.startsWith("$")) {
key = Utility.safeEncode(key);
}
ArrayList<String> list = this.parameters.get(key);
if (list == null) {
list = new ArrayList<String>();
list.add(value);
this.parameters.put(key, list);
}
else {
if (!list.contains(value)) {
list.add(value);
}
}
}
/**
* Returns a string that represents this instance. This will construct the full URI.
*
* @return a string that represents this instance.
*/
@Override
public String toString() {
final StringBuilder outString = new StringBuilder();
Boolean isFirstPair = true;
for (final String key : this.parameters.keySet()) {
if (this.parameters.get(key) != null) {
for (final String val : this.parameters.get(key)) {
if (isFirstPair) {
isFirstPair = false;
}
else {
outString.append("&");
}
outString.append(String.format("%s=%s", key, val));
}
}
}
return outString.toString();
}
}