/** * Licensed to Apereo under one or more contributor license agreements. See the NOTICE file * distributed with this work for additional information regarding copyright ownership. Apereo * 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 the * following location: * * <p>http://www.apache.org/licenses/LICENSE-2.0 * * <p>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.apereo.portal.portlet.dao.trans; import java.util.LinkedHashSet; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apereo.portal.IUserPreferencesManager; import org.apereo.portal.layout.IUserLayoutManager; import org.apereo.portal.layout.TransientUserLayoutManagerWrapper; import org.apereo.portal.layout.node.IUserLayoutChannelDescription; import org.apereo.portal.portlet.dao.IPortletEntityDao; import org.apereo.portal.portlet.om.IPortletDefinition; import org.apereo.portal.portlet.om.IPortletDefinitionId; import org.apereo.portal.portlet.om.IPortletEntity; import org.apereo.portal.portlet.om.IPortletEntityId; import org.apereo.portal.portlet.registry.IPortletDefinitionRegistry; import org.apereo.portal.url.IPortalRequestUtils; import org.apereo.portal.user.IUserInstance; import org.apereo.portal.user.IUserInstanceManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Repository; /** * Handles entity management for transient portlets, defined as portlets that aren't permanent parts * of the user's layout. Portlet preferences are still persisted but are associated with a transient * rendering of the portlet. Transient portlets are detected by checking the channel subscribe ID * against the {@link TransientUserLayoutManagerWrapper#SUBSCRIBE_PREFIX} prefix. * */ @Repository @Qualifier("transient") public class TransientPortletEntityDao implements IPortletEntityDao { protected final Log logger = LogFactory.getLog(this.getClass()); private IPortletDefinitionRegistry portletDefinitionRegistry; private IPortletEntityDao delegatePortletEntityDao; private IUserInstanceManager userInstanceManager; private IPortalRequestUtils portalRequestUtils; /** The IPortletEntityDao to delegate calls to for actual persistence */ @Autowired public void setDelegatePortletEntityDao( @Qualifier("persistence") IPortletEntityDao delegatePortletEntityDao) { this.delegatePortletEntityDao = delegatePortletEntityDao; } /** Registry for looking up data related to portlet definitions */ @Autowired public void setPortletDefinitionRegistry(IPortletDefinitionRegistry portletDefinitionRegistry) { this.portletDefinitionRegistry = portletDefinitionRegistry; } /** Used to get access to the user's layout manager */ @Autowired public void setUserInstanceManager(IUserInstanceManager userInstanceManager) { this.userInstanceManager = userInstanceManager; } /** Used to get access to the current portal request */ @Autowired public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) { this.portalRequestUtils = portalRequestUtils; } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#createPortletEntity(org.apereo.portal.portlet.om.IPortletDefinitionId, java.lang.String, int) */ @Override public IPortletEntity createPortletEntity( IPortletDefinitionId portletDefinitionId, String layoutNodeId, int userId) { if (layoutNodeId.startsWith(TransientUserLayoutManagerWrapper.SUBSCRIBE_PREFIX)) { final String transientLayoutNodeId = layoutNodeId; layoutNodeId = this.getPersistentLayoutNodeId(portletDefinitionId); final IPortletEntity portletEntity = this.delegatePortletEntityDao.createPortletEntity( portletDefinitionId, layoutNodeId, userId); return new TransientPortletEntity(portletEntity, transientLayoutNodeId); } return this.delegatePortletEntityDao.createPortletEntity( portletDefinitionId, layoutNodeId, userId); } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#deletePortletEntity(org.apereo.portal.portlet.om.IPortletEntity) */ @Override public void deletePortletEntity(IPortletEntity portletEntity) { portletEntity = this.unwrapEntity(portletEntity); this.delegatePortletEntityDao.deletePortletEntity(portletEntity); } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#getPortletEntities(org.apereo.portal.portlet.om.IPortletDefinitionId) */ @Override public Set<IPortletEntity> getPortletEntities(IPortletDefinitionId portletDefinitionId) { final Set<IPortletEntity> portletEntities = this.delegatePortletEntityDao.getPortletEntities(portletDefinitionId); return this.wrapEntities(portletEntities); } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#getPortletEntitiesForUser(int) */ @Override public Set<IPortletEntity> getPortletEntitiesForUser(int userId) { final Set<IPortletEntity> portletEntities = this.delegatePortletEntityDao.getPortletEntitiesForUser(userId); return this.wrapEntities(portletEntities); } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#getPortletEntity(org.apereo.portal.portlet.om.IPortletEntityId) */ @Override public IPortletEntity getPortletEntity(IPortletEntityId portletEntityId) { final IPortletEntity portletEntity = this.delegatePortletEntityDao.getPortletEntity(portletEntityId); return this.wrapEntity(portletEntity); } @Override public boolean portletEntityExists(IPortletEntityId portletEntityId) { return this.delegatePortletEntityDao.portletEntityExists(portletEntityId); } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#getPortletEntity(java.lang.String, int) */ @Override public IPortletEntity getPortletEntity(String layoutNodeId, int userId) { if (layoutNodeId.startsWith(TransientUserLayoutManagerWrapper.SUBSCRIBE_PREFIX)) { final String databaseChannelSubscribeId = this.determineDatabaseChannelSubscribeId(layoutNodeId); final IPortletEntity portletEntity = this.delegatePortletEntityDao.getPortletEntity( databaseChannelSubscribeId, userId); return this.wrapEntity(portletEntity); } return this.delegatePortletEntityDao.getPortletEntity(layoutNodeId, userId); } /* (non-Javadoc) * @see org.apereo.portal.portlet.dao.IPortletEntityDao#updatePortletEntity(org.apereo.portal.portlet.om.IPortletEntity) */ @Override public void updatePortletEntity(IPortletEntity portletEntity) { portletEntity = this.unwrapEntity(portletEntity); this.delegatePortletEntityDao.updatePortletEntity(portletEntity); } /** * Returns the unwrapped entity if it is an instance of TransientPortletEntity. If not the * original entity is returned. */ protected IPortletEntity unwrapEntity(IPortletEntity portletEntity) { if (portletEntity instanceof TransientPortletEntity) { return ((TransientPortletEntity) portletEntity).getDelegatePortletEntity(); } return portletEntity; } /** * Adds a TransientPortletEntity wrapper to the portletEntity if it is needed. If the specified * entity is transient but no transient subscribe id has been registered for it yet in the * transientIdMap null is returned. If no wrapping is needed the original entity is returned. */ protected IPortletEntity wrapEntity(IPortletEntity portletEntity) { if (portletEntity == null) { return null; } final String persistentLayoutNodeId = portletEntity.getLayoutNodeId(); if (persistentLayoutNodeId.startsWith(TransientUserLayoutManagerWrapper.SUBSCRIBE_PREFIX)) { final IUserLayoutManager userLayoutManager = this.getUserLayoutManager(); if (userLayoutManager == null) { this.logger.warn( "Could not find IUserLayoutManager when trying to wrap transient portlet entity: " + portletEntity); return portletEntity; } final IPortletDefinition portletDefinition = portletEntity.getPortletDefinition(); final String fname = portletDefinition.getFName(); final String layoutNodeId = userLayoutManager.getSubscribeId(fname); return new TransientPortletEntity(portletEntity, layoutNodeId); } return portletEntity; } /** * Calles {@link #wrapEntity(IPortletEntity)} on each entry in the Set, wrap calls that return * null result in the entitiy being dropped from the returned Set */ protected Set<IPortletEntity> wrapEntities(Set<IPortletEntity> portletEntities) { final Set<IPortletEntity> wrappedPortletEntities = new LinkedHashSet<IPortletEntity>(portletEntities.size()); for (final IPortletEntity portletEntity : portletEntities) { final IPortletEntity wrappedEntity = this.wrapEntity(portletEntity); if (wrappedEntity != null) { wrappedPortletEntities.add(wrappedEntity); } } return wrappedPortletEntities; } protected String determineDatabaseChannelSubscribeId(String layoutNodeId) { //Find the referenced Node in the user's layout final IUserLayoutManager userLayoutManager = this.getUserLayoutManager(); final IUserLayoutChannelDescription channelNode = (IUserLayoutChannelDescription) userLayoutManager.getNode(layoutNodeId); //Lookup the IportletDefinition for the node final String portletPublishId = channelNode.getChannelPublishId(); final IPortletDefinition portletDefinition = this.portletDefinitionRegistry.getPortletDefinition(portletPublishId); //Generate the subscribe ID used for the database return this.getPersistentLayoutNodeId(portletDefinition.getPortletDefinitionId()); } protected String getPersistentLayoutNodeId(IPortletDefinitionId portletDefinitionId) { return TransientUserLayoutManagerWrapper.SUBSCRIBE_PREFIX + "." + portletDefinitionId.getStringId(); } protected IUserLayoutManager getUserLayoutManager() { final HttpServletRequest portalRequest = this.portalRequestUtils.getCurrentPortalRequest(); final IUserInstance userInstance = this.userInstanceManager.getUserInstance(portalRequest); final IUserPreferencesManager preferencesManager = userInstance.getPreferencesManager(); return preferencesManager.getUserLayoutManager(); } }