/* * (C) Copyright 2007-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the GNU Lesser General Public License * (LGPL) version 2.1 which accompanies this distribution, and is available at * http://www.gnu.org/licenses/lgpl.html * * This library 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. * * Contributors: * Eugen Ionica * Anahide Tchertchian * Florent Guillaume */ package org.nuxeo.ecm.webapp.action; import static org.jboss.seam.ScopeType.CONVERSATION; import static org.jboss.seam.ScopeType.EVENT; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import javax.faces.context.ExternalContext; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.Component; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Factory; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Observer; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.nuxeo.ecm.core.api.ClientException; import org.nuxeo.ecm.core.api.CoreSession; import org.nuxeo.ecm.core.api.DocumentModel; import org.nuxeo.ecm.platform.actions.Action; import org.nuxeo.ecm.platform.actions.ActionContext; import org.nuxeo.ecm.platform.actions.ejb.ActionManager; import org.nuxeo.ecm.platform.ui.web.api.NavigationContext; import org.nuxeo.ecm.platform.ui.web.api.TabActionsSelection; import org.nuxeo.ecm.platform.ui.web.api.WebActions; import org.nuxeo.ecm.platform.web.common.UserAgentMatcher; import org.nuxeo.ecm.webapp.helpers.EventNames; import org.nuxeo.runtime.api.Framework; /** * Component that handles actions retrieval as well as current tab(s) * selection. * * @author Eugen Ionica * @author Anahide Tchertchian * @author Florent Guillaume * @author <a href="mailto:cbaican@nuxeo.com">Catalin Baican</a> */ @Name("webActions") @Scope(CONVERSATION) @Install(precedence = Install.FRAMEWORK) public class WebActionsBean implements WebActions, Serializable { private static final long serialVersionUID = 1959221536502251848L; private static final Log log = LogFactory.getLog(WebActionsBean.class); @In(create = true, required = false) protected transient ActionManager actionManager; @In(create = true, required = false) protected transient ActionContextProvider actionContextProvider; @In(create = true, required = false) protected transient NavigationContext navigationContext; protected List<Action> tabsActionsList; protected String subTabsCategory; protected List<Action> subTabsActionsList; protected TabActionsSelection currentTabActions = new TabActionsSelection(); // actions management @Override public List<Action> getActionsList(String category, ActionContext context, boolean hideUnavailableAction) { List<Action> list = new ArrayList<Action>(); List<String> categories = new ArrayList<String>(); if (category != null) { String[] split = category.split(",|\\s"); if (split != null) { for (String item : split) { if (!StringUtils.isBlank(item)) { categories.add(item.trim()); } } } } for (String cat : categories) { List<Action> actions = actionManager.getActions(cat, context, hideUnavailableAction); if (actions != null) { list.addAll(actions); } } return list; } @Override public List<Action> getActionsList(String category, Boolean hideUnavailableAction) { return getActionsList(category, createActionContext(), Boolean.TRUE.equals(hideUnavailableAction)); } public List<Action> getActionsList(String category, ActionContext context) { return getActionsList(category, context, true); } @Override public List<Action> getActionsListForDocument(String category, DocumentModel document, boolean hideUnavailableAction) { return getActionsList(category, createActionContext(document), hideUnavailableAction); } public List<Action> getActionsList(String category) { return getActionsList(category, createActionContext()); } public List<Action> getUnfiltredActionsList(String category, ActionContext context) { return getActionsList(category, context, false); } public List<Action> getUnfiltredActionsList(String category) { return getUnfiltredActionsList(category, createActionContext()); } public List<Action> getAllActions(String category) { return actionManager.getAllActions(category); } protected ActionContext createActionContext() { return actionContextProvider.createActionContext(); } protected ActionContext createActionContext(DocumentModel document) { return actionContextProvider.createActionContext(document); } @Override public Action getAction(String actionId, boolean hideUnavailableAction) { return actionManager.getAction(actionId, createActionContext(), hideUnavailableAction); } @Override public Action getActionForDocument(String actionId, DocumentModel document, boolean hideUnavailableAction) { return getAction(actionId, createActionContext(document), hideUnavailableAction); } @Override public Action getAction(String actionId, ActionContext context, boolean hideUnavailableAction) { return actionManager.getAction(actionId, context, hideUnavailableAction); } @Override public boolean checkFilter(String filterId) { return actionManager.checkFilter(filterId, createActionContext()); } // tabs management protected Action getDefaultTab(String category) { if (DEFAULT_TABS_CATEGORY.equals(category)) { if (getTabsList() == null) { return null; } try { return tabsActionsList.get(0); } catch (IndexOutOfBoundsException e) { return null; } } else { // check if it's a subtab if (subTabsCategory != null && subTabsCategory.equals(category)) { if (getSubTabsList() == null) { return null; } try { return subTabsActionsList.get(0); } catch (IndexOutOfBoundsException e) { return null; } } // retrieve actions in given category and take the first one found List<Action> actions = getActionsList(category, createActionContext()); if (actions != null && actions.size() > 0) { // make sure selection event is sent Action action = actions.get(0); setCurrentTabAction(category, action); return action; } return null; } } @Override public Action getCurrentTabAction(String category) { Action action = currentTabActions.getCurrentTabAction(category); if (action == null) { // return default action action = getDefaultTab(category); } return action; } @Override public void setCurrentTabAction(String category, Action tabAction) { currentTabActions.setCurrentTabAction(category, tabAction); // additional cleanup of this cache if (WebActions.DEFAULT_TABS_CATEGORY.equals(category)) { resetSubTabs(); } } @Override public Action getCurrentSubTabAction(String parentActionId) { return getCurrentTabAction(TabActionsSelection.getSubTabCategory(parentActionId)); } @Override public String getCurrentTabId(String category) { Action action = getCurrentTabAction(category); if (action != null) { return action.getId(); } return null; } public boolean hasCurrentTabId(String category) { if (currentTabActions.getCurrentTabAction(category) == null) { return false; } return true; } @Override public void setCurrentTabId(String category, String tabId, String... subTabIds) { currentTabActions.setCurrentTabId(actionManager, createActionContext(), category, tabId, subTabIds); // additional cleanup of this cache if (WebActions.DEFAULT_TABS_CATEGORY.equals(category)) { resetSubTabs(); } } @Override public String getCurrentTabIds() { return currentTabActions.getCurrentTabIds(); } @Override public void setCurrentTabIds(String tabIds) { currentTabActions.setCurrentTabIds(actionManager, createActionContext(), tabIds); // reset subtabs just in case resetSubTabs(); } @Override public void resetCurrentTabs() { currentTabActions.resetCurrentTabs(); } @Override public void resetCurrentTabs(String category) { currentTabActions.resetCurrentTabs(category); } // tabs management specific to the DEFAULT_TABS_CATEGORY public void resetCurrentTab() { resetCurrentTabs(DEFAULT_TABS_CATEGORY); } protected void resetSubTabs() { subTabsCategory = null; subTabsActionsList = null; } @Observer(value = { EventNames.USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED, EventNames.LOCATION_SELECTION_CHANGED }, create = false) @BypassInterceptors public void resetTabList() { tabsActionsList = null; resetSubTabs(); resetCurrentTab(); } @Factory(value = "tabsActionsList", scope = EVENT) public List<Action> getTabsList() { if (tabsActionsList == null) { tabsActionsList = getActionsList(DEFAULT_TABS_CATEGORY); } return tabsActionsList; } @Factory(value = "subTabsActionsList", scope = EVENT) public List<Action> getSubTabsList() { if (subTabsActionsList == null) { String currentTabId = getCurrentTabId(); if (currentTabId != null) { subTabsCategory = TabActionsSelection.getSubTabCategory(currentTabId); subTabsActionsList = getActionsList(subTabsCategory); } } return subTabsActionsList; } @Factory(value = "currentTabAction", scope = EVENT) public Action getCurrentTabAction() { return getCurrentTabAction(DEFAULT_TABS_CATEGORY); } public void setCurrentTabAction(Action currentTabAction) { setCurrentTabAction(DEFAULT_TABS_CATEGORY, currentTabAction); } @Factory(value = "currentSubTabAction", scope = EVENT) public Action getCurrentSubTabAction() { Action action = getCurrentTabAction(); if (action != null) { return getCurrentTabAction(TabActionsSelection.getSubTabCategory(action.getId())); } return null; } public void setCurrentSubTabAction(Action tabAction) { if (tabAction != null) { String[] categories = tabAction.getCategories(); if (categories == null || categories.length == 0) { log.error(String.format("Cannot set subtab with id '%s' " + "as this action does not hold any category", tabAction.getId())); return; } if (categories.length != 1) { log.error(String.format( "Setting subtab with id '%s' with category '%s': " + "use webActions#setCurrentTabAction(action, category) " + "to specify another category", tabAction.getId(), categories[0])); } setCurrentTabAction(categories[0], tabAction); } } public String getCurrentTabId() { Action currentTab = getCurrentTabAction(); if (currentTab != null) { return currentTab.getId(); } return null; } public void setCurrentTabId(String tabId) { if (tabId != null) { // do not reset tab when not set as this method // is used for compatibility in default url pattern setCurrentTabId(DEFAULT_TABS_CATEGORY, tabId); } } public String getCurrentSubTabId() { Action currentSubTab = getCurrentSubTabAction(); if (currentSubTab != null) { return currentSubTab.getId(); } return null; } public void setCurrentSubTabId(String tabId) { if (tabId != null) { // do not reset tab when not set as this method // is used for compatibility in default url pattern Action action = getCurrentTabAction(); if (action != null) { setCurrentTabId( TabActionsSelection.getSubTabCategory(action.getId()), tabId); } } } // navigation API public String setCurrentTabAndNavigate(String currentTabActionId) { return setCurrentTabAndNavigate(navigationContext.getCurrentDocument(), currentTabActionId); } public String setCurrentTabAndNavigate(DocumentModel document, String currentTabActionId) { // navigate first because it will reset the tabs list String viewId = null; try { viewId = navigationContext.navigateToDocument(document); } catch (ClientException e) { } // force creation of new actions if needed getTabsList(); // set current tab setCurrentTabId(currentTabActionId); return viewId; } // deprecated API @Deprecated public List<Action> getSubViewActionsList() { return getActionsList("SUBVIEW_UPPER_LIST"); } @Deprecated public void selectTabAction() { // if (tabAction != null) { // setCurrentTabAction(tabAction); // } } @Deprecated public String getCurrentLifeCycleState() throws ClientException { // only user of documentManager in this bean, look it up by hand CoreSession documentManager = (CoreSession) Component.getInstance("documentManager"); return documentManager.getCurrentLifeCycleState(navigationContext.getCurrentDocument().getRef()); } @Deprecated public void setTabsList(List<Action> tabsList) { tabsActionsList = tabsList; } @Deprecated public void setSubTabsList(List<Action> tabsList) { subTabsActionsList = tabsList; subTabsCategory = null; if (tabsList != null) { // BBB code for (Action action : tabsList) { if (action != null) { String[] categories = action.getCategories(); if (categories != null && categories.length > 0) { subTabsCategory = categories[0]; break; } } } } } @Deprecated public void setCurrentTabAction(String currentTabActionId) { setCurrentTabId(currentTabActionId); } @Factory(value = "useAjaxTabs", scope = ScopeType.SESSION) public boolean useAjaxTabs() { if (Framework.isBooleanPropertyTrue(AJAX_TAB_PROPERTY)) { return canUseAjaxTabs(); } return false; } @Factory(value = "canUseAjaxTabs", scope = ScopeType.SESSION) public boolean canUseAjaxTabs() { FacesContext context = FacesContext.getCurrentInstance(); ExternalContext econtext = context.getExternalContext(); HttpServletRequest request = (HttpServletRequest) econtext.getRequest(); String ua = request.getHeader("User-Agent"); return UserAgentMatcher.isHistoryPushStateSupported(ua); } }