2007年11月20日

                  如果兩個插件出現雙向的獨立性關聯就形成了循環依賴,Dengues利用Eclipse擴展點方式解決這個問題。

                  首先來介紹一下原理。Eclipse在啟動的時候會將所有的擴展點實現加載到一個注冊表里面,這里注冊的東西可以是一個類,就像是我們通過擴展點的方式實現一個Viewer一樣,我們不僅要寫入相應的icon還要寫入相關的指定的類。
                      

                      
                  同樣道理,如果我們可以定義一個擴展點,在Eclipse啟動的時候把實現了這個擴展點的類加載到一個核心插件里。如果別的插件如果要用這個類的話,直接加入對之個核心插件的依賴不就可以了從而回避了對這個插件直接的依賴見下圖:

                  
                  在圖1里A插件要引用B插件里的類,同樣B插件也有需求要引用A插件里的類,這樣就造成了插件的循環依賴。現在利用擴展點,在A,B插件里實現一個定義于Core插件里的擴展點,在Eclispe啟動的時候,實現了此擴展點的類將可以被加載到Core插件里。通過Core的橋梁作用A、B插件便可以實現類的相互引用。這里A、B插件只是對Core有一個單向的依賴關系,通過core插件的幫助A與B之間可以相互調,避免了直接的調用所以也就不會形成循環依賴了。

                  一、擴展點的定義:

                  點擊進入org.dengues.core插件的plugin.xml 文件,打開Extension Point標簽,點Add加入一個擴展點輸入如下信息:
                  
                  在Definition里加一個叫做Service的element,并加入兩條use欄為reuqired的屬性如下圖所示:

                  

                  其中serviceClass的Type要選成java,并且在Implements里定義一個接口,這個接口規定了這個擴展點在實現的時候指定的類。這里為IDenguesService。其實接口里什么也沒方法也沒有定義,只是一個申明而已。
                  

                  

          package org.dengues.core;

          public interface IDenguesService {

              String ID 
          = "org.dengues.commons.denguesService"//$NON-NLS-1$

              String SERVICE_CLASS 
          = "serviceClass"//$NON-NLS-1$

              String SERVICE_ID 
          = "serviceID"//$NON-NLS-1$
          }


                  
                  二、實現擴展點。具體怎么用一個擴展點,這里就不用多說了,只重點介紹一下怎么實現IDenguesService類。我們以Dengues里的org.dengues.design.core插件為例。在org.dengues.core里我們我建一個IDenguesService的子接口IDesignerCoreService,并寫入我們要向其它plugin公開的方法。
                  

          public interface IDesignerCoreService extends IDenguesService {

              
          public IComponentsFactory getComponentsFactory();

              
          public IComponentFilesNaming getComponentFilesNaming();

              
          public void initializeTemplates();

              
          public ICodeGenerator getCodeGenerator(ICompProcess process);

              
          public ICodeGenerator getCodeGenerator();

              
          public IJavaETLProcessor getJavaProcessor(ICompProcess process);

              
          public IJavaETLProcessor getJavaProcessor();

              
          // public Action createStartHsqldbServer(String dbName);

              
          public Action createStartHsqldbServer();

              
          public boolean checkHsqldbConnection();

              
          public void runSqlScript(IFile scriptFile);

              
          public DatabaseContainer getHsqlDatabase() throws SQLException;

              
          public Connection getCurrentConnection() throws SQLException, CoreException, ClassNotFoundException;
          }


                   以上這些方法就是org.dengues.designer.core這個插件想要對其它插件公開的方法了,它的實現自然會被寫入到這個插件里了。這段代碼很多,我們就不列在這里了,如果有興趣的朋友可以到我們Dengues的google svn去check out代碼。寫好對IDesignerCoreService的實現以后,我們就可以把它加入到事先我們定義好的擴展點里了,見下圖:
                  
                  

                  圖中的DesignerCoreService就是IDesingerCoreService的實現。好了,當Eclipse啟動的時候它就會把這個類加載到注冊表里了,我們可以從這個注冊里取到這個類了。那以后如果我們想從這個plugin里向外公開一些方法的話,就可以通過向IDesignerCoreService寫入相應的方法,在DesignerCoreService里寫入相應的實現就可以了。

                  三、從注冊表里取出擴展點的類。

                  在org.dengues.core里我們寫了一個GlobalServiceFactory里面提供了相應的代碼:

                      

          static {
                  IExtensionRegistry registry 
          = Platform.getExtensionRegistry();
                  configurationElements 
          = registry.getConfigurationElementsFor(IDenguesService.ID); //$NON-NLS-1$
              }


              
          /**
               * Comment method "getService".Gets the specific IService.
               * 
               * 
          @param klass the Service type you want to get
               * 
          @return IService IService
               
          */

              
          public IDenguesService getService(Class klass) {
                  IDenguesService service 
          = services.get(klass);
                  
          if (service == null{
                      service 
          = findService(klass);
                      
          if (service == null{
                          
          throw new RuntimeException("GlobalServiceRegister.ServiceNotRegistered" + klass.getName()); //$NON-NLS-1$
                      }

                      services.put(klass, service);
                  }

                  
          return service;
              }


                  如果我們要取剛才定義好的那個IDesignerCoreService的話,我們可以按如下方式取到:

              public IDesignerCoreService getDesignerCoreService() {
                  IDenguesService service 
          = GlobalServiceFactory.getDefault().getService(IDesignerCoreService.class);
                  
          return (IDesignerCoreService) service;
              }

                  
                  其實段代碼是寫在org.dengues.core插件里的CorePlugin里的,也就是說在任何一個插件里只要加入了對org.dengues.core的依賴都可以通過CorePlguin.getDefault().getDesignerCoreService()來得到IDesignerCoreService的實例了。
           
                     
                      
                  
                  

          posted @ 2007-11-20 13:19 小張飛刀(Dengues Studio) 閱讀(1639) | 評論 (2)編輯 收藏

          2007年10月30日

                


                 Eclipse里有一項功能就是通過update site直接將插件從網上下載到自己的IDE里,使用起來方便省時,平時只是這樣用別人的插件;那如果自己開發了一個插件,想讓別人通過這種方式下載并使用可以嗎?答案當然是肯定的。

                 首先要創建一個feature工程,步驟如下:
                 1)在New Project Wizard選擇Feature Project,點一下步。
                 2)寫入feature工程的名字比如:org.dengues.feature
                 3)在第二頁里保持ID為org.dengues.feature.將名字改為Dengues Feature.
                 4)選中要關聯的插件,在這里我選擇了所有的dengues項目插件,如下:

                
                  點擊finish這樣就創建好了一個feature插件了。這里簡單的介紹一下feature有什么用,feature可以把其它的一個或者多個插件組合到一起,以便于用戶對插件的加載,管理,命名就像是對一個單元進行操作一樣。當然也包括可以方便用于發布到網上。

                 做好feature插件以后,就是要往里面寫入相應的信息嘍,里面包括版權,可訪問網站什么的東東,填好以后就可以進入下一步創建一個update site project了。

                 創建的步驟很簡單就不再詳細說明了,工程名就叫org.dengues.update吧。

                 創建完成之后,在site map里加入一個category,并將我們剛才做好的feature加到這個category里面。就成了下面的樣子:


                 選中剛加入的feature選build,完成之后這個update site project的結構就變成了這樣。

                

                 把這個工程下的所有文件直接拷到要發布的網頁服務器上就要以了,這樣你就以通過Eclipse訪問這個網站來更新你的插件了不信你試,簡單吧!
                




          posted @ 2007-10-30 17:28 小張飛刀(Dengues Studio) 閱讀(1647) | 評論 (5)編輯 收藏

          2007年10月26日

                  最近做了一個任務,要求把一個grahpical editor里的palette里的內容重新刷新一下,要求是在不關閉editor里前提之下。

                 一開始還在懷疑這個能否實現不,不過后來看了看代碼,發現這是完全可行的,且看我細細道來:

                  先看GraphicalEditorWithFlyoutPalette里的splitter這個成員,它把整個editor分成了兩個部分一個就是大的用于GEF畫圖的那部份;另外一部分很明顯就是palette啦!說這么多,看看它的createControl方法就全明白啦:
          public void createPartControl(Composite parent) {
              splitter 
          = new FlyoutPaletteComposite(parent, SWT.NONE, getSite().getPage(),
                      getPaletteViewerProvider(), getPalettePreferences());
              
          super.createPartControl(splitter);
              splitter.setGraphicalControl(getGraphicalControl());
              
          if (page != null{
                  splitter.setExternalViewer(page.getPaletteViewer());
                  page 
          = null;
              }

          }

                  其中的setExternalviewer就是放的palette的viewer,說到viewer我的第一個聯想就是SWT里的viewer其實不是這樣的,這里的viewer其實與一個基于GEF的Graphcial Viewer;也就是說,我們在一個graphical editor里看到的palette是通過drawer2D畫上去了,和我們平時GEF里的圖形沒什么兩樣。
          /**
           * Returns the PaletteRoot for the palette viewer.
           * 
          @return the palette root
           
          */

          protected abstract PaletteRoot getPaletteRoot();
                  再看這個getPaletteRoot方法它為palette viewer提供一個root,那這個root到底是什么呢?我們再繼續往下看。沿著palette root的繼承樹往上找,最后發現了這個:

                  一看palette entry的文檔就明白了,其實它就是 palette的模型。
          /**
           * Root class (statically) for the palette model.
           * 
           * 
          @author Pratik Shah
           
          */

          public class PaletteEntry {
                  當然如果它是GEF的模型,那么必然他就會有listeners一查代碼,果真是這樣的。
          /**
           * A listener can only be added once.  Adding it more than once will do nothing.
           * 
          @param listener the PropertyChangeListener that is to be notified of changes
           * 
          @see java.beans.PropertyChangeSupport#addPropertyChangeListener(
           *                                                         java.beans.PropertyChangeListener)
           
          */

          public void addPropertyChangeListener(PropertyChangeListener listener) {
              listeners.removePropertyChangeListener(listener);
              listeners.addPropertyChangeListener(listener);
          }
                  那么這個add listener方法被誰用呢?想都不用想了,肯定是被它的edit part 嘍,MVC嘛~~~不信看PaletteEditPart.java的activate方法:

          /**
           * 
          @see org.eclipse.gef.editparts.AbstractGraphicalEditPart#activate()
           
          */

          public void activate() {
              
          super.activate();
              PaletteEntry model 
          = (PaletteEntry)getModel();
              model.addPropertyChangeListener(
          this);
              traverseChildren(model, 
          true);
          }
                  
                  
                  模型的修改必定會被通知到 edit part 里,它再根據具體的情況對viewer進行更新,見下:
          /**
           * 
          @see java.beans.PropertyChangeListener#propertyChange(PropertyChangeEvent)
           
          */

          public void propertyChange(PropertyChangeEvent evt) {
              String property 
          = evt.getPropertyName();
              
          if (property.equals(PaletteContainer.PROPERTY_CHILDREN)) {
                  traverseChildren((List)evt.getOldValue(), 
          false);
                  refreshChildren();
                  traverseChildren((List)evt.getNewValue(), 
          true);
              }
           else if (property.equals(PaletteEntry.PROPERTY_LABEL)
                      
          || property.equals(PaletteEntry.PROPERTY_SMALL_ICON)
                      
          || property.equals(PaletteEntry.PROPERTY_LARGE_ICON)
                      
          || property.equals(PaletteEntry.PROPERTY_DESCRIPTION))
                  refreshVisuals();
          }

                  明白了!?說了那么多其實只要一名句話啦:修改一下palette root里palette entry的內容GEF 就會自動的將palette里的表現更新了。在Dengues的項目里,我在GEFComponentEditor.java里加入以下方法,便可以了:
              /**
               * Reset the content of the palette root will cause palette viewer be refreshed.
               * 
               * yzhang Comment method "refreshPalette".
               
          */
              
          public void refreshPalette() {

                  List
          <PaletteContainer> containers = new ArrayList<PaletteContainer>(root.getChildren());

                  
          for (PaletteContainer element : containers) {
                      
          if (element instanceof PaletteGroup) {
                          
          continue;
                      }
                      root.remove(element);
                  }

                  CompEditorPaletteFactory.create(factory, root);

              }

                 關于這個方法是如何調用的,這就涉及到另外一個話題了,見《如何解決插件之間循環依賴的問題》。
             
                 K字好累。Han hanhan .....

          posted @ 2007-10-26 13:32 小張飛刀(Dengues Studio) 閱讀(1334) | 評論 (0)編輯 收藏
          僅列出標題  
           
          主站蜘蛛池模板: 西华县| 建瓯市| 邛崃市| 临漳县| 湘潭市| 西充县| 同德县| 张家口市| 沙雅县| 宝鸡市| 德州市| 灵寿县| 兴文县| 屏南县| 阿图什市| 汤阴县| 四子王旗| 昭平县| 襄垣县| 凤凰县| 白银市| 汤阴县| 平安县| 库伦旗| 诸暨市| 罗田县| 沅江市| 禄丰县| 通江县| 德钦县| 古蔺县| 珠海市| 彭泽县| 沈阳市| 安国市| 永登县| 安陆市| 肇州县| 波密县| 茌平县| 朝阳区|