2012-06-28 3 views
0

OSGi를 처음 다루었을 때 Maven 프로젝트에 번들을 포함하는 데 어려움을 겪었습니다.Maven 프로젝트에서 OSGi 번들을 사용하는 ClassCastException

mave-bundle-plugin을 사용하여 API 번들과 구현 번들을 만들었습니다. 필자는 메이븐 프로젝트 (Maven 프로젝트)에서 Felix Framework를 사용하여 ServiceTracker에서 구현 된 번들 서비스를 얻으려고했다. 마지막으로 얻은 서비스를 올바른 유형으로 캐스팅하려고하면 ClassCastException이 수신됩니다.

API Maven 프로젝트 :

public interface ParserTestService { 
    String validForStage(); 
} 

API의 POM :

<artifactId>ParserTest</artifactId> 
<version>0.0.2-SNAPSHOT</version> 
<packaging>bundle</packaging> 

<build> 
    <plugins> 
     <plugin> 
      <groupId>org.apache.felix</groupId> 
      <artifactId>maven-bundle-plugin</artifactId> 
      <extensions>true</extensions> 
      <configuration> 
       <instructions> 
        <Bundle-SymbolicName>${pom.groupId}.${pom.artifactId}</Bundle-SymbolicName> 
        <Bundle-Vendor>Apache-Felix</Bundle-Vendor> 
        <Bundle-Version>0.0.1</Bundle-Version> 
        <Export-Service>de.ParserTestService</Export-Service>  
       </instructions> 
      </configuration> 
     </plugin> 
    </plugins> 
</build> 

<dependencies> 
    <dependency> 
     <groupId>org.apache.felix</groupId> 
     <artifactId>org.apache.felix.framework</artifactId> 
     <version>2.0.4</version> 
    </dependency> 
</dependencies> 

IMPL Maven 프로젝트 :

public class ParserImplService implements ParserTestService { 
    public String validForStage() { 
     return "S"; 
    } 
} 

IMPL POM :

<artifactId>ParserTestVersion1</artifactId> 
<version>0.0.2-SNAPSHOT</version> 
<packaging>bundle</packaging> 

<build> 
    <plugins> 
     <plugin> 
      <groupId>org.apache.felix</groupId> 
      <artifactId>maven-bundle-plugin</artifactId> 
      <extensions>true</extensions> 
      <configuration> 
       <instructions> 
        <Bundle-SymbolicName>${pom.groupId}.${pom.artifactId}</Bundle-SymbolicName> 
        <Bundle-Vendor>Apache-Felix</Bundle-Vendor> 
        <Bundle-Version>0.0.1</Bundle-Version> 
        <Bundle-Activator>de.Activator</Bundle-Activator> 
        <Export-Package>de</Export-Package> 
        <Export-Service>de.ParserImplService</Export-Service> 
        <Import-Package>org.osgi.framework</Import-Package> 
       </instructions> 
      </configuration> 
     </plugin> 
    </plugins> 
</build> 

<dependencies> 
    <dependency> 
     <groupId>org.apache.felix</groupId> 
     <artifactId>org.apache.felix.framework</artifactId> 
     <version>2.0.4</version> 
     <type>bundle</type> 
    </dependency> 
    <dependency> 
     <groupId>de</groupId> 
     <artifactId>ParserTest</artifactId> 
     <version>0.0.2-SNAPSHOT</version> 
     <type>bundle</type> 
    </dependency> 
</dependencies> 

Maven은이 다음과 같은 매니페스트 파일과 항아리 - 파일 생성 : 내 주요 Maven 프로젝트에서

Manifest-Version: 1.0 
Bnd-LastModified: 1340890655296 
Build-Jdk: 1.6.0_24 
Built-By: br_s1 
Bundle-ManifestVersion: 2 
Bundle-Name: Parser Test Interface 
Bundle-SymbolicName: de.ParserTest 
Bundle-Vendor: Apache-Felix 
Bundle-Version: 0.0.1 
Created-By: Apache Maven Bundle Plugin 
Export-Package: de;version="0.0.1" 
Export-Service: de.ParserTestService 
Tool: Bnd-1.50.0 

Manifest-Version: 1.0 
Bnd-LastModified: 1340890661890 
Build-Jdk: 1.6.0_24 
Built-By: br_s1 
Bundle-Activator: de.Activator 
Bundle-ManifestVersion: 2 
Bundle-Name: Parser Test 
Bundle-SymbolicName: de.ParserTestVersion1 
Bundle-Vendor: Apache-Felix 
Bundle-Version: 0.0.1 
Created-By: Apache Maven Bundle Plugin 
Export-Package: de;version="0.0.1" 
Export-Service: de.ParserImplService 
Import-Package: org.osgi.framework;version="[1.5,2)" 
Tool: Bnd-1.50.0 

, I 설치 및 펠릭스 프레임 워크를 시작했다. 하위 폴더 "bundles"에서 위의 Maven 배포 프로세스로 만든 jar 파일을 복사했습니다. 설치 루틴에서, 나는이 번들을 설치하고 시작하려고 :

public class HostActivator implements BundleActivator { 
... 
    public BundleContext getContext() 
    { 
     return m_context; 
    } 
... 
} 

public class HostApplication 
{ 
    private HostActivator m_activator = null; 
    private Felix m_felix = null; 
    private ServiceTracker m_tracker = null; 

    public HostApplication() 
    { 
     Map<String, Object> configMap = new HashMap<String, Object>(); 
     configMap.put(Constants.FRAMEWORK_SYSTEMPACKAGES_EXTRA, "de.test; version=1.0.0"); 
     m_activator = new HostActivator(); 
     List<BundleActivator> list = new ArrayList<BundleActivator>(); 
     list.add(m_activator); 
     configMap.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, list); 

     m_felix = new Felix(configMap); 
     m_felix.start(); 

     m_tracker = new ServiceTracker(m_activator.getContext(), ParserTestService.class.getName(), null); 
     m_tracker.open(); 
    } 

    public void installBundlesFromDir() { 

     File dir = new File("bundles"); 
     for (File f : dir.listFiles()) { 
      try { 
       Bundle b = m_felix.getBundleContext().installBundle("file:"+f.getAbsolutePath()); 
       b.start(); 

       ServiceReference sr = m_felix.getBundleContext().getServiceReference(ParserTestService.class.getName()); 

       ParserTestService service = (ParserTestService) m_felix.getBundleContext().getService(sr); 

      } catch (BundleException e) { 
       System.err.println("could not load bundle "+f.getAbsolutePath()); 
      } 
     }   

    } 
} 

해당 POM : 나는 그러나, 나는 ClassCastException를 수신 루틴을 설치 호출 할

<artifactId>parserUse</artifactId> 
<version>0.0.1-SNAPSHOT</version> 

<dependencies> 
    <dependency> 
     <groupId>org.apache.felix</groupId> 
     <artifactId>org.apache.felix.framework</artifactId> 
     <version>2.0.4</version> 
    </dependency>    
    <dependency> 
     <groupId>de</groupId> 
     <artifactId>ParserTestVersion1</artifactId> 
     <version>0.0.2-SNAPSHOT</version> 
    </dependency> 
    <dependency> 
     <groupId>de</groupId> 
     <artifactId>ParserTest</artifactId> 
     <version>0.0.2-SNAPSHOT</version> 
    </dependency> 
</dependencies> 

:

java.lang.ClassCastException: de.ParserImplService cannot be cast to de.ParserTestService 

이미 확인 클래스 로더

ParserTestService.class.getClassLoader() 

(m_felix.getBundleContext().getService(sr)).getClass().getClassLoader() 

는 그들은 서로 다르다.

OSGi가 나를 위해 클래스 로딩을 처리 할 것이라고 항상 생각했습니다.

내가 뭘 잘못하고 있는지 실마리가 있습니까? 어떤 도움을 주셔서 감사합니다! 사전에

감사합니다, 세바스찬

답변

1

에서 그것을 얻을.

1.API는 패키지 만 내 보냅니다. <Export-Package>de</Export-Package>

2) Impl은 아무 것도 내보내지 않습니다.() 질문을 참조 m_felix의 BundleContext를 사용하여

public class HostApplication { 
    private BundleContext bundleContext; 

    public HostApplication(String profileName) { 
     BundleContext bc = null; 
     Properties frameworkProperties = readCustomProfile(profileName); 

     frameworkProperties.put("osgi.clean", "true"); 
     frameworkProperties.put("osgi.console", "true"); 

     Map<String, String> frameworkPropertiesMap = new HashMap<String, String>(); 
     for (Object o : frameworkProperties.keySet()) { 
      frameworkPropertiesMap.put((String) o, 
        (String) frameworkProperties.getProperty((String) o)); 
     } 

     EclipseStarter.setInitialProperties(frameworkPropertiesMap); 
     bc = EclipseStarter.startup(new String[] { "-console", "-dev", "bin" }, null); 
    } 

    public boolean containsIegm(String stage, byte[] msg) { 

     try { 
      ServiceReference serviceReference = bundleContext.getServiceReference(ParserTest.class.getName()); 
      return ((ParserImplService) bundleContext.getService(serviceReference)).containsIegm(msg); 

     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 

     return false; 
    } 

    public void installBundlesFromDir() { 

     File dir = new File("bundles"); 
     int i = 0; 
     for (File f : dir.listFiles()) { 
      try { 
       Bundle b = bundleContext.installBundle("file:"+ f.getAbsolutePath()); 
       b.start(); 
      } catch (BundleException e) { 
       System.err.println("could not load bundle " + f.getAbsolutePath()); 
      } 
     } 

    } 
} 

내가 정확히 펠릭스와 같은 시도 : 그것은 단지 활성화하고 수입은

<Bundle-Activator>de.Activator</Bundle-Activator> 
<Import-Package>org.osgi.framework;de</Import-Package> 

3) 나는 춘분을 사용하여 전체 HostApplication 대체 정의 completently HostActivator 제거 (나는 그것이 내 애플 리케이션에서 필요하지 않다는 것을 알고있다). 그러나, 나는 그것을 작동하게 만들 수 없었다.

어쨌든 Equinox를 사용하면 OGSi/비 번들 응용 프로그램에 OSGi 프레임 워크를 임베드하는 것이 똑같이 쉽습니다.

도움을 주신 모든 분들께 감사드립니다. Sebastian

+3

Felix와 Equinox가 여기에서 다른 이유는 분명합니다. 나는 당신이하고자하는 것을 성취 할 수있는 더 간단한 방법이 있다고 생각합니다. 세부 사항에서 물러나서 좀 더 일반적인 용어로 목표를 설명한다면. –

1

두 번들 "드"수출하고 있습니다. 이것은 "de"라는 두 개의 이름 공간이 있음을 의미합니다.
번들 번들 - SymbolicName : de.ParserTestVersion1해야 수입 "드"내가 마지막으로이 문제를 해결하는 방법을 발견,하지만 펠릭스를 피하고 대신 춘분을 사용하여 다른 번들

+1

또한 ServiceTracker 생성시 잘못된 BundleContext가 사용됩니다. 게시 번들의 컨텍스트가 사용 된 것처럼 보입니다 (설정은 * 매우 혼란 스럽지만). 결과적으로 정상적인 호환성 검사가 취소됩니다. 또한, 외부 번들이 내부 번들 (예 : HostActivator) 내부의 구현 클래스에 대한 가시성을 가지고 있다면, 서비스를 왜 귀찮게 하는가? 왜 직접적인 인스턴스화가 아닌가? –

+0

@David : 번들의 내보내기 및 가져 오기를 업데이트했지만 여전히 ClassCastException이 발생합니다. 이것이 내 문제의 원인이 아니었던 것 같습니다. – user1488793

+0

@Neil : 답변을 완전히 이해하지 못했습니다. 필자는 OSGi에 익숙하지 않아 잘못된 경로를 택한 것으로 생각하기 시작했기 때문에 내가 원하는 것을 분명히해야합니다. 호스트 응용 프로그램은 두 가지 작업을 수행 할 수 있어야합니다. 1.) 디렉토리에서 서비스를 설치하고 시작할 수 있어야합니다. 2) 이러한 서비스를 호출 할 수 있어야합니다. – user1488793

관련 문제