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    }