org.eclipse.persistence.internal.helper.linkedlist.ExposedNodeLinkedList Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of org.eclipse.persistence.core Show documentation
Show all versions of org.eclipse.persistence.core Show documentation
EclipseLink build based upon Git transaction ecdf3c32c4
/*
* Copyright (c) 1998, 2018 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.internal.helper.linkedlist;
import java.util.*;
import org.eclipse.persistence.exceptions.ValidationException;
/**
* INTERNAL:
* A custom implementation of a linked list. This list exposes the linked nodes
* directly to the developer. It allows nodes to be referenced in code for quick
* list manipulation (ie reshuffle, remove, or queuing)
* It is specifically used in the EclipseLink cache write lock mechanism in order
* to allow quick removal of objects from the list while still providing the getFirst()
* addLast() functionality of a queue. The alternative java classes LinkedList, LinkedHashMap
* do not provide both functional requirements.
* @author Gordon Yorke
* @since 10.0.3
* @see org.eclipse.persistence.internal.helper.linkedlist.LinkedNode
*/
public class ExposedNodeLinkedList implements List {
private transient LinkedNode header;
private transient int size;
/**
* Constructs an empty list.
*/
public ExposedNodeLinkedList() {
this.size = 0;
this.header = new LinkedNode(null, null, null);
header.next = header;
header.previous = header;
}
// Bunch of List methods not currently implemented.
public Object[] toArray(Object[] array) {
throw ValidationException.operationNotSupported("toArray");
}
public Object[] toArray() {
throw ValidationException.operationNotSupported("toArray");
}
public Object set(int index, Object value) {
throw ValidationException.operationNotSupported("set");
}
public ListIterator listIterator(int index) {
throw ValidationException.operationNotSupported("listIterator");
}
public ListIterator listIterator() {
throw ValidationException.operationNotSupported("listIterator");
}
public Iterator iterator() {
throw ValidationException.operationNotSupported("iterator");
}
public List subList(int start, int end) {
throw ValidationException.operationNotSupported("subList");
}
public boolean retainAll(Collection collection) {
throw ValidationException.operationNotSupported("retainAll");
}
public boolean removeAll(Collection collection) {
throw ValidationException.operationNotSupported("removeAll");
}
public boolean containsAll(Collection collection) {
throw ValidationException.operationNotSupported("containsAll");
}
public boolean addAll(Collection collection) {
throw ValidationException.operationNotSupported("addAll");
}
public boolean addAll(int index, Collection collection) {
throw ValidationException.operationNotSupported("addAll");
}
public boolean remove(Object object) {
throw ValidationException.operationNotSupported("remove");
}
public boolean add(Object object) {
addLast(object);
return true;
}
public int lastIndexOf(Object object) {
throw ValidationException.operationNotSupported("lastIndexOf");
}
public void add(int index, Object object) {
throw ValidationException.operationNotSupported("add");
}
public Object remove(int index) {
throw ValidationException.operationNotSupported("remove");
}
public Object get(int index) {
throw ValidationException.operationNotSupported("get");
}
public boolean isEmpty() {
return size() == 0;
}
/**
* Returns the first contents in this list.
*
* @return the first contents in this list. Null if this list is empty.
*/
public Object getFirst() {
if (size == 0) {
return null;
}
return header.next.contents;
}
/**
* Returns the last contents in this list.
*
* @return the last contents in this list. Null if this list is empty.
*/
public Object getLast() {
if (size == 0) {
return null;
}
return header.previous.contents;
}
/**
* Removes and returns the first contents from this list.
*
* @return the first contents from this list.
* @throws NoSuchElementException if this list is empty.
*/
public Object removeFirst() {
if (size != 0) {
Object first = header.next.contents;
remove(header.next);
return first;
}
return null;
}
/**
* Removes and returns the last contents from this list.
*
* @return the last contents from this list.
* @throws NoSuchElementException if this list is empty.
*/
public Object removeLast() {
if (size != 0) {
Object last = header.previous.contents;
remove(header.previous);
return last;
}
return null;
}
/**
* Inserts the given contents at the beginning of this list.
*
* @param o the contents to be inserted at the beginning of this list.
*/
public LinkedNode addFirst(Object o) {
return addAfter(o, header);
}
/**
* Appends the given contents to the end of this list. (Identical in
* function to the add method; included only for consistency.)
*
* @param o the contents to be inserted at the end of this list.
*/
public LinkedNode addLast(Object o) {
return addAfter(o, header.previous);
}
/**
* Returns true if this list contains the specified contents.
* More formally, returns true if and only if this list contains
* at least one contents e such that (o==null ? e==null
* : o.equals(e)).
*
* @param o contents whose presence in this list is to be tested.
* @return true if this list contains the specified contents.
*/
public boolean contains(Object o) {
return indexOf(o) != -1;
}
/**
* Returns the number of contents in this list.
*
* @return the number of contents in this list.
*/
public int size() {
return size;
}
/**
* Removes all of the contents from this list.
*/
public void clear() {
header.next = header;
header.previous = header;
size = 0;
}
/**
* Returns the index in this list of the first occurrence of the
* specified contents, or -1 if the List does not contain this
* contents. More formally, returns the lowest index i such that
* (o==null ? get(i)==null : o.equals(get(i))), or -1 if
* there is no such index.
*
* @param o contents to search for.
* @return the index in this list of the first occurrence of the
* specified contents, or -1 if the list does not contain this
* contents.
*/
public int indexOf(Object o) {
int index = 0;
if (o == null) {
for (LinkedNode n = header.next; n != header; n = n.next) {
if (n.contents == null) {
return index;
}
index++;
}
} else {
for (LinkedNode n = header.next; n != header; n = n.next) {
if (o.equals(n.contents)) {
return index;
}
index++;
}
}
return -1;
}
private LinkedNode addAfter(Object o, LinkedNode n) {
LinkedNode newNode = new LinkedNode(o, n.next, n);
newNode.previous.next = newNode;
newNode.next.previous = newNode;
size++;
return newNode;
}
/**
* Allows a node to be efficiently removed.
*/
public void remove(LinkedNode n) {
if (n == header) {
throw new NoSuchElementException();
} else if ((n.previous == null) || (n.next == null)) {
// Handles case of node having already been removed.
return;
}
n.previous.next = n.next;
n.next.previous = n.previous;
// Also clear the nodes references to know that it has been removed.
n.previous = null;
n.next = null;
n.contents = null;
size--;
}
/**
* Allows a node to be efficiently moved first.
*/
public void moveFirst(LinkedNode node) {
if (node == header) {
throw new NoSuchElementException();
} else if ((node.previous == null) || (node.next == null)) {
// Handles case of node having already been removed.
size++;
} else {
node.previous.next = node.next;
node.next.previous = node.previous;
}
node.next = header.next;
node.previous = header;
header.next = node;
node.next.previous = node;
}
}