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

org.refcodes.web.AbstractHeaderFields Maven / Gradle / Ivy

Go to download

This artifact provides web (HTTP) related definitions and types being used by REFCODES.ORG web related functionality and artifacts.

The newest version!
// /////////////////////////////////////////////////////////////////////////////
// REFCODES.ORG
// /////////////////////////////////////////////////////////////////////////////
// This code is copyright (c) by Siegfried Steiner, Munich, Germany, distributed
// on an "AS IS" BASIS WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, and licen-
// sed under the following (see "http://en.wikipedia.org/wiki/Multi-licensing")
// licenses:
// -----------------------------------------------------------------------------
// GNU General Public License, v3.0 ("http://www.gnu.org/licenses/gpl-3.0.html")
// -----------------------------------------------------------------------------
// Apache License, v2.0 ("http://www.apache.org/licenses/TEXT-2.0")
// -----------------------------------------------------------------------------
// Please contact the copyright holding author(s) of the software artifacts in
// question for licensing issues not being covered by the above listed licenses,
// also regarding commercial licensing models or regarding the compatibility
// with other open source licenses.
// /////////////////////////////////////////////////////////////////////////////

package org.refcodes.web;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.refcodes.data.Delimiter;

/**
 * Abstract implementation of the {@link HeaderFields} type.
 * 
 * @param  The {@link Cookie} type to be used by sub-classes.
 * @param  The type of the sub-class, required for the builder methods such
 *        as {@link #withHost(String)}.
 */
@SuppressWarnings("serial")
public abstract class AbstractHeaderFields> extends AbstractHttpFields implements HeaderFields {

	// /////////////////////////////////////////////////////////////////////////
	// VARIABLES:
	// /////////////////////////////////////////////////////////////////////////

	private final List _cookies = new ArrayList<>();

	// /////////////////////////////////////////////////////////////////////////
	// CONSTRUCTORS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Instantiates a new abstract Header-Fields.
	 */
	public AbstractHeaderFields() {}

	/**
	 * Instantiates a new abstract Header-Fields.
	 *
	 * @param aHttpFields the http fields
	 */
	public AbstractHeaderFields( Map> aHttpFields ) {
		toHeaderFields( aHttpFields, this );
	}

	// /////////////////////////////////////////////////////////////////////////
	// METHODS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List get( Object aKey ) {
		final String theKey = toHeaderField( aKey );
		// Cookie Header-Field bypass |-->
		if ( theKey != null && theKey.equalsIgnoreCase( getCookieFieldName() ) ) {
			final String[] theCookies = toHttpCookies();
			if ( theCookies != null ) {
				return new ArrayList<>( Arrays.asList( theCookies ) );
			}
			else {
				return null;
			}
		}
		// <--| Cookie Header-Field bypass
		return super.get( theKey );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set keySet() {
		if ( _cookies.size() != 0 ) {
			final Set theKeySet = new HashSet<>( super.keySet() );
			theKeySet.add( getCookieFieldName() );
			return theKeySet;
		}
		return super.keySet();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public Set>> entrySet() {
		if ( _cookies.size() != 0 ) {
			final String[] theCookies = toHttpCookies();
			if ( theCookies != null ) {
				final Set>> theEntrySet = new HashSet<>( super.entrySet() );
				theEntrySet.add( new Field( getCookieFieldName(), new ArrayList( Arrays.asList( theCookies ) ) ) );
				return theEntrySet;
			}
		}
		return super.entrySet();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List put( String aKey, List aValue ) {
		final String theKey = toHeaderField( aKey );
		// Cookie Header-Field bypass |-->
		if ( theKey != null && theKey.equalsIgnoreCase( getCookieFieldName() ) ) {
			synchronized ( _cookies ) {
				List theCookieFields = null;
				if ( _cookies != null && _cookies.size() != 0 ) {
					theCookieFields = new ArrayList<>();
					for ( C eCookie : _cookies ) {
						theCookieFields.add( eCookie.toHttpCookie() );
					}
				}
				_cookies.clear();
				for ( String aHttpCookie : aValue ) {
					addCookie( createCookie( aHttpCookie ) );
				}
				return theCookieFields;
			}
		}
		// <--| Cookie Header-Field bypass
		return super.put( theKey, aValue );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addTo( String aHeaderField, String aValue ) {
		final String theKey = toHeaderField( aHeaderField );
		// Cookie Header-Field bypass |-->
		if ( theKey.equals( getCookieFieldName() ) ) {
			addCookie( createCookie( aValue ) );
		}
		// <--| Cookie Header-Field bypass
		else {
			HeaderFields.super.addTo( theKey, aValue );
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public C addCookie( C aCookie ) {
		_cookies.add( aCookie );
		return aCookie;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public List getAllCookies() {
		return _cookies;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public C addCookie( String aCookieName, String aValue ) {
		return addCookie( createCookie( aCookieName, aValue ) );
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void putAll( Map> aMap ) {
		// As the field names are varying their case, we must go this way:
		List eValues;
		for ( String eKey : aMap.keySet() ) {
			eValues = aMap.get( eKey );
			eKey = HeaderField.toHttpHeaderField( eKey );
			if ( getCookieFieldName().equalsIgnoreCase( eKey ) ) {
				if ( eValues != null && !eValues.isEmpty() ) {
					for ( String eHttpCookie : eValues ) {
						addCookie( eHttpCookie );
					}
				}
			}
			else {
				put( eKey, new ArrayList( eValues ) );
			}
		}
	}

	// /////////////////////////////////////////////////////////////////////////
	// HOOKS:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * Tests the given HTTP Header-Field name whether it holds a comma separated
	 * value. You may overwrite this method and add your own implementation or
	 * extend this method by overwriting it and calling it in you overwritten
	 * method.
	 * 
	 * @param aHeaderName The name of the header to be tested.
	 * 
	 * @return True if the value being held by the given Header-Field name is a
	 *         comma separated list.
	 */
	protected static boolean isCommaSeparatedHeaderField( String aHeaderName ) {
		return HeaderField.ACCEPT.getName().equalsIgnoreCase( aHeaderName ) || HeaderField.COOKIE.getName().equalsIgnoreCase( aHeaderName ) || HeaderField.SET_COOKIE.getName().equalsIgnoreCase( aHeaderName );
	}

	/**
	 * Copies the provided "from" fields into the provided "to" fields. Omits
	 * empty or null values.
	 * 
	 * @param aFromFields The fields from which to copy.
	 * @param aToFields The fields to which to copy.
	 */
	protected static void toHeaderFields( Map> aFromFields, HeaderFields aToFields ) {
		List eValues;
		String eElement;
		for ( String eKey : aFromFields.keySet() ) {
			eValues = aFromFields.get( eKey );
			eKey = HeaderField.toHttpHeaderField( eKey );
			if ( eValues != null ) {
				final Iterator e = eValues.iterator();
				while ( e.hasNext() ) {
					eElement = e.next();
					if ( eElement != null && eElement.trim().length() != 0 ) {
						// Do https://www.metacodes.pro Header-Fields processing |-->
						// Question: Which Header-Fields are known to be comma
						// separated?
						if ( isCommaSeparatedHeaderField( eKey ) ) {
							final String[] eElements = eElement.split( "" + Delimiter.HTTP_HEADER_ELEMENTS.getChar() );
							aToFields.addTo( eKey, eElements );
						}
						// <--| Do https://www.metacodes.pro Header-Fields processing
						else {
							aToFields.addTo( eKey, eElement );
						}
					}
				}
			}
		}
	}

	/**
	 * Normalizes the case of the provided Header-Field to conform to the
	 * {@link HeaderField#getName()} format if possible. Else the unmodified
	 * Header-Field is returned.
	 * 
	 * @param aHeaderField The field to normalize.
	 * 
	 * @return The Header-Field, in case of normalization the normalized one.
	 */
	protected String toHeaderField( Object aHeaderField ) {
		final String theHeaderField;
		if ( aHeaderField == null ) {
			return null;
		}
		theHeaderField = !( aHeaderField instanceof String ) ? aHeaderField.toString() : (String) aHeaderField;
		return HeaderField.toHttpHeaderField( theHeaderField );
	}

	/**
	 * The Header-Field name for the {@link Cookie} elements. The Header-Field
	 * name differs from the context, e.g. when setting a {@link Cookie}
	 * server-side or when retrieving a {@link Cookie} client-side.
	 * 
	 * @return The Header-Field where the {@link Cookie} elements are stored.
	 */
	protected abstract String getCookieFieldName();

	/**
	 * Creates a plain {@link Cookie} with the given name and value.
	 * 
	 * @param aCookieName The name of the {@link Cookie}.
	 * @param aValue The value for the {@link Cookie}
	 * 
	 * @return The {@link Cookie} with the given name and value.
	 */
	protected abstract C createCookie( String aCookieName, String aValue );

	/**
	 * Creates a {@link Cookie} from the given HTTP cookie {@link String} as
	 * retrieved from the according Header-Field.
	 * 
	 * @param aHttpCookie The text of the Header-Field for the cookie to be
	 *        created.
	 * 
	 * @return The {@link Cookie} with the given cookie properties.
	 */
	protected abstract C createCookie( String aHttpCookie );

	// /////////////////////////////////////////////////////////////////////////
	// INNER CLASSES:
	// /////////////////////////////////////////////////////////////////////////

	/**
	 * The Class EntryImpl.
	 */
	private static class Field implements Entry> {

		private final String _key;
		private List _value;

		/**
		 * Instantiates a new entry impl.
		 *
		 * @param aKey the key
		 * @param aValue the value
		 */
		public Field( String aKey, List aValue ) {
			_key = aKey;
			_value = aValue;
		}

		/**
		 * Gets the key.
		 *
		 * @return the key
		 */
		@Override
		public String getKey() {
			return _key;
		}

		/**
		 * Gets the value.
		 *
		 * @return the value
		 */
		@Override
		public List getValue() {
			return _value;
		}

		/**
		 * Sets the value.
		 *
		 * @param value the value
		 * 
		 * @return the list
		 */
		@Override
		public List setValue( List value ) {
			final List theReturn = _value;
			_value = value;
			return theReturn;
		}
	}
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy