2 * Copyright (C) 2010, 2011 Openismus GmbH
4 * This file is part of GWT-Glom.
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.
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
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/>.
20 package org.glom.web.server;
22 import java.beans.PropertyVetoException;
24 import java.io.FilenameFilter;
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.sql.SQLException;
28 import java.util.ArrayList;
29 import java.util.Hashtable;
30 import java.util.Properties;
32 import javax.servlet.ServletException;
34 import org.glom.libglom.BakeryDocument.LoadFailureCodes;
35 import org.glom.libglom.Document;
36 import org.glom.libglom.Glom;
37 import org.glom.web.client.OnlineGlomService;
38 import org.glom.web.shared.DataItem;
39 import org.glom.web.shared.DetailsLayoutAndData;
40 import org.glom.web.shared.DocumentInfo;
41 import org.glom.web.shared.Documents;
42 import org.glom.web.shared.NavigationRecord;
43 import org.glom.web.shared.PrimaryKeyItem;
44 import org.glom.web.shared.layout.LayoutGroup;
46 import com.google.gwt.user.server.rpc.RemoteServiceServlet;
47 import com.mchange.v2.c3p0.DataSources;
50 * The servlet class for setting up the server side of Online Glom. The public methods in this class are the methods
51 * that can be called by the client side code.
53 * @author Ben Konrath <ben@bagu.org>
55 @SuppressWarnings("serial")
56 public class OnlineGlomServiceImpl extends RemoteServiceServlet implements OnlineGlomService {
58 private static final String GLOM_FILE_EXTENSION = ".glom";
60 // convenience class to for dealing with the Online Glom configuration file
61 private class OnlineGlomProperties extends Properties {
62 public String getKey(String value) {
63 for (String key : stringPropertyNames()) {
64 if (getProperty(key).trim().equals(value))
71 private final Hashtable<String, ConfiguredDocument> documentMapping = new Hashtable<String, ConfiguredDocument>();
74 * This is called when the servlet is started or restarted.
78 * @see javax.servlet.GenericServlet#init()
81 public void init() throws ServletException {
82 // Find the configuration file. See this thread for background info:
83 // http://stackoverflow.com/questions/2161054/where-to-place-properties-files-in-a-jsp-servlet-web-application
84 // FIXME move onlineglom.properties to the WEB-INF folder (option number 2 from the stackoverflow question)
85 OnlineGlomProperties config = new OnlineGlomProperties();
86 InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("onlineglom.properties");
88 Log.fatal("onlineglom.properties not found.");
89 throw new ServletException("onlineglom.properties not found.");
93 } catch (IOException e) {
94 throw new ServletException(e.getMessage(), e);
97 // check if we can read the configured glom file directory
98 String documentDirName = config.getProperty("glom.document.directory");
99 File documentDir = new File(documentDirName);
100 if (!documentDir.isDirectory()) {
101 Log.fatal(documentDirName + " is not a directory.");
102 throw new ServletException(documentDirName + " is not a directory.");
104 if (!documentDir.canRead()) {
105 Log.fatal("Can't read the files in : " + documentDirName);
106 throw new ServletException("Can't read the files in : " + documentDirName);
109 // get and check the glom files in the specified directory
110 File[] glomFiles = documentDir.listFiles(new FilenameFilter() {
112 public boolean accept(File dir, String name) {
113 return name.endsWith(GLOM_FILE_EXTENSION);
117 // don't continue if there aren't any Glom files to configure
118 if (glomFiles.length <= 0) {
119 Log.error("Unable to find any Glom documents in the configured directory: " + documentDirName);
120 Log.error("Check the onlineglom.properties file to ensure that 'glom.document.directory' is set to the correct directory.");
125 for (File glomFile : glomFiles) {
126 Document document = new Document();
127 document.set_file_uri("file://" + glomFile.getAbsolutePath());
129 boolean retval = document.load(error);
130 if (retval == false) {
132 if (LoadFailureCodes.LOAD_FAILURE_CODE_NOT_FOUND == LoadFailureCodes.swigToEnum(error)) {
133 message = "Could not find file: " + glomFile.getAbsolutePath();
135 message = "An unknown error occurred when trying to load file: " + glomFile.getAbsolutePath();
138 // continue with for loop because there may be other documents in the directory
142 ConfiguredDocument configuredDocument;
144 configuredDocument = new ConfiguredDocument(document);
145 } catch (PropertyVetoException e) {
146 throw new ServletException(e.getMessage(), e);
148 // check if a username and password have been set and work for the current document
149 String filename = glomFile.getName();
150 String key = config.getKey(filename);
152 String[] keyArray = key.split("\\.");
153 if (keyArray.length == 3 && "filename".equals(keyArray[2])) {
154 // username/password could be set, let's check to see if it works
155 String usernameKey = key.replaceAll(keyArray[2], "username");
156 String passwordKey = key.replaceAll(keyArray[2], "password");
158 configuredDocument.setUsernameAndPassword(config.getProperty(usernameKey).trim(),
159 config.getProperty(passwordKey));
160 } catch (SQLException e) {
161 throw new ServletException(e.getMessage(), e);
166 // check the if the global username and password have been set and work with this document
167 if (!configuredDocument.isAuthenticated()) {
169 configuredDocument.setUsernameAndPassword(config.getProperty("glom.document.username").trim(),
170 config.getProperty("glom.document.password"));
171 } catch (SQLException e) {
172 throw new ServletException(e.getMessage(), e);
176 // The key for the hash table is the file name without the .glom extension and with spaces ( ) replaced with
177 // pluses (+). The space/plus replacement makes the key more friendly for URLs.
178 String documentID = filename.substring(0, glomFile.getName().length() - GLOM_FILE_EXTENSION.length())
180 configuredDocument.setDocumentID(documentID);
181 documentMapping.put(documentID, configuredDocument);
184 // Allow a fake connection, so sqlbuilder_get_full_query() can work:
185 Glom.set_fake_connection();
189 * This is called when the servlet is stopped or restarted.
191 * @see javax.servlet.GenericServlet#destroy()
194 public void destroy() {
195 Glom.libglom_deinit();
197 for (String documenTitle : documentMapping.keySet()) {
198 ConfiguredDocument configuredDoc = documentMapping.get(documenTitle);
200 DataSources.destroy(configuredDoc.getCpds());
201 } catch (SQLException e) {
202 Log.error(documenTitle, "Error cleaning up the ComboPooledDataSource.", e);
210 * @see org.glom.web.client.OnlineGlomService#getDocumentInfo(java.lang.String)
213 public DocumentInfo getDocumentInfo(String documentID) {
215 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
217 // FIXME check for authentication
219 return configuredDoc.getDocumentInfo();
226 * @see org.glom.web.client.OnlineGlomService#getListViewLayout(java.lang.String, java.lang.String)
229 public LayoutGroup getListViewLayout(String documentID, String tableName) {
230 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
232 // FIXME check for authentication
234 return configuredDoc.getListViewLayoutGroup(tableName);
240 * @see org.glom.web.client.OnlineGlomService#getListViewData(java.lang.String, java.lang.String, int, int)
243 public ArrayList<DataItem[]> getListViewData(String documentID, String tableName, int start, int length) {
244 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
245 if (!configuredDoc.isAuthenticated()) {
246 return new ArrayList<DataItem[]>();
248 return configuredDoc.getListViewData(tableName, start, length, false, 0, false);
254 * @see org.glom.web.client.OnlineGlomService#getSortedListViewData(java.lang.String, java.lang.String, int, int,
258 public ArrayList<DataItem[]> getSortedListViewData(String documentID, String tableName, int start, int length,
259 int sortColumnIndex, boolean isAscending) {
260 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
261 if (!configuredDoc.isAuthenticated()) {
262 return new ArrayList<DataItem[]>();
264 return configuredDoc.getListViewData(tableName, start, length, true, sortColumnIndex, isAscending);
270 * @see org.glom.web.client.OnlineGlomService#getDocuments()
273 public Documents getDocuments() {
274 Documents documents = new Documents();
275 for (String documentID : documentMapping.keySet()) {
276 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
277 documents.addDocument(documentID, configuredDoc.getDocument().get_database_title());
285 * @see org.glom.web.client.OnlineGlomService#isAuthenticated(java.lang.String)
287 public boolean isAuthenticated(String documentID) {
288 return documentMapping.get(documentID).isAuthenticated();
294 * @see org.glom.web.client.OnlineGlomService#checkAuthentication(java.lang.String, java.lang.String,
298 public boolean checkAuthentication(String documentID, String username, String password) {
299 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
301 return configuredDoc.setUsernameAndPassword(username, password);
302 } catch (SQLException e) {
303 Log.error(documentID, "Unknown SQL Error checking the database authentication.", e);
311 * @see org.glom.web.client.OnlineGlomService#getDetailsData(java.lang.String, java.lang.String, java.lang.String)
314 public DataItem[] getDetailsData(String documentID, String tableName, PrimaryKeyItem primaryKeyValue) {
315 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
317 // FIXME check for authentication
319 return configuredDoc.getDetailsData(tableName, primaryKeyValue);
325 * @see org.glom.web.client.OnlineGlomService#getDetailsLayoutAndData(java.lang.String, java.lang.String,
329 public DetailsLayoutAndData getDetailsLayoutAndData(String documentID, String tableName,
330 PrimaryKeyItem primaryKeyValue) {
331 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
332 if (configuredDoc == null)
335 // FIXME check for authentication
337 DetailsLayoutAndData initalDetailsView = new DetailsLayoutAndData();
338 initalDetailsView.setLayout(configuredDoc.getDetailsLayoutGroup(tableName));
339 initalDetailsView.setData(configuredDoc.getDetailsData(tableName, primaryKeyValue));
341 return initalDetailsView;
347 * @see org.glom.web.client.OnlineGlomService#getRelatedListData(java.lang.String, java.lang.String, int, int)
350 public ArrayList<DataItem[]> getRelatedListData(String documentID, String tableName, String relationshipName,
351 PrimaryKeyItem foreignKeyValue, int start, int length) {
352 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
354 // FIXME check for authentication
356 return configuredDoc.getRelatedListData(tableName, relationshipName, foreignKeyValue, start, length, false, 0,
363 * @see org.glom.web.client.OnlineGlomService#getSortedRelatedListData(java.lang.String, java.lang.String, int, int,
367 public ArrayList<DataItem[]> getSortedRelatedListData(String documentID, String tableName, String relationshipName,
368 PrimaryKeyItem foreignKeyValue, int start, int length, int sortColumnIndex, boolean ascending) {
369 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
371 // FIXME check for authentication
373 return configuredDoc.getRelatedListData(tableName, relationshipName, foreignKeyValue, start, length, true,
374 sortColumnIndex, ascending);
377 public int getRelatedListRowCount(String documentID, String tableName, String relationshipName,
378 PrimaryKeyItem foreignKeyValue) {
379 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
381 // FIXME check for authentication
383 return configuredDoc.getRelatedListRowCount(tableName, relationshipName, foreignKeyValue);
389 * @see org.glom.web.client.OnlineGlomService#getSuitableRecordToViewDetails(java.lang.String, java.lang.String,
390 * java.lang.String, java.lang.String)
393 public NavigationRecord getSuitableRecordToViewDetails(String documentID, String tableName,
394 String relationshipName, PrimaryKeyItem primaryKeyValue) {
395 ConfiguredDocument configuredDoc = documentMapping.get(documentID);
397 // FIXME check for authentication
399 return configuredDoc.getSuitableRecordToViewDetails(tableName, relationshipName, primaryKeyValue);