Package org.jasig.portal.portlet.registry

Source Code of org.jasig.portal.portlet.registry.PortletEntityRegistryImpl

/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on
* an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.jasig.portal.portlet.registry;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.regex.Pattern;

import javax.portlet.WindowState;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.Validate;
import org.jasig.portal.EntityIdentifier;
import org.jasig.portal.IUserPreferencesManager;
import org.jasig.portal.PortalException;
import org.jasig.portal.layout.IUserLayoutManager;
import org.jasig.portal.layout.dao.IStylesheetDescriptorDao;
import org.jasig.portal.layout.node.IUserLayoutChannelDescription;
import org.jasig.portal.layout.node.IUserLayoutNodeDescription;
import org.jasig.portal.layout.node.IUserLayoutNodeDescription.LayoutNodeType;
import org.jasig.portal.layout.om.IStylesheetDescriptor;
import org.jasig.portal.portlet.dao.IPortletEntityDao;
import org.jasig.portal.portlet.dao.jpa.PortletPreferenceImpl;
import org.jasig.portal.portlet.om.IPortletDefinition;
import org.jasig.portal.portlet.om.IPortletDefinitionId;
import org.jasig.portal.portlet.om.IPortletDefinitionParameter;
import org.jasig.portal.portlet.om.IPortletDescriptorKey;
import org.jasig.portal.portlet.om.IPortletEntity;
import org.jasig.portal.portlet.om.IPortletEntityId;
import org.jasig.portal.portlet.om.IPortletPreference;
import org.jasig.portal.portlet.om.IPortletType;
import org.jasig.portal.portlet.om.IPortletWindowId;
import org.jasig.portal.portlet.om.PortletLifecycleState;
import org.jasig.portal.security.IAuthorizationPrincipal;
import org.jasig.portal.security.IPerson;
import org.jasig.portal.services.AuthorizationService;
import org.jasig.portal.url.IPortalRequestUtils;
import org.jasig.portal.user.IUserInstance;
import org.jasig.portal.user.IUserInstanceManager;
import org.jasig.portal.utils.ConcurrentMapUtils;
import org.jasig.portal.utils.web.PortalWebUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException;
import org.springframework.stereotype.Service;
import org.springframework.web.util.WebUtils;

import com.google.common.base.Function;

/**
* Provides access to IPortletEntity objects and convenience methods for creating
* and converting them and related objects.
*
* The portlet adaptor channel will be responsible for listenting to unsubscribe events and cleaning up entity objects
*
* @author Eric Dalquist
* @version $Revision$
*/
@Service
public class PortletEntityRegistryImpl implements IPortletEntityRegistry {
    static final char ID_PART_SEPERATOR = '_';
    static final Pattern ID_PART_SEPERATOR_PATTERN = Pattern.compile(Pattern.quote(String.valueOf(ID_PART_SEPERATOR)));
   
    static final char DELEGATE_LAYOUT_NODE_ID_SEPERATOR = '-';
    static final String DELEGATE_LAYOUT_NODE_ID_PREFIX = "dlg" + DELEGATE_LAYOUT_NODE_ID_SEPERATOR;
   
    static final String PORTLET_ENTITY_DATA_ATTRIBUTE = PortletEntityRegistryImpl.class.getName() + ".PORTLET_ENTITY_DATA";
    static final String PORTLET_ENTITY_ATTRIBUTE = PortletEntityRegistryImpl.class.getName() + ".PORTLET_ENTITY.thread-";
    static final String PORTLET_ENTITY_LOCK_MAP_ATTRIBUTE = PortletEntityRegistryImpl.class.getName() + ".PORTLET_ENTITY_LOCK_MAP_ATTRIBUTE";
    static final String PORTLET_DEFINITION_LOOKUP_MAP_ATTRIBUTE = PortletEntityRegistryImpl.class.getName() + ".PORTLET_DEFINITION_LOOKUP_MAP_ATTRIBUTE";
   
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
   
    private IUserInstanceManager userInstanceManager;
    private IPortletEntityDao portletEntityDao;
    private IPortletDefinitionRegistry portletDefinitionRegistry;
    private IPortalRequestUtils portalRequestUtils;
    private IStylesheetDescriptorDao stylesheetDescriptorDao;
    private Ehcache entityIdParseCache;

    @Autowired
    public void setStylesheetDescriptorDao(IStylesheetDescriptorDao stylesheetDescriptorDao) {
        this.stylesheetDescriptorDao = stylesheetDescriptorDao;
    }
    @Autowired
    public void setEntityIdParseCache(@Qualifier("org.jasig.portal.portlet.dao.jpa.PortletEntityImpl.idParseCache") Ehcache entityIdParseCache) {
        this.entityIdParseCache = entityIdParseCache;
    }
    @Autowired
    public void setUserInstanceManager(IUserInstanceManager userInstanceManager) {
        this.userInstanceManager = userInstanceManager;
    }
    @Autowired
    public void setPortletEntityDao(@Qualifier("transient") IPortletEntityDao portletEntityDao) {
        this.portletEntityDao = portletEntityDao;
    }
    @Autowired
    public void setPortletDefinitionRegistry(IPortletDefinitionRegistry portletDefinitionRegistry) {
        this.portletDefinitionRegistry = portletDefinitionRegistry;
    }
    @Autowired
    public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) {
        this.portalRequestUtils = portalRequestUtils;
    }
   
    /* (non-Javadoc)
     * @see org.jasig.portal.portlet.registry.IPortletEntityRegistry#getPortletEntity(org.jasig.portal.portlet.om.IPortletEntityId)
     */
    @Override
    public IPortletEntity getPortletEntity(HttpServletRequest request, IPortletEntityId portletEntityId) {
        Validate.notNull(portletEntityId, "portletEntityId can not be null");
       
        //Sync on the request map to make sure duplicate IPortletEntitys aren't ever created
        final PortletEntityCache<IPortletEntity> portletEntityCache = this.getPortletEntityMap(request);
       
        return this.getPortletEntity(request, portletEntityCache, portletEntityId, null, -1);
    }
   
    /* (non-Javadoc)
     * @see org.jasig.portal.portlet.registry.IPortletEntityRegistry#getPortletEntity(java.lang.String)
     */
    @Override
    public IPortletEntity getPortletEntity(HttpServletRequest request, String portletEntityIdString) {
        final IPortletEntityId portletEntityId = this.parseConsistentPortletEntityId(request, portletEntityIdString);
        return this.getPortletEntity(request, portletEntityId);
    }
   
    @Override
    public IPortletEntity getOrCreateDefaultPortletEntity(HttpServletRequest request, IPortletDefinitionId portletDefinitionId) {
        Validate.notNull(request, "HttpServletRequest cannot be null");
        Validate.notNull(portletDefinitionId, "portletDefinitionId cannot be null");
       
        final IPortletDefinition portletDefinition = this.getPortletDefinition(request, portletDefinitionId);
        if (portletDefinition == null) {
            throw new IllegalArgumentException("No portlet definition found for id '" + portletDefinitionId + "'.");
        }
       
        //Determine the appropriate portlet window ID for the definition
        final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
        final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager();
        final IUserLayoutManager userLayoutManager = preferencesManager.getUserLayoutManager();
       
        //Determine the subscribe ID
        final String portletFName = portletDefinition.getFName();
        final String layoutNodeId = userLayoutManager.getSubscribeId(portletFName);
        if (layoutNodeId == null) {
            throw new IllegalArgumentException("No layout node ID found for fname '" + portletFName + "'.");
        }
       
        this.logger.trace("Found layout node {} for portlet definition {}", layoutNodeId, portletFName);
       
        final IPerson person = userInstance.getPerson();
        final int personId = person.getID();
        return this.getOrCreatePortletEntity(request, portletDefinitionId, layoutNodeId, personId);
    }
   
    @Override
    public IPortletEntity getOrCreatePortletEntity(HttpServletRequest request, IUserInstance userInstance, String layoutNodeId) {
        final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager();
        final IUserLayoutManager userLayoutManager = preferencesManager.getUserLayoutManager();
       
        //Find the channel and portlet definitions
        final IUserLayoutChannelDescription channelNode = (IUserLayoutChannelDescription)userLayoutManager.getNode(layoutNodeId);
        if (channelNode == null) {
            this.logger.warn("No layout node exists for id " + layoutNodeId + ", no portlet entity will be returned.");
            return null;
        }
       
        final String channelPublishId = channelNode.getChannelPublishId();
       
        final IPortletDefinition portletDefinition = this.getPortletDefinition(request, userInstance, channelPublishId);

        if (portletDefinition != null) {
          final IPerson person = userInstance.getPerson();
        return this.getOrCreatePortletEntity(request, portletDefinition.getPortletDefinitionId(), layoutNodeId, person.getID());
      }
     
      // No permission to see the portlet
      return null;
    }
   
    /* (non-Javadoc)
     * @see org.jasig.portal.portlet.registry.IPortletEntityRegistry#getOrCreatePortletEntity(org.jasig.portal.portlet.om.IPortletDefinitionId, java.lang.String, int)
     */
    @Override
    public IPortletEntity getOrCreatePortletEntity(HttpServletRequest request, IPortletDefinitionId portletDefinitionId, String layoutNodeId, int userId) {
        final PortletEntityCache<IPortletEntity> portletEntityCache = getPortletEntityMap(request);
       
        //Try just getting an existing entity first
        IPortletEntity portletEntity = this.getPortletEntity(request, portletEntityCache, null, layoutNodeId, userId);
       
        //Found an existing entity!
        if (portletEntity != null) {
            //Verify the definition IDs match, this is a MUST in the case where the subscribed portlet changes
            final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition();
            if (portletDefinitionId.equals(portletDefinition.getPortletDefinitionId())) {
                return portletEntity;
            }
           
            //Remove the entity if the definition IDs don't match
            this.logger.warn("Found portlet entity '{}' is not the correct entity for portlet definition id: {}. The entity will be deleted and a new one created.", portletEntity, portletDefinitionId);
            this.deletePortletEntity(request, portletEntity, false);
        }
       
       
        //Create the entity data object and store it in the session map (if not already there)
        final PortletEntityCache<PortletEntityData> portletEntityDataMap = this.getPortletEntityDataMap(request);
       
        final IPortletEntityId portletEntityId = this.createConsistentPortletEntityId(portletDefinitionId, layoutNodeId, userId);
        PortletEntityData portletEntityData = new PortletEntityData(portletEntityId, portletDefinitionId, layoutNodeId, userId);
        portletEntityData = portletEntityDataMap.storeIfAbsentEntity(portletEntityData);
       
        portletEntity = wrapPortletEntityData(portletEntityData);

        //Stick the wrapper in the request map
        portletEntity = portletEntityCache.storeIfAbsentEntity(portletEntity);
       
        return portletEntity;
    }
   
    @Override
    public IPortletEntity getOrCreatePortletEntityByFname(HttpServletRequest request, IUserInstance userInstance, String fname) {
        final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager();
        final IUserLayoutManager userLayoutManager = preferencesManager.getUserLayoutManager();
        final String subscribeId = userLayoutManager.getSubscribeId(fname);
        return this.getOrCreatePortletEntity(request, userInstance, subscribeId);
    }
   
    @Override
    public IPortletEntity getOrCreatePortletEntityByFname(HttpServletRequest request, IUserInstance userInstance, String fname, String preferredChannelSubscribeId) {
        try {
            final IPortletEntity portletEntity = this.getOrCreatePortletEntity(request, userInstance, preferredChannelSubscribeId);
           
            if (portletEntity != null) {
              //Verify the fname matches before returning the entity
              final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition();
        if (fname.equals(portletDefinition.getFName())) {
                return portletEntity;
        }
            }
        }
        catch (PortalException pe) {
            //Ignored, can be the case if no layout node exists for the specified subscribe ID
        }
       
        //Either the layout node didn't exist or the entity for the node doesn't match the requested fname
        return this.getOrCreatePortletEntityByFname(request, userInstance, fname);
    }
   
    @Override
    public IPortletEntity getOrCreateDelegatePortletEntity(HttpServletRequest request, IPortletWindowId parentPortletWindowId, IPortletDefinitionId delegatePortletDefinitionId) {
        //Create a special synthetic layout node ID for the delegate entity
        final String layoutNodeId = DELEGATE_LAYOUT_NODE_ID_PREFIX + parentPortletWindowId.getStringId().replace(ID_PART_SEPERATOR, DELEGATE_LAYOUT_NODE_ID_SEPERATOR);
       
        //Grab the current user
        final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
        final IPerson person = userInstance.getPerson();
        final int userId = person.getID();
       
        //Use the general API, the only thing special is the layout node id
        return getOrCreatePortletEntity(request, delegatePortletDefinitionId, layoutNodeId, userId);
    }
   
    /* (non-Javadoc)
     * @see org.jasig.portal.portlet.registry.IPortletEntityRegistry#storePortletEntity(org.jasig.portal.portlet.om.IPortletEntity)
     */
    @Override
    public void storePortletEntity(HttpServletRequest request, final IPortletEntity portletEntity) {
        Validate.notNull(portletEntity, "portletEntity can not be null");
       
        final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
        final IPerson person = userInstance.getPerson();
        if (person.isGuest()) {
            //Never persist things for the guest user, just rely on in-memory storage
            return;
        }

        final IPortletEntityId wrapperPortletEntityId = portletEntity.getPortletEntityId();
        final Lock portletEntityLock = this.getPortletEntityLock(request, wrapperPortletEntityId);
        portletEntityLock.lock();
        try {
            final boolean shouldBePersisted = this.shouldBePersisted(portletEntity);
           
            if (portletEntity instanceof PersistentPortletEntityWrapper) {
                //Unwrap the persistent entity
                final IPortletEntity persistentEntity = ((PersistentPortletEntityWrapper)portletEntity).getPersistentEntity();
               
                //Already persistent entity that still has prefs
                if (shouldBePersisted) {
                    try {
                        this.portletEntityDao.updatePortletEntity(persistentEntity);
                    }
                    catch (HibernateOptimisticLockingFailureException e) {
                        //Check if this exception is from the entity being deleted from under us.
                        final boolean exists = this.portletEntityDao.portletEntityExists(persistentEntity.getPortletEntityId());
                        if (!exists) {
                            this.logger.warn("The persistent portlet has already been deleted: " + persistentEntity + ". The passed entity should be persistent so a new persistent entity will be created");
                            this.deletePortletEntity(request, portletEntity, true);
                            this.createPersistentEntity(persistentEntity, wrapperPortletEntityId);
                        }
                        else {
                            throw e;
                        }
                    }
                }
                //Already persistent entity that should not be, DELETE!
                else {
                    //Capture identifiers needed to recreate the entity as session persistent
                    final IPortletDefinitionId portletDefinitionId = portletEntity.getPortletDefinitionId();
                    final String layoutNodeId = portletEntity.getLayoutNodeId();
                    final int userId = portletEntity.getUserId();
                   
                    //Delete the persistent entity
                    this.deletePortletEntity(request, portletEntity, false);

                    //Create a new entity and stick it in the cache
                    this.getOrCreatePortletEntity(request, portletDefinitionId, layoutNodeId, userId);
                }
            }
            else if (portletEntity instanceof SessionPortletEntityImpl) {
                //There are preferences on the interim entity, create an store it
                if (shouldBePersisted) {
                    //Remove the session scoped entity from the request and session caches
                    this.deletePortletEntity(request, portletEntity, false);
                   
                    final IPortletEntity persistentEntity = createPersistentEntity(portletEntity, wrapperPortletEntityId);
                   
                    if (this.logger.isTraceEnabled()) {
                        this.logger.trace("Session scoped entity " + wrapperPortletEntityId + " should now be persistent. Deleted it from session cache and created persistent portlet entity " + persistentEntity.getPortletEntityId());
                    }
                }
                //Session scoped entity that is still session scoped,
                else {
                    //Look for a persistent entity and delete it
                    final String channelSubscribeId = portletEntity.getLayoutNodeId();
                    final int userId = portletEntity.getUserId();
                    IPortletEntity existingPersistentEntity = this.portletEntityDao.getPortletEntity(channelSubscribeId, userId);
                    if (existingPersistentEntity != null) {
                        final IPortletEntityId consistentPortletEntityId = this.createConsistentPortletEntityId(existingPersistentEntity);
                        existingPersistentEntity = new PersistentPortletEntityWrapper(existingPersistentEntity, consistentPortletEntityId);
                       
                        this.logger.warn("A persistent portlet entity already exists: " + existingPersistentEntity + ". The passed entity has no preferences so the persistent version will be deleted");
                        this.deletePortletEntity(request, existingPersistentEntity, false);
                       
                        //Add to request cache
                        final PortletEntityCache<IPortletEntity> portletEntityMap = this.getPortletEntityMap(request);
                        portletEntityMap.storeIfAbsentEntity(portletEntity);

                        //Add to session cache
                        final PortletEntityCache<PortletEntityData> portletEntityDataMap = this.getPortletEntityDataMap(request);
                        portletEntityDataMap.storeIfAbsentEntity(((SessionPortletEntityImpl)portletEntity).getPortletEntityData());
                    }
                }
            }
            else {
                throw new IllegalArgumentException("Invalid portlet entity implementation passed: " + portletEntity.getClass());
            }
        }
        finally {
            portletEntityLock.unlock();
        }
    }

    @Override
    public Lock getPortletEntityLock(HttpServletRequest request, IPortletEntityId portletEntityId) {
        final ConcurrentMap<IPortletEntityId, Lock> lockMap = getPortletEntityLockMap(request);
       
        //See if the lock already exist, return if it does
        Lock lock = lockMap.get(portletEntityId);
        if (lock != null) {
            return lock;
        }

        //Create a new lock and do a putIfAbsent to avoid synchronizing but still get a single lock instance for the session.
        lock = createPortletEntityLock();
        return ConcurrentMapUtils.putIfAbsent(lockMap, portletEntityId, lock);
    }
   
    protected IPortletDefinition getPortletDefinition(HttpServletRequest request, String portletDefinitionIdStr) {
      final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
      return this.getPortletDefinition(request, userInstance, portletDefinitionIdStr);
    }
   
    protected IPortletDefinition getPortletDefinition(HttpServletRequest request, IPortletDefinitionId portletDefinitionId) {
      final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
      return this.getPortletDefinition(userInstance, portletDefinitionId);
    }
   
    protected IPortletDefinition getPortletDefinition(HttpServletRequest request, IUserInstance userInstance, String portletDefinitionIdStr) {
        request = this.portalRequestUtils.getOriginalPortalRequest(request);
       
        final ConcurrentMap<String, IPortletDefinition> portletDefinitions = PortalWebUtils.getMapRequestAttribute(request, PORTLET_DEFINITION_LOOKUP_MAP_ATTRIBUTE);
       
        IPortletDefinition portletDefinition  = portletDefinitions.get(portletDefinitionIdStr);
        if (portletDefinition == NO_PERMISSION_PORTLET_DEFINITION) {
            return null;
        }
        if (portletDefinition != null) {
            return portletDefinition;
        }
       
      portletDefinition = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionIdStr);
      portletDefinition = checkPortletDefinitionRenderPermissions(userInstance, portletDefinition);
      if (portletDefinition == null) {
          portletDefinitions.put(portletDefinitionIdStr, NO_PERMISSION_PORTLET_DEFINITION);
      }
      else {
          portletDefinitions.put(portletDefinitionIdStr, portletDefinition);
      }
     
      return portletDefinition;
    }
   
    protected IPortletDefinition getPortletDefinition(IUserInstance userInstance, IPortletDefinitionId portletDefinitionId) {
      final IPortletDefinition portletDefinition = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionId);
      return checkPortletDefinitionRenderPermissions(userInstance, portletDefinition);
    }

    private IPortletDefinition checkPortletDefinitionRenderPermissions(IUserInstance userInstance, final IPortletDefinition portletDefinition) {
    if (portletDefinition == null) {
        return null;
      }
       
        final IPerson person = userInstance.getPerson();
    final EntityIdentifier ei = person.getEntityIdentifier();
      final IAuthorizationPrincipal ap = AuthorizationService.instance().newPrincipal(ei.getKey(), ei.getType());
      if (ap.canRender(portletDefinition.getPortletDefinitionId().getStringId())) {
        return portletDefinition;
      }
     
      return null;
  }
   
    protected IPortletEntity createPersistentEntity(final IPortletEntity portletEntity, final IPortletEntityId wrapperPortletEntityId) {
        final IPortletDefinitionId portletDefinitionId = portletEntity.getPortletDefinitionId();
        final String layoutNodeId = portletEntity.getLayoutNodeId();
        final int userId = portletEntity.getUserId();
       
        IPortletEntity persistentEntity = this.portletEntityDao.getPortletEntity(layoutNodeId, userId);
        if (persistentEntity != null) {
            this.logger.warn("A persistent portlet entity already exists: " + persistentEntity + ". The data from the passed in entity will be copied to the persistent entity: " + portletEntity);
        }
        else {
            persistentEntity = this.portletEntityDao.createPortletEntity(portletDefinitionId, layoutNodeId, userId);
        }
       
        //Copy over preferences to avoid modifying any part of the interim entity by reference
        final List<IPortletPreference> existingPreferences = portletEntity.getPortletPreferences();
        final List<IPortletPreference> persistentPreferences = persistentEntity.getPortletPreferences();
       
        //Only do the copy if the List objects are not the same instance
        if (persistentPreferences != existingPreferences) {
            persistentPreferences.clear();
            for (final IPortletPreference preference : existingPreferences) {
                persistentPreferences.add(new PortletPreferenceImpl(preference));
            }
        }
       
        //Copy over WindowStates
        final Map<Long, WindowState> windowStates = portletEntity.getWindowStates();
        for (Map.Entry<Long, WindowState> windowStateEntry : windowStates.entrySet()) {
            final Long stylesheetDescriptorId = windowStateEntry.getKey();
            final IStylesheetDescriptor stylesheetDescriptor = stylesheetDescriptorDao.getStylesheetDescriptor(stylesheetDescriptorId);
            final WindowState windowState = windowStateEntry.getValue();
            persistentEntity.setWindowState(stylesheetDescriptor, windowState);
        }
       
        this.portletEntityDao.updatePortletEntity(persistentEntity);
       
        return persistentEntity;
    }
   
    /**
     * Delete a portlet entity, removes it from the request, session and persistent stores
     */
    protected void deletePortletEntity(HttpServletRequest request, IPortletEntity portletEntity, boolean cacheOnly) {
        final IPortletEntityId portletEntityId = portletEntity.getPortletEntityId();
       
        //Remove from request cache
        final PortletEntityCache<IPortletEntity> portletEntityMap = this.getPortletEntityMap(request);
        portletEntityMap.removeEntity(portletEntityId);
       
        //Remove from session cache
        final PortletEntityCache<PortletEntityData> portletEntityDataMap = this.getPortletEntityDataMap(request);
        portletEntityDataMap.removeEntity(portletEntityId);
       
        if (!cacheOnly && portletEntity instanceof PersistentPortletEntityWrapper) {
            final IPortletEntity persistentEntity = ((PersistentPortletEntityWrapper)portletEntity).getPersistentEntity();
           
            try {
                this.portletEntityDao.deletePortletEntity(persistentEntity);
            }
            catch (HibernateOptimisticLockingFailureException e) {
                this.logger.warn("This persistent portlet has already been deleted: " + persistentEntity + ", trying to find and delete by layout node and user.");
                final IPortletEntity existingPersistentEntity = this.portletEntityDao.getPortletEntity(persistentEntity.getLayoutNodeId(), persistentEntity.getUserId());
                if (existingPersistentEntity != null) {
                    this.portletEntityDao.deletePortletEntity(existingPersistentEntity);
                }
            }
        }
    }
   
    /**
     * Lookup the portlet entity by layoutNodeId and userId
     */
    protected IPortletEntity getPortletEntity(
            HttpServletRequest request,
            PortletEntityCache<IPortletEntity> portletEntityCache,
            IPortletEntityId portletEntityId, String layoutNodeId, int userId) {
       
        IPortletEntity portletEntity;
   
        //First look in the request map
        if (portletEntityId != null) {
            portletEntity = portletEntityCache.getEntity(portletEntityId);
        }
        else {
            portletEntity = portletEntityCache.getEntity(layoutNodeId, userId);
        }
       
        if (portletEntity != null) {
            logger.trace("Found IPortletEntity {} in request cache", portletEntity.getPortletEntityId());
            return portletEntity;
        }
       
        //Didn't find it, next look in the session map
        final PortletEntityCache<PortletEntityData> portletEntityDataMap = this.getPortletEntityDataMap(request);
        final PortletEntityData portletEntityData;
        if (portletEntityId != null) {
            portletEntityData = portletEntityDataMap.getEntity(portletEntityId);
        }
        else {
            portletEntityData = portletEntityDataMap.getEntity(layoutNodeId, userId);
        }
       
        if (portletEntityData != null) {
           
            //Stick the entity wrapper in the request map (if it wasn't already added by another thread)
            portletEntity = portletEntityCache.storeIfAbsentEntity(portletEntityData.getPortletEntityId(), new Function<IPortletEntityId, IPortletEntity>() {
                @Override
                public IPortletEntity apply(IPortletEntityId input) {
                    //Found a session stored entity, wrap it to make it a real IPortletEntity
                    logger.trace("Found PortletEntityData {} in session cache, caching wrapper in the request", portletEntityData.getPortletEntityId());
                   
                    return wrapPortletEntityData(portletEntityData);
                }
            });
           
            return portletEntity;
        }
       
        //Still didn't find it, look in the persistent store
        if (portletEntityId != null) {
            if (portletEntityId instanceof PortletEntityIdImpl) {
                final PortletEntityIdImpl consistentPortletEntityId = (PortletEntityIdImpl)portletEntityId;
                final String localLayoutNodeId = consistentPortletEntityId.getLayoutNodeId();
                final int localUserId = consistentPortletEntityId.getUserId();
               
                portletEntity = this.portletEntityDao.getPortletEntity(localLayoutNodeId, localUserId);
            }
            else {
                portletEntity = this.portletEntityDao.getPortletEntity(portletEntityId);
            }
        }
        else {
            portletEntity = this.portletEntityDao.getPortletEntity(layoutNodeId, userId);
        }
       
        //Found a persistent entity, wrap it to make the id consistent between the persistent and session stored entities
        if (portletEntity != null) {
            final IPortletEntityId consistentPortletEntityId = this.createConsistentPortletEntityId(portletEntity);
           
            final IPortletEntity anonPortletEntity = portletEntity;
           
            //Stick the entity wrapper in the request map (if it wasn't already added by another thread)
            portletEntity = portletEntityCache.storeIfAbsentEntity(consistentPortletEntityId, new Function<IPortletEntityId, IPortletEntity>() {
                @Override
                public IPortletEntity apply(IPortletEntityId input) {
                    logger.trace("Found persistent IPortletEntity {}, mapped id to {}, caching the wrapper in the request", anonPortletEntity.getPortletEntityId(), consistentPortletEntityId);
                    return new PersistentPortletEntityWrapper(anonPortletEntity, consistentPortletEntityId);
                }
            });
           
            return portletEntity;
        }
       
        //Didn't find an entity, just return null
        return null;
    }

    protected IPortletEntityId createConsistentPortletEntityId(IPortletEntity portletEntity) {
        final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition();
        final IPortletDefinitionId portletDefinitionId = portletDefinition.getPortletDefinitionId();
        final String layoutNodeId = portletEntity.getLayoutNodeId();
        final int userId = portletEntity.getUserId();
        return this.createConsistentPortletEntityId(portletDefinitionId, layoutNodeId, userId);
    }

    protected IPortletEntityId createConsistentPortletEntityId(PortletEntityData portletEntityData) {
        final IPortletDefinitionId portletDefinitionId = portletEntityData.getPortletDefinitionId();
        final String layoutNodeId = portletEntityData.getLayoutNodeId();
        final int userId = portletEntityData.getUserId();
        return this.createConsistentPortletEntityId(portletDefinitionId, layoutNodeId, userId);
    }

    protected IPortletEntityId createConsistentPortletEntityId(IPortletDefinitionId portletDefinitionId, String layoutNodeId, int userId) {
        final String compositeId = portletDefinitionId.getStringId() + ID_PART_SEPERATOR + layoutNodeId + ID_PART_SEPERATOR + userId;
        return new PortletEntityIdImpl(portletDefinitionId, layoutNodeId, userId, compositeId);
    }

    protected IPortletEntityId parseConsistentPortletEntityId(HttpServletRequest request, String consistentEntityIdString) {
        Validate.notNull(consistentEntityIdString, "consistentEntityIdString can not be null");
       
        //Check in the cache first
        final Element element = this.entityIdParseCache.get(consistentEntityIdString);
        if (element != null) {
            final Object value = element.getObjectValue();
            if (value != null) {
                return (IPortletEntityId)value;
            }
        }
       
        final String[] idParts = ID_PART_SEPERATOR_PATTERN.split(consistentEntityIdString);
        if (idParts.length != 3) {
            throw new IllegalArgumentException("consistentEntityIdString does not have 3 parts and is invalid: " + consistentEntityIdString);
        }
       
        //Verify the portlet definition id
        final String portletDefinitionIdString = idParts[0];
        final IPortletDefinition portletDefinition = this.getPortletDefinition(request, portletDefinitionIdString);
        if (portletDefinition == null) {
            throw new IllegalArgumentException("No parent IPortletDefinition found for " + portletDefinitionIdString + " from entity id string: " + consistentEntityIdString);
        }
        final IPortletDefinitionId portletDefinitionId = portletDefinition.getPortletDefinitionId();
       
        final IUserInstance userInstance = this.userInstanceManager.getUserInstance(request);
        final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager();
        final IUserLayoutManager userLayoutManager = preferencesManager.getUserLayoutManager();
       
        //Verify non-delegate layout node id exists and is for a portlet
        final String layoutNodeId = idParts[1];
        if (!layoutNodeId.startsWith(DELEGATE_LAYOUT_NODE_ID_PREFIX)) {
            final IUserLayoutNodeDescription node = userLayoutManager.getNode(layoutNodeId);
            if (node == null || node.getType() != LayoutNodeType.PORTLET) {
                throw new IllegalArgumentException("No portlet layout node found for " + layoutNodeId + " from entity id string: " + consistentEntityIdString);
            }
       
            //TODO is this doable for delegation?
            //Verify the portlet definition matches
            final IUserLayoutChannelDescription portletNode = (IUserLayoutChannelDescription)node;
            final String channelPublishId = portletNode.getChannelPublishId();
            if (!portletDefinitionId.getStringId().equals(channelPublishId)) {
                throw new IllegalArgumentException("The portlet layout node found for " + layoutNodeId + " does not match the IPortletDefinitionId " + portletDefinitionId + " specified in entity id string: " + consistentEntityIdString);
            }
        }

        //TODO when there is a JPA backed user dao actually verify this mapping
        //User just conver to an int
        final int userId;
        try {
            userId = Integer.parseInt(idParts[2]);
        }
        catch (NumberFormatException e) {
            throw new IllegalArgumentException("The user id " + idParts[2] + " is not a valid integer from entity id string: " + consistentEntityIdString, e);
        }
       
        final IPortletEntityId portletEntityId = createConsistentPortletEntityId(portletDefinitionId, layoutNodeId, userId);
       
        //Cache the resolution
        this.entityIdParseCache.put(new Element(consistentEntityIdString, portletEntityId));
       
        return portletEntityId;
    }

    protected Lock createPortletEntityLock() {
        return new ReentrantLock(true);
    }
   
    protected ConcurrentMap<IPortletEntityId, Lock> getPortletEntityLockMap(HttpServletRequest request) {
        request = portalRequestUtils.getOriginalPortalRequest(request);
        final HttpSession session = request.getSession();
        return PortalWebUtils.getMapSessionAttribute(session, PORTLET_ENTITY_LOCK_MAP_ATTRIBUTE);
    }
   
    protected PortletEntityCache<IPortletEntity> getPortletEntityMap(HttpServletRequest request) {
        request = portalRequestUtils.getOriginalPortletOrPortalRequest(request);
       
        //create the thread specific cache name
        final String entityMapAttribute = PORTLET_ENTITY_ATTRIBUTE + Thread.currentThread().getId();

        //No need to do this in a request attribute mutex since the map is scoped to a specific thread
        @SuppressWarnings("unchecked")
        PortletEntityCache<IPortletEntity> cache = (PortletEntityCache<IPortletEntity>)request.getAttribute(entityMapAttribute);
        if (cache == null) {
            cache = new PortletEntityCache<IPortletEntity>(false);
            request.setAttribute(PORTLET_ENTITY_ATTRIBUTE, cache);
        }
       
        return cache;
    }
   
    protected PortletEntityCache<PortletEntityData> getPortletEntityDataMap(HttpServletRequest request) {
        request = portalRequestUtils.getOriginalPortalRequest(request);
        final HttpSession session = request.getSession();
        final Object mutex = WebUtils.getSessionMutex(session);
        synchronized (mutex) {
            @SuppressWarnings("unchecked")
            PortletEntityCache<PortletEntityData> cache = (PortletEntityCache<PortletEntityData>)session.getAttribute(PORTLET_ENTITY_DATA_ATTRIBUTE);
            if (cache == null) {
                cache = new PortletEntityCache<PortletEntityData>();
                session.setAttribute(PORTLET_ENTITY_DATA_ATTRIBUTE, cache);
            }
            return cache;
        }
    }
   
    protected IPortletEntity wrapPortletEntityData(final PortletEntityData portletEntityData) {
        final IPortletDefinitionId portletDefinitionId = portletEntityData.getPortletDefinitionId();
        final IPortletDefinition portletDefinition = this.portletDefinitionRegistry.getPortletDefinition(portletDefinitionId);
        return new SessionPortletEntityImpl(portletDefinition, portletEntityData);
    }
   
    @Override
    public boolean shouldBePersisted(IPortletEntity portletEntity) {
        //Delegate entities should NEVER be persisted
        final String layoutNodeId = portletEntity.getLayoutNodeId();
        if (layoutNodeId.startsWith(DELEGATE_LAYOUT_NODE_ID_PREFIX)) {
            return false;
        }
       
        //Only non delegate entities with preferences or a non-null window state should be persisted
        final List<IPortletPreference> preferences = portletEntity.getPortletPreferences();
        return CollectionUtils.isNotEmpty(preferences) || !portletEntity.getWindowStates().isEmpty();
    }
   
    private static final IPortletDefinition NO_PERMISSION_PORTLET_DEFINITION = new IPortletDefinition() {
        @Override
        public String getDataTitle() {
            return null;
        }
        @Override
        public String getDataId() {
            return null;
        }
        @Override
        public String getDataDescription() {
            return null;
        }
        @Override
        public void setType(IPortletType channelType) {
        }
        @Override
        public void setTitle(String title) {
        }
        @Override
        public void setTimeout(int timeout) {
        }
        @Override
        public void setResourceTimeout(Integer resourceTimeout) {
        }
        @Override
        public void setRenderTimeout(Integer renderTimeout) {
        }
        @Override
        public void setPublisherId(int publisherId) {
        }
        @Override
        public void setPublishDate(Date publishDate) {
        }
        @Override
        public boolean setPortletPreferences(List<IPortletPreference> portletPreferences) {
            return false;
        }
        @Override
        public void setParameters(Set<IPortletDefinitionParameter> parameters) {
        }
        @Override
        public void setName(String name) {
        }
        @Override
        public void setFName(String fname) {
        }
        @Override
        public void setExpirerId(int expirerId) {
        }
        @Override
        public void setExpirationDate(Date expirationDate) {
        }
        @Override
        public void setEventTimeout(Integer eventTimeout) {
        }
        @Override
        public void setDescription(String descr) {
        }
        @Override
        public void setApproverId(int approvalId) {
        }
        @Override
        public void setApprovalDate(Date approvalDate) {
        }
        @Override
        public void setActionTimeout(Integer actionTimeout) {
        }
        @Override
        public void removeParameter(String name) {
        }
        @Override
        public void removeParameter(IPortletDefinitionParameter parameter) {
        }
        @Override
        public IPortletType getType() {
            return null;
        }
        @Override
        public String getTitle(String locale) {
            return null;
        }
        @Override
        public String getTitle() {
            return null;
        }
        @Override
        public int getTimeout() {
            return 0;
        }
        @Override
        public Integer getResourceTimeout() {
            return null;
        }
        @Override
        public Integer getRenderTimeout() {
            return null;
        }
        @Override
        public int getPublisherId() {
            return 0;
        }
        @Override
        public Date getPublishDate() {
            return null;
        }
        @Override
        public List<IPortletPreference> getPortletPreferences() {
            return null;
        }
        @Override
        public IPortletDescriptorKey getPortletDescriptorKey() {
            return null;
        }
        @Override
        public IPortletDefinitionId getPortletDefinitionId() {
            return null;
        }
        @Override
        public Map<String, IPortletDefinitionParameter> getParametersAsUnmodifiableMap() {
            return null;
        }
        @Override
        public Set<IPortletDefinitionParameter> getParameters() {
            return null;
        }
        @Override
        public IPortletDefinitionParameter getParameter(String key) {
            return null;
        }
        @Override
        public String getName(String locale) {
            return null;
        }
        @Override
        public String getName() {
            return null;
        }
        @Override
        public PortletLifecycleState getLifecycleState() {
            return null;
        }
        @Override
        public String getFName() {
            return null;
        }
        @Override
        public int getExpirerId() {
            return 0;
        }
        @Override
        public Date getExpirationDate() {
            return null;
        }
        @Override
        public Integer getEventTimeout() {
            return null;
        }
        @Override
        public EntityIdentifier getEntityIdentifier() {
            return null;
        }
        @Override
        public String getDescription(String locale) {
            return null;
        }
        @Override
        public String getDescription() {
            return null;
        }
        @Override
        public int getApproverId() {
            return 0;
        }
        @Override
        public Date getApprovalDate() {
            return null;
        }
        @Override
        public Integer getActionTimeout() {
            return null;
        }
        @Override
        public void addParameter(String name, String value) {
        }
        @Override
        public void addParameter(IPortletDefinitionParameter parameter) {
        }
        @Override
        public void addLocalizedTitle(String locale, String chanTitle) {
        }
        @Override
        public void addLocalizedName(String locale, String chanName) {
        }
        @Override
        public void addLocalizedDescription(String locale, String chanDesc) {
        }
        @Override
        public Double getRating() {
            return null;
        }
        @Override
        public void setRating(Double rating) {
        }
        @Override
        public Long getUsersRated() {
            return null;
        }
        @Override
        public void setUsersRated(Long usersRated) {
        }
    };
}
TOP

Related Classes of org.jasig.portal.portlet.registry.PortletEntityRegistryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.