001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Anahide Tchertchian
016 */
017package org.nuxeo.ecm.webapp.contentbrowser;
018
019import java.io.Serializable;
020import java.util.HashMap;
021import java.util.List;
022import java.util.Map;
023
024import javax.faces.context.FacesContext;
025
026import org.apache.commons.lang.StringUtils;
027import org.jboss.seam.ScopeType;
028import org.jboss.seam.annotations.In;
029import org.jboss.seam.annotations.Name;
030import org.jboss.seam.annotations.Scope;
031import org.jboss.seam.annotations.web.RequestParameter;
032import org.nuxeo.ecm.core.api.CoreSession;
033import org.nuxeo.ecm.core.api.DocumentModel;
034import org.nuxeo.ecm.core.api.IdRef;
035import org.nuxeo.ecm.core.api.NuxeoException;
036import org.nuxeo.ecm.core.api.PathRef;
037import org.nuxeo.ecm.core.api.security.SecurityConstants;
038import org.nuxeo.ecm.platform.query.api.PageProvider;
039import org.nuxeo.ecm.platform.query.api.PageProviderDefinition;
040import org.nuxeo.ecm.platform.query.api.PageProviderService;
041import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider;
042import org.nuxeo.ecm.platform.ui.web.util.ComponentTagUtils;
043import org.nuxeo.runtime.api.Framework;
044
045/**
046 * Provides suggestion methods on documents
047 *
048 * @since 5.4.2
049 */
050@Name("docSuggestionActions")
051@Scope(ScopeType.PAGE)
052public class DocumentSuggestionActions implements Serializable {
053
054    private static final long serialVersionUID = 1L;
055
056    public static final String DEFAULT_PAGE_PROVIDER_NAME = "default_document_suggestion";
057
058    @In(required = true)
059    protected transient CoreSession documentManager;
060
061    @RequestParameter
062    protected String pageProviderName;
063
064    /**
065     * If true, '*' will be appended to the pattern to do a prefix search.
066     *
067     * @since 5.7.2
068     */
069    @RequestParameter
070    protected Boolean prefixSearch;
071
072    protected String cachedPageProviderName;
073
074    protected Object cachedInput;
075
076    protected List<DocumentModel> cachedSuggestions;
077
078    public List<DocumentModel> getDocSuggestions(Object input) {
079        if (equals(cachedPageProviderName, pageProviderName) && equals(cachedInput, input)) {
080            return cachedSuggestions;
081        }
082
083        String pattern = (String) input;
084        PageProvider<DocumentModel> pp = getPageProvider(pattern);
085        List<DocumentModel> documents = pp.getCurrentPage();
086        cachedInput = input;
087        cachedSuggestions = documents;
088        return documents;
089    }
090
091    /**
092     * Returns suggestion documents matching given pattern.
093     * <p>
094     * Search is performed using the page provider referenced in the widget definition (defaults to
095     * {@link #DEFAULT_PAGE_PROVIDER_NAME}).
096     * <p>
097     * Since 5.7, if the page provider defines parameters, they're added to the implicit parameter (the pattern) that
098     * stays the first one to be referenced in the search query.
099     *
100     * @param pattern: the input as typed by user in suggestion box
101     */
102    @SuppressWarnings("unchecked")
103    protected PageProvider<DocumentModel> getPageProvider(String pattern) {
104        String ppName = DEFAULT_PAGE_PROVIDER_NAME;
105        if (pageProviderName != null && !StringUtils.isEmpty(pageProviderName)) {
106            ppName = pageProviderName;
107        }
108        PageProviderService ppService = Framework.getService(PageProviderService.class);
109        Map<String, Serializable> props = new HashMap<String, Serializable>();
110        props.put(CoreQueryDocumentPageProvider.CORE_SESSION_PROPERTY, (Serializable) documentManager);
111        // resolve additional parameters
112        PageProviderDefinition ppDef = ppService.getPageProviderDefinition(ppName);
113        String[] params = ppDef.getQueryParameters();
114        if (params == null) {
115            params = new String[0];
116        }
117        FacesContext context = FacesContext.getCurrentInstance();
118        Object[] resolvedParams = new Object[params.length + 1];
119
120        if (Boolean.TRUE.equals(prefixSearch) && !pattern.endsWith(" ")) {
121            pattern += "*";
122        }
123
124        resolvedParams[0] = pattern;
125        for (int i = 0; i < params.length; i++) {
126            resolvedParams[i + 1] = ComponentTagUtils.resolveElExpression(context, params[i]);
127        }
128        PageProvider<DocumentModel> pp = (PageProvider<DocumentModel>) ppService.getPageProvider(ppName, null, null,
129                null, props, resolvedParams);
130        if (pp == null) {
131            throw new NuxeoException("Page provider not found: " + ppName);
132        }
133        return pp;
134    }
135
136    public boolean getDocumentExistsAndIsVisibleWithId(String id) {
137        if (StringUtils.isEmpty(id)) {
138            return false;
139        }
140        IdRef ref = new IdRef(id);
141        return documentManager.exists(ref) && documentManager.hasPermission(ref, SecurityConstants.READ);
142    }
143
144    public boolean getDocumentExistsAndIsVisibleWithPath(String path) {
145        if (StringUtils.isEmpty(path)) {
146            return false;
147        }
148        PathRef ref = new PathRef(path);
149        return documentManager.exists(ref) && documentManager.hasPermission(ref, SecurityConstants.READ);
150    }
151
152    public DocumentModel getDocumentWithId(String id) {
153        if (StringUtils.isEmpty(id)) {
154            return null;
155        }
156        return documentManager.getDocument(new IdRef(id));
157    }
158
159    public DocumentModel getDocumentWithPath(String path) {
160        if (StringUtils.isEmpty(path)) {
161            return null;
162        }
163        return documentManager.getDocument(new PathRef(path));
164    }
165
166    protected boolean equals(Object item1, Object item2) {
167        if (item1 == null && item2 == null) {
168            return true;
169        } else if (item1 == null) {
170            return false;
171        } else {
172            return item1.equals(item2);
173        }
174    }
175
176}