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.model;
018:
019: import java.sql.SQLException;
020: import java.util.ArrayList;
021: import java.util.Iterator;
022: import java.util.List;
023: import java.util.Map;
024:
025: import velosurf.context.RowIterator;
026: import velosurf.sql.Database;
027: import velosurf.sql.SqlUtil;
028: import velosurf.util.Logger;
029: import velosurf.util.StringLists;
030:
031: /** This class represents an attribute in the object model.
032: *
033: * @author <a href=mailto:claude.brisson@gmail.com>Claude Brisson</a>
034: *
035: */
036: public class Attribute {
037: /** Constant meaning the return type is undefined.
038: */
039: public static final int UNDEFINED = 0;
040:
041: /** Constant meaning the result is a single row.
042: */
043: public static final int ROW = 1;
044:
045: /** Constant meaning the result is a rowset.
046: */
047: public static final int ROWSET = 2;
048:
049: /** Constant meaning the result is a scalar.
050: */
051: public static final int SCALAR = 3;
052:
053: /**
054: * Constructor.
055: * @param name name of this attribute
056: * @param entity parent entity
057: */
058: public Attribute(String name, Entity entity) {
059: this .entity = entity;
060: db = entity.getDB();
061: this .name = name;
062: }
063:
064: /**
065: * Sets the result type.
066: * @param type
067: */
068: public void setResultType(int type) {
069: this .type = type;
070: }
071:
072: /** Gets the parent entity
073: * @return parent entity
074: */
075: public Entity getEntity() {
076: return entity;
077: }
078:
079: /** Gets the result type.
080: *
081: * @return a string describing the result type.
082: */
083: public String getResultEntity() {
084: return resultEntity;
085: }
086:
087: /**
088: * Sets the result entity.
089: * @param entityName the name of the result entity.
090: */
091: public void setResultEntity(String entityName) {
092: resultEntity = entityName;
093: }
094:
095: /**
096: * Declares this attribute as a foreign-key and specifies its foreign-key column.
097: * @param col the foreign-key column.
098: * @deprecated since Velosurf 2.0. Use a <imported-key> tag instead.
099: */
100: public void setForeignKeyColumn(String col) {
101: foreignKey = col;
102: }
103:
104: /**
105: * Adds a parameter name.
106: * @param name name of a parameter.
107: */
108: public void addParamName(String name) {
109: paramNames.add(name);
110: }
111:
112: /**
113: * Sets the query.
114: * @param query this attribute's query
115: */
116: public void setQuery(String query) {
117: this .query = query;
118: }
119:
120: /** Fetch a row.
121: *
122: * @param source source object
123: * @exception SQLException when thrown by the database
124: * @return instance fetched
125: */
126: public Object fetch(Map<String, Object> source) throws SQLException {
127: if (type != ROW)
128: throw new SQLException(
129: "cannot call fetch: result of attribute '" + name
130: + "' is not a row");
131: return db.prepare(getQuery()).fetch(buildArrayList(source),
132: db.getEntity(resultEntity));
133: }
134:
135: /** Query the resultset for this multivalued attribute.
136: *
137: * @param source the source object
138: * @exception SQLException when thrown from the database
139: * @return the resulting row iterator
140: */
141: public RowIterator query(Map<String, Object> source)
142: throws SQLException {
143: return query(source, null, null);
144: }
145:
146: /** Query the rowset for this attribute.
147: *
148: * @param source source object
149: * @param refineCriteria refine criteria
150: * @param order order clause
151: * @exception SQLException when thrown by the database
152: * @return the resulting row iterator
153: */
154: public RowIterator query(Map<String, Object> source,
155: List refineCriteria, String order) throws SQLException {
156: if (type != ROWSET)
157: throw new SQLException(
158: "cannot call query: result of attribute '" + name
159: + "' is not a rowset");
160: String query = getQuery();
161: if (refineCriteria != null)
162: query = SqlUtil.refineQuery(query, refineCriteria);
163: if (order != null && order.length() > 0)
164: query = SqlUtil.orderQuery(query, order);
165: return db.prepare(query).query(buildArrayList(source),
166: db.getEntity(resultEntity));
167: }
168:
169: /** Evaluate this scalar attribute.
170: *
171: * @param source source object
172: * @exception SQLException when thrown from the database
173: * @return the resulting scalar
174: */
175: public Object evaluate(Map<String, Object> source)
176: throws SQLException {
177: if (type != SCALAR)
178: throw new SQLException(
179: "cannot call evaluate: result of attribute '"
180: + name + "' is not a scalar");
181: return db.prepare(getQuery()).evaluate(buildArrayList(source));
182: }
183:
184: /** Get the type of this attribute.
185: *
186: * @return this attribute's type
187: */
188: public int getType() {
189: return type;
190: }
191:
192: /** Builds the list of parameter values.
193: *
194: * @param source source object
195: * @exception SQLException thrown by the database engine
196: * @return the built list
197: */
198: private List<Object> buildArrayList(Map<String, Object> source)
199: throws SQLException {
200: List<Object> result = new ArrayList<Object>();
201: if (source != null)
202: for (Iterator i = paramNames.iterator(); i.hasNext();) {
203: String paramName = (String) i.next();
204: Object value = null;
205: int dot = paramName.indexOf('.');
206: if (dot > 0 && dot < paramName.length() - 1) {
207: String parentKey = paramName.substring(0, dot);
208: value = source.get(parentKey);
209: if (value == null) {
210: value = source.get(entity
211: .resolveName(parentKey));
212: }
213: if (value != null && value instanceof Map) {
214: String subKey = paramName.substring(dot + 1);
215: value = ((Map) value).get(subKey);
216: }
217: }
218: if (value == null) {
219: value = source.get(paramName);
220: }
221: if (entity.isObfuscated(paramName))
222: value = db.deobfuscate(value);
223: if (value == null)
224: Logger.warn("Attribute " + getEntity().getName()
225: + "." + name + ": param " + paramName
226: + " is null!");
227: result.add(value);
228: }
229: return result;
230: }
231:
232: /** Gets the name of this attribute.
233: *
234: * @return name of the attribute
235: */
236: public String getName() {
237: return name;
238: }
239:
240: /** Debug method.
241: *
242: * @return the definition string of this attribute
243: */
244: public String toString() {
245: String result = "";
246: switch (type) {
247: case SCALAR:
248: result += "!";
249: break;
250: case ROWSET:
251: result += "*";
252: break;
253: }
254: if (resultEntity != null)
255: result += resultEntity;
256: if (foreignKey != null)
257: result += ": foreign key (" + foreignKey + ")";
258: else {
259: if (paramNames.size() > 0)
260: result += "(" + StringLists.join(paramNames, ",") + ")";
261: result += ": " + query;
262: }
263: return result;
264: }
265:
266: protected String getQuery() {
267: return query == null ? db.getEntity(resultEntity)
268: .getFetchQuery() : query;
269: }
270:
271: /** Gets the database connection.
272: *
273: * @return database connection
274: */
275: public Database getDB() {
276: return db;
277: }
278:
279: /** Gets caching state
280: * @return caching state
281: */
282: public boolean getCaching() {
283: return caching;
284: }
285:
286: /** Sets caching on or off
287: * @param c caching state
288: */
289: public void setCaching(boolean c) {
290: caching = c;
291: }
292:
293: /** Database connection.
294: */
295: protected Database db = null;
296: /** Name.
297: */
298: private String name = null;
299:
300: /** Parent entity.
301: */
302: private Entity entity;
303:
304: /** For row and rowset attributes, the resulting entity (if specified).
305: */
306: protected String resultEntity;
307:
308: /** If used, name of the foreign key.
309: * @deprecated
310: */
311: private String foreignKey = null;
312:
313: /** List of the parameter names.
314: */
315: private List<String> paramNames = new ArrayList<String>();
316: /** Attribute query.
317: */
318: protected String query = null;
319: /** Attribute type.
320: */
321: private int type = UNDEFINED;
322: /** Caching
323: */
324: private boolean caching = false;
325: }
|