Document: Static image items: Store an image URL, using the layout path.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / server / ConfiguredDocumentSet.java
1 /*
2  * Copyright (C) 2012 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.InputStream;
24 import java.sql.SQLException;
25 import java.util.Collection;
26 import java.util.Hashtable;
27 import java.util.List;
28
29 import javax.servlet.ServletException;
30
31 import org.apache.commons.io.FileUtils;
32 import org.apache.commons.io.FilenameUtils;
33 import org.apache.commons.lang3.StringUtils;
34 import org.glom.web.server.OnlineGlomProperties.Credentials;
35 import org.glom.web.server.libglom.Document;
36 import org.glom.web.shared.Documents;
37
38 import com.mchange.v2.c3p0.DataSources;
39
40 /**
41  * @author  Murray Cumming <murrayc@openismus.com>
42  */
43 public class ConfiguredDocumentSet {
44         private static final String GLOM_FILE_EXTENSION = "glom";
45
46         private Hashtable<String, ConfiguredDocument> documentMapping = new Hashtable<String, ConfiguredDocument>();
47         private Exception configurationException = null;
48
49         /**
50          * 
51          */
52         public ConfiguredDocumentSet() {
53         }
54         
55         public ConfiguredDocument getDocument(final String documentID) {
56                 return documentMapping.get(documentID);
57         }
58         
59         public Exception getConfigurationException() {
60                 return configurationException;
61         }
62
63         private static String getDocumentIdForFilename(final String filename) {
64                 // The key for the hash table is the file name without the .glom extension and with spaces ( ) replaced
65                 // with pluses (+). The space/plus replacement makes the key more friendly for URLs.
66                 return FilenameUtils.removeExtension(filename).replace(' ', '+');
67         }
68
69         private void addDocument(final ConfiguredDocument configuredDocument, final String documentID) {
70                 configuredDocument.setDocumentID(documentID);
71                 documentMapping.put(documentID, configuredDocument);
72         }
73         
74         
75
76         public void readConfiguration() throws ServletException {
77         
78                 // All of the initialisation code is surrounded by a try/catch block so that the servlet can be in an
79                 // initialised state and the error message can be retrieved by the client code.
80                 try {
81                         // Find the configuration file. See this thread for background info:
82                         // http://stackoverflow.com/questions/2161054/where-to-place-properties-files-in-a-jsp-servlet-web-application
83                         final OnlineGlomProperties config = new OnlineGlomProperties();
84                         final InputStream is = Thread.currentThread().getContextClassLoader()
85                                         .getResourceAsStream("onlineglom.properties");
86                         if (is == null) {
87                                 final String errorMessage = "onlineglom.properties not found.";
88                                 Log.fatal(errorMessage);
89                                 throw new Exception(errorMessage);
90                         }
91                         config.load(is); // can throw an IOException
92         
93                         // check if we can read the configured glom file directory
94                         final String documentDirName = config.getDocumentsDirectory();
95                         final File documentDir = new File(documentDirName);
96                         if (!documentDir.isDirectory()) {
97                                 final String errorMessage = documentDirName + " is not a directory.";
98                                 Log.fatal(errorMessage);
99                                 throw new Exception(errorMessage);
100                         }
101                         if (!documentDir.canRead()) {
102                                 final String errorMessage = "Can't read the files in directory " + documentDirName + " .";
103                                 Log.fatal(errorMessage);
104                                 throw new Exception(errorMessage);
105                         }
106         
107                         // get and check the glom files in the specified directory
108                         // TODO: Test this:
109                         final String[] extensions = { GLOM_FILE_EXTENSION };
110                         final Collection<?> glomFiles = FileUtils.listFiles(documentDir, extensions, true /* recursive */);
111                         if(!(glomFiles instanceof List<?>)) {
112                                 final String errorMessage = "onlineglom.properties: listFiles() failed.";
113                                 Log.fatal(errorMessage);
114                                 throw new Exception(errorMessage);
115                         }
116         
117                         // don't continue if there aren't any Glom files to configure
118                         if (glomFiles.size() <= 0) {
119                                 final String errorMessage = "Unable to find any Glom documents in the configured directory "
120                                                 + documentDirName
121                                                 + " . Check the onlineglom.properties file to ensure that 'glom.document.directory' is set to the correct directory.";
122                                 Log.error(errorMessage);
123                                 throw new Exception(errorMessage);
124                         }
125         
126                         // Check for a specified default locale,
127                         // for table titles, field titles, etc:
128                         final String globalLocaleID = StringUtils.defaultString(config.getGlobalLocale());
129         
130                         for (final Object objGlomFile : glomFiles) {
131                                 if(!(objGlomFile instanceof File)) {
132                                         continue;
133                                 }
134                                 
135                                 final File glomFile = (File)objGlomFile;
136                                 final String filename = glomFile.getName();
137         
138                                 final String documentID = getDocumentIdForFilename(filename);
139                                 final Document document = new Document(documentID);
140                                 document.setFileURI("file://" + glomFile.getAbsolutePath());
141                                 final boolean retval = document.load();
142                                 if (retval == false) {
143                                         final String message = "An error occurred when trying to load file: " + glomFile.getAbsolutePath();
144                                         Log.error(message);
145                                         // continue with for loop because there may be other documents in the directory
146                                         continue;
147                                 }
148         
149                                 final ConfiguredDocument configuredDocument = new ConfiguredDocument(document); // can throw a
150                                 // PropertyVetoException
151         
152                                 final String globalUserName = config.getGlobalUsername();
153                                 final String globalPassword = config.getGlobalPassword();
154         
155                                 // check if a username and password have been set and work for the current document
156                                 
157                                 // Username/password could be set. Let's check to see if it works.
158                                 final Credentials docCredentials = config.getCredentials(filename);
159                                 if(docCredentials != null) {
160                                                 configuredDocument.setUsernameAndPassword(docCredentials.userName, docCredentials.password); // can throw an SQLException
161                                 }
162         
163                                 // check the if the global username and password have been set and work with this document
164                                 if (!configuredDocument.isAuthenticated()) {
165                                         configuredDocument.setUsernameAndPassword(globalUserName, globalPassword); // can throw an SQLException
166                                 }
167         
168                                 if (!StringUtils.isEmpty(globalLocaleID)) {
169                                         configuredDocument.setDefaultLocaleID(globalLocaleID.trim());
170                                 }
171         
172                                 addDocument(configuredDocument, documentID);
173                         }
174         
175                 } catch (final Exception e) {
176                         // Don't throw the Exception so that servlet will be initialised and the error message can be retrieved.
177                         configurationException = e;
178                 }
179         
180         }
181
182         /**
183          * 
184          */
185         public void forgetDocuments() {
186                 for (final String documentID : documentMapping.keySet()) {
187                         final ConfiguredDocument configuredDoc = getDocument(documentID);
188                         if (configuredDoc == null) {
189                                 continue;
190                         }
191
192                         try {
193                                 DataSources.destroy(configuredDoc.getCpds());
194                         } catch (final SQLException e) {
195                                 Log.error(documentID, "Error cleaning up the ComboPooledDataSource.", e);
196                         }
197                 }
198                 
199         }
200
201         /**
202          * @return
203          */
204         public Documents getDocuments() {
205                 final Documents documents = new Documents();
206                 for (final String documentID : documentMapping.keySet()) {
207                         final ConfiguredDocument configuredDoc = getDocument(documentID);
208                         if (configuredDoc == null) {
209                                 continue;
210                         }
211
212                         final Document glomDocument = configuredDoc.getDocument();
213                         if (glomDocument == null) {
214                                 final String errorMessage = "getDocuments(): getDocument() failed.";
215                                 Log.fatal(errorMessage);
216                                 // TODO: throw new Exception(errorMessage);
217                                 continue;
218                         }
219
220                         final String localeID = StringUtils.defaultString(configuredDoc.getDefaultLocaleID());
221                         documents.addDocument(documentID, glomDocument.getDatabaseTitle(localeID), localeID);
222                 }
223                 return documents;
224         }
225 }