001    /**
002     * www.jcoverage.com
003     * Copyright (C)2003 jcoverage ltd.
004     *
005     * This file is part of jcoverage.
006     *
007     * jcoverage is free software; you can redistribute it and/or modify
008     * it under the terms of the GNU General Public License as published
009     * by the Free Software Foundation; either version 2 of the License,
010     * or (at your option) any later version.
011     *
012     * jcoverage is distributed in the hope that it will be useful, but
013     * WITHOUT ANY WARRANTY; without even the implied warranty of
014     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015     * General Public License for more details.
016     *
017     * You should have received a copy of the GNU General Public License
018     * along with jcoverage; if not, write to the Free Software
019     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020     * USA
021     *
022     */
023    package com.jcoverage.reporting;
024    
025    import java.util.*;
026    
027    import org.apache.log4j.Logger;
028    
029    /**
030     * This class provides a skeletal implementation of a {@link Page}.
031     * Subclasses should override the {@link
032     * #instantiateLineForCategory} method to return Line
033     * implementation instances on demand.
034     */
035    public abstract class AbstractPage implements Page {
036      
037      static Logger logger=Logger.getLogger(AbstractPage.class);
038      
039      String label;
040      Report report;
041      List categories=new ArrayList();
042      Line masterLine;
043      Map lineSetsByCategory=new HashMap();
044    
045      int state=Report.READY;
046    
047      protected AbstractPage(String label) {
048        this.label=label;
049      }
050    
051      Set getLineSetForCategory(LineCategory category) {
052        if (state==Report.CLOSED) {
053          throw new IllegalStateException("Report is closed, cannot add new lines.");
054        }
055        if (category==null) {
056          throw new IllegalArgumentException("Category cannot be null");
057        }
058        if (!categories.contains(category)) {
059          throw new IllegalArgumentException("This page (type "+getClass().getName()+") cannot handle category: "+category);
060        }
061        Set set=(Set)lineSetsByCategory.get(category);
062        if(set==null) {
063          set=new HashSet();
064          lineSetsByCategory.put(category,set);
065        }
066        return set;
067      }
068    
069      /**
070       * @return a new line instance, null if no lines match the given category.
071       */
072      public Line createLine(LineCategory category) {
073        Set set=getLineSetForCategory(category);
074        Line line=instantiateLineForCategory(category);
075        if (line!=null) {
076          line.setCategory(category);
077          line.setOwner(this);
078          line.setReport(report);
079          set.add(line);
080        }
081        return line;
082      }
083    
084      public void addLineReference(Line line,LineCategory category) {
085        getLineSetForCategory(category).add(line);    
086      }
087    
088      public Line lookupLineByField(LineCategory category,Column column,Object value) {
089        Set lines=(Set)lineSetsByCategory.get(category);
090        if (lines==null) {
091          return null;
092        }
093        for(Iterator it=lines.iterator();it.hasNext();) {
094          Line line=(Line)it.next();
095          Object field=line.getField(column);
096          if (field!=null && field.equals(value)) {
097            return line;
098          }
099        }
100        return null;
101      }
102    
103      /**
104       * 
105       */
106      public Set getLines(LineCategory category) {
107        Set result=(Set)lineSetsByCategory.get(category);
108        return result!=null?result:Collections.EMPTY_SET;
109    
110      }
111    
112      /**
113       * Subclasses should override this method to return {@link
114       * Line} implementation instances on demand.
115       * @param category guarenteed not to be null
116       */
117      protected Line instantiateLineForCategory(LineCategory category) {
118        return null;
119      }
120    
121      /**
122       * Subclasses should implemented this method to return the
123       * categories of {@link Line line}s that are applicable to this
124       * report, or else make exclusive use of the {@link #addCategory}
125       * method.
126       */
127      public LineCategory[] getCategories() {
128        return (LineCategory[])categories.toArray(new LineCategory[categories.size()]);
129      }
130    
131      public void addCategory(LineCategory category) {
132        categories.add(category);
133      }
134    
135      public void setMasterLine(Line masterLine) {
136        this.masterLine=masterLine;
137      }
138    
139      public Line getMasterLine() {
140        return masterLine;
141      }
142    
143      public void setReport(Report report) {
144        this.report=report;
145      }
146    
147      /**
148       * Call this method to indicate that no further lines will be
149       * created for this report and it can be considered immutable from
150       * the point-of-view of formatting.
151       */
152      public void close() throws ReportingException {
153        if(state==Report.READY) {
154          state=Report.CLOSED;
155          // TODO: Ensure report items are closed
156          for(Iterator it=lineSetsByCategory.values().iterator();it.hasNext();) {
157            close((Set)it.next());
158          }
159          if (report.getCollator()!=null) {
160            report.getCollator().pageClosed(this);
161          }
162        } else if (state==Report.CLOSED) {
163          throw new IllegalStateException("Aleady closed");
164        } else {
165          throw new IllegalStateException("Page in unknown state: "+state);
166        }
167      }
168    
169      public boolean isClosed() {
170        return state==Report.CLOSED;
171      }
172    
173      public String getLabel() {
174        return label;
175      }
176    
177      void close(Set set) throws ReportingException {
178        for(Iterator it=set.iterator();it.hasNext();) {
179          Line line=(Line)it.next();
180          if(!line.isClosed()) {
181            try {
182              line.close();
183            } catch(ReportingException ex) {
184              throw new ReportingException("Failed to close line "+line,ex);
185            }
186          }
187        }
188      }
189      
190    }