001 /*
002 * www.openamf.org
003 *
004 * Distributable under LGPL license.
005 * See terms of license at gnu.org.
006 */
007
008 package flex.messaging.io;
009
010 import java.beans.BeanInfo;
011 import java.beans.IntrospectionException;
012 import java.beans.Introspector;
013 import java.beans.PropertyDescriptor;
014 import java.io.IOException;
015 import java.lang.reflect.InvocationTargetException;
016 import java.lang.reflect.Method;
017 import java.sql.ResultSet;
018 import java.sql.ResultSetMetaData;
019 import java.sql.SQLException;
020 import java.util.ArrayList;
021 import java.util.HashMap;
022 import java.util.Iterator;
023 import java.util.List;
024 import java.util.Map;
025
026 import org.granite.logging.Logger;
027
028
029 /**
030 * @author Jason Calabrese <jasonc@missionvi.com>
031 * @version $Revision: 1.29 $, $Date: 2006/03/25 22:17:44 $
032 */
033 public class ASRecordSet extends ASObject {
034
035 private static final long serialVersionUID = 1L;
036
037 private static final Logger log = Logger.getLogger(ASRecordSet.class);
038
039 public static final String SERVICE_NAME = "OpenAMFPageableRecordSet";
040
041 private static final String SI = "serverInfo";
042 private static final String SI_ID = "id";
043 private static final String SI_TOTAL_COUNT = "totalCount";
044 private static final String SI_INITIAL_DATA = "initialData";
045 //private static final String SI_ROWS = "rows";
046 private static final String SI_CURSOR = "cursor";
047 private static final String SI_SERVICE_NAME = "serviceName";
048 private static final String SI_COLUMN_NAMES = "columnNames";
049 private static final String SI_VERSION = "version";
050
051 private static int count = 0;
052
053 private Map<String, Object> serverInfo;
054 private List<List<Object>> rows;
055 private int initialRowCount;
056
057 public ASRecordSet() {
058 super("RecordSet");
059 serverInfo = new HashMap<String, Object>();
060 put(SI, serverInfo);
061
062 synchronized (ASRecordSet.class)
063 {
064 count++;
065 setId("RS" + count);
066 }
067
068 setInitialData(new ArrayList<Object>());
069 setServiceName(SERVICE_NAME);
070 setCursor(1);
071 setVersion(1);
072 rows = new ArrayList<List<Object>>();
073 initialRowCount = 0;
074 }
075
076 public String getId() {
077 return (String) serverInfo.get(SI_ID);
078 }
079 public void setId(String id) {
080 serverInfo.put(SI_ID, id);
081 }
082
083 public int getTotalCount() {
084 Object value = serverInfo.get(SI_TOTAL_COUNT);
085 if (value != null)
086 return ((Integer) value).intValue();
087 return 0;
088 }
089 public void setTotalCount(int totalCount) {
090 serverInfo.put(SI_TOTAL_COUNT, Integer.valueOf(totalCount));
091 }
092
093 public List<?> getInitialData() {
094 return (List<?>)serverInfo.get(SI_INITIAL_DATA);
095 }
096 public void setInitialData(List<?> initialData) {
097 serverInfo.put(SI_INITIAL_DATA, initialData);
098 }
099
100 public Map<String, Object> getRecords(int from, int count) {
101
102 List<List<Object>> page = rows.subList(from - 1, from - 1 + count);
103
104 Map<String, Object> records = new HashMap<String, Object>();
105 records.put("Page", page);
106 records.put("Cursor", Integer.valueOf(from + 1));
107
108 return records;
109
110 }
111
112 public int getCursor() {
113 Object value = serverInfo.get(SI_CURSOR);
114 if (value != null)
115 return ((Integer) value).intValue();
116 return 0;
117 }
118 public void setCursor(int cursor) {
119 serverInfo.put(SI_CURSOR, Integer.valueOf(cursor));
120 }
121
122 public String getServiceName() {
123 return (String) serverInfo.get(SI_SERVICE_NAME);
124 }
125 public void setServiceName(String serviceName) {
126 serverInfo.put(SI_SERVICE_NAME, serviceName);
127 }
128
129 public String[] getColumnNames() {
130 return (String[]) serverInfo.get(SI_COLUMN_NAMES);
131 }
132 public void setColumnNames(String[] columnNames) {
133 serverInfo.put(SI_COLUMN_NAMES, columnNames);
134 }
135
136 public double getVersion() {
137 Object value = serverInfo.get(SI_VERSION);
138 if (value != null)
139 return ((Double) value).doubleValue();
140 return 0;
141 }
142 public void setVersion(double version) {
143 serverInfo.put(SI_VERSION, new Double(version));
144 }
145
146 public List<List<Object>> rows() {
147 return rows;
148 }
149
150 public void populate(ResultSet rs) throws IOException {
151
152 try {
153 ResultSetMetaData rsmd = rs.getMetaData();
154 int columnCount = rsmd.getColumnCount();
155 String[] columnNames = new String[columnCount];
156
157 int rowIndex = 0;
158 List<List<Object>> initialData = new ArrayList<List<Object>>();
159 while (rs.next()) {
160 rowIndex++;
161 List<Object> row = new ArrayList<Object>();
162 for (int column = 0; column < columnCount; column++) {
163 if (rowIndex == 1) {
164 columnNames[column] = rsmd.getColumnName(column + 1);
165 }
166 row.add(rs.getObject(column + 1));
167 }
168 if (rowIndex == 1) {
169 setColumnNames(columnNames);
170 }
171 rows.add(row);
172 if (rowIndex <= initialRowCount) {
173 initialData.add(row);
174 }
175 }
176 setTotalCount(rowIndex);
177 setInitialData(initialData);
178 setColumnNames(columnNames);
179 } catch (SQLException e) {
180 throw new IOException(e.getMessage());
181 }
182
183 }
184
185 /**
186 * @param columnNames
187 * @param rows ArrayList containing a ArrayList for each row
188 */
189 public void populate(String[] columnNames, List<List<Object>> rows) {
190 this.rows = rows;
191
192 List<List<Object>> initialData =
193 rows.subList(
194 0,
195 (initialRowCount > rows.size()
196 ? rows.size()
197 : initialRowCount)); // NOTE: sublist semantics are [fromIndex, toIndex]
198 setInitialData(initialData);
199 setTotalCount(rows.size());
200 setColumnNames(columnNames);
201 }
202
203 /**
204 * @param list List of JavaBeans, all beans should be of the same type
205 * @param ignoreProperties properties that should not be added to the RecordSet
206 */
207 public void populate(List<?> list, String[] ignoreProperties)
208 throws
209 IllegalArgumentException,
210 IllegalAccessException,
211 InvocationTargetException {
212
213 List<String> names = new ArrayList<String> ();
214 Object firstBean = list.get(0);
215
216 PropertyDescriptor[] properties = null;
217 try {
218 BeanInfo beanInfo = Introspector.getBeanInfo(firstBean.getClass());
219 properties = beanInfo.getPropertyDescriptors();
220 } catch (IntrospectionException e) {
221 }
222 if (properties == null)
223 properties = new PropertyDescriptor[0];
224
225 for (int i = 0; i < properties.length; i++) {
226 PropertyDescriptor descriptor = properties[i];
227 if (!ignoreProperty(descriptor, ignoreProperties)) {
228 names.add(descriptor.getDisplayName());
229 }
230 }
231 String[] columnNames = new String[names.size()];
232 columnNames = names.toArray(columnNames);
233 setColumnNames(columnNames);
234
235 int rowIndex = 0;
236 List<List<Object>> initialData = new ArrayList<List<Object>>();
237 Iterator<?> iterator = list.iterator();
238 while (iterator.hasNext()) {
239 rowIndex++;
240 Object bean = iterator.next();
241 List<Object> row = new ArrayList<Object>();
242 for (int i = 0; i < properties.length; i++) {
243 PropertyDescriptor descriptor = properties[i];
244 if (!ignoreProperty(descriptor, ignoreProperties)) {
245 Object value = null;
246 Method readMethod = descriptor.getReadMethod();
247 if (readMethod != null) {
248 value = readMethod.invoke(bean, new Object[0]);
249 }
250 row.add(value);
251 }
252 }
253 rows.add(row);
254 if (rowIndex <= initialRowCount) {
255 initialData.add(row);
256 }
257 }
258 setInitialData(initialData);
259 setTotalCount(rows.size());
260 log.debug("%s", this);
261 }
262
263 private boolean ignoreProperty(
264 PropertyDescriptor descriptor,
265 String[] ignoreProperties) {
266
267 boolean ignore = false;
268 if (descriptor.getName().equals("class")) {
269 ignore = true;
270 } else {
271 for (int i = 0; i < ignoreProperties.length; i++) {
272 String ignoreProp = ignoreProperties[i];
273 if (ignoreProp.equals(descriptor.getName())) {
274 log.debug("Ignoring %s", descriptor.getName());
275 ignore = true;
276 break;
277 }
278 }
279 }
280 return ignore;
281 }
282
283 @Override
284 public String toString() {
285
286 StringBuffer info = new StringBuffer();
287 addInfo(info, SI_ID, getId());
288 addInfo(info, SI_TOTAL_COUNT, getTotalCount());
289 addInfo(info, SI_CURSOR, getCursor());
290 addInfo(info, SI_SERVICE_NAME, getServiceName());
291 addInfo(info, SI_VERSION, getVersion());
292 StringBuffer names = new StringBuffer();
293 String[] columnNames = getColumnNames();
294 if (columnNames != null) {
295 for (int i = 0; i < columnNames.length; i++) {
296 String name = columnNames[i];
297 if (i > 0) {
298 names.append(", ");
299 }
300 names.append(name);
301 }
302 }
303 addInfo(info, SI_COLUMN_NAMES, names);
304 addInfo(info, SI_INITIAL_DATA, getInitialData().toString());
305 return info.toString();
306 }
307
308 private void addInfo(StringBuffer info, String name, int value) {
309 addInfo(info, name, new Integer(value));
310 }
311
312 private void addInfo(StringBuffer info, String name, double value) {
313 addInfo(info, name, new Double(value));
314 }
315
316 private void addInfo(StringBuffer info, String name, Object value) {
317 info.append(name);
318 info.append(" = ");
319 info.append(value);
320 info.append('\n');
321 }
322 }