cancel
Showing results for 
Search instead for 
Did you mean: 

Transaction must be active and synchronization is required

mliedtke
Champ in-the-making
Champ in-the-making
Hi,
I'm getting an error when trying to deploy a webscript in liferay. 

I'm using LifeRay 4.4.1 with Alfresco 2.1.1 deployed as a portlet on JBoss 4.2, and when I include any of the out of the box WebScrips portlets I get the following error.


The Web Script /alfresco/168s/ui/myspaces has responded with a status of 500 - Internal Error.

500 Description:   An error inside the HTTP server which prevented it from fulfilling the request.

Message:   Transaction must be active and synchronization is required

Exception:   org.alfresco.error.AlfrescoRuntimeException - Transaction must be active and synchronization is required
   
   org.alfresco.repo.transaction.AlfrescoTransactionSupport.registerSynchronizations(AlfrescoTransactionSupport.java:389)
   org.alfresco.repo.transaction.AlfrescoTransactionSupport.getSynchronization(AlfrescoTransactionSupport.java:374)
   org.alfresco.repo.transaction.AlfrescoTransactionSupport.bindDaoService(AlfrescoTransactionSupport.java:237)
   org.alfresco.repo.transaction.TransactionalDaoInterceptor.invoke(TransactionalDaoInterceptor.java:66)
   org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
   org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
   $Proxy306.getNode(Unknown Source)
   org.alfresco.repo.node.db.DbNodeServiceImpl.exists(DbNodeServiceImpl.java:166)
   sun.reflect.GeneratedMethodAccessor312.invoke(Unknown Source)
   sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   java.lang.reflect.Method.invoke(Method.java:597)
   org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:281)
   org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:187)
   org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:154)
   org.alfresco.repo.transaction.TransactionResourceInterceptor.invoke(TransactionResourceInterceptor.java:129)
   org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:176)
   org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:210)
   $Proxy308.exists(Unknown Source) […]


One curious thing to note though if I access the portlet directly (ie not through the liferay portal container) with the URL "http://server.domain.com:8080/alfresco/168s/ui/myspaces" I can see it properly.  I'm hoping that I just missed something small, but I'm lost

If anyone has any clues on this please help

Thanks,
Mark
14 REPLIES 14

mliedtke
Champ in-the-making
Champ in-the-making
I started pulling apart the code, and there seems to be an issue with the authenticator "org.alfresco.web.scripts.portlet.WebClientPortletAuthenticator". 

It's able to find the user on the request, and appears to be authenticating the user ok, but then when it attempts to get a NodeRef for the person object it craps out. 

It looks like the last part of the authenticator where it puts the user object on the session is ( in the methog createWebClientUser(PortletSession session) ) is crapping out. 

If anyone has any ideas, please write back, I'm lost 
:?:

mliedtke
Champ in-the-making
Champ in-the-making
A little more info…

More specifically it looks like the issue is with PersonServiceImpl.getPersonOrNul(user)

As far as I can tell it's getting a Null Pointer when trying to perform a search for the user…It looks like the SearchService is null, so when it tries to query the user it is crapping out….

Any clues?

mliedtke
Champ in-the-making
Champ in-the-making
Well Some more info…I'm hoping someone will be able to help…

It looks like the scriptContext (org.alfresco.web.scripts.context.WebScriptContext) that is included in the WebClientPortletAuthenticator is not fully initialized or something…

I've looked at it, and it seems like any call against it (except toString like calls) are causing this error.  To me it seems like the services used by this bean are not properly set or something. 

I got nothing here…Please help  :?

pmonks
Star Contributor
Star Contributor
Is this a standard installation of Alfresco, or are you trying to embed it in your own application?

If the former, the symptoms you're describing sound like a basic problem with the installation which are probably most easily corrected by installing again from scratch.

lucien2046
Champ in-the-making
Champ in-the-making
I have the same problem with Alfresco 2.9B and Liferay 4.4.1.  Haven't been able to figure out what it is yet …

lucien2046
Champ in-the-making
Champ in-the-making
Seems there was an issue in 2.1.1E that was fixed in 2.1.2E:
http://issues.alfresco.com/browse/AWC-1686

The fix may not have made it into 2.9B

mliedtke
Champ in-the-making
Champ in-the-making
Excellent, thanks for finding this.

Yesterday (actually the last 3 days) I ended up re-writing the Auth Handler WebClientPortletAuthenticator to bypass using the scriptContext to get the person, and directly get the PersonService bean from the application context.  This was a little goofy though because it was a little tricky to get the app context from the portlet context.  I ended up needing to use PortletApplicaitonContextUtils in the spring-portlet.jar  to get the application context from the portlet context.  Its a bit of a cludge, but it's getting me moving until the fix gets pushed.

mliedtke
Champ in-the-making
Champ in-the-making
here's the class code i created…It's kind of messy, and requires adding spring-portlet.jar


/*
* Bassed off of org.alfresco.web.scripts.portlet.WebClientPortletAuthenticator
*
* Sets and gets the Authenticated user directly off the session rather then the
* application scope of the session.
*
*
*/
package com.tca.authentication;

import javax.portlet.PortletSession;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.security.AuthenticationService;
import org.alfresco.web.app.servlet.AuthenticationHelper;
import org.alfresco.web.bean.repository.User;
import org.alfresco.web.scripts.WebScriptContext;
import org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

// TCA Added
import javax.portlet.PortletContext;

import org.alfresco.web.scripts.portlet.WebScriptPortletAuthenticator;
import org.alfresco.web.scripts.portlet.WebScriptPortletRequest;
import org.alfresco.service.cmr.security.PersonService;
import org.alfresco.service.cmr.repository.NodeService;

import org.springframework.context.ApplicationContext;
import org.springframework.web.portlet.context.PortletApplicationContextUtils;



/**
* Portlet authenticator which synchronizes with the Alfresco Web Client authentication
*
* @author davidc
*/
public class WebClientPortletAuthenticator implements WebScriptPortletAuthenticator
{
    // Logger
    private static final Log logger = LogFactory.getLog(WebClientPortletAuthenticator.class);

    // dependencies
    private AuthenticationService authenticationService;
    private WebScriptContext scriptContext;
     
    /**
     * @param authenticationService
     */
    public void setAuthenticationService(AuthenticationService authenticationService)
    {
        this.authenticationService = authenticationService;
    }
   
    /**
     * @param scriptContext
     */
    public void setScriptContext(WebScriptContext scriptContext)
    {
        this.scriptContext = scriptContext;
    }
   
    /* (non-Javadoc)
     * @see org.alfresco.web.scripts.portlet.WebScriptPortletAuthenticator#authenticate(org.alfresco.web.scripts.WebScriptDescription.RequiredAuthentication, boolean, javax.portlet.RenderRequest, javax.portlet.RenderResponse)
     */
    public boolean authenticate(RequiredAuthentication required, boolean isGuest, RenderRequest req, RenderResponse res)
    {
       logger.debug("Starting authenticate - RequiredAuthentication: " + required + " - isGuest: " + isGuest);
       logger.debug("Using authentication service: " +authenticationService);
       
       
       PortletSession session = req.getPortletSession();
       
        // first look for the username key in the session - we add this by hand for some portals
        // when the WebScriptPortletRequest is created
        String portalUser = (String)req.getPortletSession().getAttribute(WebScriptPortletRequest.ALFPORTLETUSERNAME);
        logger.debug("User Name from request: "+portalUser);
       
        if (portalUser == null)
        {
            portalUser = req.getRemoteUser();
            logger.debug("User Name from session: "+portalUser);
        }
       
        if (logger.isDebugEnabled())
        {  
            logger.debug("JSR-168 Remote user: " + portalUser);
        }
       
        if (isGuest || portalUser == null)
        {
            if (logger.isDebugEnabled())
                logger.debug("Authenticating as Guest");
           
            // authenticate as guest
            AuthenticationUtil.setCurrentUser(AuthenticationUtil.getGuestUserName());

            if (logger.isDebugEnabled())
                logger.debug("Setting Web Client authentication context for guest");
           
            createWebClientUser(session);
            removeSessionInvalidated(session);
        }
        else
        {
            if (logger.isDebugEnabled())
                logger.debug("Authenticating as user " + portalUser);
           
            AuthenticationUtil.setCurrentUser(portalUser);

            // determine if Web Client context needs to be updated
            User user = getWebClientUser(session);
            if (user == null || !portalUser.equals(user.getUserName()))
            {
                if (logger.isDebugEnabled())
                    logger.debug("Setting Web Client authentication context for user: " + portalUser);
               
                createWebClientUser(session);
                removeSessionInvalidated(session);
            }
        }
       
        return true;
    }

    /**
     * Helper.  Remove Web Client session invalidated flag
     *
     * @param session
     */
    private void removeSessionInvalidated(PortletSession session)
    {
       if (logger.isDebugEnabled())
        {  
            logger.debug("Invalidating session:  " + AuthenticationHelper.SESSION_INVALIDATED);
        }
        //session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED, PortletSession.APPLICATION_SCOPE);
        session.removeAttribute(AuthenticationHelper.SESSION_INVALIDATED);
    }
   
    /**
     * Helper.  Create Web Client session user
     *
     * @param session
     */
    private void createWebClientUser(PortletSession session)
    {
       try{
          String loginUser = authenticationService.getCurrentUserName();
          String loginTicket = authenticationService.getCurrentTicket();
          if (logger.isDebugEnabled())
           {  
               logger.debug("Starting createWebClientUser for user: " + loginUser + " and ticket " + loginTicket);
           }
                 
          PortletContext portletContext = session.getPortletContext();
          if (logger.isDebugEnabled())
             logger.debug("##portletContext " + portletContext);
          
          ApplicationContext appContext = PortletApplicationContextUtils.getRequiredWebApplicationContext(portletContext);
          if (logger.isDebugEnabled())
                logger.debug("##appContext " + appContext);
          
          PersonService personService = (PersonService)appContext.getBean("personService");
          if (logger.isDebugEnabled())
             logger.debug("##personService " + personService);
          
          NodeService nodeService = (NodeService)appContext.getBean("nodeService");
          if (logger.isDebugEnabled())
             logger.debug("##nodeService " + nodeService);
                    
           NodeRef personRef = personService.getPerson(loginUser);
          
          if (logger.isDebugEnabled())
           {  
               logger.debug("##Successfully retrieved person reference: " + personRef);
           }
          
          User user = new User(loginUser, authenticationService.getCurrentTicket(), personRef);
          
          if (logger.isDebugEnabled())
           {  
               logger.debug("##Successfully created the user: " + user);
               logger.debug("##Setting on session: " + session);
           }
          
          //session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user, PortletSession.APPLICATION_SCOPE);
          session.setAttribute(AuthenticationHelper.AUTHENTICATION_USER, user);
          
          if (logger.isDebugEnabled())
           {  
               logger.debug("Successfully set the user on the session ###");
           }
       }
       catch(Exception e)
       {

          logger.error("Error in createWebClientUser: " + e.toString());
          e.printStackTrace();

       }
    }
   
    /**
     * Helper.  Get Web Client session user
     *
     * @param session
     * @return
     */
    private User getWebClientUser(PortletSession session)
    {
       if (logger.isDebugEnabled())
        {  
            logger.debug("Getting the user from the session:  " + AuthenticationHelper.AUTHENTICATION_USER);
        }
       /* Removed and get globally at the session
        * return (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE);
        */
        //return (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER, PortletSession.APPLICATION_SCOPE);
        return (User)session.getAttribute(AuthenticationHelper.AUTHENTICATION_USER);
    }
   
}

dvignola
Champ in-the-making
Champ in-the-making
I have the same problem with Alfresco 2.9B and Liferay 4.4.1.  Haven't been able to figure out what it is yet …

I'm trying to integrate Alfresco Community 2.9B in Liferay 5.0.1 and, sadly, I have encountered the same "Transaction must be active and synchronization is required" error using Alfresco Portlets.

Is there in this forum anyone that have just implemented some workaround to go ahed in the Alfresco-Liferay Integration? I think about some peudo-sso mechanisms that allow a Liferay logged user to access Alfresco portlet avoiding a second (Alfresco) login. No matter if is not the same logical user (a real user management integration between Liferay and Alfresco seems still far) but an Alfresco recognized (and granted) user is enough.

Thanks a lot for contribution

Davide Vignola