7 Replies Latest reply on Mar 29, 2013 5:34 AM by Horia Chiorean

    Adding sequencer output to the same "nt:file" nodes

    m.sarhan Newbie

      Hi,

       

      I'm trying to upload an image file to Modeshape repository using JcrTools::uploadFile(session, path, stream) under a pre-created nt:folder node.

      At the same time, I need to benifit from the nice feature "Sequencers" to extract image's metadata and add them to the stored nt:file node:

       

      I'm using Modeshape 3.1.3 with the folowing image sequencer config:

       

      ...

      "images": {

           "name": "Images",

           "classname": "image",

           "pathExpressions": ["//(*.(gif|png|jpg))/jcr:content[@jcr:data]"]

      }

      ...

       

      Unfortunately, this is not working as the Sequencer tries to add "image:metadata" as a sub node under "nt:file" which is not allowed in JCR.

       

      So:

      1. How I can tell the sequencer to add this metadata as mixins to the nt:file not as a sub node?
      2. If 1) is N/A, what is the best way to achive this using sequencer's output, so I can fetch image file information from "nt:file" and "image:metadata"?
      3. Is it OK if I create a new Node Type as follows: [mynt:file] > nt:file, nt:unstructured, and use it for storing files, so the sequencer will be able to add metadata as a sub node to the image file? what could be the side effect for this solution?

       

      Thanks,

        • 1. Re: Adding sequencer output to the same "nt:file" nodes
          Horia Chiorean Master

          When working with sequencers, the preferred configuration is to also use an output path, for example:

          default://(*.(jpg|jpeg|gif|bmp|pcx|png))/jcr:content[@jcr:data] => default:/images/$1

          or

          default://(*.(jpg|jpeg|gif|bmp|pcx|png))/jcr:content[@jcr:data] => default:/sequenced/images

           

          The reason why this is preferred, is that as you've noticed, each sequencer uses its own custom types when it generates the output and without an output path in the expression, it would try to add the content directly under the sequenced node (like in your case).

          See https://docs.jboss.org/author/display/MODE/Sequencing for more information.

           

          Regarding option (3) - if you wanted to create your own node type and not specify an output path, you need to make sure:

          a) you don't use JcrTools anymore - because that can only use the "nt:file" type

          b) you extend nt:file  (like you suggested) and you either use nt:unstructured  or you create a mixin, which accepts image:metadata children.

           

          In general, it's always better to use mixins as opposed to multiple ("hard-type") inheritance, because it offers a lot more flexibilty.

          1 of 1 people found this helpful
          • 2. Re: Adding sequencer output to the same "nt:file" nodes
            m.sarhan Newbie

            Thanks Horia,

             

            I've tried to go with your recommendation by using sequencer output,

             

            Now, I want to query uploaded image files along with sequencer output with the following JCR-SQL2 statements:

             

             

            select * from [mode:derived] AS d where d.[mode:derivedFrom] IN (select [jcr:path] from [nt:resource] AS r)
            

            Results:

                 Empty result set

             

             

            select * from [image:metadata] AS img
            JOIN [mode:derived] AS d on ISSAMENODE(img, d)
            JOIN [nt:resource] AS r on d.[mode:derivedFrom]=r.[jcr:path]
            

            Results:

                 Exception: Equi-join condition using one 'jcr:path' column is not valid: expected "... [d].[jcr:path] = [r].[jcr:path] ..."

             

             

            select * from [image:metadata] AS img
            JOIN [mode:derived] AS d on ISSAMENODE(img, d)
            JOIN [nt:resource] AS r on r.[jcr:path] = '/Folder1/Penguins.jpg/jcr:content'
            

            Results:

                 Exception: is not well-formed: No more content, but was expecting '.'

            Static operand seems to be not allowd on equi-join conditions

             

             

            So, how I can achive such result?

            • 3. Re: Adding sequencer output to the same "nt:file" nodes
              Horia Chiorean Master

              First, a couple of notes:

              - indexing of new nodes is done asynchronously (like sequencing for that matter), so executing a query directly after sequencing might not find any results. If you really need to find results directly afterwards, you should implement your code in a similar fashion to:

              https://github.com/ModeShape/modeshape/blob/master/modeshape-jcr-api/src/main/java/org/modeshape/jcr/api/JcrTools.java#L656

              - the mode:derived mixin is only added to sequenced nodes when an ouput path is specified. In other words, the mixin is only added if you sequence in another location, this because its only purpose is to allow linking between original/sequenced node.

               

              Regarding the Equi-Join condition: [jcr:path] *is not* a jcr property defined on any node (from the standard built-in types). Rather, it's a pseudo-property added by ModeShape to enhance queries (see https://docs.jboss.org/author/display/MODE/JCR-SQL2). If you want to perform an equi-join on [jcr:path] you need to make sure that both operands use this property (i.e. a.[jcr:path] = b.[jcr:path]). You cannot use a [jcr:path] (pseudo property) on one side and a [mode:derivedFrom] (which is a real, cnd property) on the other side.

               

              In your case, assuming that content has been indexed and you want to find the sequenced node based on an input node (for which you know the path), you can use a query like: select [jcr:path] from [mode:derived] as d where d.[mode:derivedFrom] = ''/filepath/jcr:content'

              • 4. Re: Adding sequencer output to the same "nt:file" nodes
                m.sarhan Newbie

                Ok, so there is no way to join original nodes with sequenced nodes in one JCR-SQL2 statement with properties from both?

                 

                I think the only way is to use WHERE IN(...) condition like the following statement:

                 

                 

                select r.[jcr:path], r.[jcr:score], r.[jcr:lastModified], r.[jcr:lastModifiedBy] from [nt:resource] AS r where PATH() in(
                     select d.[mode:derivedFrom] 
                     from [mode:derived] AS d 
                     join [image:metadata] as img on ISSAMENODE(img, d) 
                     where img.[image:formatName]='JPEG'
                )
                

                 

                Is there any other way?

                • 5. Re: Adding sequencer output to the same "nt:file" nodes
                  Horia Chiorean Master

                  I'm not sure I understand what nodes you're trying to retrieve. The files that were "uploaded" ?

                  • 6. Re: Adding sequencer output to the same "nt:file" nodes
                    m.sarhan Newbie

                    Actually, I want to retrieve properties from both nodes(original and sequenced) in one statement.

                    But I'm not able to join [nt:resource] and [mode:derived] node types

                    • 7. Re: Adding sequencer output to the same "nt:file" nodes
                      Horia Chiorean Master

                      Hmm... I'm not sure there is an easy way to get all the results you want with just 1 query (maybe Randall Hauch can help better, he's the author of the query subssystem).

                       

                      If I had to try, I would maybe do something like this (note that i'm using nt:unstructured and just the jcr:path property):

                       

                           select [jcr:path] from [nt:unstructured] as r where r.[jcr:path] in (select d.[mode:derivedFrom] from [mode:derived] as d)

                           union

                           select [jcr:path] from [mode:derived] as d where d.[mode:derivedFrom] in (select u.[jcr:path] from [nt:unstructured] as u)

                       

                      Basically I'm selecting in 2 different queries, first the sources of the sequencing and then the sequenced output and joining them together.

                       

                      Maybe it would be easier to achieve what you're after using 2 separate queries, itering the results and "joining them" via code ?