1 2 Previous Next 22 Replies Latest reply on Jan 23, 2013 3:49 PM by rhauch

    Getting a sequencer to engage?

    ajs6f

      Firstly, congratulations on a lovely piece of software! I've enjoyed my first time working with it for the last few days.

       

       

      I've run into a perplexing problem as I first try to engage the Sequencing Framework. I'm using 3.0.1.Final in a simple web-app with RESTEasy. I'm trying to introduce a sequencer that can disassemble some complex XML with particular semantics and build portions of the repository with the same semantics. And my problem is that for the life of me, I can't seem to get the sequencer to engage. I'm not worried about the action of the sequencer, because I can't get that far! {grin}

       

       

      I'm working with a Maven-built application that I'm tinkering with by means of 'mvn jetty:run'. For reference, the source code is available here:

       

       

      https://github.com/futures/ff-modeshape-prototype/tree/FOXML

       

       

      and the sequencer is here:

       

       

      https://github.com/futures/ff-modeshape-prototype/blob/FOXML/src/main/java/org/fcrepo/ffmodeshapeprototype/foxml/FOXMLSequencer.java

       

       

      I've written a sequencer that declares no default mediatypes. It has an 'execute' method that logs its execution, but that never happens. I inserted every possible form of path expression I could develop, and my current example looks like this:

       

       

         "sequencing" : {

              "removeDerivedContentWithOriginal" : true,

              "threadPool" : "modeshape-workers",

              "sequencers" : {

                  "FOXML Sequencer" : {

                      "description" : "FOXML Files loaded under 'fedora:/foxml' and extracted into 'fedora:/'",

                      "classname" : "org.fcrepo.ffmodeshapeprototype.foxml.FOXMLSequencer",

                      "pathExpressions" : ["fedora:/foxml/(*)/jcr:content[@jcr:data] => fedora:/$1"]

                  }

              }

       

       

      By inserting logging statements and exercising my JAXRS resources, I'm quite sure that I'm storing the XML in "fedora:/foxml/{somenode}/jcr:content@jcr:data", as expected. But the dang sequencer never executes. By logging statements and examination of the the configuration as parsed and used, I'm sure that the sequencer is being initialized.

       

       

      Am I missing something very obvious about the path expressions? I've tried every combination I can find of square bracket placement, adding or removing workspaces, and everything else.

       

       

      Thanks for any help-- ModeShape has been very fun to work with, and I'm really excited about using the sequencer functionality, which seems like an excellent extension to JCR semantics.

        • 1. Re: Getting a sequencer to engage?
          hchiorean

          Hi,

           

          Looking at fedora:/foxml/(*)/jcr:content[@jcr:data], I'm not sure just (*) works. Can you try changing it for example to something like "(*.xml)" and check if it works ?


          Also, does the initialize method get called on your sequencer ?

          • 2. Re: Getting a sequencer to engage?
            ajs6f

            Thanks for the help!

             

            Yes, the sequencer initializes (I see it log its initialization and I see it show up in a diagnostic that returns  repo.getConfiguration().getSequencing().getSequencers()).

             

            I have tried (*.xml) and (.*) and a few other variants, without success... I looked hard at the configuration in the modeshape-sequencers example, but I can't see where I'm going wrong.

            • 3. Re: Getting a sequencer to engage?
              hchiorean

              Your configuration looks ok. Is there any chance you can try 3.1.0.Final to see if this is still happening ?

               

              Unfortunatelly our sequencing code isn't "log friendly" atm (I've created an issue which will fix that) so using DEBUG or TRACE level logging won't help. Is there any chance you can debug the code and see what's happening ?

              The lines which trigger the sequencing are in the Sequencers class, lines #390 (for new nodes/properties) and #402 (for existing nodes/properties), while the SequencingRunner job is called from a separate thread to perform the acutal sequencing action.

               

              Something else you could test, is configuring a default sequencer and adding a test node to check if that sequencer is being fired.

              E.g. this  https://github.com/ModeShape/modeshape/blob/master/sequencers/modeshape-sequencer-images/src/test/resources/config/repo-config.json shows the cfg for the images sequencer

               

              Thanks

              • 4. Re: Getting a sequencer to engage?
                ajs6f

                No change in behavior from using 3.1.0.Final.

                 

                I will try rebuilding ModeShape with extra debugging, but it is going to take a while for me to get the chance. Right now I'm thinking I may have to just trigger the sequencer directly from the appropriate JAXRS resource, which means I can't use getLogger(), but at least it will execute.

                 

                I will first try installing a "stock" sequencer and confirm that it is functional.

                 

                Thanks for the help so far!

                • 5. Re: Getting a sequencer to engage?
                  ajs6f

                  Okay, this may be an important clue.

                   

                  I added:

                   

                  "Images in the same location" : {

                                  "classname" : "org.modeshape.sequencer.image.ImageMetadataSequencer",

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

                              }

                   

                  to the sequencers in my repository config and added modeshape-sequencer-images to my Maven dependencies. The seqencer apppars to exist (via the same diagnostic result as described above).

                   

                  I tried adding a resource at fedora:/foxml/test.jpg. I'm using JcrTools.uploadFile in a JAXRS resource to do it, and loading the file via curl with "Content-type: image/jpg", and... nothing. Nothing in the log to indicate that anything happened in the way of sequencing. I would think I should at least get a stack trace because the file is not a proper JPG.

                   

                  Am I missing some kind of obvious global setting to turn the sequencers on? I had thought they were on all the time to support ModeShape standard functionality like full-text indexing...

                   

                  Another possiblity: my sequencer config defines to use a thread pool "modeshape-workers". Removing this seems to have no effect, but I'm wondering if I need to have a particular setting here. Perhaps my sequencers are not getting executed because there are no threads to run them?

                  • 6. Re: Getting a sequencer to engage?
                    rhauch

                    I would try to put in the exact path of the node that you want to be sequenced, without any regular expressions. This will confirm that the sequencer works when given a valid path expression. For example:

                     

                         fedora:/a/b/c/d/e/foo.png/jcr:content[@jcr:data]

                     

                    Once that works, you can then work on the path expression and use wildcards and other reg-ex patterns.

                     

                    Also, can you just double check that you're loading the file into the "fedora" workspace?

                    • 7. Re: Getting a sequencer to engage?
                      ajs6f

                      Thanks to both of you for the help!

                       

                      I put a line in my JAXRS resource:

                       

                       

                      {code}

                      logger.debug("Storing to " + ws.getName() + ":" + foxmlpath);

                      {code}

                       

                      where ws is the workspace (from which I'm getting my Session) and foxmlpath is the path under which to store. The actually storage occurs with:

                       

                      {code}

                      final Node foxmlnode = jcrtools.uploadFile(session, foxmlpath, foxml);

                      {code}

                       

                      where foxml is the InputStream from the request body. For my test this produces:

                       

                      "Storing to fedora:/foxml/test.jpg"

                       

                      I changed the config to:

                       

                      {code}

                      "Images in the same location" : {

                                      "classname" : "org.modeshape.sequencer.image.ImageMetadataSequencer",

                                      "pathExpressions" : [ "fedora:/foxml/test.jpg/jcr:content[@jcr:data]" ]

                                  }

                      {code}

                       

                      and still... nothing. As I said, the request body isn't a legitimate JPG, so I would expect to see a stack trace of some kind. Incidentally, I do see the content stored and can retrieve it (via JAXRS)...

                      • 8. Re: Getting a sequencer to engage?
                        ajs6f

                        I just noticed some odd behavior in my application that might be another clue.

                         

                        I'm using the Maven Jetty plugin to run this application. That's how I've been doing testing. I haven't configuring any transaction managment, so at repository startup I see a lot of messages from GenericTransactionManagerLookup about trying to find transaction managers from various containers and not finding them, finishing with:

                         

                        WARN  o.i.t.l.GenericTransactionManagerLookup - ISPN000104: Falling back to DummyTransactionManager from Infinispan

                         

                        In my JAXRS resource, I have a PUT method that stores request material in a JCR node (the code about which this whole discussion has centered). In that code, if the node does not exist, it gets stored (no problem). If it does exist, I was doing a

                         

                         

                        {code}

                        if (session.hasPermission(foxmlpath, "remove")) {

                             logger.debug("Removing old FOXML file at" + foxmlpath); 

                             session.removeItem(foxmlpath);

                             //session.save();

                             logger.debug("Adding new FOXML file at" + foxmlpath);

                             final Node foxmlnode = jcrtools.uploadFile(session, foxmlpath, foxml);

                             session.save();

                        {code}

                        etc.

                        and it would fail because it couldn't add a same-name sibling in that location. When I uncomment the session.save(), it works. This puzzles me, beacuse I thought part of the semantics of JCR provided for the ability to use the Session for lightweight transactionality. I shouldn't (I thought) have to persist all my changes as I go-- I should be able to make several changes and then save, and provided my changes left the repository in a valid state, no problem. But it appears that I have to save after any change to have it be visible to subsequent operations in the same Session! A colleague of mine working on the same code found the same thing happening elsewhere.

                         

                        Is it possible that my weird "No sequencing for you, buddy!" problem is related to this? Do I need to engage some kind of transaction manager to have the sequencing work correctly and have session state operate as I expect?

                        • 9. Re: Getting a sequencer to engage?
                          rhauch

                          Your repository configuration file doesn't specify a "storage" section, which means:

                          1. your repository will be in-memory, never persisted to disk; and
                          2. your repository will use a default cache configuration

                           

                          So you probably want to create a configuration for Infinispan and reference it from your repository configuration. (We use an external ISPN configuration because we don't want to duplicate all of the configuration options in ISPN; it's far better to direclty use an Infinispan configuration file.) See our documentation.

                           

                          Now, the DummyTransactionManager is used because it cannot find a real transaction manager (Infinispan looks for several; that's what the "GenericTransactionManagerLookup" class does). This might be okay for testing, but you should really consider using a real transaction manager. (We are partial to JBoss Transaction Manager; we use it for our testing when we do want to use a real transaction manager). It's included as an optional dependency in our BOM for "embedded" use, so if you're using that all you have to do is add this dependency to your dependencies:

                           

                                      <dependency>

                                          <groupId>org.jboss.jbossts</groupId>

                                          <artifactId>jbossjta</artifactId>

                                      </dependency>

                           

                          No version is necessary, since that's defined in our BOM.

                           

                          You shouldn't have to issue the "session.save()" that is commented out. There may be a strange issue when using the JcrTools -- if you want to log an issue we'll look into it.

                           

                          However, you really shouldn't need to remove the item. JcrTools.uploadFile should update the "nt:file" node (and its child node named "jcr:content") if it already exists, or create the missing node(s) if they don't yet exist. Have you tried that? (I couldn't find the aforementioned code fragment in the code that you linked to in your first post.)

                          • 10. Re: Getting a sequencer to engage?
                            hchiorean

                            You shouldn't have to issue the "session.save()" that is commented out. There may be a strange issue when using the JcrTools -- if you want to log an issue we'll look into it.

                             

                            Afaik JcrTools#uploadFile does not call session.save(). This means that even though the node hierarchy is being created as a result of that method call, everything is transient until a session.save() is issued. This also explains why the sequencing doesn't get triggered.

                            • 11. Re: Getting a sequencer to engage?
                              ajs6f

                              Right-- I had understood that to be what was going on with the GenericTransactionManagerLookup. Having latched in your suggested dependency, that sequence of logging now finishes with:

                               

                              12:37:52.810 [qtp1743416060-27] INFO  o.i.t.l.JBossStandaloneJTAManagerLookup - ISPN000107: Retrieving transaction manager Transaction: unknown

                               

                              which I assume is good news.

                               

                              Unfortunately, nothing else changes. The code still fails with a javax.jcr.ItemExistsException without the extra save in place and sequencing is not triggered. The code is a little different than what is at Github because I've been trying different changes as you talk me through this problem, so let me include it here:

                               

                               

                              {code}

                              @PUT

                              @Path("/{filename}")

                              //@Consumes("text/xml")

                                        public Response addFOXML(@PathParam("filename") final String filename,

                                                            InputStream foxml) throws RepositoryException, IOException {

                               

                                                  final Session session = ws.getSession();

                                                  if (session.hasPermission("/foxml", "add_node")) {

                                                            final String foxmlpath = "/foxml/" + filename;

                                                            logger.debug("Storing to " + ws.getName() + ":" + foxmlpath);

                                                            if (!session.nodeExists(foxmlpath)) {

                                                              logger.debug("Adding new FOXML file at" + foxmlpath);

                                                                      final Node foxmlnode = jcrtools.uploadFile(session, foxmlpath,

                                                                                          foxml);

                                                                      session.save();

                                                                      return Response.created(URI.create(foxmlnode.getPath()))

                                                                                          .build();

                                                            } else {

                                                                      if (session.hasPermission(foxmlpath, "remove")) {

                                                                      logger.debug("Removing old FOXML file at" + foxmlpath);

                                                                                session.removeItem(foxmlpath);

                                                                        //session.save();

                                                                                logger.debug("Adding new FOXML file at" + foxmlpath);

                                                                                final Node foxmlnode = jcrtools.uploadFile(session,

                                                                                                    foxmlpath, foxml);

                                                                                session.save();

                                                                                return Response.created(URI.create(foxmlnode.getPath()))

                                                                                                    .build();

                                                                      } else return four01;

                                                            }

                                                  } else return four01;

                                        }

                               

                              {code}

                               

                              I'm sorry for the rotten cut-and-paste formatting. ws is a static member which is the 'fedora' workspace. As you can see, it's fairly simple, and to speak to Horla's point, there is a final session.save() happening in both cases, which is the point after which I would expect to see sequencing. It's the (commented-out above) session.save() that seems to be required after I remove the pre-existing resource that is odd. Incidentally, the occasion when my colleague found similar behavior did not involve JcrTools at all. It was all "manual" nodebuilding, but he saw the same thing-- extra saves required in between operations.

                               

                              To the persistence configuration: we have succesfully configured Infinispan to store to disk and to use pessimistic locking, but we didn't thikn it necessary for this simple code (which is being written just for the purpose of evaluating ModeShape). Perhaps we need to do that to get sequencing to work? Is it not possible to take advantage of that great feature with an in-memory store? We'd very much like to.

                               

                              ---

                               

                              Update:

                               

                              I've gone ahead and made use of the information Randall gave: that JcrTools.updateFile() uses findOrCreateNode() behind the scenes so that I don't have to test for pre-existence myself. This works and make the code considerably shorter (yay!).

                               

                              But still no sequencing. And I'm still confused by the behavior of Sessions as lightweight transactions.

                               

                              Thanks for the help so far!

                              • 12. Re: Getting a sequencer to engage?
                                rhauch

                                ajs6f wrote:

                                 

                                Right-- I had understood that to be what was going on with the GenericTransactionManagerLookup. Having latched in your suggested dependency, that sequence of logging now finishes with:

                                 

                                12:37:52.810 [qtp1743416060-27] INFO  o.i.t.l.JBossStandaloneJTAManagerLookup - ISPN000107: Retrieving transaction manager Transaction: unknown

                                 

                                which I assume is good news.

                                 

                                Yup, the "o.i.t.l.JBossStandaloneJTAManagerLookup" means that Infinispan has found it.

                                 

                                 

                                I'm sorry for the rotten cut-and-paste formatting. ws is a static member which is the 'fedora' workspace. As you can see, it's fairly simple, and to speak to Horla's point, there is a final session.save() happening in both cases, which is the point after which I would expect to see sequencing. It's the (commented-out above) session.save() that seems to be required after I remove the pre-existing resource that is odd. Incidentally, the occasion when my colleague found similar behavior did not involve JcrTools at all. It was all "manual" nodebuilding, but he saw the same thing-- extra saves required in between operations.

                                 

                                My suggestion was to do something like this, which will update the existing file in place:

                                 

                                 

                                @PUT
                                 @Path("/{filename}")
                                 //@Consumes("text/xml")
                                          public Response addFOXML(@PathParam("filename") final String filename,
                                                              InputStream foxml) throws RepositoryException, IOException {
                                
                                                    final Session session = ws.getSession();
                                                    if (session.hasPermission("/foxml", "add_node")) {
                                                              final String foxmlpath = "/foxml/" + filename;
                                                              logger.debug("Storing to " + ws.getName() + ":" + foxmlpath);
                                                              if (!session.nodeExists(foxmlpath)) {
                                                                logger.debug("Adding new FOXML file at" + foxmlpath);
                                                                        final Node foxmlnode = jcrtools.uploadFile(session, foxmlpath,
                                                                                            foxml);
                                                                        session.save();
                                                                        return Response.created(URI.create(foxmlnode.getPath()))
                                                                                            .build();
                                                              } else {
                                                                        if (session.hasPermission(foxmlpath, "remove")) {
                                                                          // ****** BEGIN CHANGES *******
                                                                          // Don't really need to remove the existing nodes; can just update in-place
                                                                          logger.debug("Replacing new FOXML file at" + foxmlpath);
                                                                          final Node foxmlnode = jcrtools.uploadFile(session,foxmlpath, foxml);
                                                                          session.save();
                                                                          return Response.created(URI.create(foxmlnode.getPath())).build();
                                
                                                                          // ****** END CHANGES *******
                                                                        } else return four01;
                                                              }
                                                    } else return four01;
                                          }
                                



                                Try that, and see if that works for you.

                                To the persistence configuration: we have succesfully configured Infinispan to store to disk and to use pessimistic locking, but we didn't thikn it necessary for this simple code (which is being written just for the purpose of evaluating ModeShape). Perhaps we need to do that to get sequencing to work? Is it not possible to take advantage of that great feature with an in-memory store? We'd very much like to.

                                No, you don't need the persistence for testing/evaluation; I just wanted to be sure you knew you needed to persist the data for (most) production uses. Plus, sequencing is completely independent of how/whether the content is persisted.

                                • 13. Re: Getting a sequencer to engage?
                                  rhauch

                                  Afaik JcrTools#uploadFile does not call session.save(). This means that even though the node hierarchy is being created as a result of that method call, everything is transient until a session.save() is issued. This also explains why the sequencing doesn't get triggered.

                                  If you look closely at the code, "session.save()" is called after the "JcrTools.uploadFile" method is called. I was referring to the "session.save()" before the "uploadFile" method that is commented out; this shouldn't be required, because "uploadFile" should be able to create the node after it was removed in the same session.

                                  • 14. Re: Getting a sequencer to engage?
                                    ajs6f

                                    See my update to my last message above-- that works very well for this example. But I'm still confused by the behavior of Session, and why I and my colleague required "too many saves". Could this be connected with the Infinispan configuration? Shouldn't it be independent of anything else in the system, since the behavior of Session is governed by the JCR semantics? It seemed very clear to me (and him) that a change made in a Session should be immediately visible to subsequent changes in the same Session, but not visible to other Sessions. But that doesn't seem to be the case for our (possibly strange) configuration. And has this behavior any connection to the mysterious absence of sequencing...?

                                    1 2 Previous Next