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