001: //
002: // Informa -- RSS Library for Java
003: // Copyright (c) 2002 by Niko Schmuck
004: //
005: // Niko Schmuck
006: // http://sourceforge.net/projects/informa
007: // mailto:niko_schmuck@users.sourceforge.net
008: //
009: // This library is free software.
010: //
011: // You may redistribute it and/or modify it under the terms of the GNU
012: // Lesser General Public License as published by the Free Software Foundation.
013: //
014: // Version 2.1 of the license should be included with this distribution in
015: // the file LICENSE. If the license is not included with this distribution,
016: // you may find a copy at the FSF web site at 'www.gnu.org' or 'www.fsf.org',
017: // or you may write to the Free Software Foundation, 675 Mass Ave, Cambridge,
018: // MA 02139 USA.
019: //
020: // This library is distributed in the hope that it will be useful,
021: // but WITHOUT ANY WARRANTY; without even the implied waranty of
022: // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
023: // Lesser General Public License for more details.
024: //
025:
026: // $Id: ChannelRegistry.java,v 1.39 2006/12/04 23:43:27 italobb Exp $
027:
028: package de.nava.informa.utils;
029:
030: import java.net.URL;
031: import java.util.Collection;
032: import java.util.HashMap;
033: import java.util.Map;
034: import java.util.Timer;
035:
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038:
039: import de.nava.informa.core.CategoryIF;
040: import de.nava.informa.core.ChannelBuilderIF;
041: import de.nava.informa.core.ChannelGroupIF;
042: import de.nava.informa.core.ChannelIF;
043:
044: /**
045: * This class can be used as central repository for storing a
046: * collection of channel objects and maintaining them (by specifying
047: * update intervals).
048: *
049: * @author Niko Schmuck (niko@nava.de)
050: */
051: public class ChannelRegistry {
052:
053: private static Log logger = LogFactory
054: .getLog(ChannelRegistry.class);
055: public static final int DEFAULT_ACCEPT_NR_ERRORS = 10;
056:
057: private int acceptNrOfErrors;
058: private ChannelBuilderIF builder;
059: private ChannelGroupIF channels;
060: private Timer updateDaemon;
061: private Map<URL, UpdateChannelTask> updateTasks;
062: private Map<URL, UpdateChannelInfo> channelInfos;
063:
064: /**
065: * Constructor for a new ChannelRegistry object, the new items found by
066: * scanning the are created using the given <code>builder</code>.
067: *
068: * @param builder The ChannelBuilderIF to use for creating news items.
069: */
070: public ChannelRegistry(ChannelBuilderIF builder) {
071: this .builder = builder;
072: this .channels = builder.createChannelGroup("Default");
073: // start a new timer 'daemon' which controls updating tasks
074: updateDaemon = new Timer(true);
075: updateTasks = new HashMap<URL, UpdateChannelTask>();
076: channelInfos = new HashMap<URL, UpdateChannelInfo>();
077: acceptNrOfErrors = DEFAULT_ACCEPT_NR_ERRORS;
078: }
079:
080: /**
081: * Adds one new channel object (instantiated with the help of the
082: * given URL from where the channel can be retrieved from) to the
083: * registry.
084: *
085: * @param url - the URL where the channel news can be retrieved.
086: * @param interval - time in seconds between update retrieval.
087: * @param active - wether regular updates should be executed.
088: */
089: public ChannelIF addChannel(URL url, int interval, boolean active) {
090: return addChannel(url, null, interval, active);
091: }
092:
093: /**
094: * Adds one new channel object in the given category to the
095: * registry.
096: *
097: * @param url - the URL where the channel news can be retrieved.
098: * @param categories - the categories to which this channel should be
099: * added to (collection of CategoryIF objects).
100: * @param interval - time in seconds between update retrieval.
101: * @param active - wether regular updates should be executed.
102: */
103: public ChannelIF addChannel(URL url,
104: Collection<CategoryIF> categories, int interval,
105: boolean active) {
106:
107: ChannelIF channel = builder
108: .createChannel("[uninitialized channel]");
109: channel.setCategories(categories);
110: channel.setLocation(url);
111:
112: channel = addChannel(channel, active, interval);
113: return channel;
114: }
115:
116: /**
117: * Given a stand-alone Channel (i.e. just read in from disk) we
118: * add it into the ChannelGroup and activated if necessary.
119: *
120: * @param channel - Fully realized Channel
121: * @param active - Same as above
122: * @param interval - Same as above
123: */
124: public ChannelIF addChannel(ChannelIF channel, boolean active,
125: int interval) {
126: channels.add(channel);
127: logger.debug("added channel " + channel.getId()
128: + " to registry");
129: if (active) {
130: activateChannel(channel, interval);
131: }
132: return channel;
133: }
134:
135: /**
136: * Activates a channel and looks for new items for the given channel.
137: *
138: * @param channel The ChannelIF to scan for updates
139: * @param interval Difference between channel updates in seconds
140: */
141: public void activateChannel(ChannelIF channel, int interval) {
142: // TODO: what about changed interval setting?
143: // (workaround, deactivate, set interval, activate again)
144: // only create one update task per channel
145: if (updateTasks.get(channel.getLocation()) == null) {
146: // auto-deactivation after 10 times an channel parse error occurred
147: UpdateChannelInfo info = channelInfos.get(channel
148: .getLocation());
149: if (info == null) {
150: info = new UpdateChannelInfo(acceptNrOfErrors);
151: info.setFormatDetected(false);
152: channelInfos.put(channel.getLocation(), info);
153: } else {
154: info.reset();
155: }
156: // create new task
157: UpdateChannelTask task = new UpdateChannelTask(this ,
158: builder, channel, info);
159: // schedule the task for periodic execution, first time after
160: // 100 ms, and then regularly in <interval> secs.
161: updateDaemon.schedule(task, 100, interval * 1000);
162: logger.info("activating channel updates for "
163: + channel.getTitle());
164: updateTasks.put(channel.getLocation(), task);
165: // TODO: Adapt to new UserIF
166: // channel.getSubscription().setActive(true);
167: // channel.getSubscription().setUpdateInterval(interval);
168: }
169: }
170:
171: public ChannelIF getChannel(long id) {
172: return channels.getById(id);
173: }
174:
175: /**
176: * Gets all the channels in the registry.
177: *
178: * @return A collection of ChannelIF objects.
179: */
180: public Collection getChannels() {
181: return channels.getAll();
182: }
183:
184: public ChannelGroupIF getChannelGroup() {
185: return channels;
186: }
187:
188: public void setChannelGroup(ChannelGroupIF channels) {
189: this .channels = channels;
190: // === TODO: Adapt to new UserIF
191: // -- loop over channels and activate if necessary
192: // Iterator it = channels.getAll().iterator();
193: // while (it.hasNext()) {
194: // ChannelIF channel = (ChannelIF) it.next();
195: // if (channel.getSubscription().isActive()) {
196: // activateChannel(channel,
197: // channel.getSubscription().getUpdateInterval());
198: // }
199: // }
200: }
201:
202: /**
203: * Removes a channel from the registry. First it is cleanly deactivated.
204: *
205: * @param channel The ChannelIF object to remove.
206: */
207: public void removeChannel(ChannelIF channel) {
208: deactivateChannel(channel);
209: channels.remove(channel);
210: logger.debug("removing channel from registry: "
211: + channel.getTitle());
212: }
213:
214: /**
215: * Deactivates a channel, no more updates are made.
216: */
217: public void deactivateChannel(ChannelIF channel) {
218: UpdateChannelTask task = updateTasks.get(channel.getLocation());
219: if (task != null) {
220: logger.debug("update task canceled for "
221: + channel.getTitle());
222: task.cancel();
223: updateTasks.remove(channel.getLocation());
224: // TODO: Adapt to new UserIF
225: // channel.getSubscription().setActive(false);
226: }
227: }
228:
229: /**
230: * Returns wether the channel update task is still active or not.
231: */
232: public boolean isActiveChannel(ChannelIF channel) {
233: UpdateChannelTask task = updateTasks.get(channel.getLocation());
234: return (task != null);
235: }
236:
237: public UpdateChannelInfo getUpdateInfo(ChannelIF channel) {
238: return channelInfos.get(channel.getLocation());
239: }
240:
241: /**
242: * Gets the scheduled time of the next channel update.
243: *
244: * @param channel The ChannelIF to retrieve information for.
245: * @return The date of the next execution, 0 if not available
246: */
247: public long getScheduledUpdateTime(ChannelIF channel) {
248: UpdateChannelTask task = updateTasks.get(channel.getLocation());
249: if (task != null) {
250: return task.scheduledExecutionTime();
251: }
252: return 0;
253: }
254:
255: public int getAcceptNrOfErrors() {
256: return acceptNrOfErrors;
257: }
258:
259: /**
260: * Set number of channel parser errors acceptable after channel is not
261: * longer automatically updated.
262: */
263: public void setAcceptNrOfErrors(int acceptNrOfErrors) {
264: this.acceptNrOfErrors = acceptNrOfErrors;
265: }
266:
267: }
|