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 }