001: /*
002: * Copyright (c) 2002-2006 by OpenSymphony
003: * All rights reserved.
004: */
005: package com.opensymphony.xwork.util;
006:
007: import com.opensymphony.xwork.ActionContext;
008: import com.opensymphony.xwork.ObjectFactory;
009: import com.opensymphony.xwork.XworkException;
010: import org.apache.commons.logging.Log;
011: import org.apache.commons.logging.LogFactory;
012:
013: import java.util.ArrayList;
014: import java.util.Collection;
015: import java.util.Iterator;
016: import java.util.Map;
017:
018: /**
019: * A simple list that guarantees that inserting and retrieving objects will always work regardless
020: * of the current size of the list. Upon insertion, type conversion is also performed if necessary.
021: * Empty beans will be created to fill the gap between the current list size and the requested index
022: * using ObjectFactory's {@link ObjectFactory#buildBean(Class,java.util.Map) buildBean} method.
023: *
024: * @author Patrick Lightbody
025: * @deprecated Native support for expanding lists and maps is provided in XWork 1.1, so this is no longer needed.
026: */
027: public class XWorkList extends ArrayList {
028: private static final Log LOG = LogFactory
029: .getLog(XWorkConverter.class);
030:
031: private Class clazz;
032:
033: public XWorkList(Class clazz) {
034: this .clazz = clazz;
035: }
036:
037: public XWorkList(Class clazz, Collection c) {
038: super (c.size());
039: this .clazz = clazz;
040: addAll(c);
041: }
042:
043: public XWorkList(Class clazz, int initialCapacity) {
044: super (initialCapacity);
045: this .clazz = clazz;
046: }
047:
048: /**
049: * Inserts the specified element at the specified position in this list. Shifts the element
050: * currently at that position (if any) and any subsequent elements to the right (adds one to
051: * their indices).
052: * <p/>
053: * This method is guaranteed to work since it will create empty beans to fill the gap between
054: * the current list size and the requested index to enable the element to be set. This method
055: * also performs any necessary type conversion.
056: *
057: * @param index index at which the specified element is to be inserted.
058: * @param element element to be inserted.
059: */
060: public void add(int index, Object element) {
061: if (index >= this .size()) {
062: get(index);
063: }
064:
065: element = convert(element);
066:
067: super .add(index, element);
068: }
069:
070: /**
071: * Appends the specified element to the end of this list.
072: * <p/>
073: * This method performs any necessary type conversion.
074: *
075: * @param element element to be appended to this list.
076: * @return <tt>true</tt> (as per the general contract of Collection.add).
077: */
078: public boolean add(Object element) {
079: element = convert(element);
080:
081: return super .add(element);
082: }
083:
084: /**
085: * Appends all of the elements in the specified Collection to the end of this list, in the order
086: * that they are returned by the specified Collection's Iterator. The behavior of this
087: * operation is undefined if the specified Collection is modified while the operation is in
088: * progress. (This implies that the behavior of this call is undefined if the specified
089: * Collection is this list, and this list is nonempty.)
090: * <p/>
091: * This method performs any necessary type conversion.
092: *
093: * @param c the elements to be inserted into this list.
094: * @return <tt>true</tt> if this list changed as a result of the call.
095: * @throws NullPointerException if the specified collection is null.
096: */
097: public boolean addAll(Collection c) {
098: if (c == null) {
099: throw new NullPointerException("Collection to add is null");
100: }
101:
102: Iterator it = c.iterator();
103:
104: while (it.hasNext()) {
105: add(it.next());
106: }
107:
108: return true;
109: }
110:
111: /**
112: * Inserts all of the elements in the specified Collection into this list, starting at the
113: * specified position. Shifts the element currently at that position (if any) and any
114: * subsequent elements to the right (increases their indices). The new elements will appear in
115: * the list in the order that they are returned by the specified Collection's iterator.
116: * <p/>
117: * This method is guaranteed to work since it will create empty beans to fill the gap between
118: * the current list size and the requested index to enable the element to be set. This method
119: * also performs any necessary type conversion.
120: *
121: * @param index index at which to insert first element from the specified collection.
122: * @param c elements to be inserted into this list.
123: * @return <tt>true</tt> if this list changed as a result of the call.
124: */
125: public boolean addAll(int index, Collection c) {
126: if (c == null) {
127: throw new NullPointerException("Collection to add is null");
128: }
129:
130: boolean trim = false;
131:
132: if (index >= this .size()) {
133: trim = true;
134: }
135:
136: for (Iterator it = c.iterator(); it.hasNext(); index++) {
137: add(index, it.next());
138: }
139:
140: if (trim) {
141: remove(this .size() - 1);
142: }
143:
144: return true;
145: }
146:
147: /**
148: * Returns the element at the specified position in this list.
149: * <p/>
150: * An object is guaranteed to be returned since it will create empty beans to fill the gap
151: * between the current list size and the requested index.
152: *
153: * @param index index of element to return.
154: * @return the element at the specified position in this list.
155: */
156: public synchronized Object get(int index) {
157: while (index >= this .size()) {
158: try {
159: //todo
160: this .add(ObjectFactory.getObjectFactory().buildBean(
161: clazz, null)); //ActionContext.getContext().getContextMap()));
162: } catch (Exception e) {
163: throw new XworkException(e.getMessage());
164: }
165: }
166:
167: return super .get(index);
168: }
169:
170: /**
171: * Replaces the element at the specified position in this list with the specified element.
172: * <p/>
173: * This method is guaranteed to work since it will create empty beans to fill the gap between
174: * the current list size and the requested index to enable the element to be set. This method
175: * also performs any necessary type conversion.
176: *
177: * @param index index of element to replace.
178: * @param element element to be stored at the specified position.
179: * @return the element previously at the specified position.
180: */
181: public Object set(int index, Object element) {
182: if (index >= this .size()) {
183: get(index);
184: }
185:
186: element = convert(element);
187:
188: return super .set(index, element);
189: }
190:
191: private Object convert(Object element) {
192: if ((element != null)
193: && !clazz.isAssignableFrom(element.getClass())) {
194: // convert to correct type
195: if (LOG.isDebugEnabled()) {
196: LOG.debug("Converting from "
197: + element.getClass().getName() + " to "
198: + clazz.getName());
199: }
200:
201: Map context = ActionContext.getContext().getContextMap();
202: element = XWorkConverter.getInstance().convertValue(
203: context, null, null, null, element, clazz);
204: }
205:
206: return element;
207: }
208:
209: public boolean contains(Object element) {
210: element = convert(element);
211:
212: return super.contains(element);
213: }
214: }
|