001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.databinding.datagrid.runtime.config;
020:
021: import java.util.Map;
022: import java.util.HashMap;
023: import java.util.ArrayList;
024: import java.util.List;
025: import java.util.Iterator;
026:
027: import org.apache.beehive.netui.databinding.datagrid.api.DataGridState;
028: import org.apache.beehive.netui.databinding.datagrid.api.pager.PagerModel;
029: import org.apache.beehive.netui.databinding.datagrid.api.sort.SortModel;
030: import org.apache.beehive.netui.databinding.datagrid.api.sort.SortStrategy;
031: import org.apache.beehive.netui.databinding.datagrid.api.sort.Sort;
032: import org.apache.beehive.netui.databinding.datagrid.api.DataGridURLBuilder;
033: import org.apache.beehive.netui.util.Bundle;
034:
035: /**
036: * <p>
037: * This class exposes parameter maps that contain URL key / value pairs which can be data bound to anchors
038: * and other markup during page rendering. Methods exposed here are useful for building URLs that can be clicked on
039: * in the <i>future</i>. A case of this would be a pager URL that will move a UI to the "next" page of data. The
040: * URL parameters would be computed using this class and rendered to the UI so that it is clickable for the
041: * next HTTP submit.
042: * <p/>
043: * <p>
044: * An instance of this class is associated with a single data grid by name. Instances should be obtained
045: * via the {@link org.apache.beehive.netui.databinding.datagrid.api.DataGridStateFactory#getDataGridURLBuilder(String)}
046: * method.
047: * </p>
048: */
049: class DefaultDataGridURLBuilder extends DataGridURLBuilder {
050:
051: private transient DefaultDataGridStateCodec _codec;
052:
053: /**
054: * <p>
055: * Package protected constructor. This class is intended only to be created via the default
056: * {@link org.apache.beehive.netui.databinding.datagrid.api.DataGridConfig} object.
057: * </p>
058: * @param codec the state codec providing state information which will be converted into URLs here.
059: */
060: DefaultDataGridURLBuilder(DefaultDataGridStateCodec codec) {
061: _codec = codec;
062: }
063:
064: /**
065: * <p>
066: * Get the URL query parameter key used to store the current row for a data grid's pager. The value
067: * of this key is:
068: * <br/>
069: * <pre>
070: * netui_row
071: * </pre>
072: * </p>
073: * @return the URL parameter key for the current row
074: */
075: public String getPagerRowQueryParamKey() {
076: return DefaultDataGridStateCodec.PARAM_KEY_ROW;
077: }
078:
079: /**
080: * <p>
081: * Get the query parameters for the currene state of the data grid. The {@link Map} returned by this method
082: * will maintain the <i>current</i> state of the data grid and all of the associated URL parameters. The
083: * {@link Map} contains key / value pairs of type String / String[].
084: * </p>
085: * @return the current URL and data grid state
086: */
087: public Map getQueryParams() {
088: Map params = _codec.getExistingParams();
089: Map newParams = new HashMap();
090:
091: addSortParams(newParams);
092: addFilterParams(newParams);
093: addPagerParams(newParams);
094:
095: params = mergeMaps(params, newParams);
096: params = transformMap(params);
097:
098: return params;
099: }
100:
101: /**
102: * <p>
103: * Get a URL query parameter map that will change the data grid's page value to display the
104: * <i>first</i> page in a data set. This map also contains all of the other existing URL
105: * parameters. The {@link Map} contains key / value pairs of type String / String[].
106: * </p>
107: * @return the URL and data grid state needed to change to the <i>first</i> page for a data grid
108: */
109: public Map getQueryParamsForFirstPage() {
110: Map params = _codec.getExistingParams();
111: Map newParams = new HashMap();
112:
113: PagerModel pagerModel = getDataGridState().getPagerModel();
114: assert pagerModel != null;
115:
116: addSortParams(newParams);
117: addFilterParams(newParams);
118: newParams.putAll(_codec.buildPageParamMap(new Integer(
119: pagerModel.getRowForFirstPage()), new Integer(
120: pagerModel.getPageSize())));
121:
122: params = mergeMaps(params, newParams);
123: params = transformMap(params);
124:
125: return params;
126: }
127:
128: /**
129: * <p>
130: * Get a URL query parameter map that will change the data grid's page value to display the
131: * <i>previous</i> page in a data set relative to the current page. This map also contains all of
132: * the other existing URL parameters. The {@link Map} contains key / value pairs of type
133: * String / String[].
134: * </p>
135: * @return the URL and data grid state needed to change to the <i>previous</i> page for a data grid
136: */
137: public Map getQueryParamsForPreviousPage() {
138: Map params = _codec.getExistingParams();
139: Map newParams = new HashMap();
140:
141: PagerModel pagerModel = getDataGridState().getPagerModel();
142: assert pagerModel != null;
143:
144: addSortParams(newParams);
145: addFilterParams(newParams);
146: newParams.putAll(_codec.buildPageParamMap(new Integer(
147: pagerModel.getRowForPreviousPage()), new Integer(
148: pagerModel.getPageSize())));
149:
150: params = mergeMaps(params, newParams);
151: params = transformMap(params);
152:
153: return params;
154: }
155:
156: /**
157: * <p>
158: * Get a URL query parameter map that will change the data grid's page value to display the
159: * <i>next</i> page in a data set relative to the current page. This map also contains all of
160: * the other existing URL parameters. The {@link Map} contains key / value pairs of type
161: * String / String[].
162: * </p>
163: * @return the URL and data grid state needed to change to the <i>next</i> page for a data grid
164: */
165: public Map getQueryParamsForNextPage() {
166: Map params = _codec.getExistingParams();
167: Map newParams = new HashMap();
168:
169: PagerModel pagerModel = getDataGridState().getPagerModel();
170: assert pagerModel != null;
171:
172: addSortParams(newParams);
173: addFilterParams(newParams);
174: newParams.putAll(_codec.buildPageParamMap(new Integer(
175: pagerModel.getRowForNextPage()), new Integer(pagerModel
176: .getPageSize())));
177:
178: params = mergeMaps(params, newParams);
179: params = transformMap(params);
180:
181: return params;
182: }
183:
184: /**
185: * <p>
186: * Get a URL query parameter map that will change the data grid's page value to display the
187: * <i>last</i> page in a data set. This map also contains all of the other existing URL parameters.
188: * The {@link Map} contains key / value pairs of type String / String[].
189: * </p>
190: * @return the URL and data grid state needed to change to the <i>last</i> page for a data grid
191: */
192: public Map getQueryParamsForLastPage() {
193: Map params = _codec.getExistingParams();
194: Map newParams = new HashMap();
195:
196: PagerModel pagerModel = getDataGridState().getPagerModel();
197: assert pagerModel != null;
198:
199: addSortParams(newParams);
200: addFilterParams(newParams);
201: newParams.putAll(_codec.buildPageParamMap(new Integer(
202: pagerModel.getRowForLastPage()), new Integer(pagerModel
203: .getPageSize())));
204:
205: params = mergeMaps(params, newParams);
206: params = transformMap(params);
207:
208: return params;
209: }
210:
211: /**
212: * <p>
213: * Get a String[] of the URL query parameter values that could when submitted to a server to make a request
214: * can explicitly change the current page for a data grid to a specific page. The returned pager parameter
215: * values are structured as:
216: * <pre>
217: * <datagrid-name>~<row-number>
218: * </pre>
219: * These values can be attached to a URL in order to submit a query string which will set the data grid's
220: * current page.
221: * </p>
222: * @return
223: */
224: public String[] getPagerParamValues() {
225: PagerModel pagerModel = getDataGridState().getPagerModel();
226:
227: String[] params = new String[pagerModel.getPageCount()];
228: for (int i = 0; i < params.length; i++) {
229: params[i] = _codec.encodePageSize(pagerModel
230: .encodeRowForPage(i));
231: }
232:
233: return params;
234: }
235:
236: /**
237: * <p>
238: * Get a URL query parameter map that contains state which will change the direction of a
239: * {@link Sort} whose sort expression matches the given sort expression value. The {@link SortStrategy}
240: * associated with the data grid's {@link SortModel} will be used to choose the next
241: * {@link org.apache.beehive.netui.databinding.datagrid.api.sort.SortDirection} given the sort's current
242: * sort direction. This map also contains all of the other existing URL parameters. The {@link Map}
243: * contains key / value pairs of type String / String[].
244: * </p>
245: * @param sortExpression the sort expression whose direction to change
246: * @return the URL and data grid state needed to change the direction of a {@link Sort} with the given
247: * sort expression
248: */
249: public Map buildSortQueryParamsMap(String sortExpression) {
250:
251: SortModel sortModel = getDataGridState().getSortModel();
252: SortStrategy sortStrategy = sortModel.getSortStrategy();
253:
254: List currSorts = sortModel.getSorts();
255: ArrayList newSorts = new ArrayList();
256: if (currSorts == null || currSorts.size() == 0) {
257: Sort sort = new Sort();
258: sort.setSortExpression(sortExpression);
259: sort.setDirection(sortStrategy.getDefaultDirection());
260: newSorts.add(sort);
261: } else {
262: boolean foundSort = false;
263: for (int i = 0; i < currSorts.size(); i++) {
264: Sort sort = (Sort) currSorts.get(i);
265: if (!sort.getSortExpression().equals(sortExpression)) {
266: newSorts.add(sort);
267: } else {
268: Sort newSort = new Sort();
269: newSort.setSortExpression(sortExpression);
270: newSort.setDirection(sortStrategy
271: .nextDirection(sort.getDirection()));
272: newSorts.add(newSort);
273: foundSort = true;
274: }
275: }
276: if (!foundSort) {
277: Sort newSort = new Sort();
278: newSort.setSortExpression(sortExpression);
279: newSort
280: .setDirection(sortStrategy
281: .getDefaultDirection());
282: newSorts.add(newSort);
283: }
284: }
285:
286: Map params = _codec.getExistingParams();
287: Map newParams = new HashMap();
288:
289: Map tmp = _codec.buildSortParamMap(newSorts);
290: if (tmp != null)
291: newParams.putAll(tmp);
292:
293: addFilterParams(newParams);
294: addPagerParams(newParams);
295:
296: params = mergeMaps(params, newParams);
297: params = transformMap(params);
298:
299: return params;
300: }
301:
302: private final DataGridState getDataGridState() {
303: return _codec.getDataGridState();
304: }
305:
306: private void addSortParams(Map map) {
307: Map tmp = _codec.buildSortParamMap(getDataGridState()
308: .getSortModel().getSorts());
309: if (tmp != null)
310: map.putAll(tmp);
311: }
312:
313: private void addFilterParams(Map map) {
314: Map tmp = _codec.buildFilterParamMap(getDataGridState()
315: .getFilterModel().getFilters());
316: if (tmp != null)
317: map.putAll(tmp);
318: }
319:
320: private void addPagerParams(Map map) {
321: Map tmp = _codec.buildPageParamMap(new Integer(
322: getDataGridState().getPagerModel().getRow()),
323: new Integer(getDataGridState().getPagerModel()
324: .getPageSize()));
325: if (tmp != null)
326: map.putAll(tmp);
327: }
328:
329: private Map mergeMaps(Map curr, Map merge) {
330: Map newMap = new HashMap();
331: if (curr != null)
332: newMap.putAll(curr);
333:
334: Iterator iterator = merge.keySet().iterator();
335: while (iterator.hasNext()) {
336: String key = (String) iterator.next();
337: assert merge.get(key) instanceof String[];
338: String[] values = (String[]) merge.get(key);
339: if (newMap.containsKey(key)) {
340: Object currValues = newMap.get(key);
341: if (currValues instanceof List) {
342: List currList = (List) currValues;
343: for (int i = 0; i < values.length; i++) {
344: currList.add(values[i]);
345: }
346: } else
347: throw new IllegalStateException(
348: Bundle
349: .getErrorString(
350: "DataGridURLBuilder_UnableToMergeValues",
351: new Object[] { currValues
352: .getClass()
353: .getName() }));
354: } else
355: newMap.put(key, values);
356: }
357: return newMap;
358: }
359:
360: private Map transformMap(Map map) {
361: HashMap newMap = new HashMap();
362: Iterator iterator = map.keySet().iterator();
363: while (iterator.hasNext()) {
364: String key = (String) iterator.next();
365: Object values = map.get(key);
366: if (values instanceof String[])
367: newMap.put(key, values);
368: else if (values instanceof List)
369: newMap.put(key, ((List) values).toArray(new String[0]));
370: else if (values == null)
371: newMap.put(key, null);
372: else
373: assert false : "Found invalid type in map: "
374: + values.getClass().getName();
375: }
376:
377: return newMap;
378: }
379: }
|