/* * Copyright (c) 2009-2010 Clark & Parsia, LLC. <http://www.clarkparsia.com> * * 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 com.clarkparsia.empire.annotation.runtime; import java.util.AbstractList; import java.util.List; import java.util.ArrayList; /** * <p>Implementation of a {@link List} in which allows a mix of objects, but is typed for a particular object. It is * designed to allow elements of the list type <b>and</b> {@link Proxy} objects for objects of that type in the list.</p> * <p>For example, you can declare this list as List<Book> but instead of only Book objects, you can add * Proxy<Book> objects. When you call {@link #get} to get an element from the list, it will either return * the element straight away if it is of the correct type, or when it's a proxy object, it will get the actual object * from the proxy. This allows the proxies to defer the work of create/fetching the object until its actually used, * but it makes the use of the {@link #get} method potentially much more expensive. The overhead of this unwrapping * is only paid when proxy objects are in the list, otherwise the runtime performance should mirror a normal list * implementation.</p> * * @author Michael Grove * @since 0.7 * @version 0.7 */ public class ProxyAwareList<T> extends AbstractList<T> implements List<T> { /** * The actual list of data */ private List mList = new ArrayList(); /** * Create a new ProxyAwareList */ public ProxyAwareList() { this(new ArrayList<T>()); } /** * Create a ProxyAwareList * @param theList the list of elements to add to the data */ public ProxyAwareList(final List<T> theList) { mList = theList; } /** * Method to add a proxied object to the list. Because the list is typed so you can only add objects of * the type <T> this allows you to add Proxy objects which proxy for objects of the same type. * @param theProxiedObject the proxy object to add */ @SuppressWarnings("unchecked") public void add(Proxy<T> theProxiedObject) { mList.add(theProxiedObject); } /** * Returns the value at the given index. If the value is a proxied object, it will be retrieved and returned, * which can be an expensive operation. Thus calling this method can be slower than what one would normally * see from a List. * @inheritDoc */ public T get(final int index) { Object aObj = mList.get(index); return unwrap(aObj); } /** * Given an object from the underlying list, either cast it and return it, or if it's a proxy, get the proxied * object. * @param theObj the object to "unwrap" * @return the actual object */ @SuppressWarnings("unchecked") private T unwrap(Object theObj) { if (theObj != null && theObj instanceof Proxy) { return ((Proxy<T>)theObj).value(); } else { return (T) theObj; } } /** * @inheritDoc */ public int size() { return mList.size(); } /** * @inheritDoc */ @Override @SuppressWarnings("unchecked") public void add(int theIndex, T theElement) { mList.add(theIndex, theElement); } /** * @inheritDoc */ @Override @SuppressWarnings("unchecked") public T set(int theIndex, T theElement) { Object aObj = mList.set(theIndex, theElement); return unwrap(aObj); } /** * @inheritDoc */ @Override @SuppressWarnings("unchecked") public T remove(int theIndex) { return unwrap(mList.remove(theIndex)); } }