001: /*
002: * Copyright 2003 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package velosurf.context;
018:
019: import java.sql.SQLException;
020: import java.util.AbstractList;
021: import java.util.ArrayList;
022: import java.util.Iterator;
023: import java.util.List;
024: import java.util.Map;
025: import java.util.HashMap;
026:
027: import velosurf.model.Attribute;
028: import velosurf.util.Logger;
029: import velosurf.util.StringLists;
030:
031: /** Context wrapper for attributes.
032: *
033: * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
034: */
035: public class AttributeReference extends AbstractList {
036:
037: /** Constructor.
038: *
039: * @param params the parameters map this attribute reference applies to
040: * @param attribute the wrapped attribute
041: */
042: public AttributeReference(Map<String, Object> params,
043: Attribute attribute) {
044: this .params = params;
045: this .attribute = attribute;
046: }
047:
048: /** <p>Refines this attribute's reference result. The provided criterium will be added to the 'where' clause (or a 'where' clause will be added).</p>
049: * <p>This method can be called several times, thus allowing a field-by-field handling of an html search form.</p>
050: * <p>All criteria will be merged with the sql 'and' operator (if there is an initial where clause, it is wrapped into parenthesis).</p>
051: * <p>Example : suppose we have defined the attribute 'person.children' as " *person(person_id):select * from person where parent_id=?". Then, if we issue the following calls from inside the template :</p>
052: * <blockquote>
053: * $bob.children.refine("age>18")
054: * <br>
055: * $bob.children.refine("gender='F'")
056: * </blockquote>
057: * <p>the resulting query that will be issed is :</p>
058: * <p><code>select * from person where (parent_id=?) and (age>18) and (gender='F')</code></p>
059: *
060: * @param criterium a valid sql condition
061: */
062: public void refine(String criterium) {
063: if (refineCriteria == null)
064: refineCriteria = new ArrayList();
065: refineCriteria.add(criterium);
066: }
067:
068: /** Clears any refinement made on this attribute.
069: * <p>
070: */
071: public void clearRefinement() {
072: refineCriteria = null;
073: }
074:
075: /** Called by the #foreach directive.
076: * <p>
077: * Returns a RowIterator on all possible instances of this entity, possibly previously refined and ordered.</p>
078: *
079: * @return a RowIterator on instances of this entity, or null if an error
080: * occured.
081: */
082: public Iterator iterator() {
083: try {
084: RowIterator iterator = attribute.query(params,
085: refineCriteria, order);
086: return iterator;
087: } catch (SQLException sqle) {
088: Logger.log(sqle);
089: attribute.getDB().setError(sqle.getMessage());
090: return null;
091: }
092: }
093:
094: /** Gets all the rows in a list of maps.
095: *
096: * @return a list of all the rows
097: */
098: public List getRows() {
099: try {
100: RowIterator iterator = attribute.query(params,
101: refineCriteria, order);
102: return iterator.getRows();
103: } catch (SQLException sqle) {
104: Logger.log(sqle);
105: attribute.getDB().setError(sqle.getMessage());
106: return null;
107: }
108: }
109:
110: /** Gets a list of scalars
111: * @return a list of scalars
112: */
113: public List getScalars() {
114: try {
115: RowIterator iterator = attribute.query(params,
116: refineCriteria, order);
117: return iterator.getScalars();
118: } catch (SQLException sqle) {
119: Logger.log(sqle);
120: attribute.getDB().setError(sqle.getMessage());
121: return null;
122: }
123: }
124:
125: /** Get all the rows in a map firstcol->secondcol.
126: * FIXME: better in Attribute than in AttributeReference
127: * @return a list of all the rows
128: */
129: public Map getMap() {
130: /* TODO: return a hashmap or a treemap ? */
131: Map result = null;
132: try {
133: RowIterator iterator = attribute.query(params,
134: refineCriteria, order);
135: List<String> keys = iterator.keyList();
136: if (keys != null || keys.size() < 2) {
137: Logger.error(".map needs at least two result columns");
138: return null;
139: }
140: if (keys != null && keys.size() > 2) {
141: Logger
142: .warn("attribute.map needs only two result columns, only the first two will be taken into account");
143: }
144: result = new HashMap();
145: while (iterator.hasNext()) {
146: Instance i = iterator.next();
147: result.put(i.get(keys.get(0)), i.get(keys.get(1)));
148: }
149: } catch (SQLException sqle) {
150: Logger.log(sqle);
151: attribute.getDB().setError(sqle.getMessage());
152: return null;
153: }
154: return result;
155: }
156:
157: /** <p>Specify an 'order by' clause for this attribute reference result.</p>
158: * <p>If an 'order by' clause is already present in the original query, the new one is appended (but successive calls to this method overwrite previous ones)</p>
159: * <p> postfix " DESC " to a column for descending order.</p>
160: * <p>Pass it null or an empty string to clear any ordering.</p>
161: *
162: * @param order valid sql column names (separated by commas) indicating the
163: * desired order
164: */
165: public void setOrder(String order) {
166: this .order = order;
167: }
168:
169: /** Dummy method. Since this class has to appear as a Collection for Velocity, it extends the AbstractList class but only the iterator() method has a real meaning.
170: *
171: * @param i ignored
172: * @return null
173: */
174: public Object get(int i) {
175: return null;
176: }
177:
178: /** Not yet implemented. Will return the number of rows.
179: *
180: * @return 0
181: */
182: public int size() {
183: return 0;
184: }
185:
186: /** Specified refining criteria defined on this attribute reference.
187: */
188: private List<String> refineCriteria = null;
189: /** Specified 'order by' clause specified for this attribute reference.
190: */
191: private String order = null;
192: /** The map this attribute reference applies to.
193: */
194: private Map<String, Object> params = null;
195: /** The wrapped attribute.
196: */
197: private Attribute attribute = null;
198: }
|