Announcement Announcement Module
Collapse

Spring Modules forum decommissioned in favor of Spring Extensions

As the Spring Modules project has been replaced by the Spring Extensions (http://www.springsource.org/extensions) project, this forum has been decommissioned in favour of Spring Extensions one at:
http://forum.springsource.org/forumdisplay.php?f=44

Please see the Spring Extensions home page for a complete list of current projects in Java, .NET and ActionScript. You can also propose one if you want.

Cheers,
Costin Leau
SpringSource - http://www.SpringSource.com- Spring Training, Consulting, and Support - "From the Source"
http://twitter.com/costinl
See more
See less
Questions about SpringModule's JCR implementation Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Questions about SpringModule's JCR implementation

    Hi,

    I was looking at the JCR support in Spring Modules and I've got two questions:

    1) While I'm fine using the SimpleCredentials for the moment, I'd eventually like to tie my JCR security to the Acegi security I've already got up and running (not all the application data can be stored in the JCR repository... some of it needs to go in a normal database). Has anyone got plans to work on this problem?

    2) JCR is a full Java spec, just like JDO. Is there any reason the implementation shouldn't be moved into the full springframework distribution? This would certainly raise its visibility and encourage others to work on it and maintain it (something I'm sure Costin doesn't plan to do for the rest of his life).

    Thanks for the info,

    Mark

  • #2
    One more question...

    The repository layout I have in mind will use a fair number of workspaces (1 per user, plus any number of shared repositories). I'm taking this approach because I expect that I will need to split the workspaces up into multiple repositories for performance reasons later on and its a lot easier to add a new JNDI location for a particular DAO than to redo the repository layout. All the code and documentation I've seen though seem to only allow a single session (and hence, a single workspace) to participate in the current transaction. Is there any way to get multiple sessions, each with a different workspace, and have all of them in the same transaction? Many of my transactions will also involve updating JDO-based objects stored in a traditional database.

    Thanks again,

    Mark

    Comment


    • #3
      While I'm fine using the SimpleCredentials for the moment, I'd eventually like to tie my JCR security to the Acegi security I've already got up and running (not all the application data can be stored in the JCR repository... some of it needs to go in a normal database). Has anyone got plans to work on this problem?
      Yup, I have worked briefly on an implementation and definitely we'll have some integration in the near future. I haven't done it yet since I'm busy at the moment working on the infrastructure and the jbpm 3.1 integration (which should be ready this week or the next one).
      I'd like to get a release out with the current code and then add new functionality.

      JCR is a full Java spec, just like JDO. Is there any reason the implementation shouldn't be moved into the full springframework distribution? This would certainly raise its visibility and encourage others to work on it and maintain it (something I'm sure Costin doesn't plan to do for the rest of his life).
      I'm can't give you a direct answer but Spring Modules is not a bad answer from the time being. Jackrabbit (the reference implementation) hasn't got a final release (0.9 just came out) and JCR in general while it's not widely used. I'm sure that if there will be interest in the Spring community, the JCR support will get more attention, will become more robust and, if there will be demand, it will get integrated into Spring. I'd love that

      All the code and documentation I've seen though seem to only allow a single session (and hence, a single workspace) to participate in the current transaction. Is there any way to get multiple sessions, each with a different workspace, and have all of them in the same transaction? Many of my transactions will also involve updating JDO-based objects stored in a traditional database.
      the session is bound by the repository and the workspace its working on. Normally, you can create global transaction that contains your sessions - it's just like using JTA with multiple datasources. Note that the current JCR specs do not cover transactions in-depth so there is no standard implementation.
      You can take a look at the JTA example for usage with a JTA TM.

      Comment


      • #4
        Multiple sessions attached to one transaction

        Originally posted by costin
        the session is bound by the repository and the workspace its working on. Normally, you can create global transaction that contains your sessions - it's just like using JTA with multiple datasources. Note that the current JCR specs do not cover transactions in-depth so there is no standard implementation.
        You can take a look at the JTA example for usage with a JTA TM.
        I'm not so concerned with creating a transaction, that's already done as soon as a request comes into the service level (users and permissions are stored using JDO, so a transaction must be active to allow Acegi to get them out of the UserDao). The transaction is committed at the end of the service request. What I'm concerned with is how do I get multiple sessions, each with a different workspace, to participate in that transaction. This is the part of the javadoc that has me confused:

        Originally posted by org.springmodules.jcr.TransactionAwareRepository
        As the Session returned depends on the workspace and credentials given, this implementation accepts a JcrSessionFactory as parameter (basically a wrapper for Repository, Credentials and Workspace properties). The proxy will check the parameters and proxy the Repository for sessions that are retrieved with the credentials and workspace name defined on the session factory. Sessions retrieved with different workspace, credentials are not proxied.
        Well, I only have one repository in my application (at the moment) so that makes me think I'll only end up with one of these objects. But according to the javadocs there, I'd only be able to get one transactional session, and all the rest would not be handled.

        In my thinking, it isn't the repository that is transactional, but the session. The session factory should have methods to get a session based on Credentials, Workspace, both, or neither (in which case some default wired-in setting would be used). If a session with that credentials/workspace combination already exists on the thread it is returned; if one does not exist, it is created and attached to the thread's transaction. Or have I misunderstood the docs?

        Mark

        Comment


        • #5
          Well, I only have one repository in my application (at the moment) so that makes me think I'll only end up with one of these objects. But according to the javadocs there, I'd only be able to get one transactional session, and all the rest would not be handled.

          In my thinking, it isn't the repository that is transactional, but the session. The session factory should have methods to get a session based on Credentials, Workspace, both, or neither (in which case some default wired-in setting would be used). If a session with that credentials/workspace combination already exists on the thread it is returned; if one does not exist, it is created and attached to the thread's transaction. Or have I misunderstood the docs?
          TransactionAwareRepository accepts a JcrSessionFactory as target and will proxy all calls that are executed against the session factory. As the session factory is defined by repository, workspace and credentials - the proxy will check the sessions for these - if they aren't met, a normal session will be retrieved.

          If you want to end up with only one TransactionAwareRepository for multiple workspaces then you can create multiple sessionFactories and multiple TransactionAwareRepositories over the same repository - basically you'll be creating a chain of TransactionAwareRepositories.

          Code:
          <bean id="factory1" class="org.springmodules.jcr.JcrSessionFactory">
               ....
               <property name="repository" ref="realRepository"/>
           </bean>
          
          <bean id="repository1" class="org.springmodules.jcr.TransactionAwareRepository">
            <property name="targetFactory" ref="factory1">
            </bean>   
          
          
          <bean id="factory2" class="org.springmodules.jcr.JcrSessionFactory">
              ....
              <property name="repository" ref="repository1"/>
          </bean>
          
          <bean id="repository2" class="org.springmodules.jcr.TransactionAwareRepository">
           <property name="targetFactory" ref="factory2">
           </bean>
          (I haven't checked the code above but it should illustrate my idea).
          The advantage is that you can control the settings for each workspace. If you are using the same settings then you should create a template/abstract declaration.

          P.S. I'll update the docs to clearify better the usage of this class.

          Comment


          • #6
            That class makes more sense now, but I think I've been asking the wrong question. I think what I should have been asking is this: How do I create multiple transaction-aware sessions dynamically (as in, within the code)?

            Based on what you've said, and what I've read in the code and documentation, would something like the following code work? What I'm hoping is that each of the sessions created in this process will be tied to the same transaction, so that any session.save() calls defer writing to the repository until the transaction is committing.

            Code:
            public List<Object> doSomethingInRepository( List<String> workspaces, Object param )
            {
                List<Object> results = new LinkedList<Object>();
                
                for( String workspace : workspaces )
                {
                    // Get credentials initialized someplace.
                    Credentials creds = getCredentials();
                    
                    // Get repository from Spring dependency injection; probably a
                    // JndiObjectFactoryBean that returns the raw javax.jcr.Repository
                    Repository repository = getRepository();
                    
                    JcrSessionFactory jsf =
                        new JcrSessionFactory( repository, workspace, creds );
                    
                    TransactionAwareRepository txRepository =
                        new TransactionAwareRepository();
                    txRepository.setAllowCreate( false );
                    txRepository.setAllowNonTxRepository( false );
                    txRepository.setTargetFactory( jsf );
                    txRepository.afterPropertiesSet();
                    
                    JcrTemplate jcrTemplate = new JcrTemplate( jsf );
                    
                    // Get the JCR Dao object that was configured with Spring dependency
                    // injection.
                    getMyJcrDao().setJcrTemplate( jcrTemplate );
                    
                    results.add( getMyJcrDao().doSomethingInWorkspace( param ) );
                }
                
                return( results );
            }
            In my app, the Credentials and Repository instances will be the same all the time, so they'll probably be configured with dependency injection. Some of my DAO classes will only want to deal with a single workspace and I'll be able to wire them as you described. But any DAO class related to data stored in a user-owned workspace will need to be able to handle accessing one or more of those workspaces in a single transaction, with everything done in with all the workspaces (reading and writing) covered by the same transaction; I won't be able to wire those classes at all.

            Also, something unrelated to my question: looking at how the other classes work, it might be nice to have a constructor for TransactionAwareRepository that allows the allowCreate, allowNonTxRepository, and targetFactory to be set (and then calls afterPropertiesSet automatically).

            Comment


            • #7
              First of all TransactionAwareRepository is a class that should be used with code that doesn't replies on the Spring integration. The code will run against a plain Repository which underneath will be aware of any transaction that is executed at the moment.
              If you are using JcrTemplate you should not worry about it - it is aware of any jcr session bound to the thread and thus it can participate in an on-going transaction.

              The key to your problem is the transaction manager and the JCR support for transactions. First of all there is no generic transaction support for the current jcr api and transaction support is available only inside the Jackrabbit(JR) implementation. JR exposes an XAResource which is used either by LocalTransactionManager or enlisted with the JTA TM (usually through the JCA connector). For your case you'll end up with multiple XAResources which have to be enlisted with a global transaction since each session has its own XAResource - the transaction roll back or commit will be propagated on each XAResource.
              There is a very primitive example of jta usage inside the distribution. Does this answer your question?

              Also, something unrelated to my question: looking at how the other classes work, it might be nice to have a constructor for TransactionAwareRepository that allows the allowCreate, allowNonTxRepository, and targetFactory to be set (and then calls afterPropertiesSet automatically).
              Probably I'll such a convenience constructor - usually I create constructors with small signatures and that contain object which are required for the class. For the rest of the general cases, the setter are better to use.

              Comment


              • #8
                Originally posted by costin
                The key to your problem is the transaction manager and the JCR support for transactions. First of all there is no generic transaction support for the current jcr api and transaction support is available only inside the Jackrabbit(JR) implementation. JR exposes an XAResource which is used either by LocalTransactionManager or enlisted with the JTA TM (usually through the JCA connector). For your case you'll end up with multiple XAResources which have to be enlisted with a global transaction since each session has its own XAResource - the transaction roll back or commit will be propagated on each XAResource.
                There is a very primitive example of jta usage inside the distribution. Does this answer your question?
                I think I understand better (again). I hadn't seen the sample code in the distribution, so thanks for pointing that out. It'll be a big help, especially because I'm probably going to have to use JTA transactions to synchronize the JDO and JCR transactions. My biggest concern now is the conflicting posts I'm seeing about JTA support in PostgreSQL; some say there's no XA support, but PostgreSQL seems to have some support, but maybe it doesn't actually support 2 phase commits (which is what I think I'm looking for here). In any case, I'll be happy when this is all sorted out because its getting to be a huge headache.

                Originally posted by costin
                First of all TransactionAwareRepository is a class that should be used with code that doesn't replies on the Spring integration. The code will run against a plain Repository which underneath will be aware of any transaction that is executed at the moment.
                If you are using JcrTemplate you should not worry about it - it is aware of any jcr session bound to the thread and thus it can participate in an on-going transaction.
                So that means, in my code example, I can just delete the TransactionAwareRepository and the JcrTemplate I'm creating will find and attach to the existing transaction?

                Thanks for being patient with me in all this. Once I feel like I understand it well enough, I'd be happy to contribute some time to the documentation.

                Comment


                • #9
                  So that means, in my code example, I can just delete the TransactionAwareRepository and the JcrTemplate I'm creating will find and attach to the existing transaction?
                  Yes, see the samples. Btw, there is already some documentation for JCR - it's in docbook format and you have to generate it yourself. There are instructions on how to do that inside the projects/common-build. Just run ant doc (I think, you'll have to double check).
                  I'm trying to get a nice, public release for the actual code asap.

                  Comment


                  • #10
                    1) While I'm fine using the SimpleCredentials for the moment, I'd eventually like to tie my JCR security to the Acegi security I've already got up and running (not all the application data can be stored in the JCR repository... some of it needs to go in a normal database). Has anyone got plans to work on this problem?
                    Can you please raise an issue on jira (under Spring Modules project)? This way, the idea will not be lost. Add also what exactly would like to see - feedback and ideas are always welcomed. Thanks.

                    Comment

                    Working...
                    X