2009-07-21 11 views
7

Sto sviluppando un'applicazione che utilizza OSGi (piattaforma Equinox) e uno dei bundle deve analizzare i file XML. Finora l'ho implementato con SAX (javax.xml.parsers.SAXParserFactory) e vorrei recuperare SAXParserFactory dalla piattaforma.Utilizzo dell'implementazione del parser XML come servizio OSGi

Ho visto lo standard OSGi fornisce un XMLParserActivator per consentire alle implementazioni JAXP di registrarsi (http://www.osgi.org/javadoc/r4v41/org/osgi/util/xml/XMLParserActivator.html), quindi suppongo che ci debbano essere alcuni pacchetti che offrono SAXParserFactory come servizio.

Tuttavia, non sono riuscito a capire quale bundle aggiungere come dipendenza per trovare un servizio che offre SAXParserFactory. Io cerco di recuperare un riferimento al servizio utilizzando

context.getServiceReferences(SAXParserFactory.class.getName(), "(&(parser.namespaceAware=true)(parser.validating=true))") 

Dato che parsing XML è una cosa piuttosto comune da fare, suppongo che ci sono implementazioni disponibili, o altri mezzi per ottenere un servizio di parser XML dalla piattaforma.

Qualsiasi aiuto sarebbe molto gradito!

+0

Ciao, io non sono sicuro con OSGi, ma perché non utilizzare lo stack XML in bundle con il JRE? – ATorras

+0

Ciao, sì lo è, ma il meccanismo del classloader OSGi differisce - e quindi chiamare SAXParserFactory.newInstance() può dare problemi, dal momento che il meccanismo del caricatore JAXP si aspetta di trovare il parser nel threadloader del thread corrente e che potrebbe non essere necessariamente il caso . –

risposta

3

Generalmente non è una buona idea utilizzare JAXP in OSGi (principalmente per il meccanismo di caricamento in classe) e un'idea molto migliore per ottenere la fabbrica come un servizio.

Se si utilizza equinozio, il SAXParserFactory (utilizzando quello JRE/JDK si esegue su) viene effettivamente prestata dal Sistema Bundle, il che significa che non è necessario bundle aggiuntivi:

{javax.xml .parsers.SAXParserFactory} = {service.id = 6} Registrato dal pacchetto: Bundle sistema [0]

Se si desidera scrivere codice che si occupa del livello del ciclo di vita della piattaforma OSGi, suggerirei di tenere traccia del riferimento, piuttosto che cercarlo direttamente. Ci sono molti approcci per questo; Ho scritto di uno che chiami ServiceMediator here.

ad es. per il vostro caso (codice è sotto Apache 2 licenza, Coalevo Project):

 import org.osgi.framework.*; 

    import javax.xml.parsers.SAXParserFactory; 

    import net.wimpi.telnetd.util.Latch; 

    /** 
    * Implements a mediator pattern class for services from the OSGi container. 
    * <p/> 
    * 
    * @author Dieter Wimberger (wimpi) 
    * @version @[email protected] (@[email protected]) 
    */ 
    class ServiceMediator { 

     private BundleContext m_BundleContext; 

     private SAXParserFactory m_SAXParserFactory; 
     private Latch m_SAXParserFactoryLatch; 

     public SAXParserFactory getSAXParserFactory(long wait) { 
     try { 
      if (wait < 0) { 
      m_SAXParserFactoryLatch.acquire(); 
      } else if (wait > 0) { 
      m_SAXParserFactoryLatch.attempt(wait); 
      } 
     } catch (InterruptedException e) { 
      e.printStackTrace(System.err); 
     } 

     return m_SAXParserFactory; 
     }//getSAXParserFactory 

     public boolean activate(BundleContext bc) { 
     //get the context 
     m_BundleContext = bc; 

     m_SAXParserFactoryLatch = createWaitLatch(); 

     //prepareDefinitions listener 
     ServiceListener serviceListener = new ServiceListenerImpl(); 

     //prepareDefinitions the filter 
     String filter = "(objectclass=" + SAXParserFactory.class.getName() + ")"; 

     try { 
      //add the listener to the bundle context. 
      bc.addServiceListener(serviceListener, filter); 

      //ensure that already registered Service instances are registered with 
      //the manager 
      ServiceReference[] srl = bc.getServiceReferences(null, filter); 
      for (int i = 0; srl != null && i < srl.length; i++) { 
      serviceListener.serviceChanged(new ServiceEvent(ServiceEvent.REGISTERED, srl[i])); 
      } 
     } catch (InvalidSyntaxException ex) { 
      ex.printStackTrace(System.err); 
      return false; 
     } 
     return true; 
     }//activate 

     public void deactivate() { 
     m_SAXParserFactory = null; 

     m_SAXParserFactoryLatch = null; 

     m_BundleContext = null; 
     }//deactivate 

     private Latch createWaitLatch() { 
     return new Latch(); 
     }//createWaitLatch 

     private class ServiceListenerImpl 
      implements ServiceListener { 

     public void serviceChanged(ServiceEvent ev) { 
      ServiceReference sr = ev.getServiceReference(); 
      Object o = null; 
      switch (ev.getType()) { 
      case ServiceEvent.REGISTERED: 
       o = m_BundleContext.getService(sr); 
       if (o == null) { 
       return; 
       } else if (o instanceof SAXParserFactory) { 
       m_SAXParserFactory = (SAXParserFactory) o; 
       m_SAXParserFactory.setValidating(false); 
       m_SAXParserFactory.setNamespaceAware(true); 
       m_SAXParserFactoryLatch.release(); 
       } else { 
       m_BundleContext.ungetService(sr); 
       } 
       break; 
      case ServiceEvent.UNREGISTERING: 
       o = m_BundleContext.getService(sr); 
       if (o == null) { 
       return; 
       } else if (o instanceof SAXParserFactory) { 
       m_SAXParserFactory = null; 
       m_SAXParserFactoryLatch = createWaitLatch(); 
       } else { 
       m_BundleContext.ungetService(sr); 
       } 
       break; 
      } 
     } 
     }//inner class ServiceListenerImpl 

     public static long WAIT_UNLIMITED = -1; 
     public static long NO_WAIT = 0; 

    }//class ServiceMediator 
+0

Suggerirei anche di guardare "OSGI Dynamic Services" o "Spring DM" entrambi hanno mezzi simili per dichiarare/risolvere dipendenze di un bundle in modo dichiarativo. E con questi meccanismi il codice sopra potrebbe semplificare considerevolmente. –

+0

Il codice sopra non è molto complicato e può essere facilmente generato dalla macchina (il Latch può essere prelevato da diversi posti se richiesto per l'ambiente di runtime). Non dubito che DS (presumo che tu ti riferisca ai Servizi dichiarativi) sia un'alternativa, tuttavia, a volte potresti anche finire con alcuni file di configurazione piuttosto complessi. Ad ogni modo, è sempre bene avere alternative tra cui scegliere :) – Dieter

-1

È possibile utilizzare Apache Xerces per l'analisi Sax. Un pacchetto adatto è disponibile da Eclipse Orbit project. Non so che il pacchetto Xerces registri un servizio SAXParserFactory ma è possibile aggiungere una dipendenza al pacchetto e utilizzare direttamente il parser Sax.

+0

Evita le dipendenze del pacchetto ovunque sia possibile. – brindy