posts - 262,  comments - 221,  trackbacks - 0
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 阅读(1239) 评论(0)  编辑  收藏 所属分类: J2SE

只有注册用户登录后才能发表评论。


网站导航:
 
<2009年12月>
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

常用链接

留言簿(21)

随笔分类

随笔档案

BlogJava热点博客

好友博客

搜索

  •  

最新评论

阅读排行榜

评论排行榜