3 Replies Latest reply on Jan 19, 2012 9:12 AM by rhauch

    Namespaces (namespace prefixes) broken in Modeshape 2.7.0?  Error converting String to a Name: b:test_6

    martin-senne

      Hi Randell, hi all,

      as far as I can tell, namespace support seems to be broken in Modeshape 2.7.0.

       

      For a valid session object I have set namespace

      setNamespacePrefix("b", "http://abc.com");

      and added some nodes named "b:test_1", "b:test_2", ... to the repository and called session.save() afterwards. Everything smooth up to that point.  Now, using the following code excerpt, I want to do a query with JQOM to retrieve the node named b:test_3

                  
                  // Obtain the query manager for the session ...
                  QueryManager queryManager = session.getWorkspace().getQueryManager();
                  // Create a query object model factory ...
                  QueryObjectModelFactory factory = queryManager.getQOMFactory();            
                  ValueFactory valueFactory = session.getValueFactory();
                  
                  // Create the FROM clause: a selector for the [nt:unstructured] nodes ...
                  Selector source = factory.selector("nt:unstructured", "unstructNodes");
                  // Create the SELECT clause (we want all columns defined on the node type) ...
                  Column[] columns = null;
                  
                  // Create the WHERE clause
                  Constraint constraint = null;
                  
                  // EXPLICITLY WANT PropertyType.Name
                  Value ourNodeName = valueFactory.createValue( filter.getValue().toString() , PropertyType.NAME );
                  // this fails either
                  // Value ourNodeName = valueFactory.createValue( filter.getValue().toString() );
                              
                  constraint = factory.comparison( 
                          // factory.nodeLocalName( "unstructNodes" ),
                          factory.nodeName( "unstructNodes" ),
                          QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO,
                          factory.literal( 
                              valueFactory.createValue( "b:test_3", PropertyType.NAME ) 
                          ) );
                  
                  // Define the orderings (we have none for this query)...
                  Ordering[] orderings = null;
                  // Create the query ...
                  QueryObjectModel query = factory.createQuery(source, constraint, orderings, columns);
                  if (log.isDebugEnabled()) {
                      log.debug("Query is '" + query + "'.");
                  }
      

      with the result :

      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule org.modeshape.jcr.query.RewritePseudoColumns@1e2c841
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule ReplaceViews
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule CopyCriteria
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule RightOuterToLeftOuterJoins
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule AddAccessNodes
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule PushSelectCriteria
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule PushProjects
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule RewriteAsRangeCriteria
      javax.jcr.RepositoryException: Error while performing the query "Access [unstructNodes]
        Project [unstructNodes]     Select [unstructNodes]       Select [unstructNodes]         Source [unstructNodes] " against the content in the "prod" workspace of the "__ALLNODES__" source: Error converting String to a Name: b:test_4
      
           at org.modeshape.jcr.query.qom.JcrAbstractQuery.checkForProblems(JcrAbstractQuery.java:133)
           at org.modeshape.jcr.query.JcrQuery.execute(JcrQuery.java:104)
      

       

      BUT performing the query via JCR_SQL2 (as follows) WORKS as expected:

                  
                  // Obtain the query manager for the session ...
                  QueryManager queryManager = session.getWorkspace().getQueryManager();
                  
                  // String stmt = "SELECT * FROM [nt:unstructured] WHERE NAME() = '" + filter.getValue().toString()+"'";
                  String stmt = "SELECT * FROM [nt:unstructured] WHERE NAME() = CAST('" + filter.getValue().toString()+ "' AS NAME)";
                  
                  Query query = queryManager.createQuery(stmt, Query.JCR_SQL2 );
                  
                  QueryResult result = query.execute();
                  if (log.isDebugEnabled()) {
                      log.debug("QueryResult is '" + result + "'.");
                  }
      

      with the result:

      | # | jcr:primaryType | jcr:path      | jcr:name     | jcr:score         | mode:localName | mode:depth | 
      +---+-----------------+---------------+--------------+-------------------+----------------+------------+
      | 1 | nt:unstructured | /ns001:test_4 | ns001:test_4 | 2.696368455886841 | test_4         | 1          |
      

       

      By the way, doing the query ( //b:test_6 ) via XPath also results in an RepositoryException

      DEBUG [main] (JcrNodeStore.java:304) - Query is : '//b:test_6'.
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule org.modeshape.jcr.query.RewritePseudoColumns@c5f468
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule CopyCriteria
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule RightOuterToLeftOuterJoins
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule AddAccessNodes
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule PushSelectCriteria
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule PushProjects
      DEBUG [main] (SLF4JLoggerImpl.java:110) - Running query optimizer rule RewriteAsRangeCriteria
      javax.jcr.RepositoryException: Error while performing the query "Access [nodeSet1]
        Project [nodeSet1]     Select [nodeSet1]       Source [nodeSet1] " against the content in the "prod" workspace of the "__ALLNODES__" source: Error converting String to a Name: b:test_6
      
           at org.modeshape.jcr.query.qom.JcrAbstractQuery.checkForProblems(JcrAbstractQuery.java:133)
           at org.modeshape.jcr.query.JcrQuery.execute(JcrQuery.java:104)
      

      Any help is appreciated and thanks alot.. Martin

        • 1. Re: Namespaces (namespace prefixes) broken in Modeshape 2.7.0?  Error converting String to a Name: b:test_6
          rhauch

          Thanks, Martin.

          For a valid session object I have set namespace

          setNamespacePrefix("b", "http://abc.com");
          

          and added some nodes named "b:test_1", "b:test_2", ... to the repository and called session.save() afterwards.

          Are you setting the namespace on the session or on the workspace's namespace registry? If you're just setting it on the session, then the namespace declaration is transient, is not persisted in the workspace, and is not available to other sessions. Often the session's namespaces are used to override (just for that session) the prefix of namespaces registered in the workspace.

           

          If you're setting it on the session, what happens if you register the namespace using the workspace's namespace registry?

           

              session.getWorkspace().getNamespaceRegistry().registerNamespace("b","http://abc.com");

           

          and then query using JQOM or XPath?

          • 2. Re: Namespaces (namespace prefixes) broken in Modeshape 2.7.0?  Error converting String to a Name: b:test_6
            martin-senne

            Hi Randall,

             

            1. many thanks for the fast respone

            2. your suggested solution to use

            session.getWorkspace().getNamespaceRegistry().registerNamespace("b", "http://abc.com");
            

            instead of

            session.setNamespacePrefix("b", "http://abc.com");
            

            did the trick!

            3. Nevertheless and according to reference docs at http://www.day.com/maven/jsr170/javadocs/jcr-2.0/javax/jcr/Session.html, especially

            setNamespacePrefix
            
            void setNamespacePrefix(java.lang.String prefix,
                                    java.lang.String uri)
                                    throws NamespaceException,
                                           RepositoryException
            
                Within the scope of this Session, this method maps uri to prefix. The remapping only affects operations done through this Session. To clear all remappings, the client must acquire a new Session.
            
                All local mappings already present in the Session that include either the specified prefix or the specified uri are removed and the new mapping is added.
            
                Parameters:
                    prefix - a string
                    uri - a string 
                Throws:
                    NamespaceException - if an attempt is made to map a namespace URI to a prefix beginning with the characters "xml" (in any combination of case) or if an attempt is made to map either the empty prefix or the empty namespace (i.e., if either prefix or uri are the empty string). 
                    RepositoryException - if another error occurs.
            
            

            this behavior seems not to be fine. Even if the namespace is transient for the session (via session.setNamespacePrefix), queries on this session should work. What do you think?

             

            Cheers,

             

            Martin

            • 3. Re: Namespaces (namespace prefixes) broken in Modeshape 2.7.0?  Error converting String to a Name: b:test_6
              rhauch

              I'm glad that solution worked.

               

              The session-scoped namespace mappings are definitely useful in some situations, but they also add a fair amount of complexity since they can cause unexpected problems. So IMO, they should be used only when necessary.

               

              Your case is actually an interesting one. It is absolutely possible to have a session contain a namespace mapping that is not in the (repository-wide) namespace registry, and it's even possible for content to use a namespace for which the (repository-wide) namespace registry has no mapping. ModeShape behaves correctly in this case w/r/t the content itself (since we actually use the namespace URI rather than the namespace prefix in persistent storage). But ModeShape uses the namespace prefix in its indexes, meaning queries are subject to the namespace mappings within the (repository-wide) namespace registry, and any namespace with a mapping in the session that is not in the (repository-wide) namespace registry causes query problems like yours.

               

              So in 2.x, the best way to get around this is to simply make sure that the (repository-wide) namespace registry contains all of the namespaces you're using, and using the Session namespaces to simply alter the prefixes. It's too complicated for us to change the indexing structure at this point, and it would require upgraders to re-index their content (which is something we try to avoid at almost all costs).

               

              In 3.0, we're changing the index structure and handling namespaces in a different way, so we should run into any of these problems and will not require the best-practice. (For those that care about the details, we're generating for each namespace in the global registry an internal, unique, and durable prefix that will never change. The indexed content will use these prefixes, the queries will be rewritten (internally) to use these prefixes, and the results will be translated back into the namespace of the session.)

               

              Hope that helps!