Add a Field class and implement some loading of it in Document.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / shared / libglom / Document.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.shared.libglom;
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Hashtable;
25 import java.util.List;
26
27 import javax.xml.parsers.DocumentBuilder;
28 import javax.xml.parsers.DocumentBuilderFactory;
29 import javax.xml.parsers.ParserConfigurationException;
30
31 import org.apache.commons.lang3.StringUtils;
32 import org.glom.libglom.LayoutGroupVector;
33 import org.glom.libglom.StringVector;
34 import org.glom.web.shared.layout.LayoutItemField;
35 import org.jfree.util.Log;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.Node;
38 import org.w3c.dom.NodeList;
39 import org.xml.sax.SAXException;
40
41
42 /**
43  * @author Murray Cumming <murrayc@openismus.com>
44  *
45  */
46 public class Document {
47
48         
49         private class TableInfo extends Translatable {
50                 public String name = "";
51                 public boolean isDefault;
52                 public boolean isHidden;
53
54                 private final Hashtable<String, Field> fieldsMap = new Hashtable<String, Field>();
55                 private final Hashtable<String, Report> reportsMap = new Hashtable<String, Report>();
56         };
57
58         private String fileURI = "";
59         private org.w3c.dom.Document xmlDocument = null;
60         
61         private Translatable databaseTitle = new Translatable();
62         private String connectionServer = "";
63         private String connectionDatabase = "";
64         private int connectionPort = 0;
65         private final Hashtable<String, TableInfo> tablesMap = new Hashtable<String, TableInfo>();
66         
67         private static String NODE_CONNECTION = "connection";
68         private static String ATTRIBUTE_CONNECTION_SERVER = "server";
69         private static String ATTRIBUTE_CONNECTION_DATABASE = "database";
70         private static String ATTRIBUTE_CONNECTION_PORT = "port";
71         private static String NODE_TABLE = "table";
72         private static String ATTRIBUTE_NAME = "name";
73         private static String ATTRIBUTE_TITLE = "title";
74         private static String ATTRIBUTE_DEFAULT = "default";
75         private static String ATTRIBUTE_HIDDEN = "hidden";
76         private static String NODE_TRANSLATIONS_SET = "trans_set";
77         private static String NODE_TRANSLATIONS = "trans";
78         private static String ATTRIBUTE_TRANSLATION_LOCALE = "loc";
79         private static String ATTRIBUTE_TRANSLATION_TITLE = "val";
80         private static String NODE_REPORTS = "reports";
81         private static String NODE_REPORT = "report";
82         private static String NODE_FIELDS = "fields";
83         private static String NODE_FIELD = "field";
84         private static String ATTRIBUTE_PRIMARY_KEY = "primary_key";
85         private static String ATTRIBUTE_FIELD_TYPE = "type";
86         
87         public void set_file_uri(final String fileURI) {
88                 this.fileURI = fileURI;
89         }
90         
91         public String get_file_uri() {
92                 return fileURI;
93         }
94
95         //TODO: Make sure these have the correct values.
96         public enum LoadFailureCodes {
97                 LOAD_FAILURE_CODE_NONE,
98             LOAD_FAILURE_CODE_NOT_FOUND,
99                 LOAD_FAILURE_CODE_FILE_VERSION_TOO_NEW
100         };
101
102             
103         public boolean load(int failure_code) {
104                 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
105                 DocumentBuilder documentBuilder;
106                 try {
107                         documentBuilder = dbf.newDocumentBuilder();
108                 } catch (ParserConfigurationException e) {
109                         // TODO Auto-generated catch block
110                         e.printStackTrace();
111                         return false;
112                 }
113                 
114                 try {
115                         xmlDocument = documentBuilder.parse(fileURI);
116                 } catch (SAXException e) {
117                         // TODO Auto-generated catch block
118                         e.printStackTrace();
119                         return false;
120                 } catch (IOException e) {
121                         // TODO Auto-generated catch block
122                         e.printStackTrace();
123                         return false;
124                 }
125                 
126                 final Element rootNode = xmlDocument.getDocumentElement();
127                 if(rootNode.getNodeName() != "glom_document") {
128                         Log.error("Unexpected XML root node name found: " + rootNode.getNodeName());
129                         return false;
130                 }
131                 
132                 databaseTitle.set_title_original( rootNode.getAttribute(ATTRIBUTE_TITLE) );
133                 
134                 final NodeList listTableNodes = rootNode.getElementsByTagName(NODE_TABLE);
135                 final int num = listTableNodes.getLength();
136                 for(int i = 0; i < num; i++) {
137                         final Node node = listTableNodes.item(i);
138                         final Element element = (Element)node; //TODO: Check the cast.
139                         loadTableNode(element);
140                 }
141                 
142                 Element nodeConnection = getElementByName(rootNode, NODE_CONNECTION);
143                 if(nodeConnection != null) {
144                         connectionServer = nodeConnection.getAttribute(ATTRIBUTE_CONNECTION_SERVER);
145                         connectionDatabase = nodeConnection.getAttribute(ATTRIBUTE_CONNECTION_DATABASE);
146                         
147                         final String strPort = nodeConnection.getAttribute(ATTRIBUTE_CONNECTION_PORT);
148                         int port = 0;
149                         if(!StringUtils.isEmpty(strPort)) {
150                                 port = Integer.valueOf(strPort);
151                         }
152                         connectionPort = port;
153                 }
154                 
155
156                 return true;
157         };
158         
159         private Element getElementByName(final Element parentElement, final String tagName) {
160                 final NodeList listNodes = parentElement.getElementsByTagName(NODE_TABLE);
161                 if(listNodes == null)
162                         return null;
163
164                 if(listNodes.getLength() == 0)
165                         return null;
166
167                 return (Element)listNodes.item(0);
168         }
169         
170         private boolean getAttributeAsBoolean(final Element node, final String attributeName) {
171                 final String str = node.getAttribute(attributeName);
172                 if(str == null)
173                         return false;
174                 
175                 return (str.equals("true"));
176         }
177         
178         /** Load a title and its translations.
179          * 
180          * @param node The XML Element that may contain a title attribute and a trans_set of translations of the title.
181          * @param title
182          */
183         private void loadTitle(final Element node, final Translatable title) {
184                 title.set_title_original(node.getAttribute(ATTRIBUTE_TITLE));
185                 
186                 final Element nodeSet = getElementByName(node, NODE_TRANSLATIONS_SET);
187                 if(nodeSet == null) {
188                         return;
189                 }
190                 
191                 final NodeList listNodes = nodeSet.getElementsByTagName(NODE_TRANSLATIONS);
192                 if(listNodes == null)
193                         return;
194
195                 final int num = listNodes.getLength();
196                 for(int i = 0; i < num; i++) {
197                         final Node transNode = listNodes.item(i);
198                         final Element element = (Element)transNode; //TODO: Check the cast.
199                         
200                         final String locale = element.getAttribute(ATTRIBUTE_TRANSLATION_LOCALE);
201                         final String translatedTitle = element.getAttribute(ATTRIBUTE_TRANSLATION_TITLE);
202                         if(!StringUtils.isEmpty(locale) && !StringUtils.isEmpty(translatedTitle)) {
203                                 title.translationsMap.put(locale, translatedTitle);
204                         }
205                 }
206         }
207         /**
208          * @param node
209          */
210         private void loadTableNode(final Element node) {
211                 TableInfo info = new TableInfo();
212                 info.name = node.getAttribute(ATTRIBUTE_NAME);
213                 loadTitle(node, info);
214                 info.isDefault = getAttributeAsBoolean(node, ATTRIBUTE_DEFAULT);
215                 info.isHidden = getAttributeAsBoolean(node, ATTRIBUTE_HIDDEN);
216
217                 final Element fieldsNode = getElementByName(node, NODE_FIELDS);
218                 if(fieldsNode != null) {
219                         final NodeList listFieldNodes = fieldsNode.getElementsByTagName(NODE_FIELD);
220                         final int numFields = listFieldNodes.getLength();
221                         for(int i = 0; i < numFields; i++) {
222                                 final Node fieldNode = listFieldNodes.item(i);
223                                 final Element element = (Element)fieldNode; //TODO: Check the cast.
224                                 Field field = new Field();
225                                 loadField(element, field);
226
227                                 info.fieldsMap.put(field.get_name(), field);
228                         }
229                 }
230
231                 final Element reportsNode = getElementByName(node, NODE_REPORTS);
232                 if(reportsNode != null) {
233                         final NodeList listReportNodes = reportsNode.getElementsByTagName(NODE_REPORT);
234                         final int numReports = listReportNodes.getLength();
235                         for(int i = 0; i < numReports; i++) {
236                                 final Node reportNode = listReportNodes.item(i);
237                                 final Element element = (Element)reportNode; //TODO: Check the cast.
238                                 Report report = new Report();
239                                 loadReport(element, report);
240
241                                 info.reportsMap.put(report.get_name(), report);
242                         }
243                 }
244                 
245                 tablesMap.put(info.name, info);
246         }
247
248         /**
249          * @param element
250          * @param field
251          */
252         private void loadField(Element element, Field field) {
253                 field.set_name(element.getAttribute(ATTRIBUTE_NAME));
254                 
255                 Field.glom_field_type fieldType = Field.glom_field_type.TYPE_INVALID;
256                 final String fieldTypeStr = element.getAttribute(ATTRIBUTE_FIELD_TYPE);
257                 if(!StringUtils.isEmpty(fieldTypeStr)) {
258                         if(fieldTypeStr == "boolean") {
259                                 fieldType = Field.glom_field_type.TYPE_BOOLEAN;
260                         } else if (fieldTypeStr == "date") {
261                                 fieldType = Field.glom_field_type.TYPE_DATE;
262                         } else if (fieldTypeStr == "image") {
263                                 fieldType = Field.glom_field_type.TYPE_IMAGE;
264                         } else if (fieldTypeStr == "numeric") {
265                                 fieldType = Field.glom_field_type.TYPE_NUMERIC;
266                         } else if (fieldTypeStr == "text") {
267                                 fieldType = Field.glom_field_type.TYPE_TEXT;
268                         } else if (fieldTypeStr == "time") {
269                                 fieldType = Field.glom_field_type.TYPE_TIME;
270                         }
271                 }
272                         
273                 field.set_glom_field_type(fieldType);
274                 
275                 field.set_primary_key(getAttributeAsBoolean(element, ATTRIBUTE_PRIMARY_KEY));
276                 loadTitle(element, field);
277         }
278
279         /**
280          * @param element
281          * @param reportNode
282          */
283         private void loadReport(Element element, Report report) {
284                 report.set_name(element.getAttribute(ATTRIBUTE_NAME));
285                 loadTitle(element, report);
286         }
287         
288         private TableInfo getTableInfo(final String tableName) {
289                 return tablesMap.get(tableName);
290         }
291
292         public enum HostingMode {
293             HOSTING_MODE_POSTGRES_CENTRAL,
294             HOSTING_MODE_POSTGRES_SELF,
295             HOSTING_MODE_SQLITE
296         };
297         
298         public String get_database_title(final String locale) {
299                 return databaseTitle.get_title(locale);
300         }
301         
302         public String get_database_title_original() {
303                 return databaseTitle.get_title_original();
304         }
305         
306         public StringVector get_translation_available_locales() {
307                 return new StringVector();
308         }
309         
310         public Document.HostingMode get_hosting_mode() {
311                 return HostingMode.HOSTING_MODE_POSTGRES_CENTRAL;
312         }
313         
314         public String get_connection_server() {
315                 return connectionServer;
316         }
317         
318         public long get_connection_port() {
319                 return connectionPort;
320         }
321         
322         public String get_connection_database() {
323                 return connectionDatabase;
324         }
325         
326         public StringVector get_table_names() {
327                 StringVector result = new StringVector(); //TODO: Use a normal type.
328                 
329                 //return tablesMap.keySet();
330                 
331                 for (final TableInfo info : tablesMap.values()) {
332                         result.add(info.name);
333                 }
334                 
335                 return result;
336         }
337         
338         public boolean get_table_is_hidden(final String table_name) {
339                 for (final TableInfo info : tablesMap.values()) {
340                         return info.isHidden;
341                 }
342                 
343                 return false;
344         }
345                         
346         public String get_table_title(final String tableName, final String locale) {
347                 final TableInfo info = getTableInfo(tableName);
348                 if(info == null) {
349                         return "";
350                 }
351                 
352                 return info.get_title(locale);
353         }
354         
355         public String get_default_table() {
356                 for (final TableInfo info : tablesMap.values()) {
357                         if(info.isDefault) {
358                                 return info.name;
359                         }
360                 }
361                 
362                 return "";
363         }
364         
365         public boolean get_table_is_known(String tableName) {
366                 final TableInfo info = getTableInfo(tableName);
367                 if(info == null) {
368                         return false;
369                 }
370                 
371                 return true;
372         }
373         
374         public List<Field> get_table_fields(final String tableName) {
375                 final TableInfo info = getTableInfo(tableName);
376                 if(info == null)
377                         return null;
378
379                 return new ArrayList<Field>(info.fieldsMap.values());
380         }
381         
382         public Field get_field(String table_name, String strFieldName) {
383                 //TODO:
384                 return new Field();
385         }
386         
387         public LayoutGroupVector get_data_layout_groups(String layout_name, String parent_table_name) {
388                 //TODO:
389                 return new LayoutGroupVector();
390         }
391         
392         public StringVector get_report_names(String tableName) {
393                 StringVector result = new StringVector();
394
395                 final TableInfo info = getTableInfo(tableName);
396                 if(info == null)
397                         return result;
398
399                 for (final Report report : info.reportsMap.values()) {
400                         result.add(report.get_name());
401                 }
402
403                 return new StringVector();
404         }
405         
406         public Report get_report(String tableName, String reportName) {
407                 final TableInfo info = getTableInfo(tableName);
408                 if(info == null)
409                         return null;
410
411                 return info.reportsMap.get(reportName);
412         }
413 }