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