Use String arrays instead of GlomTable objects in GlomDocument GWT-RPC object.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / server / OnlineGlomServiceImpl.java
1 /*
2  * Copyright (C) 2010, 2011 Openismus GmbH
3  *
4  * This file is part of GWT-Glom.
5  *
6  * GWT-Glom is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU Lesser General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * GWT-Glom is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with GWT-Glom.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 package org.glom.web.server;
21
22 import java.beans.PropertyVetoException;
23 import java.sql.Connection;
24 import java.sql.ResultSet;
25 import java.sql.SQLException;
26 import java.sql.Statement;
27 import java.util.ArrayList;
28
29 import org.glom.libglom.Document;
30 import org.glom.libglom.Field;
31 import org.glom.libglom.Glom;
32 import org.glom.libglom.LayoutFieldVector;
33 import org.glom.libglom.LayoutGroupVector;
34 import org.glom.libglom.LayoutItem;
35 import org.glom.libglom.LayoutItemVector;
36 import org.glom.libglom.LayoutItem_Field;
37 import org.glom.libglom.SortClause;
38 import org.glom.libglom.SortFieldPair;
39 import org.glom.libglom.StringVector;
40 import org.glom.web.client.OnlineGlomService;
41 import org.glom.web.shared.GlomDocument;
42
43 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
44 import com.mchange.v2.c3p0.ComboPooledDataSource;
45 import com.mchange.v2.c3p0.DataSources;
46
47 @SuppressWarnings("serial")
48 public class OnlineGlomServiceImpl extends RemoteServiceServlet implements OnlineGlomService {
49         private Document document;
50         ComboPooledDataSource cpds;
51
52         // Called only when the servlet is stopped (the servlet container is stopped or restarted)
53         public OnlineGlomServiceImpl() {
54                 Glom.libglom_init();
55                 document = new Document();
56                 // TODO hardcoded for now, need to figure out something for this
57                 document.set_file_uri("file:///home/ben/music-collection.glom");
58                 int error = 0;
59                 @SuppressWarnings("unused")
60                 boolean retval = document.load(error);
61                 // TODO handle error condition (also below)
62
63                 cpds = new ComboPooledDataSource();
64                 // load the jdbc driver
65                 try {
66                         cpds.setDriverClass("org.postgresql.Driver");
67                 } catch (PropertyVetoException e) {
68                         // TODO log error, fatal error can't continue, user can be nofified when db access doesn't work
69                         e.printStackTrace();
70                 }
71
72                 cpds.setJdbcUrl("jdbc:postgresql://" + document.get_connection_server() + "/"
73                                 + document.get_connection_database());
74                 // TODO figure out something for db user name and password
75                 cpds.setUser("ben");
76                 cpds.setPassword("ChangeMe"); // of course it's not the password I'm using on my server
77         }
78
79         /*
80          * FIXME I think Swig is generating long on 64-bit machines and int on 32-bit machines - need to keep this constant
81          * http://stackoverflow.com/questions/1590831/safely-casting-long-to-int-in-java
82          */
83         public static int safeLongToInt(long l) {
84                 if (l < Integer.MIN_VALUE || l > Integer.MAX_VALUE) {
85                         throw new IllegalArgumentException(l + " cannot be cast to int without changing its value.");
86                 }
87                 return (int) l;
88         }
89
90         public GlomDocument getGlomDocument() {
91                 GlomDocument glomDocument = new GlomDocument();
92
93                 // get arrays of table names and titles, and find the default table index
94                 StringVector tablesVec = document.get_table_names();
95                 int numTables = safeLongToInt(tablesVec.size());
96                 String[] tableNames = new String[numTables];
97                 String[] tableTitles = new String[numTables];
98                 boolean foundDefaultTable = false;
99                 for (int i = 0; i < numTables; i++) {
100                         String tableName = tablesVec.get(i);
101                         tableNames[i] = tableName;
102                         // JNI is "expensive", the comparison will only be called if we haven't already found the default table
103                         if (!foundDefaultTable && tableName.equals(document.get_default_table())) {
104                                 glomDocument.setDefaultTableIndex(i);
105                                 foundDefaultTable = true;
106                         }
107                         tableTitles[i] = document.get_table_title(tableName);
108                 }
109
110                 // set everything we need
111                 glomDocument.setTableNames(tableNames);
112                 glomDocument.setTableTitles(tableTitles);
113                 glomDocument.setTitle(document.get_database_title());
114
115                 return glomDocument;
116         }
117
118         public String[] getLayoutListHeaders(String table) {
119                 LayoutGroupVector layoutList = document.get_data_layout_groups("list", table);
120                 LayoutItemVector layoutItems = layoutList.get(0).get_items();
121                 String[] headers = new String[safeLongToInt(layoutItems.size())];
122                 for (int i = 0; i < layoutItems.size(); i++) {
123                         headers[i] = layoutItems.get(i).get_title_or_name();
124                 }
125                 return headers;
126         }
127
128         public ArrayList<String[]> getTableData(int start, int length, String table) {
129                 LayoutGroupVector layoutList = document.get_data_layout_groups("list", table);
130                 LayoutItemVector layoutItems = layoutList.get(0).get_items();
131
132                 LayoutFieldVector layoutFields = new LayoutFieldVector();
133                 SortClause sortClause = new SortClause();
134                 for (int i = 0; i < layoutItems.size(); i++) {
135                         LayoutItem item = layoutItems.get(i);
136                         LayoutItem_Field field = LayoutItem_Field.cast_dynamic(item);
137                         if (field != null) {
138                                 layoutFields.add(field);
139                                 Field details = field.get_full_field_details();
140                                 if (details != null && details.get_primary_key()) {
141                                         sortClause.addLast(new SortFieldPair(field, true)); // ascending
142                                 }
143                         }
144                 }
145
146                 ArrayList<String[]> rowsList = new ArrayList<String[]>();
147                 try {
148                         Connection conn = cpds.getConnection();
149                         Statement st = conn.createStatement();
150
151                         String query = Glom.build_sql_select_simple(table, layoutFields, sortClause);
152                         ResultSet rs = st.executeQuery(query);
153
154                         while (rs.next()) {
155                                 String[] rowArray = new String[safeLongToInt(layoutItems.size())];
156                                 for (int i = 0; i < layoutItems.size(); i++) {
157                                         rowArray[i] = rs.getString(i + 1);
158                                 }
159                                 rowsList.add(rowArray);
160                         }
161
162                         rs.close();
163                         st.close();
164                 } catch (SQLException e) {
165                         // TODO: log error, notify user of problem
166                         e.printStackTrace();
167                 }
168
169                 return rowsList;
170         }
171
172         // Called only when the servlet is stopped (the servlet container is stopped or restarted)
173         public void destroy() {
174                 Glom.libglom_deinit();
175                 try {
176                         DataSources.destroy(cpds);
177                 } catch (SQLException e) {
178                         // TODO log error, don't need to notify user because this is a clean up method
179                         e.printStackTrace();
180                 }
181         }
182
183 }