You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@cocoon.apache.org by st...@apache.org on 2003/05/17 17:44:57 UTC

cvs commit: cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination PageRules.java Pagesheet.java Paginator.java

stephan     2003/05/17 08:44:57

  Modified:    src/scratchpad/src/org/apache/cocoon/transformation/pagination
                        PageRules.java Pagesheet.java Paginator.java
  Log:
  Patch from bug report 13685 applied.
  
  Revision  Changes    Path
  1.3       +39 -16    cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination/PageRules.java
  
  Index: PageRules.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination/PageRules.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- PageRules.java	16 Mar 2003 18:03:55 -0000	1.2
  +++ PageRules.java	17 May 2003 15:44:57 -0000	1.3
  @@ -3,34 +3,34 @@
    ============================================================================
                      The Apache Software License, Version 1.1
    ============================================================================
  - 
  +
    Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  - 
  +
    Redistribution and use in source and binary forms, with or without modifica-
    tion, are permitted provided that the following conditions are met:
  - 
  +
    1. Redistributions of  source code must  retain the above copyright  notice,
       this list of conditions and the following disclaimer.
  - 
  +
    2. Redistributions in binary form must reproduce the above copyright notice,
       this list of conditions and the following disclaimer in the documentation
       and/or other materials provided with the distribution.
  - 
  +
    3. The end-user documentation included with the redistribution, if any, must
       include  the following  acknowledgment:  "This product includes  software
       developed  by the  Apache Software Foundation  (http://www.apache.org/)."
       Alternately, this  acknowledgment may  appear in the software itself,  if
       and wherever such third-party acknowledgments normally appear.
  - 
  +
    4. The names "Apache Cocoon" and  "Apache Software Foundation" must  not  be
       used to  endorse or promote  products derived from  this software without
       prior written permission. For written permission, please contact
       apache@apache.org.
  - 
  +
    5. Products  derived from this software may not  be called "Apache", nor may
       "Apache" appear  in their name,  without prior written permission  of the
       Apache Software Foundation.
  - 
  +
    THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
    INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
    FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
  @@ -41,20 +41,24 @@
    ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
    (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  - 
  +
    This software  consists of voluntary contributions made  by many individuals
    on  behalf of the Apache Software  Foundation and was  originally created by
  - Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache 
  + Stefano Mazzocchi  <st...@apache.org>. For more  information on the Apache
    Software Foundation, please see <http://www.apache.org/>.
  - 
  +
   */
   
   package org.apache.cocoon.transformation.pagination;
   
  +import java.util.ArrayList;
  +import java.util.List;
  +
   /**
    * Container class for the immutable pagination rules for each page.
    *
    * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
  + * @author <a href="mailto:bhtek@yahoo.com">Boon Hian Tek</a>
    * @version CVS $Id$
    */
   public class PageRules {
  @@ -64,11 +68,13 @@
       public int elementCount = 0;
       public int charCount = 0;
       public int unitLinks = 0;
  -    public int rangeLink = 0;
  +    private List rangeLinks = new ArrayList();
   
       public boolean match(String element, String namespace) {
  -        boolean elementMatches = ((this.elementName != null) && this.elementName.equals(element));
  -        if (this.elementURI == null) {
  +        boolean elementMatches = ((this.elementName!=null) &&
  +                                  this.elementName.equals(element));
  +
  +        if (this.elementURI==null) {
               return elementMatches;
           } else {
               return elementMatches && this.elementURI.equals(namespace);
  @@ -76,6 +82,23 @@
       }
   
       public boolean match(String namespace) {
  -        return ((this.elementURI != null) && (this.elementURI.equals(namespace)));
  +        return ((this.elementURI!=null) &&
  +                (this.elementURI.equals(namespace)));
  +    }
  +
  +    public Integer[] getRangeLinks() {
  +        return (Integer[]) this.rangeLinks.toArray(new Integer[this.rangeLinks.size()]);
  +    }
  +
  +    public void addRangeLink(Integer rangeLink) {
  +        this.rangeLinks.add(rangeLink);
  +    }
  +
  +    public void addRangeLink(int rangeLink) {
  +        this.addRangeLink(new Integer(rangeLink));
  +    }
  +
  +    public void addRangeLink(String rangeLink) {
  +        this.addRangeLink(new Integer(rangeLink));
       }
   }
  
  
  
  1.3       +136 -71   cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination/Pagesheet.java
  
  Index: Pagesheet.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination/Pagesheet.java,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- Pagesheet.java	16 Mar 2003 18:03:55 -0000	1.2
  +++ Pagesheet.java	17 May 2003 15:44:57 -0000	1.3
  @@ -78,6 +78,7 @@
    * </pre>
    *
    * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
  + * @author <a href="mailto:bhtek@yahoo.com">Boon Hian Tek</a>
    * @version CVS $Id$
    */
   
  @@ -100,6 +101,15 @@
        <link type="unit" num="5"/>
        <link type="range" value="20"/>
      </rules>
  +   <rules>
  +     <count type="element" name="file" namespace="http://apache.org/cocoon/directory/2.0" num="16"/>
  +     <link type="unit" num="5"/>
  +     <link type="range" value="2"/>
  +     <link type="range" value="5"/>
  +     <link type="range" value="10"/>
  +     <link type="range" value="20"/>
  +     <link type="range" value="100"/>
  +   </rules>
     </pagesheet>
   
   which indicates that:
  @@ -114,8 +124,16 @@
    3) for the rest of the pages, there are three unit links (-3 -2 -1 0 +1 +2 +3)
       and range goes 20 (so +20 and -20).
   
  + 4) if more than one ranges are defined, range links will be created in sequence
  +
  + 5) range links will be from big to small (eg. 20, 10, then 5) for backward links,
  +    range links will be from small to big (eg. 5, 10, then 20) for forward links
  +
  + 6) range link(s) will have an attribute 'range' to indicate the range size
  +
   */
  -public class Pagesheet extends DefaultHandler implements Cloneable, Modifiable {
  +public class Pagesheet extends DefaultHandler
  +  implements Cloneable, Modifiable {
   
       // Used only during parsing of pagesheet document
       private int level = 0;
  @@ -125,6 +143,7 @@
   
       // Loaded pagesheet information
       ResizableContainer pageRules;
  +
       Map itemGroupsPerName;
       Map itemGroupsPerElement;
       Map itemListsPerName;
  @@ -132,23 +151,30 @@
   
       // Runtime information
       private ResizableContainer pages;
  -    private Page currentPage = new Page(1, 1);
  +    private Page currentPage = null;
       private int pageCounter = 1;
       private int elementCounter = 0;
       private int descendant = 0;
   
       private static class Page {
  +
           public int elementStart;
           public int elementEnd;
           public int characters;
   
  -        public Page(int elementStart, int elementEnd) {
  +        public Page(PageRules rules, int elementStart) {
               this.elementStart = elementStart;
  -            this.elementEnd = elementEnd;
  +
  +            if (rules.elementCount>0) {
  +                this.elementEnd = this.elementStart+rules.elementCount-1;
  +            } else {
  +                this.elementEnd = this.elementStart+1;
  +            }
           }
   
           public boolean validInPage(int elementCounter) {
  -            return (this.elementStart <= elementCounter) && (elementCounter <= this.elementEnd);
  +            return (this.elementStart<=elementCounter) &&
  +                   (elementCounter<=this.elementEnd);
           }
       }
   
  @@ -164,64 +190,73 @@
   
           public int getPageForItem(int item) {
               Integer i = (Integer) this.get(item-1);
  -            return (i == null) ? 0 : i.intValue();
  +
  +            return (i==null) ? 0 : i.intValue();
           }
   
           public boolean valid(int item) {
  -            return (item == this.size());
  +            return (item==this.size());
           }
       }
   
  -
       public Pagesheet() {
           this.pages = new ResizableContainer(2);
       }
   
  -    private Pagesheet(ResizableContainer rules, Map itemGroupsPerName, Map itemGroupsPerElement) {
  +    private Pagesheet(ResizableContainer rules, Map itemGroupsPerName,
  +                      Map itemGroupsPerElement) {
           this.pageRules = rules;
           this.itemGroupsPerName = itemGroupsPerName;
           this.itemGroupsPerElement = itemGroupsPerElement;
   
           this.pages = new ResizableContainer(5);
   
  -        if ((this.itemGroupsPerName != null) && (this.itemGroupsPerElement != null)) {
  +        if ((this.itemGroupsPerName!=null) &&
  +            (this.itemGroupsPerElement!=null)) {
               this.itemListsPerName = new HashMap(itemGroupsPerName.size());
               this.itemListsPerElement = new HashMap(itemGroupsPerName.size());
   
               Iterator iter = itemGroupsPerName.values().iterator();
  +
               for (; iter.hasNext(); ) {
                   ItemGroup group = (ItemGroup) iter.next();
                   ItemList list = new ItemList(10);
  +
                   this.itemListsPerName.put(group.getName(), list);
  -                this.itemListsPerElement.put(group.getElementURI() + group.getElementName(), list);
  +                this.itemListsPerElement.put(group.getElementURI()+
  +                                             group.getElementName(), list);
               }
           }
       }
   
       // --------------- interprets the pagesheet document ----------------
   
  -    public void startPrefixMapping(String prefix, String uri) throws SAXException {
  -        if (!uri.equals(Paginator.PAGINATE_URI)) {
  +    public void startPrefixMapping(String prefix,
  +                                   String uri) throws SAXException {
  +        if ( !uri.equals(Paginator.PAGINATE_URI)) {
               throw new SAXException("The pagesheet's namespace is not supported.");
           }
       }
   
  -    public void startElement(String uri, String loc, String raw, Attributes a) throws SAXException {
  +    public void startElement(String uri, String loc, String raw,
  +                             Attributes a) throws SAXException {
           level++;
           switch (level) {
  -            case 1:
  +            case 1 :
                   if (loc.equals("pagesheet")) {
                       // This object represents pagesheet
                       return;
                   }
                   break;
  -            case 2:
  +
  +            case 2 :
                   if (loc.equals("rules")) {
  -                    if (this.pageRules == null) {
  +                    if (this.pageRules==null) {
                           this.pageRules = new ResizableContainer(2);
                       }
                       String key = a.getValue("page");
  -                    if (key != null) {
  +
  +                    if (key!=null) {
                           try {
                               pg = Integer.parseInt(key);
                           } catch (NumberFormatException e) {
  @@ -233,16 +268,17 @@
                       rules = new PageRules();
                       return;
                   } else if (loc.equals("items")) {
  -                    if (this.itemGroupsPerName == null) {
  +                    if (this.itemGroupsPerName==null) {
                           this.itemGroupsPerName = new HashMap(2);
                       }
  -                    if (this.itemGroupsPerElement == null) {
  +                    if (this.itemGroupsPerElement==null) {
                           this.itemGroupsPerElement = new HashMap(2);
                       }
                       return;
                   }
                   break;
  -            case 3:
  +
  +            case 3 :
                   if (loc.equals("count")) {
                       rules.elementName = a.getValue("name");
                       rules.elementURI = a.getValue("namespace");
  @@ -272,7 +308,7 @@
                           }
                       } else if (a.getValue("type").equals("range")) {
                           try {
  -                            rules.rangeLink = Integer.parseInt(a.getValue("value"));
  +                            rules.addRangeLink(a.getValue("value"));
                           } catch (NumberFormatException e) {
                               throw new SAXException("Syntax error: the attribute 'link/@value' must contain a number.");
                           }
  @@ -282,24 +318,31 @@
                       return;
                   } else if (loc.equals("group")) {
                       String name = a.getValue("name");
  -                    if (name == null) {
  +
  +                    if (name==null) {
                           throw new SAXException("Syntax error: the attribute 'group/@name' must be present.");
                       }
                       String elementName = a.getValue("element");
  -                    if (elementName == null) {
  +
  +                    if (elementName==null) {
                           throw new SAXException("Syntax error: the attribute 'group/@element' must be present.");
                       }
                       String elementURI = a.getValue("namespace");
  -                    ItemGroup group = new ItemGroup(name, elementURI, elementName);
  +                    ItemGroup group = new ItemGroup(name, elementURI,
  +                                                    elementName);
  +
                       this.itemGroupsPerName.put(name, group);
  -                    this.itemGroupsPerElement.put(elementURI + elementName, group);
  +                    this.itemGroupsPerElement.put(elementURI+elementName,
  +                                                  group);
                       return;
                   }
           }
  -        throw new SAXException("Syntax error: element " + raw + " is not recognized or is misplaced.");
  +        throw new SAXException("Syntax error: element "+raw+
  +                               " is not recognized or is misplaced.");
       }
   
  -    public void endElement(String uri, String loc, String raw) throws SAXException {
  +    public void endElement(String uri, String loc,
  +                           String raw) throws SAXException {
           level--;
           if (loc.equals("rules")) {
               pageRules.set(pg, rules);
  @@ -307,10 +350,10 @@
       }
   
       public void endDocument() throws SAXException {
  -        if (pageRules.size() == 0) {
  +        if (pageRules.size()==0) {
               throw new SAXException("Pagesheet must contain at least a set of pagination rules.");
           }
  -        if (pageRules.get(0) == null) {
  +        if (pageRules.get(0)==null) {
               throw new SAXException("Pagesheet must contain the global pagination rules.");
           }
       }
  @@ -323,23 +366,30 @@
           if (rules.match(name, uri)) {
               elementCounter++;
               descendant++;
  -            if (currentPage == null || elementCounter == currentPage.elementStart) {
  -                // System.out.println(">>>> " + pageCounter + ": Starting page!!!");
  -                if (rules.elementCount > 0) {
  -                    currentPage.elementEnd = currentPage.elementStart + rules.elementCount - 1;
  -                } else {
  -                    currentPage.elementEnd = currentPage.elementStart + 1;
  -                }
  -                pages.set(pageCounter, currentPage);
  +
  +            if (currentPage==null) {
  +                currentPage = new Page(rules, 1);
  +            }
  +
  +            if (elementCounter>currentPage.elementEnd) {
  +                /*System.out.println(">>>> "+pageCounter+
  +                                   ": Starting new page!!! >>> "+
  +                                   elementCounter);*/
  +                pageCounter++;
  +                currentPage = new Page(rules, currentPage.elementEnd+1);
               }
  +
  +            pages.set(pageCounter, currentPage);
           }
   
  -        if (itemGroupsPerElement != null) {
  -            String qname = uri + name;
  +        if (itemGroupsPerElement!=null) {
  +            String qname = uri+name;
               ItemGroup group = (ItemGroup) this.itemGroupsPerElement.get(qname);
  -            if ((group != null) && (group.match(uri))) {
  +
  +            if ((group!=null) && (group.match(uri))) {
                   ItemList list = (ItemList) this.itemListsPerElement.get(qname);
  -                if (list != null) {
  +
  +                if (list!=null) {
                       list.addItem(pageCounter);
                   }
               }
  @@ -348,28 +398,24 @@
   
       public void processEndElement(String uri, String name) {
           PageRules rules = getPageRules(pageCounter);
  -        if (rules.match(name,uri)) {
  +
  +        if (rules.match(name, uri)) {
               descendant--;
   
  -            if (rules.charCount > 0 && currentPage.characters > rules.charCount) {
  +            if ((rules.charCount>0) &&
  +                (currentPage.characters>rules.charCount)) {
                   // We are over character limit. Flip the page.
                   // System.out.println(">>>> " + pageCounter + ": Flipping page!!!");
                   currentPage.elementEnd = elementCounter;
  -            } else if (rules.elementCount == 0) {
  +            } else if (rules.elementCount==0) {
                   // No limit on elements is specified, and limit on characters is not reached yet.
  -                currentPage.elementEnd ++;
  -            }
  -
  -            if (elementCounter == currentPage.elementEnd) {
  -                System.out.println(">>>> " + pageCounter + ": Ending page!!!");
  -                pageCounter++;
  -                currentPage = new Page(currentPage.elementEnd + 1, 0);
  +                currentPage.elementEnd++;
               }
           }
       }
   
       public void processCharacters(char[] ch, int index, int len) {
  -        if (descendant > 0) {
  +        if (descendant>0) {
               // Count amount of characters in the currect page.
               // System.out.println(">>>> " + pageCounter + ": " + new String(ch, index, len) + " (" + len + " bytes)");
               currentPage.characters += len;
  @@ -379,7 +425,7 @@
       // --------------- return the pagination information ----------------
   
       public boolean isInPage(int page, int item, String itemGroup) {
  -        return ((descendant == 0) || valid(page, item, itemGroup));
  +        return ((descendant==0) || valid(page, item, itemGroup));
       }
   
       public int getTotalPages() {
  @@ -387,44 +433,62 @@
       }
   
       public int getTotalItems(String itemGroup) {
  -        if (this.itemListsPerName == null) return 0;
  +        if (this.itemListsPerName==null) {
  +            return 0;
  +        }
           ItemList list = (ItemList) this.itemListsPerName.get(itemGroup);
  -        return (list == null) ? 0 : list.size();
  +
  +        return (list==null) ? 0 : list.size();
       }
   
       public int getPageForItem(int item, String itemGroup) {
  -        if (this.itemListsPerName == null) return 0;
  +        if (this.itemListsPerName==null) {
  +            return 0;
  +        }
           ItemList list = (ItemList) this.itemListsPerName.get(itemGroup);
  -        return (list == null) ? 0 : list.getPageForItem(item);
  +
  +        return (list==null) ? 0 : list.getPageForItem(item);
       }
   
       public int itemCount(String elementURI, String elementName) {
  -        if (this.itemListsPerElement == null) return 0;
  -        ItemList list = (ItemList) this.itemListsPerElement.get(elementURI+elementName);
  -        return (list == null) ? 0 : list.size();
  +        if (this.itemListsPerElement==null) {
  +            return 0;
  +        }
  +        ItemList list = (ItemList) this.itemListsPerElement.get(elementURI+
  +                            elementName);
  +
  +        return (list==null) ? 0 : list.size();
       }
   
       public String getItemGroupName(String elementURI, String elementName) {
  -        if (this.itemListsPerElement == null) return null;
  -        return ((ItemGroup) this.itemGroupsPerElement.get(elementURI+elementName)).getName();
  +        if (this.itemListsPerElement==null) {
  +            return null;
  +        }
  +        return ((ItemGroup) this.itemGroupsPerElement.get(elementURI+
  +            elementName)).getName();
       }
   
       // ---------------- miscellaneous methods ----------------------------
   
       private boolean valid(int page, int item, String itemGroup) {
  -        if (item == 0) {
  +        if (item==0) {
               Page p = (Page) pages.get(page);
  -            return (p != null) && (p.validInPage(elementCounter));
  +
  +            return (p!=null) && (p.validInPage(elementCounter));
           } else {
  -            if (this.itemListsPerElement == null) return false;
  +            if (this.itemListsPerElement==null) {
  +                return false;
  +            }
               ItemList list = (ItemList) this.itemListsPerName.get(itemGroup);
  -            return (list != null) && (list.valid(item));
  +
  +            return (list!=null) && (list.valid(item));
           }
       }
   
       public PageRules getPageRules(int page) {
           PageRules p = (PageRules) pageRules.get(page);
  -        return (p != null) ? p : (PageRules) pageRules.get(0);
  +
  +        return (p!=null) ? p : (PageRules) pageRules.get(0);
       }
   
       public void setLastModified(long lastModified) {
  @@ -432,10 +496,11 @@
       }
   
       public boolean modifiedSince(long date) {
  -        return (date != this.lastModified);
  +        return (date!=this.lastModified);
       }
   
       public Object clone() {
  -        return new Pagesheet(pageRules, itemGroupsPerName, itemGroupsPerElement);
  +        return new Pagesheet(pageRules, itemGroupsPerName,
  +                             itemGroupsPerElement);
       }
   }
  
  
  
  1.4       +309 -196  cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination/Paginator.java
  
  Index: Paginator.java
  ===================================================================
  RCS file: /home/cvs/cocoon-2.1/src/scratchpad/src/org/apache/cocoon/transformation/pagination/Paginator.java,v
  retrieving revision 1.3
  retrieving revision 1.4
  diff -u -r1.3 -r1.4
  --- Paginator.java	19 Mar 2003 15:42:16 -0000	1.3
  +++ Paginator.java	17 May 2003 15:44:57 -0000	1.4
  @@ -48,26 +48,19 @@
    Software Foundation, please see <http://www.apache.org/>.
   
   */
  -
   package org.apache.cocoon.transformation.pagination;
   
  -import java.io.IOException;
  -import java.io.Serializable;
  -import java.util.Map;
  -
   import org.apache.avalon.framework.activity.Disposable;
   import org.apache.avalon.framework.component.Component;
   import org.apache.avalon.framework.component.ComponentManager;
   import org.apache.avalon.framework.component.Composable;
   import org.apache.avalon.framework.parameters.Parameters;
  -
   import org.apache.cocoon.ProcessingException;
   import org.apache.cocoon.caching.CacheableProcessingComponent;
   import org.apache.cocoon.environment.ObjectModelHelper;
   import org.apache.cocoon.environment.Request;
   import org.apache.cocoon.environment.SourceResolver;
   import org.apache.cocoon.transformation.AbstractTransformer;
  -
   import org.apache.excalibur.source.Source;
   import org.apache.excalibur.source.SourceException;
   import org.apache.excalibur.source.SourceValidity;
  @@ -75,25 +68,29 @@
   import org.apache.excalibur.source.impl.validity.TimeStampValidity;
   import org.apache.excalibur.store.Store;
   import org.apache.excalibur.xml.sax.SAXParser;
  -
   import org.xml.sax.Attributes;
   import org.xml.sax.InputSource;
   import org.xml.sax.SAXException;
   import org.xml.sax.helpers.AttributesImpl;
   
  +import java.io.IOException;
  +import java.io.Serializable;
  +import java.util.Map;
  +
   /**
    * A paginating transformer.
    *
  - * @author <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
  - * @author <a href="mailto:stephan@apache.org">Stephan Michels</a>
  - * @version CVS $Id$
  + * @author     <a href="mailto:stefano@apache.org">Stefano Mazzocchi</a>
  + * @author     <a href="mailto:stephan@apache.org">Stephan Michels</a>
  + * @author <a href="mailto:bhtek@yahoo.com">Boon Hian Tek</a>
  + * @version    CVS $Id$
    */
   public class Paginator extends AbstractTransformer
  -    implements Composable, Disposable, CacheableProcessingComponent {
  +  implements Composable, Disposable, CacheableProcessingComponent {
   
       public static final String PAGINATE_URI = "http://apache.org/cocoon/paginate/1.0";
       public static final String PAGINATE_PREFIX = "page";
  -    public static final String PAGINATE_PREFIX_TOKEN = PAGINATE_PREFIX + ":";
  +    public static final String PAGINATE_PREFIX_TOKEN = PAGINATE_PREFIX+":";
   
       private ComponentManager manager;
       private SAXParser parser;
  @@ -111,14 +108,16 @@
       /**
        * Set the current <code>ComponentManager</code> instance used by this
        * <code>Composable</code>.
  +     *
  +     * @param  manager  Description of the Parameter
        */
       public void compose(ComponentManager manager) {
           try {
               this.manager = manager;
  -            getLogger().debug("Looking up " + SAXParser.ROLE);
  +            getLogger().debug("Looking up "+SAXParser.ROLE);
               this.parser = (SAXParser) manager.lookup(SAXParser.ROLE);
  -            getLogger().debug("Looking up " + Store.ROLE + "/TransientStore");
  -            this.store = (Store) manager.lookup(Store.ROLE + "/TransientStore");
  +            getLogger().debug("Looking up "+Store.ROLE+"/TransientStore");
  +            this.store = (Store) manager.lookup(Store.ROLE+"/TransientStore");
           } catch (Exception e) {
               getLogger().error("Could not find component", e);
           }
  @@ -128,12 +127,12 @@
        * Dispose this component.
        */
       public void dispose() {
  -        if (this.parser != null) {
  +        if (this.parser!=null) {
               this.manager.release((Component) this.parser);
           } else {
               this.parser = null;
           }
  -        if (this.store != null) {
  +        if (this.store!=null) {
               this.manager.release(this.store);
           } else {
               this.store = null;
  @@ -143,10 +142,12 @@
       /**
        * Setup the transformer.
        */
  -    public void setup(SourceResolver resolver, Map objectModel, String src, Parameters par)
  -            throws ProcessingException, SAXException, IOException {
  +    public void setup(SourceResolver resolver, Map objectModel, String src,
  +                      Parameters par)
  +                        throws ProcessingException, SAXException,
  +                               IOException {
   
  -        if (src == null) {
  +        if (src==null) {
               throw new ProcessingException("I need the paginate instructions (pagesheet) to continue. Set the 'src' attribute.");
           }
   
  @@ -155,15 +156,18 @@
               this.prefixMapping = false;
               this.inputSource = resolver.resolveURI(src);
               if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("Using pagesheet: '" + this.inputSource.getURI()
  -                                  + "' in " + this + ", last modified: " + this.inputSource.getLastModified());
  +                getLogger().debug("Using pagesheet: '"+
  +                                  this.inputSource.getURI()+"' in "+this+
  +                                  ", last modified: "+
  +                                  this.inputSource.getLastModified());
               }
               this.page = par.getParameterAsInteger("page", 1);
               this.item = par.getParameterAsInteger("item", 0);
               this.itemGroup = par.getParameter("item-group", "");
               if (getLogger().isDebugEnabled()) {
  -                getLogger().debug("Paginating with [page = " + this.page
  -                                  + ", item = " + this.item + ", item-group = " + this.itemGroup + "]");
  +                getLogger().debug("Paginating with [page = "+this.page+
  +                                  ", item = "+this.item+", item-group = "+
  +                                  this.itemGroup+"]");
               }
   
               this.request = ObjectModelHelper.getRequest(objectModel);
  @@ -171,17 +175,19 @@
   
               // Get the pagesheet factory from the Store if available,
               // otherwise load it and put it into the store for further request
  -            if (store != null) {
  +            if (store!=null) {
                   pagesheet = (Pagesheet) store.get(src);
               }
   
               // If not in the store or if pagesheet has changed, loads and stores it
  -            if (pagesheet == null || pagesheet.modifiedSince(inputSource.getLastModified())) {
  +            if ((pagesheet==null) ||
  +                pagesheet.modifiedSince(inputSource.getLastModified())) {
                   pagesheet = new Pagesheet();
                   pagesheet.setLastModified(inputSource.getLastModified());
  -                parser.parse(new InputSource(inputSource.getInputStream()), pagesheet);
  -                if (store != null) {
  -                    store.store(src,pagesheet);
  +                parser.parse(new InputSource(inputSource.getInputStream()),
  +                             pagesheet);
  +                if (store!=null) {
  +                    store.store(src, pagesheet);
                   }
               }
   
  @@ -189,37 +195,38 @@
               // implementation is not reentrant.
               this.pagesheet = (Pagesheet) this.pagesheet.clone();
           } catch (SourceException se) {
  -            throw new ProcessingException("Could not retrieve source '"+src+"'", se);
  +            throw new ProcessingException("Could not retrieve source '"+src+
  +                                          "'", se);
           }
       }
   
       /**
  -     * Generate the unique key.
  -     * This key must be unique inside the space of this component.
  -     * This method must be invoked before the generateValidity() method.
  +     * Generate the unique key. This key must be unique inside the space of
  +     * this component. This method must be invoked before the
  +     * generateValidity() method.
        *
  -     * @return The generated key or <code>null</code> if the component
  -     *              is currently not cacheable.
  +     * @return The generated key or <code>null</code> if the component is
  +     *         currently not cacheable.
        */
       public Serializable getKey() {
  -        if (this.inputSource.getLastModified() != 0) {
  -            return this.inputSource.getURI() + page;
  +        if (this.inputSource.getLastModified()!=0) {
  +            return this.inputSource.getURI()+page;
           } else {
               return null;
           }
       }
   
       /**
  -     * Generate the validity object.
  -     * Before this method can be invoked the generateKey() method
  -     * must be invoked.
  +     * Generate the validity object. Before this method can be invoked the
  +     * generateKey() method must be invoked.
        *
        * @return The generated validity object or <code>null</code> if the
        *         component is currently not cacheable.
        */
       public SourceValidity getValidity() {
  -        if (this.inputSource.getLastModified() != 0) {
  +        if (this.inputSource.getLastModified()!=0) {
               AggregatedValidity validity = new AggregatedValidity();
  +
               validity.add(new TimeStampValidity(page));
               validity.add(this.inputSource.getValidity());
               return validity;
  @@ -231,34 +238,44 @@
       /**
        * Receive notification of the beginning of an element.
        *
  -     * @param uri The Namespace URI, or the empty string if the element has no
  -     *            Namespace URI or if Namespace
  -     *            processing is not being performed.
  -     * @param loc The local name (without prefix), or the empty string if
  -     *            Namespace processing is not being performed.
  -     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
  -     *            raw names are not available.
  -     * @param a The attributes attached to the element. If there are no
  -     *          attributes, it shall be an empty Attributes object.
  -     */
  -    public void startElement(String uri, String loc, String raw, Attributes a)
  -    throws SAXException {
  -        if (!prefixMapping) {
  +     * @param uri The Namespace URI, or the empty string if the
  +     *            element has no Namespace URI or if Namespace processing is not being
  +     *            performed.
  +     * @param loc The local name (without prefix), or the empty
  +     *            string if Namespace processing is not being performed.
  +     * @param raw The raw XML 1.0 name (with prefix), or the empty
  +     *            string if raw names are not available.
  +     * @param a The attributes attached to the element. If there
  +     *          are no attributes, it shall be an empty Attributes object.
  +     */
  +    public void startElement(String uri, String loc, String raw,
  +                             Attributes a) throws SAXException {
  +        if ( !prefixMapping) {
               super.startPrefixMapping(PAGINATE_PREFIX, PAGINATE_URI);
               this.prefixMapping = true;
           }
           level++;
  -        pagesheet.processStartElement(uri,loc);
  +        pagesheet.processStartElement(uri, loc);
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            int itemCount = pagesheet.itemCount(uri,loc);
  -            if (itemCount > 0) {
  -                String itemGroup = pagesheet.getItemGroupName(uri,loc);
  +            int itemCount = pagesheet.itemCount(uri, loc);
  +
  +            if (itemCount>0) {
  +                String itemGroup = pagesheet.getItemGroupName(uri, loc);
                   AttributesImpl atts = new AttributesImpl(a);
  -                atts.addAttribute(PAGINATE_URI,"item",PAGINATE_PREFIX_TOKEN+"item","CDATA",String.valueOf(itemCount));
  -                atts.addAttribute(PAGINATE_URI,"item-group",PAGINATE_PREFIX_TOKEN+"item-group","CDATA",itemGroup);
  -                super.startElement(uri,loc,raw,atts);
  +
  +                atts.addAttribute(PAGINATE_URI, "item",
  +                                  PAGINATE_PREFIX_TOKEN+"item", "CDATA",
  +                                  String.valueOf(itemCount));
  +                atts.addAttribute(PAGINATE_URI, "item-group",
  +                                  PAGINATE_PREFIX_TOKEN+"item-group",
  +                                  "CDATA", itemGroup);
  +                getLogger().fatalError("STACK0");
  +                super.startElement(uri, loc, raw, atts);
  +
  +                getLogger().fatalError("STACK1");
               } else {
  -                super.startElement(uri,loc,raw,a);
  +                getLogger().fatalError("STACK2");
  +                super.startElement(uri, loc, raw, a);
               }
           }
       }
  @@ -266,96 +283,200 @@
       /**
        * Receive notification of the end of an element.
        *
  -     * @param uri The Namespace URI, or the empty string if the element has no
  -     *            Namespace URI or if Namespace
  -     *            processing is not being performed.
  -     * @param loc The local name (without prefix), or the empty string if
  -     *            Namespace processing is not being performed.
  -     * @param raw The raw XML 1.0 name (with prefix), or the empty string if
  -     *            raw names are not available.
  +     * @param uri The Namespace URI, or the empty string if the
  +     *            element has no Namespace URI or if Namespace processing is not being
  +     *            performed.
  +     * @param loc The local name (without prefix), or the empty
  +     *            string if Namespace processing is not being performed.
  +     * @param raw The raw XML 1.0 name (with prefix), or the empty
  +     *            string if raw names are not available.
        */
  -    public void endElement(String uri, String loc, String raw)
  -    throws SAXException {
  +    public void endElement(String uri, String loc,
  +                           String raw) throws SAXException {
           level--;
  +
  +        // Prevent infinite recursive loop.
  +        if (PAGINATE_URI.equals(uri)) {
  +            super.endElement(uri, loc, raw);
  +            return;
  +        }
  +
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            if (level == 0) {
  -                if (item == 0) {
  +            if (level==0) {
  +                if (item==0) {
                       int totalPages = pagesheet.getTotalPages();
                       PageRules rules = pagesheet.getPageRules(page);
  -                    AttributesImpl atts = new AttributesImpl();
  -                    atts.addAttribute(null,"current","current","CDATA",String.valueOf(page));
  -                    atts.addAttribute(null,"total","total","CDATA",String.valueOf(totalPages));
  -                    atts.addAttribute(null,"current-uri","current-uri","CDATA",requestURI);
  -                    atts.addAttribute(null,"clean-uri","clean-uri","CDATA",cleanURI(requestURI,page));
  -                    super.startElement(PAGINATE_URI, "page", PAGINATE_PREFIX_TOKEN + "page", atts);
  -                    if ((rules.rangeLink > 0) && (page - rules.rangeLink >= 1)) {
  -                        atts.clear();
  -                        atts.addAttribute(null,"type","type","CDATA","prev");
  -                        atts.addAttribute(null,"uri","uri","CDATA",encodeURI(requestURI,page,page - rules.rangeLink));
  -                        atts.addAttribute(null,"page","page","CDATA",String.valueOf(page - rules.rangeLink));
  -                        super.startElement(PAGINATE_URI, "range-link", PAGINATE_PREFIX_TOKEN + "range-link", atts);
  -                        super.endElement(PAGINATE_URI, "range-link", PAGINATE_PREFIX_TOKEN + "range-link");
  -                    }
  -                    for (int i = page - rules.unitLinks; i < page; i++) {
  -                        if (i > 0) {
  -                            atts.clear();
  -                            atts.addAttribute(null,"type","type","CDATA","prev");
  -                            atts.addAttribute(null,"uri","uri","CDATA",encodeURI(requestURI,page,i));
  -                            atts.addAttribute(null,"page","page","CDATA",String.valueOf(i));
  -                            super.startElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link", atts);
  -                            super.endElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link");
  -                        }
  -                    }
  -                    for (int i = page + 1; i <= page + rules.unitLinks; i++) {
  -                        if (i <= totalPages) {
  -                            atts.clear();
  -                            atts.addAttribute(null,"type","type","CDATA","next");
  -                            atts.addAttribute(null,"uri","uri","CDATA",encodeURI(requestURI,page,i));
  -                            atts.addAttribute(null,"page","page","CDATA",String.valueOf(i));
  -                            super.startElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link", atts);
  -                            super.endElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link");
  -                        }
  -                    }
  -                    if ((rules.rangeLink > 0) && (page + rules.rangeLink <= totalPages)) {
  -                        atts.clear();
  -                        atts.addAttribute(null,"type","type","CDATA","next");
  -                        atts.addAttribute(null,"uri","uri","CDATA",encodeURI(requestURI,page,page + rules.rangeLink));
  -                        atts.addAttribute(null,"page","page","CDATA",String.valueOf(page + rules.rangeLink));
  -                        super.startElement(PAGINATE_URI, "range-link", PAGINATE_PREFIX_TOKEN + "range-link", atts);
  -                        super.endElement(PAGINATE_URI, "range-link", PAGINATE_PREFIX_TOKEN + "range-link");
  -                    }
  -                    super.endElement(PAGINATE_URI, "page", PAGINATE_PREFIX_TOKEN + "page");
  -                    super.endPrefixMapping(PAGINATE_PREFIX);
  +
  +                    Integer[] rangeLinks = rules.getRangeLinks();
  +                    int unitLinks = rules.unitLinks;
  +                    int currentPage = page;
  +
  +                    // call add paginate
  +                    addPaginateTags(rangeLinks, unitLinks, currentPage,
  +                                    totalPages, requestURI, this);
  +
                   } else {
                       int totalItems = pagesheet.getTotalItems(itemGroup);
                       AttributesImpl atts = new AttributesImpl();
  -                    atts.addAttribute(null,"current","current","CDATA",String.valueOf(item));
  -                    atts.addAttribute(null,"total","total","CDATA",String.valueOf(totalItems));
  -                    atts.addAttribute(null,"current-uri","current-uri","CDATA",requestURI);
  -                    atts.addAttribute(null,"clean-uri","clean-uri","CDATA",cleanURI(requestURI,item));
  -                    atts.addAttribute(null,"page","page","CDATA",String.valueOf(pagesheet.getPageForItem(item,itemGroup)));
  -                    super.startElement(PAGINATE_URI, "item", PAGINATE_PREFIX_TOKEN + "item", atts);
  -                    if (item > 1) {
  +
  +                    atts.addAttribute(null, "current", "current", "CDATA",
  +                                      String.valueOf(item));
  +                    atts.addAttribute(null, "total", "total", "CDATA",
  +                                      String.valueOf(totalItems));
  +                    atts.addAttribute(null, "current-uri", "current-uri",
  +                                      "CDATA", requestURI);
  +                    atts.addAttribute(null, "clean-uri", "clean-uri",
  +                                      "CDATA", cleanURI(requestURI, item));
  +                    atts.addAttribute(null, "page", "page", "CDATA",
  +                                      String.valueOf(pagesheet.getPageForItem(item,
  +                                          itemGroup)));
  +                    super.startElement(PAGINATE_URI, "item",
  +                                       PAGINATE_PREFIX_TOKEN+"item", atts);
  +                    if (item>1) {
                           atts.clear();
  -                        atts.addAttribute(null,"type","type","CDATA","prev");
  -                        atts.addAttribute(null,"uri","uri","CDATA",encodeURI(requestURI,item,item-1));
  -                        super.startElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link", atts);
  -                        super.endElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link");
  +                        atts.addAttribute(null, "type", "type", "CDATA",
  +                                          "prev");
  +                        atts.addAttribute(null, "uri", "uri", "CDATA",
  +                                          encodeURI(requestURI, item,
  +                                                    item-1));
  +                        super.startElement(PAGINATE_URI, "link",
  +                                           PAGINATE_PREFIX_TOKEN+"link",
  +                                           atts);
  +                        super.endElement(PAGINATE_URI, "link",
  +                                         PAGINATE_PREFIX_TOKEN+"link");
                       }
  -                    if (item <= totalItems) {
  +                    if (item<=totalItems) {
                           atts.clear();
  -                        atts.addAttribute(null,"type","type","CDATA","next");
  -                        atts.addAttribute(null,"uri","uri","CDATA",encodeURI(requestURI,item,item+1));
  -                        super.startElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link", atts);
  -                        super.endElement(PAGINATE_URI, "link", PAGINATE_PREFIX_TOKEN + "link");
  +                        atts.addAttribute(null, "type", "type", "CDATA",
  +                                          "next");
  +                        atts.addAttribute(null, "uri", "uri", "CDATA",
  +                                          encodeURI(requestURI, item,
  +                                                    item+1));
  +                        super.startElement(PAGINATE_URI, "link",
  +                                           PAGINATE_PREFIX_TOKEN+"link",
  +                                           atts);
  +                        super.endElement(PAGINATE_URI, "link",
  +                                         PAGINATE_PREFIX_TOKEN+"link");
                       }
  -                    super.endElement(PAGINATE_URI, "item", PAGINATE_PREFIX_TOKEN + "item");
  -                    super.endPrefixMapping(PAGINATE_PREFIX);
  +                    super.endElement(PAGINATE_URI, "item",
  +                                     PAGINATE_PREFIX_TOKEN+"item");
                   }
  +
  +                super.endPrefixMapping(PAGINATE_PREFIX);
               }
  +
               super.endElement(uri, loc, raw);
           }
  -        pagesheet.processEndElement(uri,loc);
  +
  +        pagesheet.processEndElement(uri, loc);
  +    }
  +
  +    public static void addPaginateTags(Integer[] rangeLinks, int unitLinks,
  +                                       int currentPage, int totalPages,
  +                                       String requestURI,
  +                                       AbstractTransformer saxTransformer)
  +                                         throws SAXException {
  +        AttributesImpl atts = new AttributesImpl();
  +
  +        atts.addAttribute(null, "current", "current", "CDATA",
  +                          String.valueOf(currentPage));
  +        atts.addAttribute(null, "total", "total", "CDATA",
  +                          String.valueOf(totalPages));
  +        atts.addAttribute(null, "current-uri", "current-uri", "CDATA",
  +                          requestURI);
  +        atts.addAttribute(null, "clean-uri", "clean-uri", "CDATA",
  +                          Paginator.cleanURI(requestURI, currentPage));
  +        saxTransformer.startElement(Paginator.PAGINATE_URI, "page",
  +                                    Paginator.PAGINATE_PREFIX_TOKEN+"page",
  +                                    atts);
  +
  +        for (int i = rangeLinks.length-1; i>-1; i--) {
  +            int rangeLink = rangeLinks[i].intValue();
  +
  +            if ((rangeLink>0) && (currentPage-rangeLink>=1)) {
  +                atts.clear();
  +                atts.addAttribute(null, "type", "type", "CDATA", "prev");
  +                atts.addAttribute(null, "range", "range", "CDATA",
  +                                  rangeLinks[i].toString());
  +                atts.addAttribute(null, "uri", "uri", "CDATA",
  +                                  Paginator.encodeURI(requestURI,
  +                                                      currentPage,
  +                                                      currentPage-rangeLink));
  +                atts.addAttribute(null, "page", "page", "CDATA",
  +                                  String.valueOf(currentPage-rangeLink));
  +                saxTransformer.startElement(Paginator.PAGINATE_URI,
  +                                            "range-link",
  +                                            Paginator.PAGINATE_PREFIX_TOKEN+
  +                                            "range-link", atts);
  +                saxTransformer.endElement(Paginator.PAGINATE_URI,
  +                                          "range-link",
  +                                          Paginator.PAGINATE_PREFIX_TOKEN+
  +                                          "range-link");
  +            }
  +        }
  +
  +        for (int i = currentPage-unitLinks; i<currentPage; i++) {
  +            if (i>0) {
  +                atts.clear();
  +                atts.addAttribute(null, "type", "type", "CDATA", "prev");
  +                atts.addAttribute(null, "uri", "uri", "CDATA",
  +                                  Paginator.encodeURI(requestURI,
  +                                                      currentPage, i));
  +                atts.addAttribute(null, "page", "page", "CDATA",
  +                                  String.valueOf(i));
  +                saxTransformer.startElement(Paginator.PAGINATE_URI, "link",
  +                                            Paginator.PAGINATE_PREFIX_TOKEN+
  +                                            "link", atts);
  +                saxTransformer.endElement(Paginator.PAGINATE_URI, "link",
  +                                          Paginator.PAGINATE_PREFIX_TOKEN+
  +                                          "link");
  +            }
  +        }
  +        for (int i = currentPage+1; i<=currentPage+unitLinks; i++) {
  +            if (i<=totalPages) {
  +                atts.clear();
  +                atts.addAttribute(null, "type", "type", "CDATA", "next");
  +                atts.addAttribute(null, "uri", "uri", "CDATA",
  +                                  Paginator.encodeURI(requestURI,
  +                                                      currentPage, i));
  +                atts.addAttribute(null, "page", "page", "CDATA",
  +                                  String.valueOf(i));
  +                saxTransformer.startElement(Paginator.PAGINATE_URI, "link",
  +                                            Paginator.PAGINATE_PREFIX_TOKEN+
  +                                            "link", atts);
  +                saxTransformer.endElement(Paginator.PAGINATE_URI, "link",
  +                                          Paginator.PAGINATE_PREFIX_TOKEN+
  +                                          "link");
  +            }
  +        }
  +
  +        for (int i = 0; i<rangeLinks.length; i++) {
  +            int rangeLink = rangeLinks[i].intValue();
  +
  +            if ((rangeLink>0) && (currentPage+rangeLink<=totalPages)) {
  +                atts.clear();
  +                atts.addAttribute(null, "type", "type", "CDATA", "next");
  +                atts.addAttribute(null, "range", "range", "CDATA",
  +                                  rangeLinks[i].toString());
  +                atts.addAttribute(null, "uri", "uri", "CDATA",
  +                                  Paginator.encodeURI(requestURI,
  +                                                      currentPage,
  +                                                      currentPage+rangeLink));
  +                atts.addAttribute(null, "page", "page", "CDATA",
  +                                  String.valueOf(currentPage+rangeLink));
  +                saxTransformer.startElement(Paginator.PAGINATE_URI,
  +                                            "range-link",
  +                                            Paginator.PAGINATE_PREFIX_TOKEN+
  +                                            "range-link", atts);
  +                saxTransformer.endElement(Paginator.PAGINATE_URI,
  +                                          "range-link",
  +                                          Paginator.PAGINATE_PREFIX_TOKEN+
  +                                          "range-link");
  +            }
  +        }
  +
  +        saxTransformer.endElement(Paginator.PAGINATE_URI, "page",
  +                                  Paginator.PAGINATE_PREFIX_TOKEN+"page");
       }
   
       /**
  @@ -365,11 +486,10 @@
        * @param start The start position in the array.
        * @param len The number of characters to read from the array.
        */
  -    public void characters(char c[], int start, int len)
  -    throws SAXException {
  +    public void characters(char c[], int start, int len) throws SAXException {
           pagesheet.processCharacters(c, start, len);
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            super.characters(c,start,len);
  +            super.characters(c, start, len);
           }
       }
   
  @@ -380,10 +500,10 @@
        * @param start The start position in the array.
        * @param len The number of characters to read from the array.
        */
  -    public void ignorableWhitespace(char c[], int start, int len)
  -    throws SAXException {
  +    public void ignorableWhitespace(char c[], int start,
  +                                    int len) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            super.ignorableWhitespace(c,start,len);
  +            super.ignorableWhitespace(c, start, len);
           }
       }
   
  @@ -391,24 +511,23 @@
        * Receive notification of a processing instruction.
        *
        * @param target The processing instruction target.
  -     * @param data The processing instruction data, or null if none was
  -     *             supplied.
  +     * @param data The processing instruction data, or null if none
  +     *             was supplied.
        */
  -    public void processingInstruction(String target, String data)
  -    throws SAXException {
  +    public void processingInstruction(String target,
  +                                      String data) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            super.processingInstruction(target,data);
  +            super.processingInstruction(target, data);
           }
       }
   
       /**
        * Receive notification of a skipped entity.
        *
  -     * @param name The name of the skipped entity.  If it is a  parameter
  -     *             entity, the name will begin with '%'.
  +     * @param name The name of the skipped entity. If it is a
  +     *             parameter entity, the name will begin with '%'.
        */
  -    public void skippedEntity(String name)
  -    throws SAXException {
  +    public void skippedEntity(String name) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
               super.skippedEntity(name);
           }
  @@ -418,44 +537,38 @@
        * Report the start of DTD declarations, if any.
        *
        * @param name The document type name.
  -     * @param publicId The declared public identifier for the external DTD
  -     *                 subset, or null if none was declared.
  -     * @param systemId The declared system identifier for the external DTD
  -     *                 subset, or null if none was declared.
  +     * @param publicId The declared public identifier for the external
  +     *                 DTD subset, or null if none was declared.
  +     * @param systemId The declared system identifier for the external
  +     *                 DTD subset, or null if none was declared.
        */
  -    public void startDTD(String name, String publicId, String systemId)
  -    throws SAXException {
  +    public void startDTD(String name, String publicId,
  +                         String systemId) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            super.startDTD(name,publicId,systemId);
  +            super.startDTD(name, publicId, systemId);
           } else {
  -            throw new SAXException(
  -                "Recieved startDTD not in page."
  -            );
  +            throw new SAXException("Recieved startDTD not in page.");
           }
       }
   
       /**
        * Report the end of DTD declarations.
        */
  -    public void endDTD()
  -    throws SAXException {
  +    public void endDTD() throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
               super.endDTD();
           } else {
  -            throw new SAXException(
  -                "Recieved endDTD not in page."
  -            );
  +            throw new SAXException("Recieved endDTD not in page.");
           }
       }
   
       /**
        * Report the beginning of an entity.
        *
  -     * @param name The name of the entity. If it is a parameter entity, the
  -     *             name will begin with '%'.
  +     *@param name The name of the entity. If it is a parameter
  +     *            entity, the name will begin with '%'.
        */
  -    public void startEntity(String name)
  -    throws SAXException {
  +    public void startEntity(String name) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
               super.startEntity(name);
           }
  @@ -466,8 +579,7 @@
        *
        * @param name The name of the entity that is ending.
        */
  -    public void endEntity(String name)
  -    throws SAXException {
  +    public void endEntity(String name) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
               super.endEntity(name);
           }
  @@ -476,8 +588,7 @@
       /**
        * Report the start of a CDATA section.
        */
  -    public void startCDATA()
  -    throws SAXException {
  +    public void startCDATA() throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
               super.startCDATA();
           }
  @@ -486,8 +597,7 @@
       /**
        * Report the end of a CDATA section.
        */
  -    public void endCDATA()
  -    throws SAXException {
  +    public void endCDATA() throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
               super.endCDATA();
           }
  @@ -500,47 +610,50 @@
        * @param start The starting position in the array.
        * @param len The number of characters to use from the array.
        */
  -    public void comment(char ch[], int start, int len)
  -    throws SAXException {
  +    public void comment(char ch[], int start, int len) throws SAXException {
           if (pagesheet.isInPage(page, item, itemGroup)) {
  -            super.comment(ch,start,len);
  +            super.comment(ch, start, len);
           }
       }
   
       /**
  -     * Removes the pagination encoding from the URI by removing the page
  -     * number and the previous and next character.
  +     * Removes the pagination encoding from the URI by removing the page number
  +     * and the previous and next character.
        */
  -     private String cleanURI(String uri, int current) {
  +    public static String cleanURI(String uri, int current) {
           String currentS = String.valueOf(current);
           int index = uri.lastIndexOf(currentS);
  -        if (index == -1) {
  +
  +        if (index==-1) {
               return uri;
           } else {
  -            return uri.substring(0, index - 1) + uri.substring(index + currentS.length() + 1);
  +            return uri.substring(0, index-1)+
  +                   uri.substring(index+currentS.length()+1);
           }
       }
   
       /**
  -     * Encode the next page in the given URI. First tries to use the
  -     * existing encoding by replacing the current page number, but if
  -     * the current encoding is not found it appends "(xx)" to the
  -     * filename (before the file extention, if any) where "xx" is the
  -     * next page value.
  +     * Encode the next page in the given URI. First tries to use the existing
  +     * encoding by replacing the current page number, but if the current
  +     * encoding is not found it appends "(xx)" to the filename (before the file
  +     * extention, if any) where "xx" is the next page value.
        */
  -     private String encodeURI(String uri, int current, int next) {
  +    public static String encodeURI(String uri, int current, int next) {
           String currentS = String.valueOf(current);
           String nextS = String.valueOf(next);
           int index = uri.lastIndexOf(currentS);
  -        if (index == -1) {
  +
  +        if (index==-1) {
               index = uri.lastIndexOf('.');
  -            if (index == -1) {
  -                return uri + "(" + nextS + ")";
  +            if (index==-1) {
  +                return uri+"("+nextS+")";
               } else {
  -                return uri.substring(0, index) + "(" + nextS + ")." + uri.substring(index + 1);
  +                return uri.substring(0, index)+"("+nextS+")."+
  +                       uri.substring(index+1);
               }
           } else {
  -            return uri.substring(0, index) + nextS + uri.substring(index + currentS.length());
  +            return uri.substring(0, index)+nextS+
  +                   uri.substring(index+currentS.length());
           }
       }
   }