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.io.IOException;
011    import java.lang.reflect.InvocationTargetException;
012    import java.lang.reflect.Method;
013    import java.sql.ResultSet;
014    import java.sql.ResultSetMetaData;
015    import java.sql.SQLException;
016    import java.util.ArrayList;
017    import java.util.HashMap;
018    import java.util.Iterator;
019    import java.util.List;
020    import java.util.Map;
021    
022    import org.granite.logging.Logger;
023    import org.granite.util.Introspector;
024    import 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     */
031    public 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    }