DocumentInfo & NodeInfo impl for JCR

2008-10-08
2012-10-08
  • Ivan Latysh
    Ivan Latysh
    2008-10-08

    Hello All!

    I am working on DocumentInfo and NodeInfo implementations that are wrapping JCR (Java Content Repository), so we can run XQuery on it.
    But I hit a small problem when I decide to extend net.sf.saxon.tree.NodeImpl. And right away I hit the problem. The member protected ParentNodeImpl parent; is narrowed to ParentNodeImpl when it can be just NodeInfo. I can't override it and can't set it so the only option is to copy entire class, or I am doing something wrong.
    Appreciate any help with it.

     
    • Michael Kay
      Michael Kay
      2008-10-08

      The "linked tree" implementation of NodeInfo (in package net.sf.saxon.tree) isn't designed to be subclassed, and I don't think that's the right way of writing a wrapper around an external data structure. I would base your design instead on the wrapper implementations of NodeInfo, for example the net.sf.saxon.jdom.NodeWrapper.

      But frankly, it's up to you: I can't really give you help with this kind of project.

       
    • Ivan Latysh
      Ivan Latysh
      2008-10-08

      Thank you for the advice, net.sf.saxon.dom4j.NodeWrapper is an excellent example, that what I was looking for.

      I used Saxon for long time, but never went deeper than Emitters and URI Resolvers. So right now I am trying to navigate my way through the source code.

      Also I see net.sf.saxon.dom4j.DOM4JObjectModel but can't find any usage of it. What is the purpose of it ?

       
      • Michael Kay
        Michael Kay
        2008-10-08

        The "ObjectModel" classes changed fairly substantially in Saxon 9.1. The basic idea is that "core Saxon" doesn't know anything about the external object models such as JDOM or DOM4J, so new models can easily be plugged in just by registering them with the Configuration (config.registerExternalObjectModel). Then when you pass a com.example.WeirdNode to an interface such as s9api.DocumentBuilder.wrap(), Saxon will try all the registered object models to see if any of them knows what to do with it.

        I'm afraid the interface ExternalObjectModel and the various implementations of it contain a lot of rather messy code reflecting the fact that the role of this object changed quite a bit in 9.1. But it should give you the general idea.

         
    • Ivan Latysh
      Ivan Latysh
      2008-10-09

      Thanks for your help, I completed JCRDocumentWrapper and JCRNodeWrapper that allow execution of XQuery and XPath on top of JCR (JSR-170) with a decent performance.

      Now I am cleaning up the code, and would like to hear your advice on couple of things.

      1) Exception handling. Neither DocumentInfoor NodeInfo allow any exception to be thrown, but I may get some from underlying repository, here is an example:
      public NodeInfo selectID(String id) {
      try {
      Session session = ((Node)node).getSession();
      return wrap(session.getNodeByUUID(id));
      } catch (RepositoryException e) {
      e.printStackTrace();
      throw new RuntimeException(e);
      }
      }
      So what is the best approach to handle such exceptions? Throwing RuntimeException's does not look good to me.

      2) Namespace handling. JCR has a namespace registry and i would like to register those namespaces so XQuery engine would not shout on me when I am trying to get @jcr:uuid.

       
      • Michael Kay
        Michael Kay
        2008-10-09

        Exception handling: a common Java problem, it happens whenever you want to implement a standard exception-free interface like List or Iterator. The only answer I know is to throw an unchecked exception which you catch at some outer level, presumably in this case at the level where the query as a whole is invoked.

        Namespace handling. I don't understand what this "namespace registry" is. With XQuery and XPath Saxon allows you to register namespace prefixes via API calls before compiling the query. With XSLT, declaring the namespace within the stylesheet is compulsory.

         
    • Ivan Latysh
      Ivan Latysh
      2008-10-09

      I don't like throwing unchecked exceptions, but in this case I have no other option.

      JCR registry is very similar to Saxon. My intention was to take over a task of registering prefixes before executing XQuery. But from what I see prefixes are registered in StaticQueryContext.declarePassiveNamespace(...) so I don't have an access to it from inside of JCRDocumentWrapper.
      Let me re-phrase: user has to register prefixes before compiling XQuery with StaticQueryContext and this task should not be delegated to a DocumentInfo implementation. Am I right ?

       
      • You may (re)throw checked exception:

        @SuppressWarnings("unchecked")
        private <T extends Throwable> boolean error(Throwable e)
        throws T
        {
        throw (T)e;
        }

        ...

        catch(YourException e)
        {
        this.<Error>error(e);
        }

        This allows to handle YourException to those who know how to handle it.

        --
        Vladimir Nesterovsky
        http://www.nesterovsky-bros.com

         
    • Ivan Latysh
      Ivan Latysh
      2008-10-17

      JCRDocument wrapper works fine, but I have a few issues with namespaces.
      When XQuery return a property that has jcr namespace (<node jcr:uuid="123"/>)
      I am getting:
      org.xml.sax.SAXParseException: The prefix "jcr" for attribute "jcr:uuid" associated with an element type "contact" is not bound.

      So I need some help on how to properly register uri.

      declarePassiveNamespace() for static context didn't help ...

       
      • Michael Kay
        Michael Kay
        2008-10-17

        >JCRDocument wrapper works fine

        It looks to me as if it doesn't.

        There are a number of constraints that your data model implementation must adhere to. These correspond roughly to the constraints defined in the W3C XDM specification. One of them, for example, is that if an element or one of its attributes is in a particular namespace (or uses a particular namespace prefix), then the list of namespace nodes for that element must include a binding for that prefix/uri. If your model doesn't satisfy such constraints, then it is entirely possible that the serialization of the XML will not be namespace-well-formed.

        Michael Kay
        http://www.saxonica.com/

         
        • Ivan Latysh
          Ivan Latysh
          2008-10-17

          > It looks to me as if it doesn't.
          Not all attributes has jcr prefix, so you are right, it does not work as expected :)

          I understand what you have described very well.

          But I need some help on how to programmatically register namespaces.

          here is my code (simplified):

          protected static final Configuration config = new Configuration();
          protected static final StaticQueryContext staticEnv = new StaticQueryContext(config);
          static{
          // here I am doing something wrong
          staticEnv.declarePassiveNamespace("jcr", "http://www.jcp.org/jcr/1.0", true);
          }

          Node contextNode = jcrSession.getRootNode();
          JCRDocumentWrapper document = new JCRDocumentWrapper(contextNode, "jcr:root", config);
          DynamicQueryContext dynamicEnv = new DynamicQueryContext(config);
          dynamicEnv.setContextItem(document);
          XQueryExpression expression = staticEnv.compileQuery(xquery);
          expression.run(dynamicEnv, reslt, SAXHelper.omitXmlDeclarationProp);

           
          • Michael Kay
            Michael Kay
            2008-10-21

            >But I need some help on how to programmatically register namespaces.

            // here I am doing something wrong
            staticEnv.declarePassiveNamespace("jcr", "http://www.jcp.org/jcr/1.0", true);

            The declarePassiveNamespaces() method is deprecated since 9.0, and the Javadoc says that the third argument must be "false". You should be using staticEnv.declareNamespace("jcr", "http://www.jcp.org/jcr/1.0");

            However, I'm having trouble seeing how this relates to the other problems on the thread. It helps to start a new thread for a new problem, and treat it as a completely new thread: that is, describe what you are doing and how it is failing from first principles. Otherwise, I've no idea whether you have changed things since you first described your scenario.

            Michael Kay

             
            • Ivan Latysh
              Ivan Latysh
              2008-10-23

              I found the issue, it was a bug in my code.

              Thank you.