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

net.officefloor.server.http.impl.ProcessAwareHttpResponseHeaders Maven / Gradle / Ivy

The newest version!
/*-
 * #%L
 * HTTP Server
 * %%
 * Copyright (C) 2005 - 2020 Daniel Sagenschneider
 * %%
 * 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.
 * #L%
 */

package net.officefloor.server.http.impl;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Consumer;

import net.officefloor.frame.api.managedobject.ManagedObjectContext;
import net.officefloor.frame.api.managedobject.ProcessSafeOperation;
import net.officefloor.frame.internal.structure.ProcessState;
import net.officefloor.server.http.HttpHeader;
import net.officefloor.server.http.HttpHeaderName;
import net.officefloor.server.http.HttpHeaderValue;
import net.officefloor.server.http.HttpResponseHeaders;
import net.officefloor.server.http.HttpResponseWriter;
import net.officefloor.server.http.WritableHttpHeader;

/**
 * {@link ProcessState} aware {@link HttpResponseHeaders}.
 * 
 * @author Daniel Sagenschneider
 */
public class ProcessAwareHttpResponseHeaders implements HttpResponseHeaders {

	/**
	 * Head {@link WritableHttpHeader} instance.
	 */
	private WritableHttpHeader head = null;

	/**
	 * Tail {@link WritableHttpHeader} instance.
	 */
	private WritableHttpHeader tail = null;

	/**
	 * {@link ManagedObjectContext}.
	 */
	private final ManagedObjectContext context;

	/**
	 * Instantiate.
	 * 
	 * @param context {@link ManagedObjectContext}.
	 */
	public ProcessAwareHttpResponseHeaders(ManagedObjectContext context) {
		this.context = context;
	}

	/**
	 * Obtains the head {@link WritableHttpHeader} to the linked list of
	 * {@link WritableHttpHeader} instances for the {@link HttpResponseWriter}.
	 * 
	 * @return Head {@link WritableHttpHeader} to the linked list of
	 *         {@link WritableHttpHeader} instances for the
	 *         {@link HttpResponseWriter}. May be null.
	 */
	public WritableHttpHeader getWritableHttpHeaders() {
		return this.head;
	}

	/**
	 * Removes the {@link HttpHeader}.
	 * 
	 * @param header {@link WritableHttpHeader} to remove.
	 * @return Previous {@link WritableHttpHeader}. May be null if
	 *         head.
	 */
	private WritableHttpHeader removeHttpHeader(WritableHttpHeader header) {

		// Determine if first
		if (header == this.head) {
			// Drop the first
			this.head = this.head.next;
			if (this.head == null) {
				this.tail = null; // only header
			}
			return null; // removed first (no previous)

		} else {
			// Find previous
			WritableHttpHeader prev = this.head;
			while (prev.next != header) {
				prev = prev.next;
				if (prev == null) {
					throw new NoSuchElementException();
				}
			}

			// Drop the current (moving out of linked list)
			prev.next = header.next;
			if (prev.next == null) {
				// Removed last, so update list
				this.tail = prev;
			}
			return prev; // removed
		}
	}

	/**
	 * Easy access to running {@link ProcessSafeOperation}.
	 * 
	 * @param operation {@link ProcessSafeOperation}.
	 * @return Result of {@link ProcessSafeOperation}.
	 * @throws T Potential {@link Throwable} from {@link ProcessSafeOperation}.
	 */
	private final  R safe(ProcessSafeOperation operation) throws T {
		return this.context.run(operation);
	}

	/**
	 * Safely adds a {@link HttpHeader}.
	 * 
	 * @param headerName  {@link HttpHeaderName}.
	 * @param headerValue {@link HttpHeaderValue}.
	 * @return Added {@link HttpHeader}.
	 */
	private final HttpHeader safeAddHeader(HttpHeaderName headerName, HttpHeaderValue headerValue) {
		return this.safe(() -> {
			WritableHttpHeader header = new WritableHttpHeader(headerName, headerValue);
			if (this.head == null) {
				// First header
				this.head = header;
				this.tail = header;
			} else {
				// Append the header
				this.tail.next = header;
				this.tail = header;
			}
			return header;
		});
	}

	/**
	 * Obtains the {@link Iterator} to all the {@link WritableHttpHeader} instances.
	 * 
	 * @return {@link Iterator} to all the {@link WritableHttpHeader} instances.
	 */
	private Iterator getHttpHeaderIterator() {
		return new Iterator() {

			WritableHttpHeader current = null;

			@Override
			public boolean hasNext() {
				return (this.current == null ? (ProcessAwareHttpResponseHeaders.this.head != null)
						: (this.current.next != null));
			}

			@Override
			public WritableHttpHeader next() {

				// Determine if first
				if (this.current == null) {
					this.current = ProcessAwareHttpResponseHeaders.this.head;
					if (this.current == null) {
						throw new NoSuchElementException();
					}
					return this.current;
				}

				// Obtain next (ensuring exists)
				if (this.current.next == null) {
					throw new NoSuchElementException();
				}
				this.current = this.current.next;
				return this.current;
			}

			@Override
			public void remove() {
				this.current = ProcessAwareHttpResponseHeaders.this.removeHttpHeader(this.current);
			}
		};
	}

	/**
	 * Provides {@link ProcessSafeOperation} wrapping of {@link Iterator}.
	 */
	private class SafeIterator implements Iterator {

		/**
		 * Unsafe {@link Iterator}.
		 */
		private final Iterator unsafeIterator;

		/**
		 * Instantiate.
		 * 
		 * @param unsafeIterator Unsafe {@link Iterator}.
		 */
		private SafeIterator(Iterator unsafeIterator) {
			this.unsafeIterator = unsafeIterator;
		}

		/**
		 * Easy access to running {@link ProcessSafeOperation}.
		 * 
		 * @param operation {@link ProcessSafeOperation}.
		 * @return Result of {@link ProcessSafeOperation}.
		 * @throws T Potential {@link Throwable} from {@link ProcessSafeOperation}.
		 */
		private final  R safe(ProcessSafeOperation operation) throws T {
			return ProcessAwareHttpResponseHeaders.this.safe(operation);
		}

		/*
		 * =============== Iterator ===============
		 */

		@Override
		public boolean hasNext() {
			return this.safe(() -> this.unsafeIterator.hasNext());
		}

		@Override
		public HttpHeader next() {
			return this.safe(() -> this.unsafeIterator.next());
		}

		@Override
		public void remove() {
			this.safe(() -> {
				this.unsafeIterator.remove();
				return null; // void return
			});
		}

		@Override
		public void forEachRemaining(Consumer action) {
			this.safe(() -> {
				this.unsafeIterator.forEachRemaining(action);
				return null; // void return
			});
		}
	}

	/*
	 * ====================== HttpResponseHeaders ========================
	 */

	@Override
	public Iterator iterator() {
		return new SafeIterator(this.getHttpHeaderIterator());
	}

	@Override
	public HttpHeader addHeader(String name, String value) throws IllegalArgumentException {
		return this.safeAddHeader(new HttpHeaderName(name), new HttpHeaderValue(value));
	}

	@Override
	public HttpHeader addHeader(HttpHeaderName name, String value) throws IllegalArgumentException {
		return this.safeAddHeader(name, new HttpHeaderValue(value));
	}

	@Override
	public HttpHeader addHeader(String name, HttpHeaderValue value) throws IllegalArgumentException {
		return this.safeAddHeader(new HttpHeaderName(name), value);
	}

	@Override
	public HttpHeader addHeader(HttpHeaderName name, HttpHeaderValue value) throws IllegalArgumentException {
		return this.safeAddHeader(name, value);
	}

	@Override
	public boolean removeHeader(HttpHeader header) {
		if (!(header instanceof WritableHttpHeader)) {
			return false; // only contains writable headers
		}
		return this.safe(() -> {
			try {
				this.removeHttpHeader((WritableHttpHeader) header);
				return true;
			} catch (NoSuchElementException ex) {
				return false;
			}
		});
	}

	@Override
	public boolean removeHeaders(String name) {
		return this.safe(() -> {
			Iterator iterator = this.getHttpHeaderIterator();
			boolean isRemoved = false;
			while (iterator.hasNext()) {
				if (name.equalsIgnoreCase(iterator.next().getName())) {
					iterator.remove();
					isRemoved = true;
				}
			}
			return isRemoved;
		});
	}

	@Override
	public HttpHeader getHeader(String name) {
		return this.safe(() -> {
			Iterator iterator = this.getHttpHeaderIterator();
			while (iterator.hasNext()) {
				WritableHttpHeader header = iterator.next();
				if (name.equalsIgnoreCase(header.getName())) {
					return header;
				}
			}
			return null; // not found
		});
	}

	@Override
	public Iterable getHeaders(String name) {
		return () -> new SafeIterator(new Iterator() {

			WritableHttpHeader current = null;

			@Override
			public boolean hasNext() {

				// Obtain the next header
				WritableHttpHeader next;
				if (this.current == null) {
					// First header
					next = ProcessAwareHttpResponseHeaders.this.head;
				} else {
					next = this.current.next;
				}

				// Determine if further values
				while (next != null) {
					if (name.equalsIgnoreCase(next.getName())) {
						return true;
					}
					next = next.next;
				}
				return false; // no further headers by name
			}

			@Override
			public HttpHeader next() {

				// Obtain the next header
				WritableHttpHeader next;
				if (this.current == null) {
					// First header
					next = ProcessAwareHttpResponseHeaders.this.head;
				} else {
					next = this.current.next;
				}

				// Move to next position
				while (next != null) {
					if (name.equalsIgnoreCase(next.getName())) {
						// Found next value
						this.current = next;
						return this.current;
					}
					next = next.next;
				}

				// As here, no next header by name
				throw new NoSuchElementException();
			}

			@Override
			public void remove() {
				this.current = ProcessAwareHttpResponseHeaders.this.removeHttpHeader(this.current);
			}
		});
	}

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy