DetailsActivity: Check for authentication here too.
[online-glom:gwt-glom.git] / src / main / java / org / glom / web / server / database / RelatedListDBAccess.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.database;
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.apache.commons.lang3.StringUtils;
26 import org.glom.web.server.Log;
27 import org.glom.web.server.SqlUtils;
28 import org.glom.web.server.libglom.Document;
29 import org.glom.web.shared.DataItem;
30 import org.glom.web.shared.TypedDataItem;
31 import org.glom.web.shared.libglom.Field;
32 import org.glom.web.shared.libglom.Relationship;
33 import org.glom.web.shared.libglom.layout.LayoutGroup;
34 import org.glom.web.shared.libglom.layout.LayoutItemField;
35 import org.glom.web.shared.libglom.layout.LayoutItemPortal;
36 import org.glom.web.shared.libglom.layout.SortClause;
37 import org.jooq.Condition;
38
39 import com.mchange.v2.c3p0.ComboPooledDataSource;
40
41 /**
42  *
43  */
44 public class RelatedListDBAccess extends ListDBAccess {
45         private TypedDataItem foreignKeyValue = null;
46         private LayoutItemPortal portal = null;
47         private String parentTable = null;
48         private String whereClauseToTableName = null;
49         private Field whereClauseToKeyField = null;
50
51         public RelatedListDBAccess(final Document document, final String documentID, final ComboPooledDataSource cpds,
52                         final String tableName, final LayoutItemPortal portal) {
53                 super(document, documentID, cpds, tableName);
54
55                 if (portal == null) {
56                         Log.error(documentID, tableName, "portal is null in table \"" + tableName + "\". "
57                                         + "Cannot retrieve data for the related list.");
58                         return;
59                 }
60
61                 parentTable = tableName;
62                 // Reassign the tableName variable to table that is being used for the related list. This needs to be set before
63                 // getFieldsToShowForSQLQuery().
64                 this.tableName = portal.getTableUsed("" /* parent table - not relevant */);
65
66                 // Convert the libglom LayoutGroup object into a List<LayoutItem_Field> suitable for SQL queries.
67                 final List<LayoutGroup> tempLayoutGroupVec = new ArrayList<LayoutGroup>();
68                 tempLayoutGroupVec.add(portal);
69                 fieldsToGet = getFieldsToShowForSQLQuery(tempLayoutGroupVec);
70
71                 /*
72                  * The code from the rest of this method was inspired by code from Glom:
73                  * Base_DB::set_found_set_where_clause_for_portal()
74                  */
75                 final Relationship relationship = portal.getRelationship();
76
77                 // Notice that, in the case that this is a portal to doubly-related records,
78                 // The WHERE clause mentions the first-related table (though by the alias defined in extra_join)
79                 // and we add an extra JOIN to mention the second-related table.
80
81                 whereClauseToTableName = relationship.getToTable();
82                 whereClauseToKeyField = getFieldInTable(relationship.getToField(), whereClauseToTableName);
83
84                 // Add primary key
85                 final LayoutItemField primaryKey = getPrimaryKeyLayoutItemField(this.tableName);
86                 if (primaryKey == null) {
87                         Log.error(documentID, tableName, "RelatedListDBAccess: getPrimaryKeyLayoutItemField() failed.");
88                 } else {
89                         fieldsToGet.add(primaryKey);
90                 }
91
92                 final Relationship relationshipRelated = portal.getRelatedRelationship();
93                 if (relationshipRelated != null) {
94                         Log.error(documentID, tableName, "The related relationship " + relationshipRelated.getName()
95                                         + " is not empty but the related relationship code has not been implemented yet.");
96
97                         // FIXME port this Glom code to Java
98                         // @formatter:off
99                         /*
100                     //Add the extra JOIN:
101                     sharedptr<UsesRelationship> uses_rel_temp = sharedptr<UsesRelationship>::create();
102                     uses_rel_temp->set_relationship(relationship);
103                     found_set.m_extra_join = relationship;
104
105                     //Adjust the WHERE clause appropriately for the extra JOIN:
106                     whereClauseToTableName = uses_rel_temp->get_sql_join_alias_name();
107
108                     const Glib::ustring to_field_name = uses_rel_temp->get_to_field_used();
109                     where_clause_to_key_field = get_fields_for_table_one_field(relationship->get_to_table(), to_field_name);
110                     std::cout << "extra_join=" << found_set.m_extra_join << std::endl;
111                     std::cout << "extra_join where_clause_to_key_field=" << where_clause_to_key_field->get_name() << std::endl;
112                          */
113                         // @formatter:on
114                 }
115
116                 // set portal field
117                 this.portal = portal;
118
119         }
120
121         /**
122          * 
123          * @param start
124          * @param length
125          * @param foreignKeyValue
126          * @param sortColumnIndex
127          *            The index of the column to sort by, or -1 for none.
128          * @param isAscending
129          * @return
130          */
131         public ArrayList<DataItem[]> getData(final int start, final int length, final TypedDataItem foreignKeyValue,
132                         final int sortColumnIndex, final boolean isAscending) {
133
134                 if (tableName == null || foreignKeyValue == null || foreignKeyValue.isEmpty()) {
135                         return null;
136                 }
137
138                 // Set the foreignKeyValue
139                 this.foreignKeyValue = foreignKeyValue;
140
141                 return getListData("" /* quickFind */, start, length, sortColumnIndex, isAscending);
142         }
143
144         /*
145          * (non-Javadoc)
146          * 
147          * @see org.glom.web.server.ListDBAccess#getExpectedResultSize()
148          */
149         public int getExpectedResultSize(final TypedDataItem foreignKeyValue) {
150
151                 // Set the foreignKeyValue
152                 this.foreignKeyValue = foreignKeyValue;
153
154                 if (fieldsToGet == null || fieldsToGet.size() <= 0 || this.foreignKeyValue == null) {
155                         return -1;
156                 }
157
158                 return getResultSizeOfSQLQuery();
159         }
160
161         /*
162          * (non-Javadoc)
163          * 
164          * @see org.glom.web.server.ListDBAccess#getSelectQuery(org.glom.libglom.LayoutFieldVector,
165          * org.glom.libglom.SortClause)
166          */
167         @Override
168         protected String getSelectQuery(final String quickFind, final SortClause sortClause) {
169                 // TODO: combine this method with getCountQuery() to remove duplicate code
170                 if (portal == null) {
171                         Log.error(documentID, parentTable,
172                                         "The Portal has not been found. Cannot build query for the related list.");
173                         return "";
174                 }
175
176                 if (foreignKeyValue == null || foreignKeyValue.isEmpty()) {
177                         Log.error(documentID, parentTable,
178                                         "The value for the foreign key has not been set. Cannot build query for the related list.");
179                         return "";
180                 }
181
182                 Condition whereClause = null; // Note that we ignore quickFind.
183                 // only attempt to make a where clause if it makes sense to do so
184                 if (!StringUtils.isEmpty(whereClauseToTableName)) {
185                         if (foreignKeyValue != null) {
186                                 whereClause = SqlUtils.buildSimpleWhereExpression(whereClauseToTableName, whereClauseToKeyField,
187                                                 foreignKeyValue);
188                         }
189                 }
190
191                 return SqlUtils.buildSqlSelectWithWhereClause(tableName, fieldsToGet, whereClause, sortClause);
192
193         }
194
195         private Field getFieldInTable(final String fieldName, final String tableName) {
196
197                 if (StringUtils.isEmpty(tableName)) {
198                         return null;
199                 }
200
201                 final List<Field> fields = document.getTableFields(tableName);
202                 for (int i = 0; i < fields.size(); i++) {
203                         final Field field = fields.get(i);
204                         if (fieldName.equals(field.getName())) {
205                                 return field;
206                         }
207                 }
208
209                 return null;
210         }
211
212         /*
213          * (non-Javadoc)
214          * 
215          * @see org.glom.web.server.ListDBAccess#getCountQuery()
216          */
217         @Override
218         protected String getCountQuery() {
219                 // TODO: combine this method with getSelectQuery() to remove duplicate code
220                 if (portal == null) {
221                         Log.error(documentID, parentTable,
222                                         "The Portal has not been found. Cannot build query for the related list.");
223                         return "";
224                 }
225
226                 if (foreignKeyValue == null || foreignKeyValue.isEmpty()) {
227                         Log.error(documentID, parentTable,
228                                         "The value for the foreign key has not been set. Cannot build query for the related list.");
229                         return "";
230                 }
231
232                 Condition whereClause = null;
233                 // only attempt to make a where clause if it makes sense to do so
234                 if (!whereClauseToTableName.isEmpty() && whereClauseToKeyField != null) {
235                         if (foreignKeyValue != null) {
236                                 whereClause = SqlUtils.buildSimpleWhereExpression(whereClauseToTableName, whereClauseToKeyField,
237                                                 foreignKeyValue);
238                         }
239                 }
240
241                 return SqlUtils.buildSqlCountSelectWithWhereClause(tableName, fieldsToGet, whereClause);
242         }
243
244 }