Rename GlomDocument to DocumentInfo and update associated methods.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / server / ConfiguredDocument.java
1 /*
2  * Copyright (C) 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.beans.PropertyVetoException;
23 import java.sql.Connection;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26
27 import org.glom.libglom.Document;
28 import org.glom.libglom.Field;
29 import org.glom.libglom.FieldFormatting;
30 import org.glom.libglom.FieldVector;
31 import org.glom.libglom.LayoutGroupVector;
32 import org.glom.libglom.LayoutItemVector;
33 import org.glom.libglom.LayoutItem_Field;
34 import org.glom.libglom.LayoutItem_Portal;
35 import org.glom.libglom.Relationship;
36 import org.glom.libglom.StringVector;
37 import org.glom.web.server.database.DetailsDBAccess;
38 import org.glom.web.server.database.ListDBAccess;
39 import org.glom.web.server.database.ListViewDBAccess;
40 import org.glom.web.server.database.RelatedListDBAccess;
41 import org.glom.web.shared.DocumentInfo;
42 import org.glom.web.shared.GlomField;
43 import org.glom.web.shared.layout.Formatting;
44 import org.glom.web.shared.layout.LayoutGroup;
45 import org.glom.web.shared.layout.LayoutItemField;
46 import org.glom.web.shared.layout.LayoutItemPortal;
47
48 import com.mchange.v2.c3p0.ComboPooledDataSource;
49
50 /**
51  * A class to hold configuration information for a given Glom document. This class is used to retrieve layout
52  * information from libglom and data from the underlying PostgreSQL database.
53  * 
54  * @author Ben Konrath <ben@bagu.org>
55  * 
56  */
57 final class ConfiguredDocument {
58
59         private Document document;
60         private ComboPooledDataSource cpds;
61         private boolean authenticated = false;
62         private String documentID;
63
64         @SuppressWarnings("unused")
65         private ConfiguredDocument() {
66                 // disable default constructor
67         }
68
69         ConfiguredDocument(Document document) throws PropertyVetoException {
70
71                 // load the jdbc driver
72                 cpds = new ComboPooledDataSource();
73
74                 // We don't support sqlite or self-hosting yet.
75                 if (document.get_hosting_mode() != Document.HostingMode.HOSTING_MODE_POSTGRES_CENTRAL) {
76                         Log.fatal("Error configuring the database connection." + " Only central PostgreSQL hosting is supported.");
77                         // FIXME: Throw exception?
78                 }
79
80                 try {
81                         cpds.setDriverClass("org.postgresql.Driver");
82                 } catch (PropertyVetoException e) {
83                         Log.fatal("Error loading the PostgreSQL JDBC driver."
84                                         + " Is the PostgreSQL JDBC jar available to the servlet?", e);
85                         throw e;
86                 }
87
88                 // setup the JDBC driver for the current glom document
89                 cpds.setJdbcUrl("jdbc:postgresql://" + document.get_connection_server() + ":" + document.get_connection_port()
90                                 + "/" + document.get_connection_database());
91
92                 this.document = document;
93         }
94
95         /**
96          * Sets the username and password for the database associated with the Glom document.
97          * 
98          * @return true if the username and password works, false otherwise
99          */
100         boolean setUsernameAndPassword(String username, String password) throws SQLException {
101                 cpds.setUser(username);
102                 cpds.setPassword(password);
103
104                 int acquireRetryAttempts = cpds.getAcquireRetryAttempts();
105                 cpds.setAcquireRetryAttempts(1);
106                 Connection conn = null;
107                 try {
108                         // FIXME find a better way to check authentication
109                         // it's possible that the connection could be failing for another reason
110                         conn = cpds.getConnection();
111                         authenticated = true;
112                 } catch (SQLException e) {
113                         Log.info(Utils.getFileName(document.get_file_uri()), e.getMessage());
114                         Log.info(Utils.getFileName(document.get_file_uri()),
115                                         "Connection Failed. Maybe the username or password is not correct.");
116                         authenticated = false;
117                 } finally {
118                         if (conn != null)
119                                 conn.close();
120                         cpds.setAcquireRetryAttempts(acquireRetryAttempts);
121                 }
122                 return authenticated;
123         }
124
125         Document getDocument() {
126                 return document;
127         }
128
129         ComboPooledDataSource getCpds() {
130                 return cpds;
131         }
132
133         boolean isAuthenticated() {
134                 return authenticated;
135         }
136
137         String getDocumentID() {
138                 return documentID;
139         }
140
141         void setDocumentID(String documentID) {
142                 this.documentID = documentID;
143         }
144
145         /**
146          * @return
147          */
148         DocumentInfo getDocumentInfo() {
149                 DocumentInfo documentInfo = new DocumentInfo();
150
151                 // get arrays of table names and titles, and find the default table index
152                 StringVector tablesVec = document.get_table_names();
153
154                 int numTables = Utils.safeLongToInt(tablesVec.size());
155                 // we don't know how many tables will be hidden so we'll use half of the number of tables for the default size
156                 // of the ArrayList
157                 ArrayList<String> tableNames = new ArrayList<String>(numTables / 2);
158                 ArrayList<String> tableTitles = new ArrayList<String>(numTables / 2);
159                 boolean foundDefaultTable = false;
160                 int visibleIndex = 0;
161                 for (int i = 0; i < numTables; i++) {
162                         String tableName = tablesVec.get(i);
163                         if (!document.get_table_is_hidden(tableName)) {
164                                 tableNames.add(tableName);
165                                 // JNI is "expensive", the comparison will only be called if we haven't already found the default table
166                                 if (!foundDefaultTable && tableName.equals(document.get_default_table())) {
167                                         documentInfo.setDefaultTableIndex(visibleIndex);
168                                         foundDefaultTable = true;
169                                 }
170                                 tableTitles.add(document.get_table_title(tableName));
171                                 visibleIndex++;
172                         }
173                 }
174
175                 // set everything we need
176                 documentInfo.setTableNames(tableNames);
177                 documentInfo.setTableTitles(tableTitles);
178                 documentInfo.setTitle(document.get_database_title());
179
180                 return documentInfo;
181         }
182
183         /*
184          * Gets the layout group for the list view using the defined layout list in the document or the table fields if
185          * there's no defined layout group for the list view.
186          */
187         private org.glom.libglom.LayoutGroup getValidListViewLayoutGroup(String tableName) {
188
189                 LayoutGroupVector layoutGroupVec = document.get_data_layout_groups("list", tableName);
190
191                 int listViewLayoutGroupSize = Utils.safeLongToInt(layoutGroupVec.size());
192                 org.glom.libglom.LayoutGroup libglomLayoutGroup = null;
193                 if (listViewLayoutGroupSize > 0) {
194                         // a list layout group is defined; we can use the first group as the list
195                         if (listViewLayoutGroupSize > 1)
196                                 Log.warn(documentID, tableName, "The size of the list layout group is greater than 1. "
197                                                 + "Attempting to use the first item for the layout list view.");
198
199                         libglomLayoutGroup = layoutGroupVec.get(0);
200                 } else {
201                         // a list layout group is *not* defined; we are going make a libglom layout group from the list of fields
202                         Log.info(documentID, tableName,
203                                         "A list layout is not defined for this table. Displaying a list layout based on the field list.");
204
205                         FieldVector fieldsVec = document.get_table_fields(tableName);
206                         libglomLayoutGroup = new org.glom.libglom.LayoutGroup();
207                         for (int i = 0; i < fieldsVec.size(); i++) {
208                                 Field field = fieldsVec.get(i);
209                                 LayoutItem_Field layoutItemField = new LayoutItem_Field();
210                                 layoutItemField.set_full_field_details(field);
211                                 libglomLayoutGroup.add_item(layoutItemField);
212                         }
213                 }
214
215                 return libglomLayoutGroup;
216         }
217
218         ArrayList<GlomField[]> getListViewData(String tableName, int start, int length, boolean useSortClause,
219                         int sortColumnIndex, boolean isAscending) {
220                 // Validate the table name.
221                 tableName = getTableNameToUse(tableName);
222
223                 // Get the libglom LayoutGroup that represents the list view.
224                 org.glom.libglom.LayoutGroup libglomLayoutGroup = getValidListViewLayoutGroup(tableName);
225
226                 // Create a database access object for the list view.
227                 ListViewDBAccess listViewDBAccess = new ListViewDBAccess(document, documentID, cpds, tableName,
228                                 libglomLayoutGroup);
229
230                 // Return the data.
231                 return listViewDBAccess.getData(start, length, useSortClause, sortColumnIndex, isAscending);
232         }
233
234         GlomField[] getDetailsData(String tableName, String primaryKeyValue) {
235                 // Validate the table name.
236                 tableName = getTableNameToUse(tableName);
237
238                 DetailsDBAccess detailsDBAccess = new DetailsDBAccess(document, documentID, cpds, tableName);
239
240                 return detailsDBAccess.getData(primaryKeyValue);
241         }
242
243         ArrayList<GlomField[]> getRelatedListData(String tableName, String relationshipName, String foreignKeyValue,
244                         int start, int length, boolean useSortClause, int sortColumnIndex, boolean isAscending) {
245                 // Validate the table name.
246                 tableName = getTableNameToUse(tableName);
247
248                 // Create a database access object for the related list
249                 RelatedListDBAccess relatedListDBAccess = new RelatedListDBAccess(document, documentID, cpds, tableName,
250                                 relationshipName);
251
252                 // Return the data
253                 return relatedListDBAccess.getData(start, length, foreignKeyValue, useSortClause, sortColumnIndex, isAscending);
254         }
255
256         ArrayList<LayoutGroup> getDetailsLayoutGroup(String tableName) {
257                 // Validate the table name.
258                 tableName = getTableNameToUse(tableName);
259
260                 // Get the details layout group information for each LayoutGroup in the LayoutGroupVector
261                 LayoutGroupVector layoutGroupVec = document.get_data_layout_groups("details", tableName);
262                 ArrayList<LayoutGroup> layoutGroups = new ArrayList<LayoutGroup>();
263                 for (int i = 0; i < layoutGroupVec.size(); i++) {
264                         org.glom.libglom.LayoutGroup libglomLayoutGroup = layoutGroupVec.get(i);
265
266                         // satisfy the precondition of getDetailsLayoutGroup(String, org.glom.libglom.LayoutGroup)
267                         if (libglomLayoutGroup == null)
268                                 continue;
269
270                         layoutGroups.add(getDetailsLayoutGroup(tableName, libglomLayoutGroup));
271                 }
272
273                 return layoutGroups;
274         }
275
276         LayoutGroup getListViewLayoutGroup(String tableName) {
277                 // Validate the table name.
278                 tableName = getTableNameToUse(tableName);
279
280                 org.glom.libglom.LayoutGroup libglomLayoutGroup = getValidListViewLayoutGroup(tableName);
281
282                 return getListLayoutGroup(tableName, libglomLayoutGroup);
283         }
284
285         /*
286          * Gets the expected row count for a related list.
287          */
288         int getRelatedListRowCount(String tableName, String relationshipName, String foreignKeyValue) {
289                 // Validate the table name.
290                 tableName = getTableNameToUse(tableName);
291
292                 // Create a database access object for the related list
293                 RelatedListDBAccess relatedListDBAccess = new RelatedListDBAccess(document, documentID, cpds, tableName,
294                                 relationshipName);
295
296                 // Return the row count
297                 return relatedListDBAccess.getExpectedResultSize(foreignKeyValue);
298         }
299
300         /*
301          * Gets a LayoutGroup DTO for the given table name and libglom LayoutGroup. This method can be used for the main
302          * list view table and for the related list table.
303          */
304         private LayoutGroup getListLayoutGroup(String tableName, org.glom.libglom.LayoutGroup libglomLayoutGroup) {
305                 LayoutGroup layoutGroup = new LayoutGroup();
306
307                 // look at each child item
308                 LayoutItemVector layoutItemsVec = libglomLayoutGroup.get_items();
309                 int numItems = Utils.safeLongToInt(layoutItemsVec.size());
310                 for (int i = 0; i < numItems; i++) {
311                         org.glom.libglom.LayoutItem libglomLayoutItem = layoutItemsVec.get(i);
312
313                         // TODO add support for other LayoutItems (Text, Image, Button etc.)
314                         LayoutItem_Field libglomLayoutField = LayoutItem_Field.cast_dynamic(libglomLayoutItem);
315                         if (libglomLayoutField != null) {
316                                 layoutGroup.addItem(convertToGWTGlomLayoutItemField(libglomLayoutField));
317                         } else {
318                                 Log.info(documentID, tableName,
319                                                 "Ignoring unknown LayoutItem of type " + libglomLayoutItem.get_part_type_name() + ".");
320                                 continue;
321                         }
322                 }
323
324                 ListDBAccess listDBAccess = null;
325                 LayoutItem_Portal libglomLayoutItemPortal = LayoutItem_Portal.cast_dynamic(libglomLayoutGroup);
326                 if (libglomLayoutItemPortal != null) {
327                         // libglomLayoutGroup is a related view
328                         listDBAccess = new RelatedListDBAccess(document, documentID, cpds, tableName,
329                                         libglomLayoutItemPortal.get_relationship_name_used());
330                         layoutGroup.setExpectedResultSize(listDBAccess.getExpectedResultSize());
331                 } else {
332                         // libglomLayoutGroup is a list view
333                         listDBAccess = new ListViewDBAccess(document, documentID, cpds, tableName, libglomLayoutGroup);
334                         layoutGroup.setExpectedResultSize(listDBAccess.getExpectedResultSize());
335                 }
336
337                 // Set the primary key index for the table
338                 int primaryKeyIndex = listDBAccess.getPrimaryKeyIndex();
339                 if (primaryKeyIndex < 0) {
340                         // Add a LayoutItemField for the primary key to the end of the item list in the LayoutGroup because it
341                         // doesn't already contain a primary key.
342                         LayoutItem_Field libglomLayoutItemField = listDBAccess.getPrimaryKeyLayoutItemField();
343                         layoutGroup.addItem(convertToGWTGlomLayoutItemField(libglomLayoutItemField));
344                         layoutGroup.setPrimaryKeyIndex(layoutGroup.getItems().size() - 1);
345                         layoutGroup.setHiddenPrimaryKey(true);
346
347                 } else {
348                         layoutGroup.setPrimaryKeyIndex(primaryKeyIndex);
349                 }
350
351                 layoutGroup.setTableName(tableName);
352
353                 return layoutGroup;
354         }
355
356         /*
357          * Gets a recursively defined Details LayoutGroup DTO for the specified libglom LayoutGroup object. This is used for
358          * getting layout information for the details view.
359          * 
360          * @param documentID Glom document identifier
361          * 
362          * @param tableName table name in the specified Glom document
363          * 
364          * @param libglomLayoutGroup libglom LayoutGroup to convert
365          * 
366          * @precondition libglomLayoutGroup must not be null
367          * 
368          * @return {@link LayoutGroup} object that represents the layout for the specified {@link
369          * org.glom.libglom.LayoutGroup}
370          */
371         private LayoutGroup getDetailsLayoutGroup(String tableName, org.glom.libglom.LayoutGroup libglomLayoutGroup) {
372                 LayoutGroup layoutGroup = new LayoutGroup();
373                 layoutGroup.setColumnCount(Utils.safeLongToInt(libglomLayoutGroup.get_columns_count()));
374                 layoutGroup.setTitle(libglomLayoutGroup.get_title());
375
376                 // look at each child item
377                 LayoutItemVector layoutItemsVec = libglomLayoutGroup.get_items();
378                 for (int i = 0; i < layoutItemsVec.size(); i++) {
379                         org.glom.libglom.LayoutItem libglomLayoutItem = layoutItemsVec.get(i);
380
381                         // just a safety check
382                         if (libglomLayoutItem == null)
383                                 continue;
384
385                         org.glom.web.shared.layout.LayoutItem layoutItem = null;
386                         org.glom.libglom.LayoutGroup group = org.glom.libglom.LayoutGroup.cast_dynamic(libglomLayoutItem);
387                         if (group != null) {
388                                 // libglomLayoutItem is a LayoutGroup
389                                 LayoutItem_Portal libglomLayoutItemPortal = LayoutItem_Portal.cast_dynamic(group);
390                                 if (libglomLayoutItemPortal != null) {
391                                         // group is a LayoutItemPortal
392                                         LayoutItemPortal layoutItemPortal = new LayoutItemPortal();
393                                         Relationship relationship = libglomLayoutItemPortal.get_relationship();
394                                         if (relationship != null) {
395                                                 layoutItemPortal.setNavigationType(convertToGWTGlomNavigationType(libglomLayoutItemPortal
396                                                                 .get_navigation_type()));
397
398                                                 layoutItemPortal.setTitle(libglomLayoutItemPortal.get_title_used("")); // parent title not
399                                                                                                                                                                                                 // relevant
400                                                 LayoutGroup tempLayoutGroup = getListLayoutGroup(tableName, libglomLayoutItemPortal);
401                                                 for (org.glom.web.shared.layout.LayoutItem item : tempLayoutGroup.getItems()) {
402                                                         // TODO EDITING If the relationship does not allow editing, then mark all these fields as
403                                                         // non-editable. Check relationship.get_allow_edit() to see if it's editable.
404                                                         layoutItemPortal.addItem(item);
405                                                 }
406                                                 layoutItemPortal.setPrimaryKeyIndex(tempLayoutGroup.getPrimaryKeyIndex());
407                                                 layoutItemPortal.setHiddenPrimaryKey(tempLayoutGroup.hasHiddenPrimaryKey());
408                                                 layoutItemPortal.setName(libglomLayoutItemPortal.get_relationship_name_used());
409                                                 layoutItemPortal.setTableName(relationship.get_from_table());
410                                                 layoutItemPortal.setFromField(relationship.get_from_field());
411                                         }
412
413                                         // Note: empty layoutItemPortal used if relationship is null
414                                         layoutItem = layoutItemPortal;
415
416                                 } else {
417                                         // group is *not* a LayoutItemPortal//
418                                         // recurse into child groups
419                                         layoutItem = getDetailsLayoutGroup(tableName, group);
420                                 }
421                         } else {
422                                 // libglomLayoutItem is *not* a LayoutGroup
423                                 // create LayoutItem DTOs based on the the libglom type
424                                 // TODO add support for other LayoutItems (Text, Image, Button etc.)
425                                 LayoutItem_Field libglomLayoutField = LayoutItem_Field.cast_dynamic(libglomLayoutItem);
426                                 if (libglomLayoutField != null) {
427                                         layoutItem = convertToGWTGlomLayoutItemField(libglomLayoutField);
428                                 } else {
429                                         Log.info(documentID, tableName,
430                                                         "Ignoring unknown LayoutItem of type " + libglomLayoutItem.get_part_type_name() + ".");
431                                         continue;
432                                 }
433                         }
434
435                         layoutGroup.addItem(layoutItem);
436                 }
437
438                 return layoutGroup;
439         }
440
441         private LayoutItemField convertToGWTGlomLayoutItemField(LayoutItem_Field libglomLayoutItemField) {
442                 LayoutItemField layoutItemField = new LayoutItemField();
443
444                 // set type
445                 layoutItemField.setType(convertToGWTGlomFieldType(libglomLayoutItemField.get_glom_type()));
446
447                 // set formatting
448                 Formatting formatting = new Formatting();
449                 formatting.setHorizontalAlignment(convertToGWTGlomHorizonalAlignment(libglomLayoutItemField
450                                 .get_formatting_used_horizontal_alignment()));
451                 FieldFormatting libglomFormatting = libglomLayoutItemField.get_formatting_used();
452                 if (libglomFormatting.get_text_format_multiline()) {
453                         formatting.setTextFormatMultilineHeightLines(Utils.safeLongToInt(libglomFormatting
454                                         .get_text_format_multiline_height_lines()));
455                 }
456                 layoutItemField.setFormatting(formatting);
457
458                 // set title and name
459                 layoutItemField.setTitle(libglomLayoutItemField.get_title_or_name());
460                 layoutItemField.setName(libglomLayoutItemField.get_name());
461
462                 return layoutItemField;
463         }
464
465         /*
466          * This method converts a Field.glom_field_type to the equivalent ColumnInfo.FieldType. The need for this comes from
467          * the fact that the GWT FieldType classes can't be used with RPC and there's no easy way to use the java-libglom
468          * Field.glom_field_type enum with RPC. An enum identical to FieldFormatting.glom_field_type is included in the
469          * ColumnInfo class.
470          */
471         private LayoutItemField.GlomFieldType convertToGWTGlomFieldType(Field.glom_field_type type) {
472                 switch (type) {
473                 case TYPE_BOOLEAN:
474                         return LayoutItemField.GlomFieldType.TYPE_BOOLEAN;
475                 case TYPE_DATE:
476                         return LayoutItemField.GlomFieldType.TYPE_DATE;
477                 case TYPE_IMAGE:
478                         return LayoutItemField.GlomFieldType.TYPE_IMAGE;
479                 case TYPE_NUMERIC:
480                         return LayoutItemField.GlomFieldType.TYPE_NUMERIC;
481                 case TYPE_TEXT:
482                         return LayoutItemField.GlomFieldType.TYPE_TEXT;
483                 case TYPE_TIME:
484                         return LayoutItemField.GlomFieldType.TYPE_TIME;
485                 case TYPE_INVALID:
486                         Log.info("Returning TYPE_INVALID.");
487                         return LayoutItemField.GlomFieldType.TYPE_INVALID;
488                 default:
489                         Log.error("Recieved a type that I don't know about: " + Field.glom_field_type.class.getName() + "."
490                                         + type.toString() + ". Returning " + LayoutItemField.GlomFieldType.TYPE_INVALID.toString() + ".");
491                         return LayoutItemField.GlomFieldType.TYPE_INVALID;
492                 }
493         }
494
495         /*
496          * This method converts a FieldFormatting.HorizontalAlignment to the equivalent Formatting.HorizontalAlignment. The
497          * need for this comes from the fact that the GWT HorizontalAlignment classes can't be used with RPC and there's no
498          * easy way to use the java-libglom FieldFormatting.HorizontalAlignment enum with RPC. An enum identical to
499          * FieldFormatting.HorizontalAlignment is included in the Formatting class.
500          */
501         private Formatting.HorizontalAlignment convertToGWTGlomHorizonalAlignment(
502                         FieldFormatting.HorizontalAlignment alignment) {
503                 switch (alignment) {
504                 case HORIZONTAL_ALIGNMENT_AUTO:
505                         return Formatting.HorizontalAlignment.HORIZONTAL_ALIGNMENT_AUTO;
506                 case HORIZONTAL_ALIGNMENT_LEFT:
507                         return Formatting.HorizontalAlignment.HORIZONTAL_ALIGNMENT_LEFT;
508                 case HORIZONTAL_ALIGNMENT_RIGHT:
509                         return Formatting.HorizontalAlignment.HORIZONTAL_ALIGNMENT_RIGHT;
510                 default:
511                         Log.error("Recieved an alignment that I don't know about: "
512                                         + FieldFormatting.HorizontalAlignment.class.getName() + "." + alignment.toString() + ". Returning "
513                                         + Formatting.HorizontalAlignment.HORIZONTAL_ALIGNMENT_RIGHT.toString() + ".");
514                         return Formatting.HorizontalAlignment.HORIZONTAL_ALIGNMENT_RIGHT;
515                 }
516         }
517
518         /*
519          * This method converts a LayoutItem_Portal.navigation_type from java-libglom to the equivalent
520          * LayoutItemPortal.NavigationType from Online Glom. This conversion is required because the LayoutItem_Portal class
521          * from java-libglom can't be used with GWT-RPC. An enum identical to LayoutItem_Portal.navigation_type from
522          * java-libglom is included in the LayoutItemPortal data transfer object.
523          */
524         private LayoutItemPortal.NavigationType convertToGWTGlomNavigationType(
525                         LayoutItem_Portal.navigation_type navigationType) {
526                 switch (navigationType) {
527                 case NAVIGATION_NONE:
528                         return LayoutItemPortal.NavigationType.NAVIGATION_NONE;
529                 case NAVIGATION_AUTOMATIC:
530                         return LayoutItemPortal.NavigationType.NAVIGATION_AUTOMATIC;
531                 case NAVIGATION_SPECIFIC:
532                         return LayoutItemPortal.NavigationType.NAVIGATION_SPECIFIC;
533                 default:
534                         Log.error("Recieved an unknown NavigationType: " + LayoutItem_Portal.navigation_type.class.getName() + "."
535                                         + navigationType.toString() + ". Returning " + LayoutItemPortal.NavigationType.NAVIGATION_AUTOMATIC
536                                         + ".");
537                         return LayoutItemPortal.NavigationType.NAVIGATION_AUTOMATIC;
538                 }
539         }
540
541         /**
542          * Gets the table name to use when accessing the database and the document. This method guards against SQL injection
543          * attacks by returning the default table if the requested table is not in the database or if the table name has not
544          * been set.
545          * 
546          * @param tableName
547          *            The table name to validate.
548          * @return The table name to use.
549          */
550         private String getTableNameToUse(String tableName) {
551                 if (tableName == null || tableName.isEmpty() || !document.get_table_is_known(tableName)) {
552                         return document.get_default_table();
553                 }
554                 return tableName;
555         }
556
557 }