Add related lists to details view.
[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.io.File;
23 import java.io.FilenameFilter;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.sql.SQLException;
27 import java.util.ArrayList;
28 import java.util.Hashtable;
29 import java.util.Properties;
30
31 import org.glom.libglom.BakeryDocument.LoadFailureCodes;
32 import org.glom.libglom.Document;
33 import org.glom.libglom.Glom;
34 import org.glom.web.client.OnlineGlomService;
35 import org.glom.web.shared.DetailsLayoutAndData;
36 import org.glom.web.shared.Documents;
37 import org.glom.web.shared.GlomDocument;
38 import org.glom.web.shared.GlomField;
39 import org.glom.web.shared.layout.LayoutGroup;
40
41 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
42 import com.mchange.v2.c3p0.DataSources;
43
44 /**
45  * The servlet class for setting up the server side of Online Glom. The public methods in this class are the methods
46  * that can be called by the client side code.
47  * 
48  * @author Ben Konrath <ben@bagu.org>
49  */
50 @SuppressWarnings("serial")
51 public class OnlineGlomServiceImpl extends RemoteServiceServlet implements OnlineGlomService {
52
53         // convenience class to for dealing with the Online Glom configuration file
54         private class OnlineGlomProperties extends Properties {
55                 public String getKey(String value) {
56                         for (String key : stringPropertyNames()) {
57                                 if (getProperty(key).trim().equals(value))
58                                         return key;
59                         }
60                         return null;
61                 }
62         }
63
64         private final Hashtable<String, ConfiguredDocument> documentMapping = new Hashtable<String, ConfiguredDocument>();
65
66         /*
67          * This is called when the servlet is started or restarted.
68          */
69         public OnlineGlomServiceImpl() throws Exception {
70
71                 // Find the configuration file. See this thread for background info:
72                 // http://stackoverflow.com/questions/2161054/where-to-place-properties-files-in-a-jsp-servlet-web-application
73                 OnlineGlomProperties config = new OnlineGlomProperties();
74                 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("onlineglom.properties");
75                 if (is == null) {
76                         Log.fatal("onlineglom.properties not found.");
77                         throw new IOException();
78                 }
79                 config.load(is);
80
81                 // check if we can read the configured glom file directory
82                 String documentDirName = config.getProperty("glom.document.directory");
83                 File documentDir = new File(documentDirName);
84                 if (!documentDir.isDirectory()) {
85                         Log.fatal(documentDirName + " is not a directory.");
86                         throw new IOException();
87                 }
88                 if (!documentDir.canRead()) {
89                         Log.fatal("Can't read the files in : " + documentDirName);
90                         throw new IOException();
91                 }
92
93                 // get and check the glom files in the specified directory
94                 final String glomFileExtension = ".glom";
95                 File[] glomFiles = documentDir.listFiles(new FilenameFilter() {
96                         @Override
97                         public boolean accept(File dir, String name) {
98                                 return name.endsWith(glomFileExtension);
99                         }
100                 });
101                 Glom.libglom_init();
102                 for (File glomFile : glomFiles) {
103                         Document document = new Document();
104                         document.set_file_uri("file://" + glomFile.getAbsolutePath());
105                         int error = 0;
106                         boolean retval = document.load(error);
107                         if (retval == false) {
108                                 String message;
109                                 if (LoadFailureCodes.LOAD_FAILURE_CODE_NOT_FOUND == LoadFailureCodes.swigToEnum(error)) {
110                                         message = "Could not find file: " + glomFile.getAbsolutePath();
111                                 } else {
112                                         message = "An unknown error occurred when trying to load file: " + glomFile.getAbsolutePath();
113                                 }
114                                 Log.error(message);
115                                 // continue with for loop because there may be other documents in the directory
116                                 continue;
117                         }
118
119                         ConfiguredDocument configuredDocument = new ConfiguredDocument(document);
120                         // check if a username and password have been set and work for the current document
121                         String filename = glomFile.getName();
122                         String key = config.getKey(filename);
123                         if (key != null) {
124                                 String[] keyArray = key.split("\\.");
125                                 if (keyArray.length == 3 && "filename".equals(keyArray[2])) {
126                                         // username/password could be set, let's check to see if it works
127                                         String usernameKey = key.replaceAll(keyArray[2], "username");
128                                         String passwordKey = key.replaceAll(keyArray[2], "password");
129                                         configuredDocument.setUsernameAndPassword(config.getProperty(usernameKey),
130                                                         config.getProperty(passwordKey));
131                                 }
132                         }
133
134                         // check the if the global username and password have been set and work with this document
135                         if (!configuredDocument.isAuthenticated()) {
136                                 configuredDocument.setUsernameAndPassword(config.getProperty("glom.document.username"),
137                                                 config.getProperty("glom.document.password"));
138                         }
139
140                         // The key for the hash table is the file name without the .glom extension and with spaces ( ) replaced with
141                         // pluses (+). The space/plus replacement makes the key more friendly for URLs.
142                         String documentID = filename.substring(0, glomFile.getName().length() - glomFileExtension.length())
143                                         .replace(' ', '+');
144                         configuredDocument.setDocumentID(documentID);
145                         documentMapping.put(documentID, configuredDocument);
146
147                 }
148         }
149
150         /*
151          * This is called when the servlet is stopped or restarted.
152          * 
153          * @see javax.servlet.GenericServlet#destroy()
154          */
155         @Override
156         public void destroy() {
157                 Glom.libglom_deinit();
158
159                 for (String documenTitle : documentMapping.keySet()) {
160                         ConfiguredDocument configuredDoc = documentMapping.get(documenTitle);
161                         try {
162                                 DataSources.destroy(configuredDoc.getCpds());
163                         } catch (SQLException e) {
164                                 Log.error(documenTitle, "Error cleaning up the ComboPooledDataSource.", e);
165                         }
166                 }
167
168         }
169
170         /*
171          * (non-Javadoc)
172          * 
173          * @see org.glom.web.client.OnlineGlomService#getGlomDocument(java.lang.String)
174          */
175         @Override
176         public GlomDocument getGlomDocument(String documentID) {
177
178                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
179
180                 // FIXME check for authentication
181
182                 return configuredDoc.getGlomDocument();
183
184         }
185
186         /*
187          * (non-Javadoc)
188          * 
189          * @see org.glom.web.client.OnlineGlomService#getListViewLayout(java.lang.String, java.lang.String)
190          */
191         @Override
192         public LayoutGroup getListViewLayout(String documentID, String tableName) {
193                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
194
195                 // FIXME check for authentication
196
197                 return configuredDoc.getListViewLayoutGroup(tableName);
198         }
199
200         /*
201          * (non-Javadoc)
202          * 
203          * @see org.glom.web.client.OnlineGlomService#getListViewData(java.lang.String, java.lang.String, int, int)
204          */
205         @Override
206         public ArrayList<GlomField[]> getListViewData(String documentID, String tableName, int start, int length) {
207                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
208                 if (!configuredDoc.isAuthenticated()) {
209                         return new ArrayList<GlomField[]>();
210                 }
211                 return configuredDoc.getListViewData(tableName, start, length, false, 0, false);
212         }
213
214         /*
215          * (non-Javadoc)
216          * 
217          * @see org.glom.web.client.OnlineGlomService#getSortedListViewData(java.lang.String, java.lang.String, int, int,
218          * int, boolean)
219          */
220         @Override
221         public ArrayList<GlomField[]> getSortedListViewData(String documentID, String tableName, int start, int length,
222                         int sortColumnIndex, boolean isAscending) {
223                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
224                 if (!configuredDoc.isAuthenticated()) {
225                         return new ArrayList<GlomField[]>();
226                 }
227                 return configuredDoc.getListViewData(tableName, start, length, true, sortColumnIndex, isAscending);
228         }
229
230         /*
231          * (non-Javadoc)
232          * 
233          * @see org.glom.web.client.OnlineGlomService#getDocuments()
234          */
235         @Override
236         public Documents getDocuments() {
237                 Documents documents = new Documents();
238                 for (String documentID : documentMapping.keySet()) {
239                         ConfiguredDocument configuredDoc = documentMapping.get(documentID);
240                         documents.addDocument(documentID, configuredDoc.getDocument().get_database_title());
241                 }
242                 return documents;
243         }
244
245         /*
246          * (non-Javadoc)
247          * 
248          * @see org.glom.web.client.OnlineGlomService#isAuthenticated(java.lang.String)
249          */
250         public boolean isAuthenticated(String documentID) {
251                 return documentMapping.get(documentID).isAuthenticated();
252         }
253
254         /*
255          * (non-Javadoc)
256          * 
257          * @see org.glom.web.client.OnlineGlomService#checkAuthentication(java.lang.String, java.lang.String,
258          * java.lang.String)
259          */
260         @Override
261         public boolean checkAuthentication(String documentID, String username, String password) {
262                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
263                 try {
264                         return configuredDoc.setUsernameAndPassword(username, password);
265                 } catch (SQLException e) {
266                         Log.error(documentID, "Unknown SQL Error checking the database authentication.", e);
267                         return false;
268                 }
269         }
270
271         /*
272          * (non-Javadoc)
273          * 
274          * @see org.glom.web.client.OnlineGlomService#getDetailsData(java.lang.String, java.lang.String, java.lang.String)
275          */
276         @Override
277         public GlomField[] getDetailsData(String documentID, String tableName, String primaryKeyValue) {
278                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
279
280                 // FIXME check for authentication
281
282                 return configuredDoc.getDetailsData(tableName, primaryKeyValue);
283         }
284
285         /*
286          * (non-Javadoc)
287          * 
288          * @see org.glom.web.client.OnlineGlomService#getDetailsLayoutAndData(java.lang.String, java.lang.String,
289          * java.lang.String)
290          */
291         @Override
292         public DetailsLayoutAndData getDetailsLayoutAndData(String documentID, String tableName, String primaryKeyValue) {
293                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
294                 DetailsLayoutAndData initalDetailsView = new DetailsLayoutAndData();
295
296                 // FIXME check for authentication
297
298                 initalDetailsView.setLayout(configuredDoc.getDetailsLayoutGroup(tableName));
299                 initalDetailsView.setData(configuredDoc.getDetailsData(tableName, primaryKeyValue));
300
301                 return initalDetailsView;
302         }
303
304         /*
305          * (non-Javadoc)
306          * 
307          * @see org.glom.web.client.OnlineGlomService#getRelatedListData(java.lang.String, java.lang.String, int, int)
308          */
309         @Override
310         public ArrayList<GlomField[]> getRelatedListData(String documentID, String tableName, String relationshipName,
311                         String foreignKeyValue, int start, int length) {
312                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
313
314                 // FIXME check for authentication
315
316                 return configuredDoc.getRelatedListData(tableName, relationshipName, foreignKeyValue, start, length, false, 0,
317                                 false);
318         }
319
320         /*
321          * (non-Javadoc)
322          * 
323          * @see org.glom.web.client.OnlineGlomService#getSortedRelatedListData(java.lang.String, java.lang.String, int, int,
324          * int, boolean)
325          */
326         @Override
327         public ArrayList<GlomField[]> getSortedRelatedListData(String documentID, String tableName,
328                         String relationshipName, String foreignKeyValue, int start, int length, int sortColumnIndex, boolean ascending) {
329                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
330
331                 // FIXME check for authentication
332
333                 return configuredDoc.getRelatedListData(tableName, relationshipName, foreignKeyValue, start, length, true,
334                                 sortColumnIndex, ascending);
335         }
336
337         public int getRelatedListRowCount(String documentID, String tableName, String relationshipName,
338                         String foreignKeyValue) {
339                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
340
341                 // FIXME check for authentication
342
343                 return configuredDoc.getRelatedListRowCount(tableName, relationshipName, foreignKeyValue);
344         }
345
346 }