/* * Copyright (C) 2010 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.mop.user; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Locale; import org.exoplatform.portal.config.UserPortalConfigService; import org.exoplatform.portal.config.model.PageNavigation; import org.exoplatform.portal.config.model.PortalConfig; import org.exoplatform.portal.mop.SiteKey; import org.exoplatform.portal.mop.SiteType; import org.exoplatform.portal.mop.navigation.GenericScope; import org.exoplatform.portal.mop.navigation.NavigationContext; import org.exoplatform.portal.mop.navigation.NavigationServiceException; import org.exoplatform.portal.mop.navigation.NodeChangeListener; import org.exoplatform.portal.mop.navigation.NodeContext; import org.exoplatform.portal.mop.navigation.NodeState; import org.exoplatform.portal.mop.navigation.Scope; import org.exoplatform.portal.mop.navigation.VisitMode; import org.exoplatform.services.organization.Group; import org.gatein.common.logging.Logger; import org.gatein.common.logging.LoggerFactory; /** * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> * @version $Revision$ */ public class UserPortalImpl implements UserPortal { public static final Comparator<UserNavigation> USER_NAVIGATION_COMPARATOR = new Comparator<UserNavigation>() { public int compare(UserNavigation nav1, UserNavigation nav2) { /* Because we cannot tell how expensive getPriority() is * we better store the priorities into local variables */ int priority1 = nav1.getPriority(); int priority2 = nav2.getPriority(); if (priority1 == priority2) { /* A fix for GTNPORTAL-3322. The original comparator has not imposed * a total ordering as required by the Comparator interface: "The implementor * must ensure that sgn(compare(x, y)) == -sgn(compare(y, x)) for all x and y." * This was not the case when comparing two nodes both having UNDEFINED_PRIORITY. */ return 0; } else if (priority1 == PageNavigation.UNDEFINED_PRIORITY) { return 1; } else if (priority2 == PageNavigation.UNDEFINED_PRIORITY) { return -1; } else { return priority1 - priority2; } } }; private final Logger log = LoggerFactory.getLogger(UserPortalImpl.class); /** . */ final UserPortalConfigService service; /** . */ private final PortalConfig portal; /** . */ final UserPortalContext context; /** . */ final String userName; /** . */ private List<UserNavigation> navigations; /** . */ private final String portalName; /** . */ private final Locale portalLocale; public UserPortalImpl(UserPortalConfigService service, String portalName, PortalConfig portal, String userName, UserPortalContext context) { if (context == null) { throw new NullPointerException("No null context argument allowed"); } // String locale = portal.getLocale(); // this.portalLocale = locale != null ? new Locale(locale) : null; this.service = service; this.portalName = portalName; this.portal = portal; this.userName = userName; this.context = context; this.navigations = null; } public Locale getLocale() { return portalLocale; } /** * Returns an immutable sorted list of the valid navigations related to the user. * * @return the navigations * @throws UserPortalException any user portal exception */ public List<UserNavigation> getNavigations() throws UserPortalException, NavigationServiceException { if (navigations == null) { List<UserNavigation> navigations = new ArrayList<UserNavigation>(userName == null ? 1 : 10); NavigationContext portalNav = service.getNavigationService().loadNavigation( new SiteKey(SiteType.PORTAL, portalName)); if (portalNav != null && portalNav.getState() != null) { navigations.add(new UserNavigation(this, portalNav, service.getUserACL().hasEditPermission(portal))); } // if (userName != null) { // Add user nav if any NavigationContext userNavigation = service.getNavigationService().loadNavigation(SiteKey.user(userName)); if (userNavigation != null && userNavigation.getState() != null) { navigations.add(new UserNavigation(this, userNavigation, true)); } // Add group navigations if (service.getUserACL().getSuperUser().equals(userName)) { List<NavigationContext> navCtxs = service.getNavigationService().loadNavigations(SiteType.GROUP); for (NavigationContext navCtx : navCtxs) { if (!navCtx.getKey().getName().equals(service.getUserACL().getGuestsGroup())) { navigations.add(new UserNavigation(this, navCtx, true)); } } } else { Collection<?> groups = null; try { groups = service.getOrganizationService().getGroupHandler().findGroupsOfUser(userName); } catch (Exception e) { if(log.isDebugEnabled()) { log.debug("Could not retrieve groups", e); } //throw new UserPortalException("Could not retrieve groups", e); } // if(groups != null) { for (Object group : groups) { Group m = (Group) group; String groupId = m.getId().trim(); if (!groupId.equals(service.getUserACL().getGuestsGroup())) { NavigationContext groupNavigation = service.getNavigationService().loadNavigation( SiteKey.group(groupId)); if (groupNavigation != null && groupNavigation.getState() != null) { navigations.add(new UserNavigation(this, groupNavigation, service.getUserACL() .hasEditPermissionOnNavigation(groupNavigation.getKey()))); } } } } } // Sort the list finally Collections.sort(navigations, USER_NAVIGATION_COMPARATOR); } // this.navigations = Collections.unmodifiableList(navigations); } return navigations; } public UserNavigation getNavigation(SiteKey key) throws NullPointerException, UserPortalException, NavigationServiceException { if (key == null) { throw new NullPointerException("No null key accepted"); } for (UserNavigation navigation : getNavigations()) { if (navigation.getKey().equals(key)) { return navigation; } } return null; } public void refresh() { navigations = null; } public UserNode getNode(UserNavigation userNavigation, Scope scope, UserNodeFilterConfig filterConfig, NodeChangeListener<UserNode> listener) throws NullPointerException, UserPortalException, NavigationServiceException { UserNodeContext context = new UserNodeContext(userNavigation, filterConfig); NodeContext<UserNode> nodeContext = service.getNavigationService().loadNode(context, userNavigation.navigation, scope, new UserNodeListener(listener)); if (nodeContext != null) { return nodeContext.getNode().filter(); } else { return null; } } public void updateNode(UserNode node, Scope scope, NodeChangeListener<UserNode> listener) throws NullPointerException, IllegalArgumentException, UserPortalException, NavigationServiceException { if (node == null) { throw new NullPointerException("No null node accepted"); } service.getNavigationService().updateNode(node.context, scope, new UserNodeListener(listener)); node.filter(); } public void rebaseNode(UserNode node, Scope scope, NodeChangeListener<UserNode> listener) throws NullPointerException, IllegalArgumentException, UserPortalException, NavigationServiceException { if (node == null) { throw new NullPointerException("No null node accepted"); } service.getNavigationService().rebaseNode(node.context, scope, new UserNodeListener(listener)); node.filter(); } public void saveNode(UserNode node, NodeChangeListener<UserNode> listener) throws NullPointerException, UserPortalException, NavigationServiceException { if (node == null) { throw new NullPointerException("No null node accepted"); } service.getNavigationService().saveNode(node.context, new UserNodeListener(listener)); node.filter(); } /** * Note : the scope implementation is not stateless but we don't care in this case. */ private class MatchingScope extends GenericScope.Branch.Visitor implements Scope { final UserNavigation userNavigation; final UserNodeFilterConfig filterConfig; final String[] match; int score; String id; UserNode userNode; MatchingScope(UserNavigation userNavigation, UserNodeFilterConfig filterConfig, String[] match) { this.userNavigation = userNavigation; this.filterConfig = filterConfig; this.match = match; } public Visitor get() { return this; } @Override protected int getSize() { return match.length; } @Override protected String getName(int index) { return match[index]; } @Override protected Visitor getFederated() { return Scope.CHILDREN.get(); } void resolve() throws NavigationServiceException { UserNodeContext context = new UserNodeContext(userNavigation, filterConfig); NodeContext<UserNode> nodeContext = service.getNavigationService().loadNode(context, userNavigation.navigation, this, null); if (score > 0) { userNode = nodeContext.getNode().filter().find(id); } } public VisitMode enter(int depth, String id, String name, NodeState state) { VisitMode vm = super.enter(depth, id, name, state); if (depth == 0) { score = 0; MatchingScope.this.id = null; } else { if (vm == VisitMode.ALL_CHILDREN) { MatchingScope.this.id = id; score++; } } return vm; } } public UserNode getDefaultPath(UserNodeFilterConfig filterConfig) throws UserPortalException, NavigationServiceException { for (UserNavigation userNavigation : getNavigations()) { UserNode node = getDefaultPath(userNavigation, filterConfig); if (node != null) { return node; } } // return null; } public UserNode getDefaultPath(UserNavigation userNavigation, UserNodeFilterConfig filterConfig) throws UserPortalException, NavigationServiceException { NavigationContext navigation = userNavigation.navigation; if (navigation.getState() != null) { UserNodeContext context = new UserNodeContext(userNavigation, null); NodeContext<UserNode> nodeContext = service.getNavigationService().loadNode(context, navigation, Scope.CHILDREN, null); if (nodeContext != null) { UserNode root = nodeContext.getNode(); // if (filterConfig == null) { filterConfig = UserNodeFilterConfig.builder().build(); } UserNodeFilter filter = new UserNodeFilter(userNavigation.portal, filterConfig); // Filter node by node for (UserNode node : root.getChildren()) { if (node.context.accept(filter)) { return node; } } } } return null; } public UserNode resolvePath(UserNodeFilterConfig filterConfig, String path) throws NullPointerException, UserPortalException, NavigationServiceException { if (path == null) { throw new NullPointerException("No null path accepted"); } // Parse path String[] segments = Utils.parsePath(path); // Find the first navigation available or return null if (segments == null) { return getDefaultPath(filterConfig); } // Create a filter as we need one for the path if (filterConfig == null) { filterConfig = UserNodeFilterConfig.builder().build(); } else { filterConfig = UserNodeFilterConfig.builder(filterConfig).build(); } // Restrict the filter with path filterConfig.path = segments; // Get navigations List<UserNavigation> navigations = getNavigations(); // MatchingScope best = null; for (UserNavigation navigation : navigations) { MatchingScope scope = new MatchingScope(navigation, filterConfig, segments); scope.resolve(); if (scope.score == segments.length) { best = scope; break; } else { if (best == null) { best = scope; } else { if (scope.score > best.score) { best = scope; } } } } // if (best != null && best.score > 0) { UserNode ret = best.userNode; if (ret != null) { ret.owner.filterConfig.path = null; } return ret; } else { return getDefaultPath(null); } } public UserNode resolvePath(UserNavigation navigation, UserNodeFilterConfig filterConfig, String path) throws NullPointerException, UserPortalException, NavigationServiceException { if (navigation == null) { throw new NullPointerException("No null navigation accepted"); } if (path == null) { throw new NullPointerException("No null path accepted"); } // String[] segments = Utils.parsePath(path); // if (segments == null) { return null; } // Create a filter as we need one for the path if (filterConfig == null) { filterConfig = UserNodeFilterConfig.builder().build(); } else { filterConfig = UserNodeFilterConfig.builder(filterConfig).build(); } // Restrict the filter with the path filterConfig.path = segments; // MatchingScope scope = new MatchingScope(navigation, filterConfig, segments); scope.resolve(); // if (scope.score > 0) { UserNode ret = scope.userNode; if (ret != null) { ret.owner.filterConfig.path = null; } return ret; } else { return null; } } }