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