From 6c40443d9cedc805ddeacc1c92cfa1f79a595499 Mon Sep 17 00:00:00 2001 From: Ben Konrath Date: Tue, 28 Jun 2011 10:51:37 +0200 Subject: [PATCH] Enable the table selector in the DetailsView. * src/main/java/org/glom/web/client/OnlineGlomService.java: * src/main/java/org/glom/web/client/OnlineGlomServiceAsync.java: * src/main/java/org/glom/web/server/OnlineGlomServiceImpl.java: Remove getDefaultDetailsLayout(). The default layout is now returned by the getDetailsLayout() method when the table name is an empty string. * src/main/java/org/glom/web/client/activity/DetailsActivity.java: Add event handler for table change event. Change to using getDetailsLayout() for the default details layout. * src/main/java/org/glom/web/client/place/DetailsPlace.java: Add table name to URL token. * src/main/java/org/glom/web/client/ui/ListViewImpl.java: Use table when navigating to the details place. --- ChangeLog | 18 +++++++ .../org/glom/web/client/OnlineGlomService.java | 13 +---- .../glom/web/client/OnlineGlomServiceAsync.java | 2 - .../glom/web/client/activity/DetailsActivity.java | 63 ++++++++++------------ .../org/glom/web/client/place/DetailsPlace.java | 32 +++++++---- .../java/org/glom/web/client/ui/ListViewImpl.java | 3 +- .../org/glom/web/server/OnlineGlomServiceImpl.java | 32 +++++------ 7 files changed, 89 insertions(+), 74 deletions(-) diff --git a/ChangeLog b/ChangeLog index f433371..c49193f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +2011-06-28 Ben Konrath + + Enable the table selector in the DetailsView. + + * src/main/java/org/glom/web/client/OnlineGlomService.java: + * src/main/java/org/glom/web/client/OnlineGlomServiceAsync.java: + * src/main/java/org/glom/web/server/OnlineGlomServiceImpl.java: + Remove getDefaultDetailsLayout(). The default layout is now returned + by the getDetailsLayout() method when the table name is an empty + string. + * src/main/java/org/glom/web/client/activity/DetailsActivity.java: Add + event handler for table change event. Change to using + getDetailsLayout() for the default details layout. + * src/main/java/org/glom/web/client/place/DetailsPlace.java: Add table + name to URL token. + * src/main/java/org/glom/web/client/ui/ListViewImpl.java: Use table + when navigating to the details place. + 2011-06-27 Ben Konrath Use filename based unique document ID in URL and for RPC. diff --git a/src/main/java/org/glom/web/client/OnlineGlomService.java b/src/main/java/org/glom/web/client/OnlineGlomService.java index 9f4e2b5..79fd79b 100644 --- a/src/main/java/org/glom/web/client/OnlineGlomService.java +++ b/src/main/java/org/glom/web/client/OnlineGlomService.java @@ -98,22 +98,13 @@ public interface OnlineGlomService extends RemoteService { * @param documentID * identifier for the Glom document * @param tableName - * name of the table in the Glom document + * name of the table in the Glom document or an empty {@link String} ("") to get the layout for the + * default table * @return a {@link LayoutGroup} the represents the layout of the {@link DetailsView} */ ArrayList getDetailsLayout(String documentID, String tableName); /** - * Gets a {@link LayoutGroup} that represents the layout of the {@link DetailsView} for the default table in the - * specified Glom document. - * - * @param documentID - * identifier for the Glom document - * @return a {@link LayoutGroup} the represents the layout of the {@link DetailsView} - */ - ArrayList getDefaultDetailsLayout(String documentID); - - /** * Gets data for the Details View. * * @param documentID diff --git a/src/main/java/org/glom/web/client/OnlineGlomServiceAsync.java b/src/main/java/org/glom/web/client/OnlineGlomServiceAsync.java index ba13f52..9ca68da 100644 --- a/src/main/java/org/glom/web/client/OnlineGlomServiceAsync.java +++ b/src/main/java/org/glom/web/client/OnlineGlomServiceAsync.java @@ -69,8 +69,6 @@ public interface OnlineGlomServiceAsync { void getDetailsLayout(String documentID, String tableName, AsyncCallback> callback); - void getDefaultDetailsLayout(String documentID, AsyncCallback> callback); - void getDetailsData(String documentID, String tableName, String primaryKeyValue, AsyncCallback callback); } diff --git a/src/main/java/org/glom/web/client/activity/DetailsActivity.java b/src/main/java/org/glom/web/client/activity/DetailsActivity.java index d1e0e0c..5afb2c8 100644 --- a/src/main/java/org/glom/web/client/activity/DetailsActivity.java +++ b/src/main/java/org/glom/web/client/activity/DetailsActivity.java @@ -23,6 +23,8 @@ import java.util.ArrayList; import org.glom.web.client.ClientFactory; import org.glom.web.client.OnlineGlomServiceAsync; +import org.glom.web.client.event.TableChangeEvent; +import org.glom.web.client.event.TableChangeEventHandler; import org.glom.web.client.place.DetailsPlace; import org.glom.web.client.ui.DetailsView; import org.glom.web.shared.GlomField; @@ -41,12 +43,14 @@ import com.google.gwt.user.client.ui.AcceptsOneWidget; */ public class DetailsActivity extends AbstractActivity implements DetailsView.Presenter { private final String documentID; + private final String tableName; private final String primaryKey; private final ClientFactory clientFactory; private final DetailsView detailsView; public DetailsActivity(DetailsPlace place, ClientFactory clientFactory) { this.documentID = place.getDocumentID(); + this.tableName = place.getTableName(); this.primaryKey = place.getPrimaryKeyValue(); this.clientFactory = clientFactory; detailsView = clientFactory.getDetailsView(); @@ -63,38 +67,29 @@ public class DetailsActivity extends AbstractActivity implements DetailsView.Pre // register this class as the presenter detailsView.setPresenter(this); + // TODO here's where we should check for database authentication - see ListActivity.start() for how to do this + + // set the change handler for the table selection widget + eventBus.addHandler(TableChangeEvent.TYPE, new TableChangeEventHandler() { + @Override + public void onTableChange(final TableChangeEvent event) { + goTo(new DetailsPlace(documentID, event.getTableName(), "")); + } + }); + // get the layout for the DetailsView - final String selectedTable = clientFactory.getTableSelectionView().getSelectedTable(); - if (!selectedTable.isEmpty()) { - // The table name has been set so we can use the selected table name to populate the cell table. - AsyncCallback> callback = new AsyncCallback>() { - public void onFailure(Throwable caught) { - // FIXME: need to deal with failure - System.out.println("AsyncCallback Failed: OnlineGlomService.getDetailsLayout()"); - } - - @Override - public void onSuccess(ArrayList result) { - addLayoutGroups(result); - } - }; - OnlineGlomServiceAsync.Util.getInstance().getDetailsLayout(documentID, selectedTable, callback); - } else { - // The table name has not been set so we need to fill in the details layout using the default table for the - // glom document. - AsyncCallback> callback = new AsyncCallback>() { - public void onFailure(Throwable caught) { - // FIXME: need to deal with failure - System.out.println("AsyncCallback Failed: OnlineGlomService.getDefaultDetailsLayout()"); - } - - @Override - public void onSuccess(ArrayList result) { - addLayoutGroups(result); - } - }; - OnlineGlomServiceAsync.Util.getInstance().getDefaultDetailsLayout(documentID, callback); - } + AsyncCallback> layoutCallback = new AsyncCallback>() { + public void onFailure(Throwable caught) { + // FIXME: need to deal with failure + System.out.println("AsyncCallback Failed: OnlineGlomService.getDetailsLayout()"); + } + + @Override + public void onSuccess(ArrayList result) { + addLayoutGroups(result); + } + }; + OnlineGlomServiceAsync.Util.getInstance().getDetailsLayout(documentID, tableName, layoutCallback); // get the data from the server AsyncCallback callback = new AsyncCallback() { @@ -109,11 +104,7 @@ public class DetailsActivity extends AbstractActivity implements DetailsView.Pre detailsView.setData(result); } }; - // FIXME Need a getDefaultDetailsData so that we can grab data from the default list when a table is not - // specified in the URL (which it's not now). This affects starting OnlineGlom from a bookmarked or shared - // URL to the DetailsView. We'll also want to add a table URL variable and perform validation of the URL - // variables. - OnlineGlomServiceAsync.Util.getInstance().getDetailsData(documentID, selectedTable, primaryKey, callback); + OnlineGlomServiceAsync.Util.getInstance().getDetailsData(documentID, tableName, primaryKey, callback); // indicate that the view is ready to be displayed panel.setWidget(detailsView.asWidget()); diff --git a/src/main/java/org/glom/web/client/place/DetailsPlace.java b/src/main/java/org/glom/web/client/place/DetailsPlace.java index 39a89e5..a046997 100644 --- a/src/main/java/org/glom/web/client/place/DetailsPlace.java +++ b/src/main/java/org/glom/web/client/place/DetailsPlace.java @@ -23,10 +23,12 @@ import com.google.gwt.place.shared.PlaceTokenizer; import com.google.gwt.place.shared.Prefix; public class DetailsPlace extends HasSelectableTablePlace { - private String primaryKeyValue; + private String primaryKeyValue = ""; + private String tableName = ""; - public DetailsPlace(String documentID, String primarykey) { + public DetailsPlace(String documentID, String tableName, String primarykey) { super(documentID); + this.tableName = tableName; this.primaryKeyValue = primarykey; } @@ -34,34 +36,46 @@ public class DetailsPlace extends HasSelectableTablePlace { return primaryKeyValue; } + public String getTableName() { + return tableName; + } + @Prefix("details") public static class Tokenizer implements PlaceTokenizer { final String documentKey = "document="; + final String tableKey = "table="; private final String primaryKeyValueKey = "value="; protected final String seperator = "&"; @Override public String getToken(DetailsPlace place) { - return documentKey + place.getDocumentID() + seperator + primaryKeyValueKey + place.getPrimaryKeyValue(); + return documentKey + place.getDocumentID() + seperator + tableKey + place.getTableName() + seperator + + primaryKeyValueKey + place.getPrimaryKeyValue(); } @Override public DetailsPlace getPlace(String token) { String[] tokenArray = token.split(seperator); - String documentID = "", primaryKeyValue = ""; - if (tokenArray.length != 2) - return new DetailsPlace(documentID, primaryKeyValue); + + if (tokenArray.length != 3) + return new DetailsPlace("", "", ""); + + String documentID = "", tableName = "", primaryKeyValue = ""; if (documentKey.equals(tokenArray[0].substring(0, documentKey.length()))) { documentID = tokenArray[0].substring(documentKey.length()); } - if (primaryKeyValueKey.equals(tokenArray[1].substring(0, primaryKeyValueKey.length()))) { - primaryKeyValue = tokenArray[1].substring(primaryKeyValueKey.length()); + if (tableKey.equals(tokenArray[1].substring(0, tableKey.length()))) { + tableName = tokenArray[1].substring(tableKey.length()); + } + + if (primaryKeyValueKey.equals(tokenArray[2].substring(0, primaryKeyValueKey.length()))) { + primaryKeyValue = tokenArray[2].substring(primaryKeyValueKey.length()); } - return new DetailsPlace(documentID, primaryKeyValue); + return new DetailsPlace(documentID, tableName, primaryKeyValue); } } diff --git a/src/main/java/org/glom/web/client/ui/ListViewImpl.java b/src/main/java/org/glom/web/client/ui/ListViewImpl.java index c5ed616..7869866 100644 --- a/src/main/java/org/glom/web/client/ui/ListViewImpl.java +++ b/src/main/java/org/glom/web/client/ui/ListViewImpl.java @@ -250,7 +250,8 @@ public class ListViewImpl extends Composite implements ListView { protected void onEnterKeyDown(Context context, Element parent, String value, NativeEvent event, ValueUpdater valueUpdater) { super.onEnterKeyDown(context, parent, value, event, valueUpdater); - presenter.goTo(new DetailsPlace(documentID, (String) context.getKey())); + + presenter.goTo(new DetailsPlace(documentID, tableName, (String) context.getKey())); } }) { diff --git a/src/main/java/org/glom/web/server/OnlineGlomServiceImpl.java b/src/main/java/org/glom/web/server/OnlineGlomServiceImpl.java index 6696859..79f9305 100644 --- a/src/main/java/org/glom/web/server/OnlineGlomServiceImpl.java +++ b/src/main/java/org/glom/web/server/OnlineGlomServiceImpl.java @@ -778,23 +778,18 @@ public class OnlineGlomServiceImpl extends RemoteServiceServlet implements Onlin /* * (non-Javadoc) * - * @see org.glom.web.client.OnlineGlomService#getDefaultDetailsLayoutGroup(java.lang.String) - */ - @Override - public ArrayList getDefaultDetailsLayout(String documentID) { - GlomDocument glomDocument = getGlomDocument(documentID); - String tableName = glomDocument.getTableNames().get(glomDocument.getDefaultTableIndex()); - return getDetailsLayout(documentID, tableName); - } - - /* - * (non-Javadoc) - * * @see org.glom.web.client.OnlineGlomService#getDetailsLayoutGroup(java.lang.String, java.lang.String) */ public ArrayList getDetailsLayout(String documentID, String tableName) { ConfiguredDocument configuredDoc = documentMapping.get(documentID); Document document = configuredDoc.getDocument(); + + // Use the default table if the table name hasn't been set or if the table name isn't in the glom document. + // The last check guards against SQL injection attacks since the table name could come from the URL. + if (tableName == null || tableName.isEmpty() || !document.get_table_is_known(tableName)) { + tableName = document.get_default_table(); + } + LayoutGroupVector layoutGroupVec = document.get_data_layout_groups("details", tableName); ArrayList layoutGroups = new ArrayList(); @@ -884,6 +879,12 @@ public class OnlineGlomServiceImpl extends RemoteServiceServlet implements Onlin ConfiguredDocument configuredDoc = documentMapping.get(documentID); Document document = configuredDoc.getDocument(); + // Use the default table if the table name hasn't been set or if the table name isn't in the glom document. + // The last check guards against SQL injection attacks since the table name could come from the URL. + if (tableName == null || tableName.isEmpty() || !document.get_table_is_known(tableName)) { + tableName = document.get_default_table(); + } + LayoutFieldVector fieldsToGet = getFieldsToShowForSQLQuery(document, tableName, "details"); if (fieldsToGet == null || fieldsToGet.size() <= 0) { @@ -920,7 +921,7 @@ public class OnlineGlomServiceImpl extends RemoteServiceServlet implements Onlin rs = st.executeQuery(query); // get the results from the ResultSet - // using 2 as a length parameter so we can log a warning if the result set is greater than one + // using 2 as a length parameter so we can log a warning if appropriate rowsList = getData(documentID, tableName, 2, fieldsToGet, rs); } catch (SQLException e) { Log.error(documentID, tableName, "Error executing database query.", e); @@ -944,9 +945,10 @@ public class OnlineGlomServiceImpl extends RemoteServiceServlet implements Onlin if (rowsList.size() == 0) { Log.error(documentID, tableName, "The query returned an empty ResultSet. Returning null."); return null; - } else if (rowsList.size() > 1) { + } else if (rowsList.size() > 1 && primaryKeyValue != null && !primaryKeyValue.isEmpty()) { + // only log a warning if the result size is greater than 1 and the primaryKeyValue was set Log.warn(documentID, tableName, - "The query did not return a unique result. Returning the first result in the set."); + "The query did not return the expected unique result. Returning the first result in the set."); } return rowsList.get(0); -- 2.1.4