降低Eclipse RCP 项目 插件依赖度(OSGI 服务的理解)

 

下面这篇文章思路颇有点 osgi service 意思, 有思想的可以看看

 

Talend产品中,模块之间的依赖都是给予代码直接访问,每个插件项目没有自身的使用规则。造成插件间的混乱无序依赖。参见大型RCP项目,降低插件依赖度

 
例如:
降低Eclipse RCP 项目 插件依赖度(OSGI 服务的理解)_第1张图片
上图中, org.talend.designer.core插件项目要依赖于如此多的其它项目。
从整个系统的体系结构看,org.talend.designer.core对于红线连接的插件的依赖是不符合逻辑的。
 
另外,其他插件之间也存在着相互依赖的情况,例如Runprocess就要依赖于Repository。
 
随着以后插件项目的增多,这么复杂的依赖型将导致软件的维护越来越困难。
 
解决的方案是提供一个服务的注册,提供机制,所有的服务在一个地方统一注册,其他插件到这里取用。
 
以Repository模块为例:可以体现为如下设计方案。
Repository作为服务的提供者,其他使用该功能的插件作为消费者。
 
降低Eclipse RCP 项目 插件依赖度(OSGI 服务的理解)_第2张图片
 
 
实际实现
1 在基础项目org.talend.core中提供统一的服务注册接口程序如下:
 
package  org.talend.core;

import  java.util.HashMap;
import  java.util.Map;

import  org.eclipse.core.runtime.CoreException;
import  org.eclipse.core.runtime.IConfigurationElement;
import  org.eclipse.core.runtime.IExtensionRegistry;
import  org.eclipse.core.runtime.Platform;
import  org.talend.commons.exception.ExceptionHandler;

/**
 * DOC qian class global comment. A global service register provides the service registration and acquirement. <br/>
 * 
 * $Id: talend-code-templates.xml 1 2006-09-29 17:06:40 +0000 (星期五, 29 九月 2006) nrousseau $
 * 
 
*/

public   class  GlobalServiceRegister  {

    
// The shared instance
    private static GlobalServiceRegister instance = new GlobalServiceRegister();

    
private static IConfigurationElement[] configurationElements;

    
public static GlobalServiceRegister getDefault() {
        
return instance;
    }


    
private Map<Class, IService> services = new HashMap<Class, IService>();

    
static {
        IExtensionRegistry registry 
= Platform.getExtensionRegistry();
        configurationElements 
= registry.getConfigurationElementsFor("org.talend.core.service");
    }


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

    
public IService getService(Class klass) {
        IService service 
= services.get(klass);
        
if (service == null{
            service 
= findService(klass);
            
if (service == null{
                
throw new RuntimeException("The service " + klass.getName() + " has not been registered.");
            }

            services.put(klass, service);
        }

        
return service;
    }


    
/**
     * DOC qian Comment method "findService".Finds the specific service from the list.
     * 
     * 
@param klass the interface type want to find.
     * 
@return IService
     
*/

    
private IService findService(Class klass) {
        String key 
= klass.getName();
        
for (int i = 0; i < configurationElements.length; i++{
            IConfigurationElement element 
= configurationElements[i];
            String id 
= element.getAttribute("serviceId");
            
            
if (!key.endsWith(id)) {
                
continue;
            }

            
try {
                Object service 
= element.createExecutableExtension("class");
                
if (klass.isInstance(service)) {
                    
return (IService) service;
                }

            }
 catch (CoreException e) {
                ExceptionHandler.process(e);
            }

        }

        
return null;
    }

}
 
 
2 服务接口为:
 
public   interface  IService  {

}
3 插件扩展点定义为;
org.talend.core/plugin.xml
< extension-point  id ="service"  name ="Service Registration"  schema ="schema/service.exsd" />
4对于希望提供服务插件需要声明自己的服务类型。
例如org.talend.repository插件希望提供服务。
定义 IRepositoryService .java  此类放入org.talend.core中。
在org.talend.repository实现 IrepositoryService
 
public   interface  IRepositoryService  extends  IService  {

    
public IComponentsFactory getComponentsFactory();

    
public IPath getPathFileName(String folderName, String fileName);
    
    
public IProxyRepositoryFactory getProxyRepositoryFactory();
    
    
public IPath getRepositoryPath(RepositoryNode node);
}
 
public   class  RepositoryService  implements  IRepositoryService  {

    
public IComponentsFactory getComponentsFactory() {
        
return ComponentsFactoryProvider.getInstance();
    }


    
public IPath getPathFileName(String folderName, String fileName) {
        
return RepositoryPathProvider.getPathFileName(folderName, fileName);
    }


    
public IProxyRepositoryFactory getProxyRepositoryFactory() {
        
return ProxyRepositoryFactory.getInstance();
    }

    
    
public IPath getRepositoryPath(RepositoryNode node){
        
return RepositoryNodeUtilities.getPath(node);
    }

}
 
5 org.talend.repository使用扩展点,使自己注册到org.talend.core中.
org.talend.repository/plugin.xml
< extension
         
point ="org.talend.core.service" >
      
< Service
            
serviceId ="IRepositoryService"
            class
="org.talend.repository.RepositoryService" />
 
</ extension >
 
 
6 消费者使用org.talend.repository提供的服务时,只需要调用
 
/**
     * DOC get a implement of IRepositoryService.
     * 
     * 
@return a implement of IRepositoryService
     
*/

    
public  IRepositoryService getRepositoryService()  {
        IService service 
= GlobalServiceRegister.getDefault().getService(IRepositoryService.class);
        
return (IRepositoryService) service;
    }
 
经过这样的改造,所有的插件都只要依赖org.talend.core即可,解决了插件间依赖结构混乱的问题。而且系统具有很好的开放性,很容易的加入其他服务的注册,有利于今后的扩展。
 
P.S. 一开始想利用Eclipse 的getAdaptable(Class) 机制来实现此功能,虽然也能实现,但是使用者还要自己写Facotry类,增加了扩展的难度,而且getAdaptable(Class)机制也不是用来解决这种问题的。而且自己控制服务的加载可以避免很多额外的麻烦。

 

你可能感兴趣的:(eclipse,xml,osgi)