001/*
002 * (C) Copyright 2010 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.platform.query.core;
018
019import java.io.Serializable;
020import java.util.Collections;
021import java.util.HashMap;
022import java.util.List;
023import java.util.Map;
024import java.util.Set;
025
026import org.nuxeo.ecm.core.api.DocumentModel;
027import org.nuxeo.ecm.core.api.NuxeoException;
028import org.nuxeo.ecm.core.api.SortInfo;
029import org.nuxeo.ecm.platform.query.api.PageProvider;
030import org.nuxeo.ecm.platform.query.api.PageProviderClassReplacerDefinition;
031import org.nuxeo.ecm.platform.query.api.PageProviderDefinition;
032import org.nuxeo.ecm.platform.query.api.PageProviderService;
033import org.nuxeo.ecm.platform.query.nxql.CoreQueryDocumentPageProvider;
034import org.nuxeo.runtime.model.ComponentContext;
035import org.nuxeo.runtime.model.ComponentInstance;
036import org.nuxeo.runtime.model.DefaultComponent;
037
038/**
039 * @author Anahide Tchertchian
040 * @since 5.4
041 */
042public class PageProviderServiceImpl extends DefaultComponent implements PageProviderService {
043
044    private static final long serialVersionUID = 1L;
045
046    public static final String PROVIDER_EP = "providers";
047
048    // @since 6.0
049    public static final String REPLACER_EP = "replacers";
050
051    /**
052     * @deprecated since 6.0, use {@link PageProviderService#NAMED_PARAMETERS} instead.
053     */
054    @Deprecated
055    public static final String NAMED_PARAMETERS = "namedParameters";
056
057    protected PageProviderRegistry providerReg = new PageProviderRegistry();
058
059    // @since 6.0
060    protected PageProviderClassReplacerRegistry replacersReg = new PageProviderClassReplacerRegistry();
061
062    @Override
063    public PageProviderDefinition getPageProviderDefinition(String name) {
064        PageProviderDefinition def = providerReg.getPageProvider(name);
065        if (def != null) {
066            return def.clone();
067        }
068        return def;
069    }
070
071    @Override
072    public PageProvider<?> getPageProvider(String name, PageProviderDefinition desc, DocumentModel searchDocument,
073            List<SortInfo> sortInfos, Long pageSize, Long currentPage, Map<String, Serializable> properties,
074            Object... parameters) {
075        if (desc == null) {
076            return null;
077        }
078        PageProvider<?> pageProvider = newPageProviderInstance(name, desc);
079        // XXX: set local properties without resolving, and merge with given
080        // properties.
081        Map<String, Serializable> allProps = new HashMap<String, Serializable>();
082        Map<String, String> localProps = desc.getProperties();
083        if (localProps != null) {
084            allProps.putAll(localProps);
085        }
086        if (properties != null) {
087            allProps.putAll(properties);
088        }
089        pageProvider.setProperties(allProps);
090        pageProvider.setSortable(desc.isSortable());
091        pageProvider.setParameters(parameters);
092        pageProvider.setPageSizeOptions(desc.getPageSizeOptions());
093        if (searchDocument != null) {
094            pageProvider.setSearchDocumentModel(searchDocument);
095        }
096
097        Long maxPageSize = desc.getMaxPageSize();
098        if (maxPageSize != null) {
099            pageProvider.setMaxPageSize(maxPageSize.longValue());
100        }
101
102        if (sortInfos == null) {
103            pageProvider.setSortInfos(desc.getSortInfos());
104        } else {
105            pageProvider.setSortInfos(sortInfos);
106        }
107        if (pageSize == null || pageSize.longValue() < 0) {
108            pageProvider.setPageSize(desc.getPageSize());
109        } else {
110            pageProvider.setPageSize(pageSize.longValue());
111        }
112        if (currentPage != null && currentPage.longValue() > 0) {
113            pageProvider.setCurrentPage(currentPage.longValue());
114        }
115
116        return pageProvider;
117    }
118
119    protected PageProvider<?> newPageProviderInstance(String name, PageProviderDefinition desc) {
120        PageProvider<?> ret;
121        if (desc instanceof CoreQueryPageProviderDescriptor) {
122            ret = newCoreQueryPageProviderInstance(name);
123        } else if (desc instanceof GenericPageProviderDescriptor) {
124            Class<PageProvider<?>> klass = ((GenericPageProviderDescriptor) desc).getPageProviderClass();
125            ret = newPageProviderInstance(name, klass);
126        } else {
127            throw new NuxeoException(String.format("Invalid page provider definition with name '%s'", name));
128        }
129        ret.setName(name);
130        ret.setDefinition(desc);
131        return ret;
132    }
133
134    protected PageProvider<?> newCoreQueryPageProviderInstance(String name) {
135        PageProvider<?> ret;
136        Class<? extends PageProvider<?>> klass = replacersReg.getClassForPageProvider(name);
137        if (klass == null) {
138            ret = new CoreQueryDocumentPageProvider();
139        } else {
140            ret = newPageProviderInstance(name, klass);
141        }
142        return ret;
143    }
144
145    protected PageProvider<?> newPageProviderInstance(String name, Class<? extends PageProvider<?>> klass)
146            {
147        PageProvider<?> ret;
148        if (klass == null) {
149            throw new NuxeoException(String.format(
150                    "Cannot find class for page provider definition with name '%s': check" + " ERROR logs at startup",
151                    name));
152        }
153        try {
154            ret = klass.newInstance();
155        } catch (ReflectiveOperationException e) {
156            throw new NuxeoException(String.format(
157                    "Cannot create an instance of class %s for page provider definition" + " with name '%s'",
158                    klass.getName(), name), e);
159        }
160        return ret;
161    }
162
163    @Deprecated
164    @Override
165    public PageProvider<?> getPageProvider(String name, PageProviderDefinition desc, List<SortInfo> sortInfos,
166            Long pageSize, Long currentPage, Map<String, Serializable> properties, Object... parameters)
167            {
168        return getPageProvider(name, desc, null, sortInfos, pageSize, currentPage, properties, parameters);
169    }
170
171    @Override
172    public PageProvider<?> getPageProvider(String name, DocumentModel searchDocument, List<SortInfo> sortInfos,
173            Long pageSize, Long currentPage, Map<String, Serializable> properties, Object... parameters)
174            {
175        PageProviderDefinition desc = providerReg.getPageProvider(name);
176        if (desc == null) {
177            throw new NuxeoException(String.format("Could not resolve page provider with name '%s'", name));
178        }
179        return getPageProvider(name, desc, searchDocument, sortInfos, pageSize, currentPage, properties, parameters);
180    }
181
182    @Override
183    public PageProvider<?> getPageProvider(String name, List<SortInfo> sortInfos, Long pageSize, Long currentPage,
184            Map<String, Serializable> properties, Object... parameters) {
185        return getPageProvider(name, (DocumentModel) null, sortInfos, pageSize, currentPage, properties, parameters);
186    }
187
188    @Override
189    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
190        if (PROVIDER_EP.equals(extensionPoint)) {
191            PageProviderDefinition desc = (PageProviderDefinition) contribution;
192            registerPageProviderDefinition(desc);
193        } else if (REPLACER_EP.equals(extensionPoint)) {
194            PageProviderClassReplacerDefinition desc = (PageProviderClassReplacerDefinition) contribution;
195            replacersReg.addContribution(desc);
196        }
197    }
198
199    @Override
200    public void unregisterContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
201        if (PROVIDER_EP.equals(extensionPoint)) {
202            PageProviderDefinition desc = (PageProviderDefinition) contribution;
203            unregisterPageProviderDefinition(desc);
204        }
205    }
206
207    @Override
208    public void applicationStarted(ComponentContext context) {
209        super.applicationStarted(context);
210        replacersReg.dumpReplacerMap();
211    }
212
213    @Override
214    public void registerPageProviderDefinition(PageProviderDefinition desc) {
215        providerReg.addContribution(desc);
216    }
217
218    @Override
219    public void unregisterPageProviderDefinition(PageProviderDefinition desc) {
220        providerReg.removeContribution(desc);
221    }
222
223    @Override
224    public Set<String> getPageProviderDefinitionNames() {
225        return Collections.unmodifiableSet(providerReg.providers.keySet());
226    }
227
228}