001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thomas Roger
018 */
019package org.nuxeo.ecm.webapp.action;
020
021import static org.jboss.seam.ScopeType.CONVERSATION;
022import static org.nuxeo.ecm.webapp.helpers.EventNames.NAVIGATE_TO_DOCUMENT;
023
024import java.io.Serializable;
025import java.util.HashMap;
026import java.util.Map;
027
028import javax.faces.context.FacesContext;
029import javax.servlet.ServletRequest;
030import javax.servlet.http.HttpServletRequest;
031
032import org.jboss.seam.annotations.In;
033import org.jboss.seam.annotations.Install;
034import org.jboss.seam.annotations.Name;
035import org.jboss.seam.annotations.Observer;
036import org.jboss.seam.annotations.Scope;
037import org.nuxeo.ecm.core.api.CoreSession;
038import org.nuxeo.ecm.core.api.DocumentModel;
039import org.nuxeo.ecm.core.api.PathRef;
040import org.nuxeo.ecm.core.api.repository.RepositoryManager;
041import org.nuxeo.ecm.core.api.security.SecurityConstants;
042import org.nuxeo.ecm.platform.actions.Action;
043import org.nuxeo.ecm.platform.actions.ejb.ActionManager;
044import org.nuxeo.ecm.platform.types.adapter.TypeInfo;
045import org.nuxeo.ecm.platform.ui.web.api.NavigationContext;
046import org.nuxeo.ecm.platform.ui.web.api.WebActions;
047import org.nuxeo.ecm.platform.ui.web.rest.api.URLPolicyService;
048import org.nuxeo.ecm.platform.url.api.DocumentView;
049import org.nuxeo.runtime.api.Framework;
050
051/**
052 * Handle Main tab related actions.
053 * <p>
054 * Maintains a Map of tab id -> contextual document.
055 *
056 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
057 * @since 5.4.2
058 */
059@Name("mainTabsActions")
060@Scope(CONVERSATION)
061@Install(precedence = Install.FRAMEWORK)
062public class MainTabsActions implements Serializable {
063
064    private static final long serialVersionUID = 1L;
065
066    /**
067     * @deprecated since 5.5, use {@link WebActions#MAIN_TABS_CATEGORY} instead
068     */
069    @Deprecated
070    public static final String MAIN_TABS_CATEGORY = WebActions.MAIN_TABS_CATEGORY;
071
072    /**
073     * @deprecated since 5.5, use {@link WebActions#DOCUMENTS_MAIN_TAB_ID} instead
074     */
075    @Deprecated
076    public static final String DOCUMENT_MANAGEMENT_ACTION = WebActions.DOCUMENTS_MAIN_TAB_ID;
077
078    /**
079     * @deprecated since 5.5, use {@link WebActions#TAB_IDS_PARAMETER} instead
080     */
081    @Deprecated
082    public static final String TAB_IDS_PARAMETER = WebActions.TAB_IDS_PARAMETER;
083
084    /**
085     * @deprecated since 5.5, use {@link WebActions#MAIN_TAB_ID_PARAMETER} instead
086     */
087    @Deprecated
088    public static final String MAIN_TAB_ID_PARAMETER = WebActions.MAIN_TAB_ID_PARAMETER;
089
090    public static final String DEFAULT_VIEW = "view_documents";
091
092    @In(create = true)
093    protected transient RepositoryManager repositoryManager;
094
095    @In(create = true, required = false)
096    protected transient CoreSession documentManager;
097
098    @In(create = true, required = false)
099    protected transient NavigationContext navigationContext;
100
101    @In(create = true)
102    protected transient WebActions webActions;
103
104    @In(create = true, required = false)
105    protected transient ActionManager actionManager;
106
107    protected Map<String, DocumentModel> documentsByMainTabs = new HashMap<String, DocumentModel>();
108
109    @Observer({ NAVIGATE_TO_DOCUMENT })
110    public void updateContextualDocument() {
111        if (!shouldHandleRequest()) {
112            return;
113        }
114        String currentMainTab = getCurrentMainTabFromRequest();
115        if (currentMainTab == null) {
116            currentMainTab = webActions.getCurrentTabId(WebActions.MAIN_TABS_CATEGORY);
117        }
118        DocumentModel currentDocument = navigationContext.getCurrentDocument();
119        documentsByMainTabs.put(currentMainTab, currentDocument);
120    }
121
122    /**
123     * Only handle non POST requests
124     */
125    protected boolean shouldHandleRequest() {
126        ServletRequest request = (ServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
127        if (request instanceof HttpServletRequest) {
128            HttpServletRequest httpServletRequest = (HttpServletRequest) request;
129            return !httpServletRequest.getMethod().equalsIgnoreCase("post");
130        }
131        return false;
132    }
133
134    protected String getCurrentMainTabFromRequest() {
135        URLPolicyService service = Framework.getService(URLPolicyService.class);
136        ServletRequest request = (ServletRequest) FacesContext.getCurrentInstance().getExternalContext().getRequest();
137        if (request instanceof HttpServletRequest) {
138            DocumentView docView = service.getDocumentViewFromRequest((HttpServletRequest) request);
139            if (docView == null) {
140                return null;
141            }
142            String tabIds = docView.getParameter(WebActions.TAB_IDS_PARAMETER);
143            String mainTabId = docView.getParameter(WebActions.MAIN_TAB_ID_PARAMETER);
144            if (mainTabId != null && !mainTabId.isEmpty()) {
145                tabIds = mainTabId;
146            }
147            if (tabIds != null && tabIds.contains(WebActions.MAIN_TABS_CATEGORY)) {
148                String[] encodedActions = tabIds.split(",");
149                for (String encodedAction : encodedActions) {
150                    if (encodedAction.startsWith(WebActions.MAIN_TABS_CATEGORY)) {
151                        String[] actionInfo = encodedAction.split(":");
152                        if (actionInfo != null && actionInfo.length > 1) {
153                            return actionInfo[1];
154                        }
155                    }
156                }
157            }
158        }
159        return null;
160    }
161
162    /**
163     * Set the document used for a given {@code mainTabId}.
164     *
165     * @since 5.7
166     */
167    public void setDocumentFor(String mainTabId, DocumentModel doc) {
168        documentsByMainTabs.put(mainTabId, doc);
169    }
170
171    public DocumentModel getDocumentFor(String mainTabId) {
172        return getDocumentFor(mainTabId, navigationContext.getCurrentDocument());
173    }
174
175    public DocumentModel getDocumentFor(String mainTabId, DocumentModel defaultDocument) {
176        DocumentModel doc = documentsByMainTabs.get(mainTabId);
177        if (doc == null || !documentManager.exists(doc.getRef())
178                || !documentManager.hasPermission(doc.getRef(), SecurityConstants.READ)) {
179            documentsByMainTabs.put(mainTabId, defaultDocument);
180            doc = null;
181        }
182
183        if (doc != null && !documentManager.exists(new PathRef(doc.getPathAsString()))) {
184            // path has changed, refresh the document to have a correct URL
185            doc = documentManager.getDocument(doc.getRef());
186            documentsByMainTabs.put(mainTabId, doc);
187        }
188
189        return doc != null ? doc : defaultDocument;
190    }
191
192    public String getViewFor(Action mainTabAction) {
193        if (!mainTabAction.getId().equals(WebActions.DOCUMENTS_MAIN_TAB_ID)) {
194            return mainTabAction.getLink();
195        }
196
197        DocumentModel doc = getDocumentFor(mainTabAction.getId(), navigationContext.getCurrentDocument());
198        if (doc != null) {
199            TypeInfo typeInfo = doc.getAdapter(TypeInfo.class);
200            return typeInfo.getDefaultView();
201        }
202        return DEFAULT_VIEW;
203    }
204
205    public String getViewFor(String mainTabId) {
206        Action mainTabAction = actionManager.getAction(mainTabId);
207        return mainTabAction != null ? getViewFor(mainTabAction) : null;
208    }
209
210    public String getPatternFor(String mainTabId) {
211        URLPolicyService service = Framework.getService(URLPolicyService.class);
212        // FIXME: find some way to reference the pattern in the action,
213        // assume the pattern will be the same than the default one for
214        // now, or use the default one.
215        if (!WebActions.DOCUMENTS_MAIN_TAB_ID.equals(mainTabId) && service.hasPattern(mainTabId)) {
216            return mainTabId;
217        }
218        return service.getDefaultPatternName();
219    }
220
221    public boolean isOnMainTab(String mainTabId) {
222        if (mainTabId != null && mainTabId.equals(webActions.getCurrentTabId(WebActions.MAIN_TABS_CATEGORY))) {
223            return true;
224        }
225        return false;
226    }
227
228}