Breakup the OnlineGlomServiceImpl class to make it more manageable.
[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.Documents;
36 import org.glom.web.shared.GlomDocument;
37 import org.glom.web.shared.GlomField;
38 import org.glom.web.shared.layout.LayoutGroup;
39
40 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
41 import com.mchange.v2.c3p0.DataSources;
42
43 /**
44  * The servlet class for setting up the server side of Online Glom. The public methods in this class are the methods
45  * that can be called by the client side code.
46  * 
47  * @author Ben Konrath <ben@bagu.org>
48  */
49 @SuppressWarnings("serial")
50 public class OnlineGlomServiceImpl extends RemoteServiceServlet implements OnlineGlomService {
51
52         // convenience class to for dealing with the Online Glom configuration file
53         private class OnlineGlomProperties extends Properties {
54                 public String getKey(String value) {
55                         for (String key : stringPropertyNames()) {
56                                 if (getProperty(key).trim().equals(value))
57                                         return key;
58                         }
59                         return null;
60                 }
61         }
62
63         private final Hashtable<String, ConfiguredDocument> documentMapping = new Hashtable<String, ConfiguredDocument>();
64
65         /*
66          * This is called when the servlet is started or restarted.
67          */
68         public OnlineGlomServiceImpl() throws Exception {
69
70                 // Find the configuration file. See this thread for background info:
71                 // http://stackoverflow.com/questions/2161054/where-to-place-properties-files-in-a-jsp-servlet-web-application
72                 OnlineGlomProperties config = new OnlineGlomProperties();
73                 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("onlineglom.properties");
74                 if (is == null) {
75                         Log.fatal("onlineglom.properties not found.");
76                         throw new IOException();
77                 }
78                 config.load(is);
79
80                 // check if we can read the configured glom file directory
81                 String documentDirName = config.getProperty("glom.document.directory");
82                 File documentDir = new File(documentDirName);
83                 if (!documentDir.isDirectory()) {
84                         Log.fatal(documentDirName + " is not a directory.");
85                         throw new IOException();
86                 }
87                 if (!documentDir.canRead()) {
88                         Log.fatal("Can't read the files in : " + documentDirName);
89                         throw new IOException();
90                 }
91
92                 // get and check the glom files in the specified directory
93                 final String glomFileExtension = ".glom";
94                 File[] glomFiles = documentDir.listFiles(new FilenameFilter() {
95                         @Override
96                         public boolean accept(File dir, String name) {
97                                 return name.endsWith(glomFileExtension);
98                         }
99                 });
100                 Glom.libglom_init();
101                 for (File glomFile : glomFiles) {
102                         Document document = new Document();
103                         document.set_file_uri("file://" + glomFile.getAbsolutePath());
104                         int error = 0;
105                         boolean retval = document.load(error);
106                         if (retval == false) {
107                                 String message;
108                                 if (LoadFailureCodes.LOAD_FAILURE_CODE_NOT_FOUND == LoadFailureCodes.swigToEnum(error)) {
109                                         message = "Could not find file: " + glomFile.getAbsolutePath();
110                                 } else {
111                                         message = "An unknown error occurred when trying to load file: " + glomFile.getAbsolutePath();
112                                 }
113                                 Log.error(message);
114                                 // continue with for loop because there may be other documents in the directory
115                                 continue;
116                         }
117
118                         ConfiguredDocument configuredDocument = new ConfiguredDocument(document);
119                         // check if a username and password have been set and work for the current document
120                         String filename = glomFile.getName();
121                         String key = config.getKey(filename);
122                         if (key != null) {
123                                 String[] keyArray = key.split("\\.");
124                                 if (keyArray.length == 3 && "filename".equals(keyArray[2])) {
125                                         // username/password could be set, let's check to see if it works
126                                         String usernameKey = key.replaceAll(keyArray[2], "username");
127                                         String passwordKey = key.replaceAll(keyArray[2], "password");
128                                         configuredDocument.setUsernameAndPassword(config.getProperty(usernameKey),
129                                                         config.getProperty(passwordKey));
130                                 }
131                         }
132
133                         // check the if the global username and password have been set and work with this document
134                         if (!configuredDocument.isAuthenticated()) {
135                                 configuredDocument.setUsernameAndPassword(config.getProperty("glom.document.username"),
136                                                 config.getProperty("glom.document.password"));
137                         }
138
139                         // The key for the hash table is the file name without the .glom extension and with spaces ( ) replaced with
140                         // pluses (+). The space/plus replacement makes the key more friendly for URLs.
141                         String documentID = filename.substring(0, glomFile.getName().length() - glomFileExtension.length())
142                                         .replace(' ', '+');
143                         configuredDocument.setDocumentID(documentID);
144                         documentMapping.put(documentID, configuredDocument);
145
146                 }
147         }
148
149         /*
150          * This is called when the servlet is stopped or restarted.
151          * 
152          * @see javax.servlet.GenericServlet#destroy()
153          */
154         @Override
155         public void destroy() {
156                 Glom.libglom_deinit();
157
158                 for (String documenTitle : documentMapping.keySet()) {
159                         ConfiguredDocument configuredDoc = documentMapping.get(documenTitle);
160                         try {
161                                 DataSources.destroy(configuredDoc.getCpds());
162                         } catch (SQLException e) {
163                                 Log.error(documenTitle, "Error cleaning up the ComboPooledDataSource.", e);
164                         }
165                 }
166
167         }
168
169         public GlomDocument getGlomDocument(String documentID) {
170
171                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
172
173                 // FIXME check for authentication
174
175                 return configuredDoc.getGlomDocument();
176
177         }
178
179         public LayoutGroup getListLayout(String documentID, String tableName) {
180                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
181
182                 // FIXME check for authentication
183
184                 return configuredDoc.getListViewLayoutGroup(tableName);
185         }
186
187         public ArrayList<GlomField[]> getListData(String documentID, String tableName, int start, int length) {
188                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
189                 if (!configuredDoc.isAuthenticated()) {
190                         return new ArrayList<GlomField[]>();
191                 }
192                 return configuredDoc.getListViewData(tableName, start, length, false, 0, false);
193         }
194
195         public ArrayList<GlomField[]> getSortedListData(String documentID, String tableName, int start, int length,
196                         int sortColumnIndex, boolean isAscending) {
197                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
198                 if (!configuredDoc.isAuthenticated()) {
199                         return new ArrayList<GlomField[]>();
200                 }
201                 return configuredDoc.getListViewData(tableName, start, length, true, sortColumnIndex, isAscending);
202         }
203
204         public Documents getDocuments() {
205                 Documents documents = new Documents();
206                 for (String documentID : documentMapping.keySet()) {
207                         ConfiguredDocument configuredDoc = documentMapping.get(documentID);
208                         documents.addDocument(documentID, configuredDoc.getDocument().get_database_title());
209                 }
210                 return documents;
211         }
212
213         /*
214          * (non-Javadoc)
215          * 
216          * @see org.glom.web.client.OnlineGlomService#isAuthenticated(java.lang.String)
217          */
218         public boolean isAuthenticated(String documentID) {
219                 return documentMapping.get(documentID).isAuthenticated();
220         }
221
222         /*
223          * (non-Javadoc)
224          * 
225          * @see org.glom.web.client.OnlineGlomService#checkAuthentication(java.lang.String, java.lang.String,
226          * java.lang.String)
227          */
228         public boolean checkAuthentication(String documentID, String username, String password) {
229                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
230                 try {
231                         return configuredDoc.setUsernameAndPassword(username, password);
232                 } catch (SQLException e) {
233                         Log.error(documentID, "Unknown SQL Error checking the database authentication.", e);
234                         return false;
235                 }
236         }
237
238         /*
239          * (non-Javadoc)
240          * 
241          * @see org.glom.web.client.OnlineGlomService#getDetailsLayoutGroup(java.lang.String, java.lang.String)
242          */
243         public ArrayList<LayoutGroup> getDetailsLayout(String documentID, String tableName) {
244                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
245
246                 // FIXME check for authentication
247
248                 return configuredDoc.getDetailsLayoutGroup(tableName);
249         }
250
251         public GlomField[] getDetailsData(String documentID, String tableName, String primaryKeyValue) {
252                 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
253
254                 // FIXME check for authentication
255
256                 return configuredDoc.getDetailsData(tableName, primaryKeyValue);
257         }
258
259 }