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