【问题标题】:Using XML parser implementation as OSGi service使用 XML 解析器实现作为 OSGi 服务
【发布时间】:2009-07-21 11:09:12
【问题描述】:

我正在使用 OSGi(Equinox 平台)开发一个应用程序,其中一个包需要解析 XML 文件。到目前为止,我使用 SAX (javax.xml.parsers.SAXParserFactory) 实现了这个,我想从平台检索 SAXParserFactory。

我看到 OSGi 标准提供了一个 XMLParserActivator 以允许 JAXP 实现注册自己 (http://www.osgi.org/javadoc/r4v41/org/osgi/util/xml/XMLParserActivator.html),所以我猜应该有一些捆绑提供 SAXParserFactory 作为服务。

但是,我无法确定要添加哪个包作为依赖项才能找到提供 SAXParserFactory 的服务。我尝试使用

检索服务引用
context.getServiceReferences(SAXParserFactory.class.getName(), "(&(parser.namespaceAware=true)(parser.validating=true))")

鉴于 XML 解析是一件相当常见的事情,我想有可用的实现,或其他方式从平台获取 XML 解析器服务。

非常欢迎任何帮助!

【问题讨论】:

  • 嗨,我对 OSGi 没有信心,但为什么不使用与 JRE 捆绑的 XML 堆栈呢?
  • 嗨,是的,但是 OSGi 类加载器机制不同 - 因此调用 SAXParserFactory.newInstance() 可能会产生问题,因为 JAXP 加载器机制希望在当前线程的类加载器中找到解析器,并且不一定是这样。

标签: java xml parsing osgi sax


【解决方案1】:

一般来说,在 OSGi 中使用 JAXP 不是一个好主意(主要是因为类加载机制),而让工厂像服务一样是一个更好的主意。

如果您使用的是Equinox,SaxParserFactory(使用您正在运行的JRE/JDK)实际上是由系统捆绑提供的,这意味着您不需要额外的捆绑:

{javax.xml.parsers.SAXParserFactory}={service.id=6} 通过捆绑注册:系统捆绑[0]

如果您想编写处理 OSGi 平台生命周期层的代码,我建议您跟踪参考,而不是直接查找。 有很多方法可以做到这一点;我写过一篇我称之为 ServiceMediator here 的文章。

例如对于您的情况(代码在 Apache 2 许可下,Coalevo 项目):

        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 @version@ (@date@)
     */
    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

【讨论】:

  • 我还建议查看“OSGI 动态服务”或“Spring DM”两者都有类似的方式来声明/解决捆绑包的依赖关系。有了这些机制,上面的代码将大大简化。
  • 上面的代码并不复杂,可以很容易地机器生成(如果运行时环境需要,可以从不同的地方获取Latch)。我不怀疑 DS(我假设您指的是声明式服务)是一种替代方案,但是,有时您可能会得到一些非常复杂的配置文件。无论如何,有替代品可供选择总是好的:)
【解决方案2】:

您可以使用 Apache Xerces 进行 Sax 解析。可以从Eclipse Orbit project 获得合适的捆绑包。我不知道 Xerces 包注册了 SAXParserFactory 服务,但您可以添加对包的依赖项并直接使用 Sax 解析器。

【讨论】:

  • 尽可能避免捆绑依赖。
猜你喜欢
  • 2012-05-11
  • 1970-01-01
  • 1970-01-01
  • 2010-12-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-04
相关资源
最近更新 更多