/** * Copyright (C) 2009 eXo Platform SAS. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.exoplatform.portal.config; import org.exoplatform.commons.utils.LazyPageList; import org.exoplatform.container.component.ComponentPlugin; import org.exoplatform.container.xml.InitParams; import org.exoplatform.container.xml.ValueParam; import org.exoplatform.portal.config.model.Application; import org.exoplatform.portal.config.model.Container; import org.exoplatform.portal.config.model.ModelObject; import org.exoplatform.portal.config.model.Page; import org.exoplatform.portal.config.model.PortalConfig; import org.exoplatform.portal.config.model.TransientApplicationState; import org.exoplatform.portal.mop.SiteKey; import org.exoplatform.portal.mop.description.DescriptionService; import org.exoplatform.portal.mop.importer.ImportMode; import org.exoplatform.portal.mop.navigation.NavigationContext; import org.exoplatform.portal.mop.navigation.NavigationService; import org.exoplatform.portal.mop.navigation.NavigationState; import org.exoplatform.portal.mop.user.UserNavigation; import org.exoplatform.portal.mop.user.UserPortalContext; import org.exoplatform.portal.pom.data.ModelChange; import org.exoplatform.services.log.ExoLogger; import org.exoplatform.services.log.Log; import org.exoplatform.services.organization.Group; import org.exoplatform.services.organization.OrganizationService; import org.picocontainer.Startable; import java.util.*; /** * Created by The eXo Platform SAS Apr 19, 2007 This service is used to load the PortalConfig, Page config and * Navigation config for a given user. */ public class UserPortalConfigService implements Startable { DataStorage storage_; UserACL userACL_; OrganizationService orgService_; private NewPortalConfigListener newPortalConfigListener_; /** . */ final NavigationService navService; /** . */ final DescriptionService descriptionService; /** . */ boolean createUserPortal; /** . */ boolean destroyUserPortal; /** . */ private final ImportMode defaultImportMode; private Log log = ExoLogger.getLogger("Portal:UserPortalConfigService"); public UserPortalConfigService( UserACL userACL, DataStorage storage, OrganizationService orgService, NavigationService navService, DescriptionService descriptionService, InitParams params) throws Exception { // ValueParam createUserPortalParam = params == null ? null : params.getValueParam("create.user.portal"); boolean createUserPortal = createUserPortalParam == null || createUserPortalParam.getValue().toLowerCase().trim().equals("true"); // ValueParam destroyUserPortalParam = params == null ? null : params.getValueParam("destroy.user.portal"); boolean destroyUserPortal = destroyUserPortalParam == null || destroyUserPortalParam.getValue().toLowerCase().trim().equals("true"); // ValueParam defaultImportModeParam = params == null ? null : params.getValueParam("default.import.mode"); ImportMode defaultImportMode = defaultImportModeParam == null ? ImportMode.CONSERVE : ImportMode.valueOf(defaultImportModeParam.getValue().toUpperCase().trim()); // this.storage_ = storage; this.orgService_ = orgService; this.userACL_ = userACL; this.navService = navService; this.descriptionService = descriptionService; this.createUserPortal = createUserPortal; this.destroyUserPortal = destroyUserPortal; this.defaultImportMode = defaultImportMode; } public ImportMode getDefaultImportMode() { return defaultImportMode; } public boolean getCreateUserPortal() { return createUserPortal; } public void setCreateUserPortal(boolean createUserPortal) { this.createUserPortal = createUserPortal; } public boolean getDestroyUserPortal() { return destroyUserPortal; } public void setDestroyUserPortal(boolean destroyUserPortal) { this.destroyUserPortal = destroyUserPortal; } /** * Returns the navigation service associated with this service. * * @return the navigation service; */ public NavigationService getNavigationService() { return navService; } public DescriptionService getDescriptionService() { return descriptionService; } public UserACL getUserACL() { return userACL_; } public OrganizationService getOrganizationService() { return orgService_; } /** Temporary until the {@link #getUserPortalConfig(String, String)} is removed. */ private static final UserPortalContext NULL_CONTEXT = new UserPortalContext() { public ResourceBundle getBundle(UserNavigation navigation) { return null; } public Locale getUserLocale() { return Locale.ENGLISH; } }; /** * <p> Build and returns an instance of <tt>UserPortalConfig</tt>. </p> * <p/> * <p> To return a valid config, the current thread must be associated with an identity that will grant him access to * the portal as returned by the {@link UserACL#hasPermission(org.exoplatform.portal.config.model.PortalConfig)} * method. </p> * <p/> * <p> The navigation loaded on the <tt>UserPortalConfig<tt> object are obtained according to the specified user * argument. The portal navigation is always loaded. If the specified user is null then the navigation of the guest * group as configured by {@link org.exoplatform.portal.config.UserACL#getGuestsGroup()} is also loaded, otherwise * the navigations are loaded according to the following rules: * <p/> * <ul> <li>The navigation corresponding to the user is loaded.</li> <li>When the user is root according to the value * returned by {@link org.exoplatform.portal.config.UserACL#getSuperUser()} then the navigation of all groups are * loaded.</li> <li>When the user is not root, then all its groups are added except the guest group as configued per * {@link org.exoplatform.portal.config.UserACL#getGuestsGroup()}.</li> </ul> * <p/> * All the navigations are sorted using the value returned by {@link org.exoplatform.portal.config.model.PageNavigation#getPriority()}. * </p> * * @param portalName the portal name * @param accessUser the user name * @return the config * @throws Exception any exception * @deprecated the method {@link #getUserPortalConfig(String, String, org.exoplatform.portal.mop.user.UserPortalContext)} should be used instead */ @Deprecated public UserPortalConfig getUserPortalConfig(String portalName, String accessUser) throws Exception { return getUserPortalConfig(portalName, accessUser, NULL_CONTEXT); } public UserPortalConfig getUserPortalConfig(String portalName, String accessUser, UserPortalContext userPortalContext) throws Exception { PortalConfig portal = storage_.getPortalConfig(portalName); if (portal == null || !userACL_.hasPermission(portal)) { return null; } return new UserPortalConfig(portal, this, portalName, accessUser, userPortalContext); } /** * Compute and returns the list that the specified user can manage. If the user is root then all existing groups are * returned otherwise the list is computed from the groups in which the user has a configured membership. The * membership is configured from the value returned by {@link org.exoplatform.portal.config.UserACL#getMakableMT()} * * @param remoteUser the user to get the makable navigations * @param withSite true if a site must exist * @return the list of groups * @throws Exception any exception */ public List<String> getMakableNavigations(String remoteUser, boolean withSite) throws Exception { Collection<Group> groups; if (remoteUser.equals(userACL_.getSuperUser())) { groups = orgService_.getGroupHandler().getAllGroups(); } else { groups = orgService_.getGroupHandler().findGroupByMembership(remoteUser, userACL_.getMakableMT()); } // List<String> list = new ArrayList<String>(); if (groups != null) { Set<String> existingNames = null; if (withSite) { existingNames = new HashSet<String>(); Query<PortalConfig> q = new Query<PortalConfig>("group", null, PortalConfig.class); LazyPageList<PortalConfig> lpl = storage_.find(q); for (PortalConfig groupSite : lpl.getAll()) { existingNames.add(groupSite.getName()); } } // for (Group group : groups) { String groupId = group.getId().trim(); if (existingNames == null || existingNames.contains(groupId)) { list.add(groupId); } } } // return list; } /** * Create a user site for the specified user. It will perform the following: * <ul> * <li>create the user site by calling {@link #createUserPortalConfig(String, String, String)} which may create * a site or not according to the default configuration</li> * <li>if not site exists then it creates a site then it creates an empty site</li> * <li>if not navigation exists for the user site then it creates an empty navigation</li> * </ul> * * @param userName the user name * @throws Exception a nasty exception */ public void createUserSite(String userName) throws Exception { // Create the portal from the template createUserPortalConfig(PortalConfig.USER_TYPE, userName, "user"); // Need to insert the corresponding user site if needed PortalConfig cfg = storage_.getPortalConfig(PortalConfig.USER_TYPE, userName); if (cfg == null) { cfg = new PortalConfig(PortalConfig.USER_TYPE); cfg.setPortalLayout(new Container()); cfg.setName(userName); storage_.create(cfg); } // Create a blank navigation if needed SiteKey key = SiteKey.user(userName); NavigationContext nav = navService.loadNavigation(key); if (nav == null) { nav = new NavigationContext(key, new NavigationState(5)); navService.saveNavigation(nav); } } /** * Create a group site for the specified group. It will perform the following: * <ul> * <li>create the group site by calling {@link #createUserPortalConfig(String, String, String)} which may create * a site or not according to the default configuration</li> * <li>if not site exists then it creates a site then it creates an empty site</li> * </ul> * * @param groupId the group id * @throws Exception a nasty exception */ public void createGroupSite(String groupId) throws Exception { // Create the portal from the template createUserPortalConfig(PortalConfig.GROUP_TYPE, groupId, "group"); // Need to insert the corresponding group site PortalConfig cfg = storage_.getPortalConfig(PortalConfig.GROUP_TYPE, groupId); if (cfg == null) { cfg = new PortalConfig(PortalConfig.GROUP_TYPE); cfg.setPortalLayout(new Container()); cfg.setName(groupId); storage_.create(cfg); } } /** * This method should create a the portal config, pages and navigation according to the template name. * * @param siteType the site type * @param siteName the Site name * @param template the template to use * @throws Exception any exception */ public void createUserPortalConfig(String siteType, String siteName, String template) throws Exception { String templatePath = newPortalConfigListener_.getTemplateConfig(siteType, template); NewPortalConfig portalConfig = new NewPortalConfig(templatePath); portalConfig.setTemplateName(template); portalConfig.setOwnerType(siteType); if (!portalConfig.getOwnerType().equals(PortalConfig.USER_TYPE)) { newPortalConfigListener_.createPortletPreferences(portalConfig, siteName); } newPortalConfigListener_.createPortalConfig(portalConfig, siteName); newPortalConfigListener_.createPage(portalConfig, siteName); newPortalConfigListener_.createPageNavigation(portalConfig, siteName); } /** * This method removes the PortalConfig, Page and PageNavigation that belong to the portal in the database. * * @param portalName the portal name * @throws Exception any exception */ public void removeUserPortalConfig(String portalName) throws Exception { removeUserPortalConfig(PortalConfig.PORTAL_TYPE, portalName); } /** * This method removes the PortalConfig, Page and PageNavigation that belong to the portal in the database. * * @param ownerType the owner type * @param ownerId the portal name * @throws Exception any exception */ public void removeUserPortalConfig(String ownerType, String ownerId) throws Exception { PortalConfig config = storage_.getPortalConfig(ownerType, ownerId); if (config != null) { storage_.remove(config); } } /** * This method should update the PortalConfig object * * @deprecated This method is not useful anymore. The preferred way to do this is * using directly {@link org.exoplatform.portal.config.DataStorage#save(PortalConfig)} * * @param portal * @throws Exception */ @Deprecated public void update(PortalConfig portal) throws Exception { storage_.save(portal); } /** * This method load the page according to the pageId and returns. * * @param pageId the page id * @return the page * @throws Exception any exception */ public Page getPage(String pageId) throws Exception { if (pageId == null) { return null; } return storage_.getPage(pageId); // TODO: pageConfigCache_ needs to be } /** * This method load the page according to the pageId and returns it if the current thread is associated with an * identity that allows to view the page according to the {@link UserACL#hasPermission(org.exoplatform.portal.config.model.Page)} * method. * * @param pageId the page id * @param accessUser never used * @return the page * @throws Exception any exception */ public Page getPage(String pageId, String accessUser) throws Exception { Page page = getPage(pageId); if (page == null || !userACL_.hasPermission(page)) { return null; } return page; } /** * Removes a page and broadcast an event labelled as {@link org.exoplatform.portal.config.UserPortalConfigService#PAGE_REMOVED} * when the removal is successful. * * @deprecated This method is not useful anymore. The preferred way to do this is * using directly {@link org.exoplatform.portal.config.DataStorage#remove(Page)} * * @param page the page to remove * @throws Exception any exception */ @Deprecated public void remove(Page page) throws Exception { storage_.remove(page); } /** * Creates a page and broadcast an event labelled as {@link org.exoplatform.portal.config.UserPortalConfigService#CREATE_PAGE_EVENT} * when the creation is successful. * * @deprecated This method is not useful anymore. The preferred way to do this is * using directly {@link org.exoplatform.portal.config.DataStorage#create(Page)} * * @param page the page to create * @throws Exception any exception */ @Deprecated public void create(Page page) throws Exception { storage_.create(page); } /** * Updates a page and broadcast an event labelled as {@link org.exoplatform.portal.config.UserPortalConfigService#PAGE_UPDATED} * when the creation is successful. * * @deprecated This method is not useful anymore. The preferred way to do this is * using directly {@link org.exoplatform.portal.config.DataStorage#save(Page)} * * @param page the page to update * @return the list of model changes that occured * @throws Exception any exception */ @Deprecated public List<ModelChange> update(Page page) throws Exception { List<ModelChange> changes = storage_.save(page); return changes; } /** * Clones a page. * * @deprecated This method is not useful anymore. The preferred way to do this is * using directly {@link org.exoplatform.portal.config.DataStorage#clonePage(String, String, String, String)} * * @param pageId the id of the page to clone * @param pageName the new page name * @param ownerType the new page owner type * @param ownerId the new page owner id * @return the newly created page * @throws Exception any exception */ @Deprecated public Page renewPage(String pageId, String pageName, String ownerType, String ownerId) throws Exception { return storage_.clonePage(pageId, ownerType, ownerId, pageName); } /** * Creates a page from an existing template. * * @param temp the template name * @param ownerType the new owner type * @param ownerId the new owner id * @return the page * @throws Exception any exception */ public Page createPageTemplate(String temp, String ownerType, String ownerId) throws Exception { Page page = newPortalConfigListener_.createPageFromTemplate(ownerType, ownerId, temp); updateOwnership(page, ownerType, ownerId); return page; } /** * Returns the list of all portal names. * * @return the list of all portal names * @throws Exception any exception */ public List<String> getAllPortalNames() throws Exception { List<String> list = storage_.getAllPortalNames(); for (Iterator<String> i = list.iterator();i.hasNext();) { String name = i.next(); PortalConfig config = storage_.getPortalConfig(name); if (config == null || !userACL_.hasPermission(config)) { i.remove(); } } return list; } /** * Update the ownership recursively on the model graph. * * @param object the model object graph root * @param ownerType the new owner type * @param ownerId the new owner id */ private void updateOwnership(ModelObject object, String ownerType, String ownerId) { if (object instanceof Container) { Container container = (Container)object; if (container instanceof Page) { Page page = (Page)container; page.setOwnerType(ownerType); page.setOwnerId(ownerId); } for (ModelObject child : container.getChildren()) { updateOwnership(child, ownerType, ownerId); } } else if (object instanceof Application) { Application application = (Application)object; TransientApplicationState applicationState = (TransientApplicationState)application.getState(); if (applicationState != null && (applicationState.getOwnerType() == null || applicationState.getOwnerId() == null)) { applicationState.setOwnerType(ownerType); applicationState.setOwnerId(ownerId); } } } public void initListener(ComponentPlugin listener) { if (listener instanceof NewPortalConfigListener) { synchronized (this) { if (newPortalConfigListener_ == null) { this.newPortalConfigListener_ = (NewPortalConfigListener)listener; } else { newPortalConfigListener_.mergePlugin((NewPortalConfigListener)listener); } } } } public void deleteListenerElements(ComponentPlugin listener) { if (listener instanceof NewPortalConfigListener) { synchronized (this) { if (newPortalConfigListener_ != null) { newPortalConfigListener_.deleteListenerElements((NewPortalConfigListener)listener); } } } } public void start() { try { if (newPortalConfigListener_ == null) { return; } // newPortalConfigListener_.run(); } catch (Exception e) { log.error("Could not import initial data", e); } } public void stop() { } public String getDefaultPortal() { return newPortalConfigListener_.getDefaultPortal(); } public Set<String> getPortalTemplates() { return newPortalConfigListener_.getTemplateConfigs(PortalConfig.PORTAL_TYPE); } public PortalConfig getPortalConfigFromTemplate(String templateName) { return newPortalConfigListener_.getPortalConfigFromTemplate(PortalConfig.PORTAL_TYPE, templateName); } }