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 }