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
029package flex.messaging.io;
030
031import java.io.IOException;
032import java.lang.reflect.InvocationTargetException;
033import java.lang.reflect.Method;
034import java.sql.ResultSet;
035import java.sql.ResultSetMetaData;
036import java.sql.SQLException;
037import java.util.ArrayList;
038import java.util.HashMap;
039import java.util.Iterator;
040import java.util.List;
041import java.util.Map;
042
043import org.granite.logging.Logger;
044import org.granite.util.Introspector;
045import 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 */
052public 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}