io.guise.framework.Bookmark Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of guise-framework Show documentation
Show all versions of guise-framework Show documentation
Guise™ Internet application framework.
/*
* Copyright © 2005-2008 GlobalMentor, Inc.
*
* 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 io.guise.framework;
import static java.util.Collections.*;
import static java.util.Objects.*;
import java.util.*;
import static com.globalmentor.net.URIs.*;
import com.globalmentor.model.NameValuePair;
import com.globalmentor.net.URIQueryParameter;
import com.globalmentor.net.URIs;
import com.globalmentor.text.ArgumentSyntaxException;
/**
* An identification of a saved state at a navigation point. The bookmark is relative to the navigation path.
* @author Garret Wilson
*/
public class Bookmark implements Cloneable {
/**
* The map of parameters keyd to parameter names. This map is not thread-safe, but it should never be modified by more than one thread because this is an
* immutable class.
*/
private HashMap parameterMap = new HashMap();
/** @return A read-only set of parameters. */
public Set getParameters() {
return unmodifiableSet(new HashSet(parameterMap.values()));
} //return a read-only set of the parameters
/**
* Returns the value associated with the first parameter of the given name.
* @param parameterName The name of the parameter.
* @return The value of the first parameter with the given name, or null
if there is no parameter with the given name.
* @throws NullPointerException if the given name is null
.
*/
public String getParameterValue(final String parameterName) {
final Parameter parameter = parameterMap.get(requireNonNull(parameterName, "Parameter name cannot be null.")); //get the requested parameter
return parameter != null ? parameter.getValue() : null; //return the parameter value, if there was a parameter
}
/**
* String constructor. The string must be suitable for use as a URI query, in the form
* "?parameter1Name=parameter1Value¶meter2Name=parameter2Value…". The parameter names and values
* should be percent-encoded as required for URIs. If there are parameters with duplicate names, only the first ones are used and the rest with the same name
* are ignored.
* @param bookmark A string representation of the bookmark, beginning with '?'.
* @throws NullPointerException if the given bookmark string is null
.
* @throws ArgumentSyntaxException if the bookmark does not begin with '?' or otherwise is not in the correct format.
*/
public Bookmark(final CharSequence bookmark) throws ArgumentSyntaxException {
final int bookmarkLength = requireNonNull(bookmark, "Bookmark string cannot be null.").length(); //get the length of the bookmark
if(bookmarkLength == 0 || bookmark.charAt(0) != QUERY_SEPARATOR) { //if the bookmark string does not begin with '?'
throw new ArgumentSyntaxException("Bookmark string " + bookmark + " must being with '?'.");
}
final NameValuePair[] parameters = URIs.getParameters(bookmark.subSequence(1, bookmarkLength).toString()); //get the parameters from the string following the query character
final Parameter[] bookmarkParameters = new Parameter[parameters.length]; //create a new array of bookmark parameters
for(int i = parameters.length - 1; i >= 0; --i) { //for each parameter
final NameValuePair parameter = parameters[i]; //get a reference to this parameter
bookmarkParameters[i] = new Parameter(parameter.getName(), parameter.getValue()); //create a corresponding bookmark parameter
}
setParameters(bookmarkParameters); //set the parameters
}
/**
* Parameter list constructor. If there are parameters with duplicate names, only the first ones are used and the rest with the same name are ignored.
* @param parameters The bookmark parameters.
* @throws NullPointerException if the given parameters list is null
.
*/
public Bookmark(final List parameters) {
setParameters(parameters); //set the parameters
}
/**
* Parameter array constructor. If there are parameters with duplicate names, only the first ones are used and the rest with the same name are ignored.
* @param parameters The optional bookmark parameters.
* @throws NullPointerException if the given parameters array is null
.
*/
public Bookmark(final Parameter... parameters) {
setParameters(parameters); //set the parameters
}
/**
* Sets bookmark parameters. If there are parameters with duplicate names, only the first ones are used and the rest with the same name are ignored. This
* method should only be called during constructor initialization.
* @param parameters The optional bookmark parameters.
*/
protected void setParameters(final Parameter... parameters) {
for(final Parameter parameter : parameters) { //for each parameter
final String parameterName = parameter.getName(); //get the parameter name
if(!parameterMap.containsKey(parameterName)) { //if this parameter is not already stored in the map
parameterMap.put(parameterName, parameter); //store this parameter in the map
}
}
}
/**
* Sets bookmark parameters. If there are parameters with duplicate names, only the first ones are used and the rest with the same name are ignored. This
* method should only be called during constructor initialization.
* @param parameters The optional bookmark parameters.
*/
protected void setParameters(final List parameters) {
for(final Parameter parameter : parameters) { //for each parameter
final String parameterName = parameter.getName(); //get the parameter name
if(!parameterMap.containsKey(parameterName)) { //if this parameter is not already stored in the map
parameterMap.put(parameterName, parameter); //store this parameter in the map
}
}
}
/**
* Creates a new bookmark with the given parameter set to the given value. If the named parameter does not exist, it will be added. If this bookmark already
* contains a parameter with the given value, this bookmark will be returned.
* @param name The parameter name.
* @param value The parameter value.
* @throws NullPointerException if the given name and/or value is null
.
* @return The new bookmark with the given parameter set to the given value.
*/
public Bookmark setParameter(final String name, final String value) {
if(value.equals(getParameterValue(name))) { //if this bookmark already has the given parameter name and value
return this; //return this bookmark; it already has the correct values
}
final Parameter newParameter = new Parameter(name, value); //create the new parameter with the new value
final Bookmark newBookmark = (Bookmark)clone(); //clone this bookmark
newBookmark.parameterMap.put(name, newParameter); //store the new parameter in the new bookmark
return newBookmark; //return our modified clone
}
/**
* Creates a new bookmark with the given parameter removed. If this bookmark does not contains the given parameter, this bookmark will be returned.
* @param name The parameter name.
* @throws NullPointerException if the given name is null
.
* @return The new bookmark with the given parameter removed.
*/
public Bookmark removeParameter(final String name) {
if(getParameterValue(name) == null) { //if this bookmark does not have given parameter name and value
return this; //return this bookmark; it already has the parameter removed
}
final Bookmark newBookmark = (Bookmark)clone(); //clone this bookmark
newBookmark.parameterMap.remove(name); //remove the parameter from the new bookmark
return newBookmark; //return our modified clone
}
@Override
@SuppressWarnings("unchecked")
//we clone our internal hash map, so we know the generic return type
public Object clone() {
try {
final Bookmark clone = (Bookmark)super.clone(); //create a clone of the bookmark
clone.parameterMap = (HashMap)parameterMap.clone(); //clone the map of parameters
return clone; //return the clone
} catch(final CloneNotSupportedException cloneNotSupportedException) { //we support cloning in this class, so we should never get this exception
throw new AssertionError(cloneNotSupportedException);
}
}
@Override
public int hashCode() {
return parameterMap.hashCode(); //return the hash code of the parameter map
}
/**
* {@inheritDoc}
*
* This implementation returns whether the given object is a bookmark with the same ID and parameters.
*
*/
@Override
public boolean equals(final Object object) {
if(object instanceof Bookmark) { //if the given object is a bookmark
return parameterMap.equals(((Bookmark)object).parameterMap); //compare parameter maps
} else { //if the given object is not a bookmark
return false; //indicate that the objects are not equal
}
}
@Override
public String toString() {
final StringBuilder bookmarkQueryStringBuilder = new StringBuilder(); //create a new string builder
if(!parameterMap.isEmpty()) { //if there are parameters
final Set parameterSet = getParameters(); //get the parameters
final Parameter[] parameters = parameterSet.toArray(new Parameter[parameterSet.size()]); //create an array of parameters
bookmarkQueryStringBuilder.append(constructQuery(parameters)); //append the parameters to the query string
} else { //if there are no parameters
bookmarkQueryStringBuilder.append(QUERY_SEPARATOR); //append the query prefix
}
return bookmarkQueryStringBuilder.toString(); //return the string we constructed
}
/**
* A bookmark parameter name/value pair. Neither the name nor the value of a bookmark parameter can be null
.
* @author Garret Wilson
*/
public static class Parameter extends URIQueryParameter {
/**
* Constructor specifying the name and value.
* @param name The parameter name.
* @param value The parameter value.
* @throws NullPointerException if the given name and/or value is null
.
*/
public Parameter(final String name, final String value) {
super(requireNonNull(name, "Parameter name cannot be null."), requireNonNull(value, "Parameter value cannot be null.")); //construct the parent class
}
}
}