/** * VMware Continuent Tungsten Replicator * Copyright (C) 2015 VMware, Inc. All rights reserved. * * 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. * * Initial developer(s): * Contributor(s): */ package com.continuent.tungsten.common.patterns.order; import java.io.Serializable; import java.util.ArrayList; import java.util.Iterator; import org.apache.log4j.Logger; /** * This class defines a simple RingBuffer. * * @author <a href="mailto:edward.archibald@continuent.com">Edward Archibald</a> * @version 1.0 */ public class RingBuffer<T> implements Iterable<T>, Serializable { /** * */ private static final long serialVersionUID = 4591478646508939995L; private static Logger logger = Logger.getLogger(RingBuffer.class); private int capacity; private ArrayList<T> elements; private int nextElementIndex; public RingBuffer(int capacity) { if (capacity <= 0) { logger.warn(String.format("Capacity changed from %d to %d", capacity, 20)); capacity = 20; } elements = new ArrayList<T>(capacity); this.capacity = capacity; nextElementIndex = 0; } /** * Add an element to the buffer. * * @param newElement */ public synchronized void add(T newElement) { if (elements.size() - 1 > nextElementIndex) { elements.set(nextElementIndex++, newElement); } else { elements.add(nextElementIndex++, newElement); } if (nextElementIndex == capacity) { nextElementIndex = 0; } } public synchronized void setNextElementIndex(int nextElementIndex) { this.nextElementIndex = nextElementIndex; } public synchronized void addAll(RingBuffer<T> ringBuffer) { this.elements.addAll(ringBuffer.getElements()); } public synchronized ArrayList<T> getElements() { return elements; } /** * Formats a string with elements counted and delimited by a simple text * header. {@inheritDoc} * * @see java.lang.Object#toString() */ public String toString() { StringBuilder builder = new StringBuilder(); int elementCount = 0; for (T element : this) { builder.append(String.format( "============== %d ===============\n%s\n", ++elementCount, (element != null ? element : "EMPTY"))); } return builder.toString(); } /** * Get the total number of elements in the buffer. */ public synchronized int getElementCount() { return elements.size(); } /** * Get the maximum capacity of the buffer. */ public synchronized int getCapacity() { return capacity; } /** * Get a synchronized copy of the elements in this buffer. */ public synchronized RingBuffer<T> clone() { RingBuffer<T> clonedBuffer = new RingBuffer<T>(this.capacity); clonedBuffer.addAll(this); clonedBuffer.setNextElementIndex(this.getnextElementIndex()); return clonedBuffer; } /** * Returns the nextElementIndex value. * * @return Returns the nextElementIndex. */ public int getnextElementIndex() { return nextElementIndex; } public int getLastElement() { if (nextElementIndex == 0) { return capacity - 1; } return nextElementIndex - 1; } /** * Quick and dirty unit test for this class. * * @param argv */ public static void main(String argv[]) { RingBuffer<String> ringBuffer = new RingBuffer<String>(6); for (int i = 0; i < 4; i++) { String element = String.format("ELEMENT %d", i); ringBuffer.add(element); } System.out.println("SHOULD SHOW ONLY 4 ELEMENTS"); System.out.println(ringBuffer); ringBuffer = new RingBuffer<String>(1); for (int i = 0; i < 50; i++) { String element = String.format("ELEMENT %d", i); ringBuffer.add(element); } System.out.println("SHOULD SHOW ONLY 1 ELEMENT, NUMBERED 49"); System.out.println(ringBuffer); ringBuffer = new RingBuffer<String>(10); System.out.println("SHOULD NOT SHOW ANY ELEMENTS"); System.out.println(ringBuffer.toString()); for (int i = 0; i < 20; i++) { String element = String.format("ELEMENT %d", i); ringBuffer.add(element); } System.out.println("SHOULD SHOW ONLY 10 ELEMENTS, HIGHEST IS 19"); System.out.println(ringBuffer); System.out.println("SHOULD PRINT A WARNING AND RESET CAPACITY TO 20"); ringBuffer = new RingBuffer<String>(0); ringBuffer.add("FOO"); ringBuffer.add("BAR"); System.out.println(ringBuffer); } /** * Let's be iterable! {@inheritDoc} * * @see java.lang.Iterable#iterator() */ public Iterator<T> iterator() { return new RingBufferIterator<T>(this); } /** * This class defines a RingBufferIterator * * @author <a href="mailto:edward.archibald@continuent.com">Edward * Archibald</a> * @version 1.0 */ public class RingBufferIterator<E> implements Iterator<E> { private ArrayList<E> elements; private int lastElementIndex; private int elementCursor; boolean rolledOver = false; /** * Creates a new <code>RingBufferIterator</code> object * * @param ringBuffer */ public RingBufferIterator(RingBuffer<E> ringBuffer) { RingBuffer<E> clonedBuffer = ringBuffer.clone(); this.elements = clonedBuffer.getElements(); this.lastElementIndex = clonedBuffer.getLastElement(); this.elementCursor = this.lastElementIndex; } /** * {@inheritDoc} * * @see java.util.Iterator#hasNext() */ public boolean hasNext() { if (elements.size() == 0) { return false; } if (!rolledOver) { return true; } else if (elementCursor <= lastElementIndex) { return false; } return true; } /** * {@inheritDoc} * * @see java.util.Iterator#next() */ public E next() { E element = null; element = this.elements.get(elementCursor--); if (!rolledOver) { if (elementCursor == -1) { this.elementCursor = elements.size() - 2; rolledOver = true; } return element; } else { return element; } } /** * {@inheritDoc} * * @see java.util.Iterator#remove() */ public void remove() { } } }