Informa的core包中定义了所有基本的标记接口,实体接口,行为接口。对应的实现有2种:
★In-memory实现:de.nava.informa.impl.basic
★hibernate实现:de.nava.informa.impl.hibernate
前者在内存中实现了Channel和Item的创建,访问,存储(内存数据库),后者通过Hibernate来持久化,访问。根据Informa的文档,最简单的是basic实现。先从这个入手:
可以看到在basic包中,类并不是很多。其中几个在core包出现的接口如:ChannelParser, ChannelExporter, ChannelObservable, ChannelObserver都没有在basic中实现。它们分别在各自的parser, exporter包中被实现了。而一系列的标记接口则分别被basic包中的一众类实现了。
basic包其实非常简单,几乎就是一系列的Java Bean,经过几个小时的学习,总结了里面几个比较重要的类:
★Channel类
Channel类构造方法如下:
public Channel(Element channelElement, String title) {
this.id = IdGenerator.getInstance().getId();
this.channelElement = channelElement;
this.title = title;
this.items = Collections.synchronizedMap((new LinkedHashMap<Long, ItemIF>()));
this.categories = new ArrayList<CategoryIF>();
this.observers = new ArrayList<ChannelObserverIF>();
this.format = ChannelFormat.UNKNOWN_CHANNEL_FORMAT;
this.lastUpdated = new Date();
}
在Channel内部了定义了RSS规范中所需的属性,其中比较重要的就是items:即该channel下的所有item。其次是categories:标明该channel属于哪个(些)分类。除了直接地从外部接收参数构造,Channel类还提供了一个“cheap-copy”方法,叫做setAllProperties。该方法的实现如下:
/** *//**
* setAllProperties - Set all the properties in this Channel by copying them
* from a source Channel.
* N.B. This includes all properties, but not children such as items etc.
* N.B. Location and Format are also not copied.
*
* @param sourceChan - ChannelIF that will supply new values
*/
public void setAllProperties(ChannelIF sourceChan) {
setTitle(sourceChan.getTitle());
setDescription(sourceChan.getDescription());
setSite(sourceChan.getSite());
setCreator(sourceChan.getCreator());
setCopyright(sourceChan.getCopyright());
setPublisher(sourceChan.getPublisher());
setLanguage(sourceChan.getLanguage());
setImage(sourceChan.getImage());
}
为什么说这是一个“cheap-copy”呢?从API中就可以看出:它只拷贝顶层的属性和元素,但对于嵌套的子元素不会拷贝。至于为什么location和format不拷贝我想是因为这个做法通常用于RSS Feed之间的共享,此时location肯定是不同的,而format也可能不同(大家使用相同的内容,但可能有不同格式协议。如RSS 1.0和RSS 2.0)。
注意在Channel中有一个观察者列表:observers---由于ChannelIF继承了ChannelObservable接口,所以Channel实现类必须包含,维护一组对其感兴趣的观察者列表。
public void addObserver(ChannelObserverIF o) {
observers.add(o);
}
public void removeObserver(ChannelObserverIF o) {
observers.remove(o);
}
当channel中新增了item的时候,channel必须及时通知这些观察者有对应的事件发生。在ChannelObserverIF接口中定义了两种观察者感兴趣的事件:
public interface ChannelObserverIF {
/** *//**
* Called when a new Item is added to this Channel
*
* @param newItem - Item that was added.
*/
void itemAdded(ItemIF newItem);
/** *//**
* Called when a new Channel is added
*
* @param channel - Channel that was added
*/
void channelRetrieved(ChannelIF channel);
}
可以看到观察者只对新增channel和item感兴趣,实际上当channel本身有信心更新时,也会调用channelRetrieved方法。但是对于channel和item的删除事件并不在这里定义,而是在另外一个包:cleaner中定义。
channel中通过addItem,removeItem,getItem来增加,移除,访问其下的item信息,只有当addItem发生时才会通知观察者:
public void addItem(ItemIF item) {
items.put(new Long(item.getId()), item);
item.setChannel(this);
notifyObserversItemAdded(item);
}
public void removeItem(ItemIF item) {
items.remove(new Long(item.getId()));
}
public ItemIF getItem(long anId) {
return (ItemIF) items.get(new Long(anId));
}
当channel自身发生更新时,也会通知观察者
public void setLastUpdated(Date lastUpdated) {
this.lastUpdated = lastUpdated;
notifyObserversChannelUpdated();
}
请看下面这两个notify的过程:
private void notifyObserversItemAdded(ItemIF newItem) {
Iterator it = observers.iterator();
while (it.hasNext()) {
ChannelObserverIF o = (ChannelObserverIF) it.next();
o.itemAdded(newItem);
}
}
/** *//**
* Loops through and notifies each observer if a new item was
* detected.
*/
private void notifyObserversChannelUpdated() {
Iterator it = observers.iterator();
while (it.hasNext()) {
ChannelObserverIF o = (ChannelObserverIF) it.next();
o.channelRetrieved(this);
}
}
总结起来,channel的创建,更新过程如下:
①接收经过ChannelParser解析后的XML Element元素,和其他一系列属性,调用构造方法
②构造方法为channel生成一个全局唯一ID
③构造方法创建item列表,观察者列表,设置好分类(Category),首次更新时间
④如果有新item到来,则添加到item列表,同时更新item的channel归属
⑤如果现有channel更新,则设置最新更新时间
⑥通知每一个已注册的观察者有事件发生
在Channel类里面提供了若干访问channel子元素的方法,它们分别是:
public String getElementValue(final String path)
public String[] getElementValues(final String path, final String[] elements)
public String getAttributeValue(final String path, final String attribute)
public String[] getAttributeValues(final String path, final String[] attributes)
在这些方法的内部,都是使用了一个叫做XmlPathUtils的类提供的静态方法,至于XPATH访问的Element就是在构造方法中缓存的经ChannelParser解析后的XML Element。
-------------------------------------------------------------
生活就像打牌,不是要抓一手好牌,而是要尽力打好一手烂牌。
posted on 2009-12-22 23:31
Paul Lin 阅读(1249)
评论(0) 编辑 收藏 所属分类:
J2SE