001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.file.collectors;
029
030import org.opencms.file.CmsDataAccessException;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProject;
033import org.opencms.file.CmsProperty;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.main.CmsException;
037
038import java.util.ArrayList;
039import java.util.Arrays;
040import java.util.Collections;
041import java.util.Iterator;
042import java.util.List;
043
044/**
045 * A collector to fetch sorted XML contents in a folder or subtree based on their priority
046 * and date or title values.<p>
047 *
048 * The date or title information has to be stored as property for each resource.<p>
049 *
050 * @since 6.0.0
051 */
052public class CmsPriorityResourceCollector extends A_CmsResourceCollector {
053
054    /** The standard priority value if no value was set on resource. */
055    public static final int PRIORITY_STANDARD = 3;
056
057    /** The name of the channel property to read. */
058    public static final String PROPERTY_CHANNEL = "collector.channel";
059
060    /** The name of the priority property to read. */
061    public static final String PROPERTY_PRIORITY = "collector.priority";
062
063    /** Static array of the collectors implemented by this class. */
064    private static final String[] COLLECTORS = {
065        "allInFolderPriorityDateAsc",
066        "allInSubTreePriorityDateAsc",
067        "allInFolderPriorityDateDesc",
068        "allInSubTreePriorityDateDesc",
069        "allInFolderPriorityTitleDesc",
070        "allInSubTreePriorityTitleDesc",
071        "allMappedToUriPriorityDateAsc",
072        "allMappedToUriPriorityDateDesc"};
073
074    /** Array list for fast collector name lookup. */
075    private static final List<String> COLLECTORS_LIST = Collections.unmodifiableList(Arrays.asList(COLLECTORS));
076
077    /**
078     * @see org.opencms.file.collectors.I_CmsResourceCollector#getCollectorNames()
079     */
080    public List<String> getCollectorNames() {
081
082        return COLLECTORS_LIST;
083    }
084
085    /**
086     * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateLink(org.opencms.file.CmsObject, java.lang.String, java.lang.String)
087     */
088    public String getCreateLink(CmsObject cms, String collectorName, String param) throws CmsException {
089
090        // if action is not set, use default action
091        if (collectorName == null) {
092            collectorName = COLLECTORS[1];
093        }
094
095        switch (COLLECTORS_LIST.indexOf(collectorName)) {
096            case 0:
097            case 2:
098            case 4:
099                // "allInFolderPriorityDateAsc", "allInFolderPriorityDateDesc" or "allInFolderPriorityTitleDesc"
100                return getCreateInFolder(cms, param);
101            case 1:
102            case 3:
103            case 5:
104            case 6:
105            case 7:
106                // "allInSubTreePriorityDateAsc", "allInSubTreePriorityDateDesc" or "allInSubTreePriorityTitleDesc"
107                // "allMappedToUriPriorityDateAsc", "allMappedToUriPriorityDateDesc"
108                return null;
109            default:
110                throw new CmsDataAccessException(
111                    Messages.get().container(Messages.ERR_COLLECTOR_NAME_INVALID_1, collectorName));
112        }
113    }
114
115    /**
116     * @see org.opencms.file.collectors.I_CmsResourceCollector#getCreateParam(org.opencms.file.CmsObject, java.lang.String, java.lang.String)
117     */
118    public String getCreateParam(CmsObject cms, String collectorName, String param) throws CmsDataAccessException {
119
120        // if action is not set, use default action
121        if (collectorName == null) {
122            collectorName = COLLECTORS[1];
123        }
124
125        switch (COLLECTORS_LIST.indexOf(collectorName)) {
126            case 0:
127            case 2:
128            case 4:
129                // "allInFolderPriorityDateAsc", "allInFolderPriorityDateDesc" or "allInFolderPriorityTitleDesc"
130                return param;
131            case 1:
132            case 3:
133            case 5:
134            case 6:
135            case 7:
136                // "allInSubTreePriorityDateAsc", "allInSubTreePriorityDateDesc" or "allInSubTreePriorityTitleDesc"
137                // "allMappedToUriPriorityDateAsc", "allMappedToUriPriorityDateDesc"
138                return null;
139            default:
140                throw new CmsDataAccessException(
141                    Messages.get().container(Messages.ERR_COLLECTOR_NAME_INVALID_1, collectorName));
142        }
143    }
144
145    /**
146     * @see org.opencms.file.collectors.A_CmsResourceCollector#getCreateTypeId(org.opencms.file.CmsObject, java.lang.String, java.lang.String)
147     */
148    @Override
149    public int getCreateTypeId(CmsObject cms, String collectorName, String param) {
150
151        int result = -1;
152        if (param != null) {
153            result = new CmsCollectorData(param).getType();
154        }
155        return result;
156    }
157
158    /**
159     * @see org.opencms.file.collectors.I_CmsResourceCollector#getResults(org.opencms.file.CmsObject, java.lang.String, java.lang.String)
160     */
161    public List<CmsResource> getResults(CmsObject cms, String collectorName, String param)
162    throws CmsDataAccessException, CmsException {
163
164        return getResults(cms, collectorName, param, -1);
165    }
166
167    /**
168     * @see org.opencms.file.collectors.I_CmsResourceCollector#getResults(org.opencms.file.CmsObject, java.lang.String, java.lang.String)
169     */
170    public List<CmsResource> getResults(CmsObject cms, String collectorName, String param, int numResults)
171    throws CmsException, CmsDataAccessException {
172
173        // if action is not set use default
174        if (collectorName == null) {
175            collectorName = COLLECTORS[0];
176        }
177
178        switch (COLLECTORS_LIST.indexOf(collectorName)) {
179
180            case 0:
181                // "allInFolderPriorityDateAsc"
182                return allInFolderPriorityDate(cms, param, false, true, numResults);
183            case 1:
184                // "allInSubTreePriorityDateAsc"
185                return allInFolderPriorityDate(cms, param, true, true, numResults);
186            case 2:
187                // "allInFolderPriorityDateDesc"
188                return allInFolderPriorityDate(cms, param, false, false, numResults);
189            case 3:
190                // "allInSubTreePriorityDateDesc"
191                return allInFolderPriorityDate(cms, param, true, false, numResults);
192            case 4:
193                // "allInFolderPriorityTitleDesc"
194                return allInFolderPriorityTitle(cms, param, false, numResults);
195            case 5:
196                // "allInSubTreePriorityTitleDesc"
197                return allInFolderPriorityTitle(cms, param, true, numResults);
198            case 6:
199                // "allMappedToUriPriorityDateAsc"
200                return allMappedToUriPriorityDate(cms, param, true, numResults);
201            case 7:
202                // "allMappedToUriPriorityDateDesc"
203                return allMappedToUriPriorityDate(cms, param, false, numResults);
204            default:
205                throw new CmsDataAccessException(
206                    Messages.get().container(Messages.ERR_COLLECTOR_NAME_INVALID_1, collectorName));
207        }
208
209    }
210
211    /**
212     * Returns a list of all resource in a specified folder sorted by priority, then date ascending or descending.<p>
213     *
214     * @param cms the current OpenCms user context
215     * @param param the folder name to use
216     * @param tree if true, look in folder and all child folders, if false, look only in given folder
217     * @param asc if true, the date sort order is ascending, otherwise descending
218     * @param numResults the number of results
219     *
220     * @return all resources in the folder matching the given criteria
221     *
222     * @throws CmsException if something goes wrong
223     */
224    protected List<CmsResource> allInFolderPriorityDate(
225        CmsObject cms,
226        String param,
227        boolean tree,
228        boolean asc,
229        int numResults) throws CmsException {
230
231        CmsCollectorData data = new CmsCollectorData(param);
232        String foldername = CmsResource.getFolderPath(data.getFileName());
233
234        CmsResourceFilter filter = CmsResourceFilter.DEFAULT.addRequireType(data.getType()).addExcludeFlags(
235            CmsResource.FLAG_TEMPFILE);
236        if (data.isExcludeTimerange() && !cms.getRequestContext().getCurrentProject().isOnlineProject()) {
237            // include all not yet released and expired resources in an offline project
238            filter = filter.addExcludeTimerange();
239        }
240        List<CmsResource> result = cms.readResources(foldername, filter, tree);
241
242        // create priority comparator to use to sort the resources
243        CmsPriorityDateResourceComparator comparator = new CmsPriorityDateResourceComparator(cms, asc);
244        Collections.sort(result, comparator);
245
246        return shrinkToFit(result, data.getCount(), numResults);
247    }
248
249    /**
250     * Returns a list of all resource in a specified folder sorted by priority descending, then Title ascending.<p>
251     *
252     * @param cms the current OpenCms user context
253     * @param param the folder name to use
254     * @param tree if true, look in folder and all child folders, if false, look only in given folder
255     * @param numResults the number of results
256     *
257     * @return all resources in the folder matching the given criteria
258     *
259     * @throws CmsException if something goes wrong
260     */
261    protected List<CmsResource> allInFolderPriorityTitle(CmsObject cms, String param, boolean tree, int numResults)
262    throws CmsException {
263
264        CmsCollectorData data = new CmsCollectorData(param);
265        String foldername = CmsResource.getFolderPath(data.getFileName());
266
267        CmsResourceFilter filter = CmsResourceFilter.DEFAULT.addRequireType(data.getType()).addExcludeFlags(
268            CmsResource.FLAG_TEMPFILE);
269        if (data.isExcludeTimerange() && !cms.getRequestContext().getCurrentProject().isOnlineProject()) {
270            // include all not yet released and expired resources in an offline project
271            filter = filter.addExcludeTimerange();
272        }
273        List<CmsResource> result = cms.readResources(foldername, filter, tree);
274
275        // create priority comparator to use to sort the resources
276        CmsPriorityTitleResourceComparator comparator = new CmsPriorityTitleResourceComparator(cms);
277        Collections.sort(result, comparator);
278
279        return shrinkToFit(result, data.getCount(), numResults);
280    }
281
282    /**
283     * Returns a list of all resource from specified folder that have been mapped to
284     * the currently requested uri, sorted by priority, then date ascending or descending.<p>
285     *
286     * @param cms the current OpenCms user context
287     * @param param the folder name to use
288     * @param asc if true, the date sort order is ascending, otherwise descending
289     * @param numResults the number of results
290     *
291     * @return all resources in the folder matching the given criteria
292     *
293     * @throws CmsException if something goes wrong
294     */
295    protected List<CmsResource> allMappedToUriPriorityDate(CmsObject cms, String param, boolean asc, int numResults)
296    throws CmsException {
297
298        CmsCollectorData data = new CmsCollectorData(param);
299        String foldername = CmsResource.getFolderPath(data.getFileName());
300
301        CmsResourceFilter filter = CmsResourceFilter.DEFAULT.addRequireType(data.getType()).addExcludeFlags(
302            CmsResource.FLAG_TEMPFILE);
303        if (data.isExcludeTimerange() && !cms.getRequestContext().getCurrentProject().isOnlineProject()) {
304            // include all not yet released and expired resources in an offline project
305            filter = filter.addExcludeTimerange();
306        }
307
308        List<CmsResource> result = cms.readResources(foldername, filter, true);
309        List<CmsResource> mapped = new ArrayList<CmsResource>();
310
311        // sort out the resources mapped to the current page
312        Iterator<CmsResource> i = result.iterator();
313        while (i.hasNext()) {
314            CmsResource res = i.next();
315            // read all properties - reason: comparator will do this later anyway, so we just prefill the cache
316            CmsProperty prop = cms.readPropertyObject(res, PROPERTY_CHANNEL, false);
317            if (!prop.isNullProperty()) {
318                if (CmsProject.isInsideProject(
319                    prop.getValueList(),
320                    cms.getRequestContext().getSiteRoot() + cms.getRequestContext().getUri())) {
321                    mapped.add(res);
322                }
323            }
324        }
325
326        if (mapped.isEmpty()) {
327            // nothing was mapped, no need for further processing
328            return mapped;
329        }
330
331        // create priority comparator to use to sort the resources
332        CmsPriorityDateResourceComparator comparator = new CmsPriorityDateResourceComparator(cms, asc);
333        Collections.sort(mapped, comparator);
334
335        return shrinkToFit(mapped, data.getCount(), numResults);
336    }
337}