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 閱讀(1261) 評論(0)  編輯  收藏 所屬分類: J2SE
          <2009年12月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          常用鏈接

          留言簿(21)

          隨筆分類

          隨筆檔案

          BlogJava熱點博客

          好友博客

          搜索

          •  

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 全州县| 浦东新区| 辽源市| 醴陵市| 格尔木市| 新疆| 吴川市| 汉阴县| 都昌县| 柳林县| 桐柏县| 昌吉市| 手游| 含山县| 微山县| 莲花县| 宜宾市| 长武县| 简阳市| 桐乡市| 保亭| 乌鲁木齐市| 安福县| 兴安盟| 四川省| 望江县| 屯留县| 那曲县| 江阴市| 宜良县| 濉溪县| 连平县| 曲沃县| 宜章县| 灵丘县| 鹤峰县| 靖州| 杭锦旗| 鹿邑县| 桐梓县| 开鲁县|