001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.amber.query;
031:
032: import com.caucho.amber.manager.AmberConnection;
033: import com.caucho.amber.type.EntityType;
034: import com.caucho.amber.type.Type;
035: import com.caucho.bytecode.JClass;
036: import com.caucho.util.Alarm;
037:
038: import java.sql.PreparedStatement;
039: import java.sql.ResultSet;
040: import java.sql.SQLException;
041: import java.util.ArrayList;
042: import java.util.List;
043:
044: /**
045: * Represents the application's view of the query.
046: */
047: public class CachedQuery {
048: private SelectQuery _query;
049: private CachedQueryKey _key;
050: private ResultSetImpl _rs;
051:
052: private Type[] _argTypes;
053: private Object[] _argValues;
054: private int _argLength = 0;
055:
056: private long _loadTime;
057:
058: private ArrayList<Object> _values = new ArrayList<Object>();
059:
060: private volatile boolean _isLoading;
061: private volatile boolean _isValidLoad;
062:
063: CachedQuery(UserQuery query) {
064: _query = (SelectQuery) query.getQuery();
065:
066: Type[] argTypes = query.getArgTypes();
067: Object[] argValues = query.getArgValues();
068:
069: _argLength = query.getArgLength();
070:
071: if (_argLength > 0) {
072: _argTypes = new Type[_argLength];
073: _argValues = new Object[_argLength];
074:
075: for (int i = _argLength - 1; i >= 0; i--) {
076: _argTypes[i] = argTypes[i];
077: _argValues[i] = argValues[i];
078: }
079: }
080:
081: _key = new CachedQueryKey();
082: _key.init(_query.getQueryString(), _argValues, _argLength);
083:
084: _query.registerUpdates(this );
085: }
086:
087: /**
088: * returns the key.
089: */
090: public CachedQueryKey getKey() {
091: return _key;
092: }
093:
094: /**
095: * Updates the query.
096: */
097: public void update() {
098: synchronized (this ) {
099: _loadTime = 0;
100: _isValidLoad = false;
101: }
102: }
103:
104: /**
105: * Executes the query, filling the list.
106: */
107: public void list(List<Object> list, AmberConnection aConn,
108: long maxAge) throws SQLException {
109: Type type = _query.getResultType(0);
110: EntityType entityType = (EntityType) type;
111: JClass cl = entityType.getBeanClass();
112:
113: synchronized (this ) {
114: long now = Alarm.getCurrentTime();
115:
116: if (now < _loadTime + maxAge || _isLoading && _loadTime > 0) {
117: int length = _values.size();
118:
119: for (int i = 0; i < length; i++) {
120: Object key = _values.get(i);
121:
122: list.add(aConn.loadLazy(cl.getName(), entityType
123: .getName(), (java.io.Serializable) key));
124: }
125: return;
126: }
127:
128: _isLoading = true;
129: _isValidLoad = true;
130: }
131:
132: try {
133: ArrayList<Object> values = new ArrayList<Object>();
134:
135: ResultSetImpl rs = executeQuery(aConn);
136:
137: while (rs.next()) {
138: values.add(rs.getKey(1));
139:
140: list.add(rs.getObject(1));
141: }
142:
143: rs.close();
144:
145: synchronized (this ) {
146: if (_isValidLoad) {
147: _values = values;
148:
149: _loadTime = Alarm.getCurrentTime();
150: }
151: }
152: } finally {
153: _isLoading = false;
154: }
155: }
156:
157: /**
158: * Executes the query returning a result set.
159: */
160: private ResultSetImpl executeQuery(AmberConnection aConn)
161: throws SQLException {
162: if (_rs == null)
163: _rs = new ResultSetImpl();
164:
165: PreparedStatement pstmt;
166: pstmt = aConn.prepareStatement(_query.getSQL());
167:
168: pstmt.clearParameters();
169:
170: for (int i = 0; i < _argLength; i++) {
171: if (_argValues[i] != null)
172: _argTypes[i].setParameter(pstmt, i + 1, _argValues[i]);
173: }
174:
175: ResultSet rs = pstmt.executeQuery();
176:
177: _rs.setResultSet(rs);
178: _rs.setQuery((SelectQuery) _query);
179: _rs.setSession(aConn);
180: _rs.init();
181:
182: return _rs;
183: }
184:
185: public String toString() {
186: return "UserQuery[" + _query.getQueryString() + "]";
187: }
188: }
|