2 * Copyright 2005 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.wamblee.crawler.kiss.main;
19 import java.util.EnumMap;
20 import java.util.HashSet;
23 import java.util.TreeMap;
24 import java.util.TreeSet;
26 import org.apache.commons.logging.Log;
27 import org.apache.commons.logging.LogFactory;
28 import org.dom4j.DocumentFactory;
29 import org.dom4j.Element;
30 import org.wamblee.crawler.kiss.guide.Program;
31 import org.wamblee.crawler.kiss.guide.TimeInterval;
32 import org.wamblee.crawler.kiss.guide.Program.RecordingResult;
35 * Provides execution of actions for programs. Actions use this class to tell
36 * the executor what to do. The executor then decides on exactly what to do and
37 * in what order and makes decisions in case of conflicts.
39 public class ProgramActionExecutor {
41 private static final Log LOG = LogFactory
42 .getLog(ProgramActionExecutor.class);
45 * A map of category name to a set of program. Useful for displaying the
46 * output of possibly interesting programs on a per category basis.
48 private Map<String, Set<Program>> _interestingShows;
51 * Map of priority to set of programs.
53 private Map<Integer, Set<Program>> _showsToRecord;
56 * Map or recording result to a set of programs.
58 private EnumMap<RecordingResult, Set<Program>> _recordings;
61 * Constructs the program action executor.
64 public ProgramActionExecutor() {
65 _interestingShows = new TreeMap<String, Set<Program>>();
66 _showsToRecord = new TreeMap<Integer, Set<Program>>();
67 _recordings = new EnumMap<RecordingResult, Set<Program>>(
68 RecordingResult.class);
69 for (RecordingResult result : RecordingResult.values()) {
70 _recordings.put(result, new TreeSet<Program>(
71 new Program.TimeSorter()));
76 * Called by an action to indicate the desire to record a program.
79 * Priority of the program. Used to resolve conflicts.
83 public void recordProgram(int aPriority, Program aProgram) {
84 LOG.info("priority = " + aPriority + ", program: " + aProgram);
85 // Putting -priority into the set makes sure that iteration order
86 // over the priorities will go from higher priority to lower priority.
87 Set<Program> programs = _showsToRecord.get(-aPriority);
88 if (programs == null) {
89 programs = new TreeSet<Program>(new Program.TimeSorter());
90 _showsToRecord.put(-aPriority, programs);
92 programs.add(aProgram);
96 * Called by an action to indicate that a program is interesting.
99 * Category of the program.
103 public void interestingProgram(String aCategory, Program aProgram) {
104 LOG.info("category = '" + aCategory + "', program: " + aProgram);
105 Set<Program> programs = _interestingShows.get(aCategory);
106 if (programs == null) {
107 programs = new TreeSet<Program>(new Program.TimeSorter());
108 _interestingShows.put(aCategory, programs);
110 programs.add(aProgram);
114 * Makes sure that the actions are performed.
116 public void commit() {
117 Set<TimeInterval> previouslyRecorded = new HashSet<TimeInterval>();
118 for (Integer priority : _showsToRecord.keySet()) {
119 for (Program program : _showsToRecord.get(priority)) {
120 TimeInterval interval = program.getInterval();
121 if ( recordingConflictExists(previouslyRecorded, interval)) {
122 _recordings.get(RecordingResult.CONFLICT).add(program);
124 RecordingResult result = program.record();
125 _recordings.get(result).add(program);
126 previouslyRecorded.add(interval);
133 * Checks an interval for overlap with a previously recorded program.
134 * @param aPreviouslyRecorded Previously recorded programs.
135 * @param interval Interval.
136 * @return True iff there is a recording conflict.
138 private boolean recordingConflictExists(Set<TimeInterval> aPreviouslyRecorded, TimeInterval interval) {
139 for (TimeInterval recordedInterval: aPreviouslyRecorded ) {
140 if ( interval.overlap(recordedInterval)) {
152 public Element getReport() {
153 DocumentFactory factory = DocumentFactory.getInstance();
154 Element report = factory.createElement("report");
156 Set<Program> reportedPrograms = new HashSet<Program>();
158 for (RecordingResult result : RecordingResult.values()) {
159 if (_recordings.get(result).size() > 0) {
160 Element recordingResult = report.addElement("recorded")
161 .addAttribute("result", result.toString());
163 for (Program program : _recordings.get(result)) {
164 recordingResult.add(program.asXml());
165 reportedPrograms.add(program);
170 if (_interestingShows.size() > 0) {
171 Element interesting = report.addElement("interesting");
172 for (String category : _interestingShows.keySet()) {
173 Element categoryElem = interesting;
174 if (category.length() > 0) {
175 categoryElem = interesting.addElement("category");
176 categoryElem.addAttribute("name", category);
178 for (Program program : _interestingShows.get(category)) {
179 if ( !reportedPrograms.contains(program)) {
180 categoryElem.add(program.asXml());
182 LOG.info("Category '" + category + "', program " + program + " already reported");
185 if ( categoryElem.elements().size() == 0 ) {
186 // Remove empty category element.
187 LOG.info("Removing element for category '" + category + "'");
188 interesting.remove(categoryElem);