Main Content

Magnolia Community Forums: Development: Lock node issue for public users


  • gzalys
    gzalys
    Full name: Gediminas Zalys
    Posts: 27
    Last post: Nov 23, 2016 7:04:41 AM
    Registered on: Aug 13, 2015
    Lock node issue for public users
    #1 by gzalys on Sep 10, 2016 7:36:33 AM

    I ran into an issue when attempting to lock nodes using public users session, see sample code snippet bellow:

    Session session = MgnlContext.getJCRSession(CommonConstants.Repositories.DAM);
    Node root = session.getRootNode();
    Node test = JcrUtils.getOrAddNode(root, "test1", CommonConstants.NodeTypes.FOLDER);
    test.addMixin("mix:lockable");
    session.save();

    LockManager lock = session.getWorkspace().getLockManager();
    lock.lock(test.getPath(), false, true, 5000, MgnlContext.getUser().getIdentifier());
    Node test2 = JcrUtils.getOrAddNode(root, "test2", CommonConstants.NodeTypes.FOLDER);

    session.save();
    session.getWorkspace().getLockManager().unlock(test.getPath());



    Running this snippet will blow up with this error:


    javax.jcr.lock.LockException: Node locked.
    at org.apache.jackrabbit.core.lock.LockManagerImpl.checkLock(LockManagerImpl.java:694)
    at org.apache.jackrabbit.core.lock.LockManagerImpl.checkLock(LockManagerImpl.java:670)
    at org.apache.jackrabbit.core.lock.LockManagerImpl.checkLock(LockManagerImpl.java:655)
    at org.apache.jackrabbit.core.lock.XALockManager.checkLock(XALockManager.java:174)
    at org.apache.jackrabbit.core.ItemValidator.checkLock(ItemValidator.java:367)
    at org.apache.jackrabbit.core.ItemValidator.checkCondition(ItemValidator.java:288)
    at org.apache.jackrabbit.core.ItemValidator.checkModify(ItemValidator.java:248)
    at org.apache.jackrabbit.core.NodeImpl.checkSetProperty(NodeImpl.java:984)
    at org.apache.jackrabbit.core.NodeImpl$SetPropertyOperation.perform(NodeImpl.java:2047)
    at org.apache.jackrabbit.core.NodeImpl$SetPropertyOperation.perform(NodeImpl.java:2002)
    at org.apache.jackrabbit.core.session.SessionState.perform(SessionState.java:216)
    at org.apache.jackrabbit.core.NodeImpl.setProperty(NodeImpl.java:1924)
    at org.apache.jackrabbit.core.NodeImpl.setProperty(NodeImpl.java:1966)
    at info.magnolia.jcr.wrapper.DelegateNodeWrapper.setProperty(DelegateNodeWrapper.java:427)
    at info.magnolia.jcr.decoration.ContentDecoratorNodeWrapper.setProperty(ContentDecoratorNodeWrapper.java:229)
    at info.magnolia.jcr.wrapper.DelegateNodeWrapper.setProperty(DelegateNodeWrapper.java:427)
    at info.magnolia.jcr.decoration.ContentDecoratorNodeWrapper.setProperty(ContentDecoratorNodeWrapper.java:229)
    at info.magnolia.jcr.wrapper.DelegateNodeWrapper.setProperty(DelegateNodeWrapper.java:427)
    at info.magnolia.jcr.decoration.ContentDecoratorNodeWrapper.setProperty(ContentDecoratorNodeWrapper.java:229)
    at info.magnolia.audit.MgnlAuditLoggingContentDecoratorNodeWrapper.setProperty(MgnlAuditLoggingContentDecoratorNodeWrapper.java:190)
    at info.magnolia.jcr.util.NodeTypes$LastModified.update(NodeTypes.java:125)
    at info.magnolia.jcr.wrapper.MgnlPropertySettingContentDecorator$MgnlPropertySettingSessionWrapper.applyPendingChanges(MgnlPropertySettingContentDecorator.java:512)
    at info.magnolia.jcr.wrapper.MgnlPropertySettingContentDecorator$MgnlPropertySettingSessionWrapper.save(MgnlPropertySettingContentDecorator.java:502)
    at info.magnolia.jcr.wrapper.DelegateSessionWrapper.save(DelegateSessionWrapper.java:297)
    at info.magnolia.audit.MgnlAuditLoggingContentDecoratorSessionWrapper.save(MgnlAuditLoggingContentDecoratorSessionWrapper.java:82)
    at com.flavoryt.places.services.impl.AbstractAddPlaceService.addImage(AbstractAddPlaceService.java:202)
    at com.flavoryt.places.services.impl.DefaultAddPlaceService.addImage(DefaultAddPlaceService.java:206)
    at com.flavoryt.frontend.facades.impl.DefaultAddPlaceFacade.addImageForPlace(DefaultAddPlaceFacade.java:103)
    at com.flavoryt.frontend.controllers.PlacesController.addImageForPlace(PlacesController.java:163)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:777)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:706)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:943)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
    at info.magnolia.cms.filters.ServletDispatchingFilter.doFilter(ServletDispatchingFilter.java:148)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.filters.CompositeFilter.doFilter(CompositeFilter.java:65)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.VirtualUriFilter.doFilter(VirtualUriFilter.java:69)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.module.cache.executor.Bypass.processCacheRequest(Bypass.java:58)
    at info.magnolia.module.cache.executor.CompositeExecutor.processCacheRequest(CompositeExecutor.java:67)
    at info.magnolia.module.cache.filter.CacheFilter.doFilter(CacheFilter.java:174)
    at info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter.doFilter(OncePerRequestAbstractMgnlFilter.java:59)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.i18n.I18nContentSupportFilter.doFilter(I18nContentSupportFilter.java:74)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.RangeSupportFilter.doFilter(RangeSupportFilter.java:84)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.security.BaseSecurityFilter.doFilter(BaseSecurityFilter.java:57)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.security.SecurityCallbackFilter.doFilter(SecurityCallbackFilter.java:80)
    at info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter.doFilter(OncePerRequestAbstractMgnlFilter.java:59)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.security.LogoutFilter.doFilter(LogoutFilter.java:94)
    at info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter.doFilter(OncePerRequestAbstractMgnlFilter.java:59)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.MultiChannelFilter.doFilter(MultiChannelFilter.java:83)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.module.cache.filter.GZipFilter.doFilter(GZipFilter.java:73)
    at info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter.doFilter(OncePerRequestAbstractMgnlFilter.java:59)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:81)
    at info.magnolia.cms.security.auth.login.LoginFilter.doFilter(LoginFilter.java:127)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.UnicodeNormalizationFilter.doFilter(UnicodeNormalizationFilter.java:88)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.CosMultipartRequestFilter.doFilter(CosMultipartRequestFilter.java:87)
    at info.magnolia.cms.filters.OncePerRequestAbstractMgnlFilter.doFilter(OncePerRequestAbstractMgnlFilter.java:59)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.ContentTypeFilter.doFilter(ContentTypeFilter.java:148)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.ContextFilter.doFilter(ContextFilter.java:128)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.MgnlFilterChain.doFilter(MgnlFilterChain.java:79)
    at info.magnolia.cms.filters.CompositeFilter.doFilter(CompositeFilter.java:65)
    at info.magnolia.cms.filters.AbstractMgnlFilter.doFilter(AbstractMgnlFilter.java:85)
    at info.magnolia.cms.filters.SafeDestroyMgnlFilterWrapper.doFilter(SafeDestroyMgnlFilterWrapper.java:107)
    at info.magnolia.cms.filters.MgnlFilterDispatcher.doDispatch(MgnlFilterDispatcher.java:67)
    at info.magnolia.cms.filters.MgnlMainFilter.doFilter(MgnlMainFilter.java:108)
    at info.magnolia.cms.filters.MgnlMainFilter.doFilter(MgnlMainFilter.java:94)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:956)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:625)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:745)





    However if i execute same code as a superuser:

    return MgnlContext.doInSystemContext(new JCRSessionOp<Node>(CommonConstants.Repositories.DAM) {

    @Override
    public Node exec(Session session) throws RepositoryException {

    //Session session = MgnlContext.getJCRSession(CommonConstants.Repositories.DAM);
    Node root = session.getRootNode();
    Node test = JcrUtils.getOrAddNode(root, "test1", CommonConstants.NodeTypes.FOLDER);
    test.addMixin("mix:lockable");
    session.save();

    LockManager lock = session.getWorkspace().getLockManager();
    lock.lock(test.getPath(), false, true, 5000, MgnlContext.getUser().getIdentifier());
    Node test2 = JcrUtils.getOrAddNode(root, "test2", CommonConstants.NodeTypes.FOLDER);

    session.save();
    session.getWorkspace().getLockManager().unlock(test.getPath());
    return test2;
    }
    });


    It works perfectly, however this is not ideal as this approach ignores the access permissions per user...

    Do you have to be superuser to perform node locks ?

  • had
    had
    Full name: Jan Haderka
    Posts: 1,405
    Last post: Feb 6, 2017 1:59:05 PM
    Re: Lock node issue for public users
    #2 by had on Sep 15, 2016 8:28:31 AM

    No you don't have to be superuser. The code above seems to work just fine for me. Make sure your public user has write access to the repo tho.

    Few notes tho, spec says (17.3 Lock owner): "Strictly speaking it is the session, not the user, that owns a particular lock at a particular time" and later in same section "user will not automatically have the ability to alter the locked node if accessing it through another session". That might or might not be relevant depending on whether the above code was concatenation of code executed in different places or is ran verbatim.

    I've also noticed in that code that you are locking "test1" folder, but creating "test2" next to it. is that on purpose?
    As a side note, I was also wondering why to bother w/ locking at all? What does it guard here? First idea I had was that you are trying to copy content of the folder into another, but that would not be protected anyway because you are using shallow lock and not the deep one. You are not even protecting against removal of the "test1" since spec clearly states in multiple places that removal of a node is operation performed on it's parent (so in case of the example above, you would have to have locked the root node itself, which unfortunately is not lockable).

    And as a last remark, consider digging into spec section 17.10 Locks and Transactions - it seems like the ops in example above fits directly in when they describe as being of no consequence (due to all session ops being persisted only on safe and the fact that magnolia creates sessions per request and doesn't share them with multiple threads) ... unless of course the above is just a simplification of what you are really doing.

    HTH,
    Jan

  • gzalys
    gzalys
    Full name: Gediminas Zalys
    Posts: 27
    Last post: Nov 23, 2016 7:04:41 AM
    Registered on: Aug 13, 2015
    Re: Lock node issue for public users
    #3 by gzalys on Sep 20, 2016 12:29:16 PM

    Thanks Jan,

    Really good inputs and you definitely put me to the right direction, especially in regards to point 17.10, that taught me a lot!
    And yes, i see that my sample snippet is full of misleading errors, i was trying to make it simple but i think i over simplified it:S

    Another correction to my earlier point. This is an issue to any workspace not just DAM.

    Nonetheless, i do think there is a bug when it comes to performing locks by public users

    see "slightly" better code below:

    Session sess = MgnlContext.getJCRSession("dam");
    LockManager lock = sess.getWorkspace().getLockManager();

    Node one = NodeUtil.createPath(sess.getRootNode(), "one", "mgnl:folder", true);

    //NOTE: MgnlContext.getJCRSession("dam").getUserID() will return null if session is instantiated by public user.
    //sess.toString() give something like session-123 for public users and session-admin-123 for superuser (im using this as a workaround, when getting null for getUserID())
    String owner = StringUtils.defaultIfEmpty(sess.getUserID(), sess.toString());
    lock.lock(one.getPath(), true, true, 5000, owner);
    sess.save(); //saving the lock that has just been applied

    Node two = NodeUtil.createPath(one, "two", "mgnl:folder");
    sess.save(); //will EXPLODE here!!!!!!
    lock.unlock(one.getPath());


    As you can see in the code above i invoke the save() method which in turn invokes MgnlPropertySettingContentDecorator.save()
    in this save() method there is a line (line 498 if my decompiler is correct):
    Session sysSession = MgnlContext.getSystemContext().getJCRSession(workspaceName);

    This line is the culprit, as it creates new session, also it creates the session as an admin, which looks something like "session-admin-123"
    My previously created session (sess) had a name of session-123, see the difference?

    Then this save() method attempts to modify my node "two" to apply pending changes such as creation date etc...
    However it attempts to apply those changes using new session (session-admin-123), but my node is locked by session-123.

    which is why i get the error posted in my first post, stating that the node is locked:(
    -------------------------------------------------------------

    slight modification to my code such as
    FROM Session sess = MgnlContext.getJCRSession("dam");
    TO Session sess = MgnlContext.getSystemContext().getJCRSession("dam");

    solves the problem as my "sess" becomes session-admin-123, and later same session is retrieved by save() method..... but feels like a dirty workaround?...

    -------------------------------------------------------------
    To answer your question why use locking?
    well we have multiple instances of public, and DAM workspace is in clustered repository (shared between publics).
    Our public users can add images, and we store them in DAM, so we use locking to assure that two users dont modify same node at once...

    Once again, thanks for your support, any help is always appreciated!

    Best,
    Ged

You don't have the permission to post on this thread

Sign in

To login on this forum, you can use your Magnolia Forge, Support or Partner account, or, below, your Google, Yahoo! or OpenID account. If you have trouble logging in, or any other sort of issue, please let us know in the Meta forum, on the user-list, or simply by email at forum-admin at magnolia-cms dot com.

* Required

... or sign in with:

  • icon http://{your-openid-url}
  • icon
  • icon https://me.yahoo.com/