KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > beehive > netui > databinding > datagrid > runtime > config > DefaultDataGridStateCodec


1 /*
2  * Copyright 2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * $Header:$
17  */

18 package org.apache.beehive.netui.databinding.datagrid.runtime.config;
19
20 import org.apache.beehive.netui.util.internal.InternalStringBuilder;
21
22 import java.util.HashMap JavaDoc;
23 import java.util.Map JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.ArrayList JavaDoc;
27
28 import org.apache.beehive.netui.databinding.datagrid.api.sort.Sort;
29 import org.apache.beehive.netui.databinding.datagrid.api.sort.SortModel;
30 import org.apache.beehive.netui.databinding.datagrid.api.sort.SortDirection;
31 import org.apache.beehive.netui.databinding.datagrid.api.DataGridState;
32 import org.apache.beehive.netui.databinding.datagrid.api.pager.PagerModel;
33 import org.apache.beehive.netui.databinding.datagrid.api.filter.FilterModel;
34 import org.apache.beehive.netui.databinding.datagrid.api.filter.FilterOperation;
35 import org.apache.beehive.netui.databinding.datagrid.api.filter.Filter;
36 import org.apache.beehive.netui.databinding.datagrid.api.DataGridStateCodec;
37 import org.apache.beehive.netui.databinding.datagrid.api.DataGridConfig;
38 import org.apache.beehive.netui.databinding.datagrid.api.DataGridURLBuilder;
39 import org.apache.beehive.netui.databinding.datagrid.runtime.sql.SQLSupport;
40 import org.apache.beehive.netui.util.logging.Logger;
41 import org.apache.beehive.netui.util.Bundle;
42
43 /**
44  * <p>
45  * Derault implementation of the {@link DataGridStateCodec} abstract base class. This class provides support
46  * for obtaining a {@link DataGridState} object which contains "current" state for a data grid and will
47  * be used when rendering a data grid.
48  * </p>
49  */

50 class DefaultDataGridStateCodec
51     extends DataGridStateCodec {
52
53     /* filter format: netui_filter=<namespace>;<fExpr>~<fOp>~<fVal>,<fExpr>~<fOp>~<fVal> */
54     /* sort format: netui_sort=<namespace>;<expr>,-<expr> */
55     /* row format: netui_row=<namespace>~<row> */
56     /* page size format: netui_pagesize=<namespace>~<pagesize> */
57
58     static final String JavaDoc PARAM_KEY_FILTER = "netui_filter";
59     static final String JavaDoc PARAM_KEY_SORT = "netui_sort";
60     static final String JavaDoc PARAM_KEY_PAGE_SIZE = "netui_pagesize";
61     static final String JavaDoc PARAM_KEY_ROW = "netui_row";
62
63     private static final Logger LOGGER = Logger.getInstance(DefaultDataGridStateCodec.class);
64     private static final String JavaDoc DELIM_GRID_NAME = ";";
65     private static final String JavaDoc DELIM_SORT_TERM = ",";
66     private static final String JavaDoc DELIM_FILTER_TERM = ",";
67     private static final String JavaDoc DELIM_FILTER = "~";
68     private static final String JavaDoc SORT_DESCENDING = "-";
69
70     private static final int DEFAULT_PAGE_SIZE = 10;
71     private static final int DEFAULT_ROW = 0;
72
73     private boolean _decoded = false;
74     
75     /**
76      * The ServletRequest needs to be processed such that the parameter values of
77      * interest are removed from the query param map. Then, the Map is stateless
78      * relative to the state that the current data grid needs to add.
79      */

80     private HashMap JavaDoc _queryParams = null;
81     private DataGridConfig _config = null;
82     private DataGridState _state = null;
83     private DefaultDataGridURLBuilder _urlBuilder = null;
84
85     /**
86      * Package protected constructor; this class should only be constructed via the {@link DefaultDataGridConfig}
87      * class.
88      * @param config the data grid config object used to manufacture a state object
89      */

90     DefaultDataGridStateCodec(DataGridConfig config) {
91         super();
92         _config = config;
93         _state = _config.createDataGridState();
94         _urlBuilder = new DefaultDataGridURLBuilder(this);
95     }
96
97     /**
98      * Get the current {@link DataGridState}.
99      * @return the data grid state
100      */

101     public DataGridState getDataGridState() {
102         if(!_decoded) {
103             decode(getServletRequest().getParameterMap());
104         }
105         return _state;
106     }
107
108     /**
109      * Get the {@link DataGridURLBuilder} for this state codec. The URL builder can be used to build
110      * URLs managing the {@link DataGridState} obtainable via {@link #getDataGridState()}.
111      * @return the data grid URL builder
112      */

113     public DataGridURLBuilder getDataGridURLBuilder() {
114         return _urlBuilder;
115     }
116
117     /**
118      * <p>
119      * Set the {@link DataGridState} object. This mechanism provides callers a way to explicitly set the
120      * {@link DataGridState}. This useful when a grid's state needs to be provided from an outside source
121      * and attached so it is obtainable from the data grid via the usual mechanism.
122      * </p>
123      *
124      * @param state the new data grid state
125      */

126     public void setDataGridState(DataGridState state) {
127         _state = state;
128     }
129
130     /**
131      * Returns the existing query parameters map. This is a clone that can be augmented by client code but the
132      * existing parameters are not changed.
133      *
134      * @return
135      */

136     Map JavaDoc getExistingParams() {
137         return _queryParams;
138     }
139
140     /**
141      * Build the sort parameter map given this list of {@link Sort} instances. Note, the query parameters returned
142      * here are <b>not</b> URL encoded. The map contains key / value pairs as (String, String[]).
143      * @param sorts the sorts
144      * @return a map containing the sort query parameters
145      */

146     Map JavaDoc buildSortParamMap(List JavaDoc sorts) {
147         if(sorts == null || sorts.size() == 0)
148             return null;
149
150         String JavaDoc encoded = encodeSorts(sorts);
151         if(encoded == null)
152             return null;
153         else {
154             HashMap JavaDoc params = new HashMap JavaDoc();
155             params.put(PARAM_KEY_SORT, new String JavaDoc[]{encoded});
156             return params;
157         }
158     }
159
160     /**
161      * Build the filter parameter map given this list of {@link Filter} instances. Note, the query parameters
162      * returned here are <b>not</b> URL encoded. The map contains key / value pairs as (String, String[]).
163      * @param filters the filters
164      * @return a map containing the filter query parameters
165      */

166     Map JavaDoc buildFilterParamMap(List JavaDoc filters) {
167         if(filters == null || filters.size() == 0)
168             return null;
169
170         String JavaDoc encoded = encodeFilters(filters);
171         if(encoded == null)
172             return null;
173         else {
174             HashMap JavaDoc params = new HashMap JavaDoc();
175             params.put(PARAM_KEY_FILTER, new String JavaDoc[]{encoded});
176             return params;
177         }
178     }
179
180     /**
181      * Build the URL parameter map given a current row and page size. Note, the query parameters returned
182      * here are <b>not</b> URL encoded. The map contains key / value pairs as (String, String[]).
183      * @param row the current row
184      * @param pageSize the current page size
185      * @return a map containing the pager query parameters
186      */

187     Map JavaDoc buildPageParamMap(Integer JavaDoc row, Integer JavaDoc pageSize) {
188         HashMap JavaDoc map = new HashMap JavaDoc();
189         if(row != null && row.intValue() != DEFAULT_ROW)
190             map.put(PARAM_KEY_ROW, new String JavaDoc[]{encodeRow(row.intValue())});
191
192         /* only encode the page size if it is not equal to the default page size for this data grid
193         
194            for example, if a data grid's default page size is 20 but is set somehow by the application
195            to be 50, the default will read 20 but overridden pageSize value should be encoded in the URL
196          */

197         if(pageSize != null && pageSize.intValue() != _state.getPagerModel().getDefaultPageSize())
198             map.put(PARAM_KEY_PAGE_SIZE, new String JavaDoc[]{encodePageSize(pageSize.intValue())});
199
200         return map;
201     }
202
203     /**
204      * Decode a Map of URL parameters. This method will convert a complete set of URL parameters into several
205      * buckets including the sorts, filters, and paging information for the data grid name associated with this
206      * state codec. In addition, a bucket of 'other' parameters is also collected which are the ones that
207      * were in the current request URL and should be maintained on all generated URLs.
208      * @param parameters the list of parameters to decode
209      */

210     private void decode(Map JavaDoc parameters) {
211         _decoded = true;
212
213         String JavaDoc namespacePrefix = getGridName() + ";";
214
215         Iterator JavaDoc keys = parameters.keySet().iterator();
216         while(keys.hasNext()) {
217             String JavaDoc key = (String JavaDoc)keys.next();
218             String JavaDoc[] values = (String JavaDoc[])parameters.get(key);
219
220             if(key.equals(PARAM_KEY_SORT)) {
221                 List JavaDoc sorts = null;
222                 for(int i = 0; i < values.length; i++) {
223                     String JavaDoc value = values[i];
224                     if(value.startsWith(namespacePrefix))
225                         sorts = decodeSort(value);
226                     else
227                         addParam(key, value);
228                 }
229                 SortModel sortModel = _config.createSortModel(sorts);
230                 _state.setSortModel(sortModel);
231             }
232             else if(key.equals(PARAM_KEY_FILTER)) {
233                 List JavaDoc filters = null;
234                 for(int i = 0; i < values.length; i++) {
235                     String JavaDoc value = values[i];
236                     if(value.startsWith(namespacePrefix))
237                         filters = decodeFilter(value);
238                     else
239                         addParam(key, value);
240                 }
241                 FilterModel filterModel = _config.createFilterModel(filters);
242                 _state.setFilterModel(filterModel);
243             }
244             else if(key.equals(PARAM_KEY_ROW)) {
245                 int row = DEFAULT_ROW;
246                 for(int i = 0; i < values.length; i++) {
247                     String JavaDoc value = values[i];
248                     if(value.startsWith(namespacePrefix))
249                         row = decodeRow(value).intValue();
250                     else
251                         addParam(key, value);
252                 }
253                 PagerModel pagerModel = _state.getPagerModel();
254                 if(pagerModel == null) {
255                     pagerModel = _config.createPagerModel();
256                     _state.setPagerModel(pagerModel);
257                 }
258                 pagerModel.setRow(row);
259             }
260             else if(key.equals(PARAM_KEY_PAGE_SIZE)) {
261                 int pageSize = DEFAULT_PAGE_SIZE;
262                 for(int i = 0; i < values.length; i++) {
263                     String JavaDoc value = values[i];
264                     if(value.startsWith(namespacePrefix))
265                         pageSize = decodeRow(value).intValue();
266                     else
267                         addParam(key, value);
268                 }
269                 PagerModel pagerModel = _state.getPagerModel();
270                 if(pagerModel == null) {
271                     pagerModel = _config.createPagerModel();
272                     _state.setPagerModel(pagerModel);
273                 }
274                 pagerModel.setPageSize(pageSize);
275             }
276             else
277                 addParam(key, values);
278         }
279
280         /* ensure that there is something created for the grid state model objects */
281         if(_state.getSortModel() == null)
282             _state.setSortModel(_config.createSortModel(null));
283         if(_state.getFilterModel() == null)
284             _state.setFilterModel(_config.createFilterModel(null));
285         if(_state.getPagerModel() == null)
286             _state.setPagerModel(_config.createPagerModel());
287     }
288
289     private void addParam(String JavaDoc key, String JavaDoc value) {
290         if(_queryParams == null)
291             _queryParams = new HashMap JavaDoc();
292
293         ArrayList JavaDoc list = (ArrayList JavaDoc)_queryParams.get(key);
294         if(list == null) {
295             list = new ArrayList JavaDoc();
296             _queryParams.put(key, list);
297         }
298
299         list.add(value);
300     }
301
302     private void addParam(String JavaDoc key, String JavaDoc[] values) {
303         if(_queryParams == null)
304             _queryParams = new HashMap JavaDoc();
305
306         ArrayList JavaDoc list = (ArrayList JavaDoc)_queryParams.get(key);
307         if(list == null) {
308             list = new ArrayList JavaDoc();
309             _queryParams.put(key, list);
310         }
311
312         for(int i = 0; i < values.length; i++) {
313             list.add(values[i]);
314         }
315     }
316
317     private int decodeInt(String JavaDoc value, int defaultValue) {
318         int intValue = defaultValue;
319         try {
320             intValue = Integer.parseInt(value);
321         }
322         catch(NumberFormatException JavaDoc nfe) {
323             LOGGER.error(Bundle.getErrorString("DataGridStateCodec_IllegalIntegerValue", new Object JavaDoc[]{value, nfe}));
324         }
325         return intValue;
326     }
327
328     /*
329       Sort handling
330      */

331     private List JavaDoc decodeSort(String JavaDoc value) {
332         ArrayList JavaDoc sorts = new ArrayList JavaDoc();
333
334         String JavaDoc[] nameAndSorts = value.split(DELIM_GRID_NAME);
335         if(nameAndSorts.length != 2)
336             return null;
337
338         String JavaDoc namespace = nameAndSorts[0];
339         String JavaDoc[] sortStrings = nameAndSorts[1].split(DELIM_SORT_TERM);
340
341         // find the list of sorted columns
342
// two columns of the bugs grid would be sorted as:
343
//
344
// netui_sort=bugs~id,-priority
345
for(int i = 0; i < sortStrings.length; i++) {
346             String JavaDoc sort = sortStrings[i];
347             SortDirection sortDirection = SortDirection.NONE;
348             if(sort.startsWith("-"))
349                 sortDirection = SortDirection.DESCENDING;
350             else
351                 sortDirection = SortDirection.ASCENDING;
352             String JavaDoc sortExpression = (sortDirection == SortDirection.DESCENDING ? sort.substring(1) : sort);
353             Sort gridSort = _config.createSort();
354             gridSort.setSortExpression(sortExpression);
355             gridSort.setDirection(sortDirection);
356             sorts.add(gridSort);
357         }
358
359         return sorts;
360     }
361
362     String JavaDoc encodeSorts(List JavaDoc sorts) {
363         boolean hasSorts = false;
364         InternalStringBuilder sb = new InternalStringBuilder(16);
365         sb.append(getGridName());
366         sb.append(DELIM_GRID_NAME);
367         for(int i = 0; i < sorts.size(); i++) {
368             Sort sort = (Sort)sorts.get(i);
369
370             if(sort.getDirection() == SortDirection.NONE)
371                 continue;
372
373             if(hasSorts)
374                 sb.append(DELIM_SORT_TERM);
375             else
376                 hasSorts = true;
377
378             if(sort.getDirection() == SortDirection.DESCENDING)
379                 sb.append(SORT_DESCENDING);
380             sb.append(sort.getSortExpression());
381         }
382
383         if(!hasSorts)
384             return null;
385         else
386             return sb.toString();
387     }
388
389     /*
390       Filter handling
391      */

392     private List JavaDoc decodeFilter(String JavaDoc value) {
393         String JavaDoc[] nameAndFilters = value.split(DELIM_GRID_NAME);
394
395         assert nameAndFilters.length == 2;
396
397         String JavaDoc namespace = nameAndFilters[0];
398         String JavaDoc[] filters = nameAndFilters[1].split(DELIM_FILTER_TERM);
399
400         ArrayList JavaDoc/*<Filter>*/ gridFilters = new ArrayList JavaDoc/*<Filter>*/();
401         for(int i = 0; i < filters.length; i++) {
402             String JavaDoc[] terms = filters[i].split(DELIM_FILTER);
403             Filter filter = null;
404
405             if(terms.length == 2 && terms[1].equals("*"))
406                 continue;
407             else if(terms.length == 3) {
408                 FilterOperation fOp = SQLSupport.mapFilterAbbreviationToOperation(terms[1]);
409                 filter = _config.createFilter();
410                 filter.setFilterExpression(terms[0]);
411                 filter.setOperation(fOp);
412                 filter.setValue(terms[2]);
413             }
414             else {
415                 LOGGER.error(Bundle.getErrorString("DataGridStateCodec_IllegalFilter", new Object JavaDoc[]{filter}));
416                 continue;
417             }
418
419             assert filter != null;
420             gridFilters.add(filter);
421         }
422         return gridFilters;
423     }
424
425     String JavaDoc encodeFilters(List JavaDoc filters) {
426         boolean hasFilters = false;
427         InternalStringBuilder sb = new InternalStringBuilder();
428         sb.append(getGridName());
429         sb.append(DELIM_GRID_NAME);
430         for(int i = 0; i < filters.size(); i++) {
431             Filter filter = (Filter)filters.get(i);
432
433             if(hasFilters)
434                 sb.append(DELIM_FILTER_TERM);
435
436             sb.append(filter.getFilterExpression());
437             sb.append(DELIM_FILTER);
438             sb.append(filter.getOperation().getAbbreviation());
439             sb.append(DELIM_FILTER);
440             sb.append(filter.getValue());
441
442             hasFilters = true;
443         }
444
445         return sb.toString();
446     }
447
448     /*
449        Pager handling
450      */

451     private Integer JavaDoc decodeRow(final String JavaDoc page) {
452         String JavaDoc[] terms = page.split(DELIM_GRID_NAME);
453
454         /* todo: this is really an exception, not an assert */
455         assert terms != null && terms.length == 2;
456         String JavaDoc intString = terms[1];
457         return new Integer JavaDoc(decodeInt(intString, DEFAULT_ROW));
458     }
459
460     String JavaDoc encodeRow(final int row) {
461         InternalStringBuilder sb = new InternalStringBuilder(16);
462         sb.append(getGridName());
463         sb.append(DELIM_GRID_NAME);
464         sb.append(row);
465         return sb.toString();
466     }
467
468     private Integer JavaDoc decodePageSize(final String JavaDoc pageSize) {
469         String JavaDoc[] terms = pageSize.split(DELIM_GRID_NAME);
470
471         /* todo: this is really an exception, not an assert */
472         assert terms != null && terms.length == 2;
473         String JavaDoc intString = terms[1];
474         return new Integer JavaDoc(decodeInt(intString, DEFAULT_PAGE_SIZE));
475     }
476
477     String JavaDoc encodePageSize(final int pageSize) {
478         InternalStringBuilder sb = new InternalStringBuilder(16);
479         sb.append(getGridName());
480         sb.append(DELIM_GRID_NAME);
481         sb.append(pageSize);
482         return sb.toString();
483     }
484 }
485
Popular Tags