001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.core.misc;
066:
067: import com.jcorporate.expresso.core.controller.ControllerException;
068: import com.jcorporate.expresso.core.controller.ControllerRequest;
069: import com.jcorporate.expresso.core.dataobjects.DataObject;
070: import com.jcorporate.expresso.core.db.DBException;
071: import com.jcorporate.expresso.core.dbobj.MultiDBObject;
072: import com.jcorporate.expresso.core.dbobj.SecuredDBObject;
073: import com.jcorporate.expresso.services.dbobj.DBObjLimit;
074:
075: import java.io.IOException;
076: import java.io.ObjectInputStream;
077: import java.io.ObjectOutputStream;
078: import java.io.Serializable;
079: import java.util.ArrayList;
080: import java.util.List;
081:
082: /**
083: * <p>Copyright: Copyright (c) 2001-2002 JCorporate Ltd.<p>
084: * <p>This class takes care of the low-level logic for when dealing
085: * with "e;pages"e; of data. It is used in the Download Controller
086: * to allow paging through masses of download files, as well as in <code>DBMaint</code> for
087: * paging through the data records.</p>
088: *
089: * @author Michael Rimov
090: */
091: public class RecordPaginator implements Serializable {
092:
093: /**
094: * Are there more records that can be retrieved
095: */
096: private boolean moreRecords;
097:
098: /**
099: * Are there previous records that can be retrieved
100: */
101: private boolean previousRecords;
102:
103: /**
104: * What is the page number of the current record set.
105: */
106: private int pageNumber = 1;
107:
108: private int pageLimit;
109:
110: /**
111: * What is the start record number of the current set
112: */
113: private int startRecordNumber;
114:
115: /**
116: * What is the end record number of the current set.
117: */
118: private int endRecordNumber;
119:
120: /**
121: * Boolean that states whether a DBObject.count() should be issued before
122: * issuing the search and retrieve call.
123: */
124: private boolean countRecords;
125:
126: /**
127: * Total Number of records retrieved
128: */
129: private int totalRecordCount;
130:
131: public RecordPaginator() {
132: }
133:
134: // //
135: // Serialization Methods //
136: // //
137: private void readObject(ObjectInputStream ois)
138: throws ClassNotFoundException, IOException {
139: ois.defaultReadObject();
140: }
141:
142: private void writeObject(ObjectOutputStream oos) throws IOException {
143: oos.defaultWriteObject();
144: }
145:
146: // //
147: // Getter/Setter Methods for attributes //
148: // //
149: // //
150: public void setMoreRecords(boolean newMoreRecords) {
151: moreRecords = newMoreRecords;
152: }
153:
154: public boolean isMoreRecords() {
155: return moreRecords;
156: }
157:
158: public void setPreviousRecords(boolean newPreviousRecords) {
159: previousRecords = newPreviousRecords;
160: }
161:
162: public boolean isPreviousRecords() {
163: return previousRecords;
164: }
165:
166: public void setPageNumber(int newPageNumber) {
167: pageNumber = newPageNumber;
168: }
169:
170: public int getPageNumber() {
171: return pageNumber;
172: }
173:
174: public void setStartRecordNumber(int newStartRecordNumber) {
175: startRecordNumber = newStartRecordNumber;
176: }
177:
178: /**
179: * Modified code based upon xin lee.
180: *
181: * @return the Start Record Number
182: */
183: public int getStartRecordNumber() {
184: if (endRecordNumber > startRecordNumber) {
185: return startRecordNumber;
186: } else {
187: return endRecordNumber;
188: }
189: }
190:
191: /**
192: * Sets the ending record number
193: *
194: * @param newEndRecordNumber int for the new end record number
195: */
196: public void setEndRecordNumber(int newEndRecordNumber) {
197: endRecordNumber = newEndRecordNumber;
198: }
199:
200: /**
201: * Returns the end record number for a particular page.
202: *
203: * @return integer >= 0
204: */
205: public int getEndRecordNumber() {
206: return endRecordNumber;
207: }
208:
209: /**
210: * Sets whether or not the total record count should be used or not.
211: *
212: * @param newCountRecords true if you wish for the recordset to retrieve
213: * a total record count.
214: */
215: public void setCountRecords(boolean newCountRecords) {
216: countRecords = newCountRecords;
217: }
218:
219: /**
220: * Returns true if the system is expected to get the total record count.
221: *
222: * @return true if the record count will be active.
223: */
224: public boolean isCountRecords() {
225: return countRecords;
226: }
227:
228: /**
229: * Returns the total record count retrieved for this database search
230: *
231: * @return total record count as long.
232: */
233: public long getTotalRecordCount() {
234: return totalRecordCount;
235: }
236:
237: /**
238: * Get the number of pages [using recorg pagination] that exist for this record.
239: *
240: * @return
241: */
242: public int getPageCount() {
243: if (pageLimit == 0) {
244: return 1;
245: } else {
246: int pageCount = (int) (this .getTotalRecordCount() / pageLimit);
247: int mod = (int) (this .getTotalRecordCount() % pageLimit);
248: if (mod != 0 || pageCount == 0) {
249: pageCount++;
250: }
251: return pageCount;
252: }
253: }
254:
255: // //
256: // Bean Methods //
257: // //
258: /**
259: * Returns a search and retrieve list from the DBObject who's criteria
260: * you have set. Also sets its internal attributes such as start record number
261: * etc.
262: *
263: * @param searchCriteria The DBObject to search against
264: * @param sortKey the field to search against.
265: * @return an ArrayList of DBObjects retrieved by the searchCriteria
266: */
267: public ArrayList searchAndRetrieve(DataObject searchCriteria,
268: String sortKey) throws DBException {
269: if (isCountRecords()) {
270: totalRecordCount = searchCriteria.count();
271: }
272: if (getPageNumber() > 1) {
273: setPreviousRecords(true);
274: }
275:
276: Integer pageLimitObj = (Integer) searchCriteria
277: .getAttribute("pageLimit");
278:
279: if (pageLimitObj == null) {
280: this .setPageLimitAttribute(searchCriteria);
281: pageLimitObj = (Integer) searchCriteria
282: .getAttribute("pageLimit");
283: }
284:
285: if (pageLimitObj != null) {
286: pageLimit = pageLimitObj.intValue();
287: } else {
288: pageLimit = 0;
289: }
290:
291: searchCriteria.setMaxRecords(pageLimit);
292: searchCriteria.setOffsetRecord(pageLimit
293: * (getPageNumber() - 1));
294:
295: ArrayList allRecords = (ArrayList) searchCriteria
296: .searchAndRetrieveList(sortKey);
297:
298: if (!isCountRecords()) {
299: totalRecordCount = allRecords.size();
300: }
301:
302: startRecordNumber = (pageLimit * (getPageNumber() - 1)) + 1;
303: endRecordNumber = startRecordNumber + allRecords.size() - 1;
304:
305: if (endRecordNumber >= totalRecordCount) {
306: setMoreRecords(false);
307: } else {
308: setMoreRecords(true);
309: }
310:
311: return allRecords;
312: }
313:
314: // //
315: // Bean Methods //
316: // //
317: /**
318: * Returns a search and retrieve list from the DBObject who's criteria
319: * you have set. Also sets its internal attributes such as start record number
320: * etc.
321: *
322: * @param searchCriteria The DBObject to search against
323: * @param sortKey the field to search against.
324: * @return an ArrayList of DBObjects retrieved by the searchCriteria
325: */
326: public List searchAndRetrieve(MultiDBObject searchCriteria,
327: String sortKey) throws DBException {
328: if (isCountRecords()) {
329: totalRecordCount = searchCriteria.count();
330: }
331: if (getPageNumber() > 1) {
332: setPreviousRecords(true);
333: }
334:
335: Integer pageLimitObj = (Integer) searchCriteria
336: .getAttribute("pageLimit");
337:
338: if (pageLimitObj == null) {
339: this .setPageLimitAttribute(searchCriteria);
340: pageLimitObj = (Integer) searchCriteria
341: .getAttribute("pageLimit");
342: }
343:
344: if (pageLimitObj != null) {
345: pageLimit = pageLimitObj.intValue();
346: } else {
347: pageLimit = 0;
348: }
349:
350: searchCriteria.setMaxRecords(pageLimit);
351: searchCriteria.setOffsetRecord(pageLimit
352: * (getPageNumber() - 1));
353:
354: List allRecords = searchCriteria.searchAndRetrieveList(sortKey);
355:
356: if (!isCountRecords()) {
357: totalRecordCount = allRecords.size();
358: }
359:
360: startRecordNumber = (pageLimit * (getPageNumber() - 1)) + 1;
361: endRecordNumber = startRecordNumber + allRecords.size() - 1;
362:
363: if (endRecordNumber >= totalRecordCount) {
364: setMoreRecords(false);
365: } else {
366: setMoreRecords(true);
367: }
368:
369: return allRecords;
370: }
371:
372: /**
373: * Sets the size of the page limit. It uses the DBObject Limit to define
374: * how many records per page are displayed
375: *
376: * @param dbObj The dbobject to set for.
377: */
378: protected void setPageLimitAttribute(DataObject dbObj)
379: throws DBException {
380:
381: /* Now see if there is a "page limit" for this object */
382: DBObjLimit dl = new DBObjLimit(SecuredDBObject.SYSTEM_ACCOUNT);
383: dl.setDataContext(dbObj.getDataContext());
384: dl.setField("DBObjectName", ((Object) dbObj).getClass()
385: .getName());
386:
387: int pageLimit = 0;
388:
389: if (dl.find()) {
390: try {
391: pageLimit = new Integer(dl.getField("PageLimit"))
392: .intValue();
393: } catch (NumberFormatException ne) {
394: throw new DBException("Can't use limit of '"
395: + dl.getField("PageLimit") + "' for "
396: + ((Object) dbObj).getClass().getName());
397: }
398:
399: dbObj.setMaxRecords((getPageNumber() * pageLimit) + 1);
400: dbObj.setAttribute("pageLimit", new Integer(pageLimit));
401: } else {
402:
403: //Set it per controller defaults then.
404: dl
405: .setField("DBObjectName",
406: "com.jcorporate.expresso.services.dbobj.ControllerDefault");
407:
408: if (dl.find()) {
409: try {
410: pageLimit = new Integer(dl.getField("PageLimit"))
411: .intValue();
412: } catch (NumberFormatException ne) {
413: throw new DBException("Can't use limit of '"
414: + dl.getField("PageLimit") + "' for "
415: + ((Object) dbObj).getClass().getName());
416: }
417:
418: dbObj.setMaxRecords((getPageNumber() * pageLimit) + 1);
419: dbObj.setAttribute("pageLimit", new Integer(pageLimit));
420: } else {
421: pageLimit = 0;
422: }
423: }
424: }
425:
426: /**
427: * Sets the size of the page limit. It uses the DBObject Limit to define
428: * how many records per page are displayed
429: *
430: * @param dbObj The dbobject to set for.
431: */
432: protected void setPageLimitAttribute(MultiDBObject dbObj)
433: throws DBException {
434:
435: /* Now see if there is a "page limit" for this object */
436: DBObjLimit dl = new DBObjLimit(SecuredDBObject.SYSTEM_ACCOUNT);
437: dl.setDataContext(dbObj.getDBName());
438: dl.setField("DBObjectName", ((Object) dbObj).getClass()
439: .getName());
440:
441: int pageLimit = 0;
442:
443: if (dl.find()) {
444: try {
445: pageLimit = new Integer(dl.getField("PageLimit"))
446: .intValue();
447: } catch (NumberFormatException ne) {
448: throw new DBException("Can't use limit of '"
449: + dl.getField("PageLimit") + "' for "
450: + ((Object) dbObj).getClass().getName());
451: }
452:
453: dbObj.setMaxRecords((getPageNumber() * pageLimit) + 1);
454: dbObj.setAttribute("pageLimit", new Integer(pageLimit));
455: } else {
456:
457: //Set it per controller defaults then.
458: dl
459: .setField("DBObjectName",
460: "com.jcorporate.expresso.services.dbobj.ControllerDefault");
461:
462: if (dl.find()) {
463: try {
464: pageLimit = new Integer(dl.getField("PageLimit"))
465: .intValue();
466: } catch (NumberFormatException ne) {
467: throw new DBException("Can't use limit of '"
468: + dl.getField("PageLimit") + "' for "
469: + ((Object) dbObj).getClass().getName());
470: }
471:
472: dbObj.setMaxRecords((getPageNumber() * pageLimit) + 1);
473: dbObj.setAttribute("pageLimit", new Integer(pageLimit));
474: } else {
475: pageLimit = 0;
476: }
477: }
478: }
479:
480: /**
481: * Sets the page number based upon the controller request object.
482: * If the page parameters is not included with the request, then page
483: * is set to zero.
484: *
485: * @param request The controller request fed to the controller from which the
486: * function can extract the page= controller parameter.
487: * @throws ControllerException if page= is not a number.
488: */
489: public void setPageNumber(ControllerRequest request)
490: throws ControllerException {
491: String pg = request.getParameter("page");
492:
493: if (pg != null) {
494: try {
495: this .setPageNumber(Integer.parseInt(pg));
496: } catch (NumberFormatException nfe) {
497: throw new ControllerException(
498: "Page number parameter is not an integer");
499: }
500: } else {
501: setPageNumber(1);
502: }
503: }
504: }
|