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, 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.ade.galleries;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.formatters.CmsFormatterConfigurationCacheState;
032import org.opencms.ade.galleries.CmsGalleryFilteredNavTreeBuilder.NavigationNode;
033import org.opencms.ade.galleries.preview.I_CmsPreviewProvider;
034import org.opencms.ade.galleries.shared.CmsGalleryActionInfo;
035import org.opencms.ade.galleries.shared.CmsGalleryConfiguration;
036import org.opencms.ade.galleries.shared.CmsGalleryDataBean;
037import org.opencms.ade.galleries.shared.CmsGalleryFolderBean;
038import org.opencms.ade.galleries.shared.CmsGalleryGroup;
039import org.opencms.ade.galleries.shared.CmsGallerySearchBean;
040import org.opencms.ade.galleries.shared.CmsGallerySearchScope;
041import org.opencms.ade.galleries.shared.CmsGalleryTabConfiguration;
042import org.opencms.ade.galleries.shared.CmsResourceTypeBean;
043import org.opencms.ade.galleries.shared.CmsResourceTypeBean.TypeVisibility;
044import org.opencms.ade.galleries.shared.CmsResultItemBean;
045import org.opencms.ade.galleries.shared.CmsSitemapEntryBean;
046import org.opencms.ade.galleries.shared.CmsVfsEntryBean;
047import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants;
048import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryMode;
049import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryTabId;
050import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.SortParams;
051import org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService;
052import org.opencms.file.CmsObject;
053import org.opencms.file.CmsProperty;
054import org.opencms.file.CmsPropertyDefinition;
055import org.opencms.file.CmsResource;
056import org.opencms.file.CmsResourceFilter;
057import org.opencms.file.CmsUser;
058import org.opencms.file.CmsVfsResourceNotFoundException;
059import org.opencms.file.types.CmsResourceTypeBinary;
060import org.opencms.file.types.CmsResourceTypeFunctionConfig;
061import org.opencms.file.types.CmsResourceTypeImage;
062import org.opencms.file.types.CmsResourceTypePointer;
063import org.opencms.file.types.CmsResourceTypeXmlContent;
064import org.opencms.file.types.CmsResourceTypeXmlPage;
065import org.opencms.file.types.I_CmsResourceType;
066import org.opencms.flex.CmsFlexController;
067import org.opencms.gwt.CmsCoreService;
068import org.opencms.gwt.CmsGwtService;
069import org.opencms.gwt.CmsIconUtil;
070import org.opencms.gwt.CmsRpcException;
071import org.opencms.gwt.CmsVfsService;
072import org.opencms.gwt.shared.CmsGalleryContainerInfo;
073import org.opencms.gwt.shared.CmsListInfoBean;
074import org.opencms.gwt.shared.CmsTemplateContextInfo;
075import org.opencms.i18n.CmsLocaleManager;
076import org.opencms.i18n.CmsMessages;
077import org.opencms.json.JSONException;
078import org.opencms.json.JSONObject;
079import org.opencms.jsp.CmsJspNavBuilder;
080import org.opencms.jsp.CmsJspNavBuilder.Visibility;
081import org.opencms.jsp.CmsJspNavElement;
082import org.opencms.loader.CmsLoaderException;
083import org.opencms.loader.CmsResourceManager;
084import org.opencms.loader.I_CmsTemplateContextProvider;
085import org.opencms.main.CmsException;
086import org.opencms.main.CmsLog;
087import org.opencms.main.CmsPermalinkResourceHandler;
088import org.opencms.main.CmsStaticResourceHandler;
089import org.opencms.main.OpenCms;
090import org.opencms.search.fields.CmsSearchFieldMapping;
091import org.opencms.search.galleries.CmsGallerySearch;
092import org.opencms.search.galleries.CmsGallerySearchParameters;
093import org.opencms.search.galleries.CmsGallerySearchResult;
094import org.opencms.search.galleries.CmsGallerySearchResultList;
095import org.opencms.security.CmsPermissionSet;
096import org.opencms.security.CmsPermissionViolationException;
097import org.opencms.site.CmsSite;
098import org.opencms.staticexport.CmsLinkManager;
099import org.opencms.ui.components.CmsResourceIcon;
100import org.opencms.util.CmsDateUtil;
101import org.opencms.util.CmsPath;
102import org.opencms.util.CmsRequestUtil;
103import org.opencms.util.CmsStringUtil;
104import org.opencms.util.CmsUUID;
105import org.opencms.util.CmsUriSplitter;
106import org.opencms.workplace.CmsWorkplace;
107import org.opencms.workplace.CmsWorkplaceMessages;
108import org.opencms.workplace.CmsWorkplaceSettings;
109import org.opencms.workplace.explorer.CmsResourceUtil;
110import org.opencms.xml.containerpage.CmsADESessionCache;
111import org.opencms.xml.containerpage.CmsFormatterConfiguration;
112import org.opencms.xml.containerpage.CmsFunctionFormatterBean;
113import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler;
114import org.opencms.xml.containerpage.I_CmsFormatterBean;
115
116import java.text.Collator;
117import java.text.DateFormat;
118import java.text.ParseException;
119import java.util.ArrayList;
120import java.util.Arrays;
121import java.util.Collection;
122import java.util.Collections;
123import java.util.Comparator;
124import java.util.Date;
125import java.util.HashMap;
126import java.util.HashSet;
127import java.util.Iterator;
128import java.util.List;
129import java.util.Locale;
130import java.util.Map;
131import java.util.Map.Entry;
132import java.util.Set;
133import java.util.TreeMap;
134import java.util.TreeSet;
135import java.util.function.Predicate;
136
137import javax.servlet.http.HttpServletRequest;
138import javax.servlet.http.HttpSession;
139
140import org.apache.commons.logging.Log;
141
142import com.google.common.collect.ArrayListMultimap;
143import com.google.common.collect.ComparisonChain;
144import com.google.common.collect.Lists;
145import com.google.common.collect.Maps;
146import com.google.common.collect.Multimap;
147import com.google.common.collect.Sets;
148
149/**
150 * Handles all RPC services related to the gallery dialog.<p>
151 *
152 * @since 8.0.0
153 *
154 * @see org.opencms.ade.galleries.CmsGalleryService
155 * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService
156 * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryServiceAsync
157 */
158public class CmsGalleryService extends CmsGwtService implements I_CmsGalleryService {
159
160    /**
161     * Gallery info object.<p>
162     */
163    protected class CmsGalleryTypeInfo {
164
165        /** The content types using this gallery. */
166        private List<I_CmsResourceType> m_contentTypes;
167
168        /** The gallery folder resources. */
169        private List<CmsResource> m_galleries;
170
171        /** The resource type of this gallery. */
172        private I_CmsResourceType m_resourceType;
173
174        /**
175         * Constructor.<p>
176         *
177         * @param resourceType the resource type of the gallery
178         * @param contentType the resource type of the gallery content
179         * @param galleries the gallery resources
180         */
181        protected CmsGalleryTypeInfo(
182            I_CmsResourceType resourceType,
183            I_CmsResourceType contentType,
184            List<CmsResource> galleries) {
185
186            m_resourceType = resourceType;
187            m_contentTypes = new ArrayList<I_CmsResourceType>();
188            m_contentTypes.add(contentType);
189            m_galleries = galleries;
190        }
191
192        /**
193         * Adds a type to the list of content types.<p>
194         *
195         * @param type the type to add
196         */
197        protected void addContentType(I_CmsResourceType type) {
198
199            m_contentTypes.add(type);
200        }
201
202        /**
203         * Returns the contentTypes.<p>
204         *
205         * @return the contentTypes
206         */
207        protected List<I_CmsResourceType> getContentTypes() {
208
209            return m_contentTypes;
210        }
211
212        /**
213         * Returns the gallery folder resources.<p>
214         *
215         * @return the resources
216         */
217        protected List<CmsResource> getGalleries() {
218
219            return m_galleries;
220        }
221
222        /**
223         * Returns the resourceType.<p>
224         *
225         * @return the resourceType
226         */
227        protected I_CmsResourceType getResourceType() {
228
229            return m_resourceType;
230        }
231
232        /**
233         * Sets the contentTypes.<p>
234         *
235         * @param contentTypes the contentTypes to set
236         */
237        protected void setContentTypes(List<I_CmsResourceType> contentTypes) {
238
239            m_contentTypes = contentTypes;
240        }
241
242        /**
243         * Sets the galleries.<p>
244         *
245         * @param galleries the gallery resource list to set
246         */
247        protected void setGalleries(List<CmsResource> galleries) {
248
249            m_galleries = galleries;
250        }
251
252        /**
253         * Sets the resourceType.<p>
254         *
255         * @param resourceType the resourceType to set
256         */
257        protected void setResourceType(I_CmsResourceType resourceType) {
258
259            m_resourceType = resourceType;
260        }
261    }
262
263    /** Bean used to store a single type together with a flag indicating its visibility. */
264    class TypeWithVisibility {
265
266        /** True if the type should only be shown in the full list. */
267        private boolean m_onlyShowInFullList;
268
269        /** The resource type. */
270        private I_CmsResourceType m_type;
271
272        /**
273         * Creates a new instance.<p>
274         *
275         * @param type the resource type
276         * @param onlyShowInFullList the flag to control the visibility
277         */
278        public TypeWithVisibility(I_CmsResourceType type, boolean onlyShowInFullList) {
279
280            m_type = type;
281            m_onlyShowInFullList = onlyShowInFullList;
282        }
283
284        /**
285         * Returns the type.<p>
286         *
287         * @return the type
288         */
289        public I_CmsResourceType getType() {
290
291            return m_type;
292        }
293
294        /**
295         * Returns the onlyShowInFullList.<p>
296         *
297         * @return the onlyShowInFullList
298         */
299        public boolean isOnlyShowInFullList() {
300
301            return m_onlyShowInFullList;
302        }
303
304    }
305
306    /** Key for additional info gallery folder filter. */
307    public static final String FOLDER_FILTER_ADD_INFO_KEY = "gallery_folder_filter";
308
309    /** Limit to the number results loaded on initial search. */
310    public static final int INITIAL_SEARCH_MAX_RESULTS = 200;
311
312    /** The key used for storing the last used gallery in adeview mode. */
313    public static final String KEY_LAST_USED_GALLERY_ADEVIEW = "__adeView";
314
315    /** Name for the 'galleryShowInvalidDefault' preference. */
316    public static final String PREF_GALLERY_SHOW_INVALID_DEFAULT = "galleryShowInvalidDefault";
317
318    /** Key for additional info gallery result view type. */
319    public static final String RESULT_VIEW_TYPE_ADD_INFO_KEY = "gallery_result_view_type";
320
321    /** The dynamic function resource type names. */
322    private static final Set<String> FUNCTION_TYPES = new HashSet<>(
323        Arrays.asList(
324            new String[] {CmsXmlDynamicFunctionHandler.TYPE_FUNCTION, CmsResourceTypeFunctionConfig.TYPE_NAME}));
325
326    /** The logger instance for this class. */
327    private static final Log LOG = CmsLog.getLog(CmsGalleryService.class);
328
329    /** Serialization uid. */
330    private static final long serialVersionUID = 1673026761080584889L;
331
332    /** Compares the VFS entry beans. */
333    private static final Comparator<CmsVfsEntryBean> VFS_COMPARATOR = new Comparator<CmsVfsEntryBean>() {
334
335        public int compare(CmsVfsEntryBean o1, CmsVfsEntryBean o2) {
336
337            String o1Path = o1.getRootPath();
338            String o2Path = o2.getRootPath();
339            if (o1Path.endsWith("/")) {
340                o1Path = o1Path.substring(0, o1Path.length() - 1);
341            }
342            if (o2Path.endsWith("/")) {
343                o2Path = o2Path.substring(0, o2Path.length() - 1);
344            }
345            return o1Path.compareTo(o2Path);
346        }
347    };
348
349    /** The instance of the resource manager. */
350    CmsResourceManager m_resourceManager;
351
352    /** The workplace settings of the current user. */
353    private CmsWorkplaceSettings m_workplaceSettings;
354
355    /** The workplace locale from the current user's settings. */
356    private Locale m_wpLocale;
357
358    /**
359     * Generates the pre-loaded contents for the VFS tab of the gallery dialog.<p>
360     *
361     * @param cms the current CMS context
362     * @param vfsState the saved VFS tree state (may be null)
363     * @param folders the saved search folders (may be null)
364     *
365     * @return the root tree entry for the VFS tab
366     */
367    public static CmsVfsEntryBean generateVfsPreloadData(
368        final CmsObject cms,
369        final CmsTreeOpenState vfsState,
370        final Set<String> folders) {
371
372        CmsVfsEntryBean vfsPreloadData = null;
373
374        A_CmsTreeTabDataPreloader<CmsVfsEntryBean> vfsloader = new A_CmsTreeTabDataPreloader<CmsVfsEntryBean>() {
375
376            @SuppressWarnings("synthetic-access")
377            @Override
378            protected CmsVfsEntryBean createEntry(CmsObject innerCms, CmsResource resource) throws CmsException {
379
380                String title = innerCms.readPropertyObject(
381                    resource,
382                    CmsPropertyDefinition.PROPERTY_TITLE,
383                    false).getValue();
384                boolean isEditable = false;
385                try {
386                    isEditable = innerCms.hasPermissions(
387                        resource,
388                        CmsPermissionSet.ACCESS_WRITE,
389                        false,
390                        CmsResourceFilter.ALL);
391                } catch (CmsException e) {
392                    LOG.info(e.getLocalizedMessage(), e);
393                }
394
395                return internalCreateVfsEntryBean(innerCms, resource, title, true, isEditable, null, false);
396            }
397
398        };
399        Set<CmsResource> treeOpenResources = Sets.newHashSet();
400        if (vfsState != null) {
401
402            for (CmsUUID structureId : vfsState.getOpenItems()) {
403                try {
404                    treeOpenResources.add(cms.readResource(structureId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
405                } catch (CmsException e) {
406                    LOG.warn(e.getLocalizedMessage(), e);
407                }
408            }
409        }
410        CmsObject rootCms = null;
411        Set<CmsResource> folderSetResources = Sets.newHashSet();
412        try {
413            rootCms = OpenCms.initCmsObject(cms);
414            rootCms.getRequestContext().setSiteRoot("");
415            if (!((folders == null) || folders.isEmpty())) {
416                for (String folder : folders) {
417                    try {
418                        folderSetResources.add(rootCms.readResource(folder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED));
419                    } catch (CmsException e) {
420                        LOG.warn(e.getLocalizedMessage(), e);
421                    }
422                }
423            }
424        } catch (CmsException e1) {
425            LOG.error(e1.getLocalizedMessage(), e1);
426        }
427        try {
428            vfsPreloadData = vfsloader.preloadData(cms, treeOpenResources, folderSetResources);
429        } catch (CmsException e) {
430            LOG.error(e.getLocalizedMessage(), e);
431        }
432
433        return vfsPreloadData;
434
435    }
436
437    /**
438     * Returns the initial gallery settings.<p>
439     *
440     * @param request the current request
441     * @param config the gallery configuration
442     *
443     * @return the initial gallery settings
444     *
445     * @throws CmsRpcException if something goes wrong
446     */
447    public static CmsGalleryDataBean getInitialSettings(HttpServletRequest request, CmsGalleryConfiguration config)
448    throws CmsRpcException {
449
450        CmsGalleryService srv = new CmsGalleryService();
451        srv.setCms(CmsFlexController.getCmsObject(request));
452        srv.setRequest(request);
453        CmsGalleryDataBean result = null;
454        try {
455            result = srv.getInitialSettings(config);
456        } finally {
457            srv.clearThreadStorage();
458        }
459        return result;
460    }
461
462    /**
463     * Returns the initial search data.<p>
464     *
465     * @param request the current request
466     * @param config the gallery configuration
467     *
468     * @return the search data
469     */
470    public static CmsGallerySearchBean getSearch(HttpServletRequest request, CmsGalleryDataBean config) {
471
472        CmsGalleryService srv = new CmsGalleryService();
473        srv.setCms(CmsFlexController.getCmsObject(request));
474        srv.setRequest(request);
475        CmsGallerySearchBean result = null;
476        try {
477            result = srv.getSearch(config);
478        } finally {
479            srv.clearThreadStorage();
480        }
481        return result;
482    }
483
484    /**
485     * Gets the attribute name for a tree open state.<p>
486     *
487     * @param treeName the tree name
488     * @param treeToken the tree token
489     *
490     * @return the attribute name for the tree
491     */
492    public static String getTreeOpenStateAttributeName(String treeName, String treeToken) {
493
494        return "tree_" + treeName + "_" + treeToken;
495    }
496
497    /**
498     * Convenience method for reading the saved VFS tree state from the session.<p>
499     *
500     * @param request the current request
501     * @param treeToken the tree token (may be null)
502     *
503     * @return the saved tree open state (may be null)
504     */
505    public static CmsTreeOpenState getVfsTreeState(HttpServletRequest request, String treeToken) {
506
507        return (CmsTreeOpenState)request.getSession().getAttribute(
508            getTreeOpenStateAttributeName(I_CmsGalleryProviderConstants.TREE_VFS, treeToken));
509
510    }
511
512    /**
513     * Creates the VFS entry bean for a resource.<p>
514     *
515     * @param cms the CMS context to use
516     * @param resource the resource for which to create the VFS entry bean
517     * @param title the title
518     * @param isRoot true if this is a root entry
519     * @param isEditable true if this entry is editable
520     * @param children the children of the entry
521     * @param isMatch true if the VFS entry bean is a match for the quick search
522     *
523     * @return the created VFS entry bean
524     * @throws CmsException if something goes wrong
525     */
526    public static CmsVfsEntryBean internalCreateVfsEntryBean(
527        CmsObject cms,
528        CmsResource resource,
529        String title,
530        boolean isRoot,
531        boolean isEditable,
532        List<CmsVfsEntryBean> children,
533        boolean isMatch)
534    throws CmsException {
535
536        String rootPath = resource.getRootPath();
537        CmsUUID structureId = resource.getStructureId();
538        CmsVfsEntryBean result = new CmsVfsEntryBean(
539            rootPath,
540            structureId,
541            title,
542            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resource), resource.getName(), true),
543            isRoot,
544            isEditable,
545            children,
546            isMatch);
547        String siteRoot = null;
548        if (resource.isFolder()) {
549            cms = OpenCms.initCmsObject(cms);
550            cms.getRequestContext().setSiteRoot("");
551            List<CmsResource> realChildren = cms.getResourcesInFolder(
552                rootPath,
553                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
554            List<CmsResource> effectiveChildren = new ArrayList<CmsResource>();
555            for (CmsResource realChild : realChildren) {
556                if (realChild.isFolder()) {
557                    effectiveChildren.add(realChild);
558                }
559            }
560            if (effectiveChildren.isEmpty()) {
561                result.setChildren(new ArrayList<CmsVfsEntryBean>());
562            }
563        }
564
565        if (OpenCms.getSiteManager().startsWithShared(rootPath)) {
566            siteRoot = OpenCms.getSiteManager().getSharedFolder();
567        } else {
568            String tempSiteRoot = OpenCms.getSiteManager().getSiteRoot(rootPath);
569            if (tempSiteRoot != null) {
570                siteRoot = tempSiteRoot;
571            } else {
572                siteRoot = "";
573            }
574        }
575        result.setSiteRoot(siteRoot);
576        return result;
577    }
578
579    /**
580     * Helper function for getting the IDs of functions which do not fit into a given set of container type/width combinations.
581     *
582     * @param cms the current CMS context
583     * @param config the sitemap configuration
584     * @param containerInfo the information about available container type/width combinations
585     *
586     * @return the set of functions which should be excluded
587     */
588    private static Set<CmsUUID> getExcludedFunctionsForContainerInfo(
589        CmsObject cms,
590        CmsADEConfigData config,
591        CmsGalleryContainerInfo containerInfo) {
592
593        CmsFormatterConfigurationCacheState formatterCache = config.getCachedFormatters();
594        // start with all functions, then go through each item in the container info and remove formatters if they match that item
595        // -> we end up with the functions that don't match anything
596        Map<CmsUUID, I_CmsFormatterBean> remainingUnmatchedFunctions = new HashMap<>(
597            Maps.filterValues(
598                formatterCache.getFormatters(),
599                formatter -> formatter instanceof CmsFunctionFormatterBean));
600        for (CmsGalleryContainerInfo.Item item : containerInfo.getItems()) {
601            Iterator<Map.Entry<CmsUUID, I_CmsFormatterBean>> iterator = remainingUnmatchedFunctions.entrySet().iterator();
602            while (iterator.hasNext()) {
603                Map.Entry<CmsUUID, I_CmsFormatterBean> entry = iterator.next();
604                I_CmsFormatterBean formatter = entry.getValue();
605                if (CmsFormatterConfiguration.matchFormatter(formatter, item.getType(), item.getWidth())) {
606                    iterator.remove();
607                }
608            }
609        }
610        return new TreeSet<>(remainingUnmatchedFunctions.keySet());
611    }
612
613    /**
614     * Returns the resource types beans.<p>
615     *
616     * @param resourceTypes the resource types
617     * @param creatableTypes the creatable types
618     * @param deactivatedTypes the deactivated types
619     * @param typesForTypeTab the types which should be shown in the types tab according to the gallery configuration
620     *
621     * @return the resource types
622     */
623    public List<CmsResourceTypeBean> buildTypesList(
624        List<I_CmsResourceType> resourceTypes,
625        Set<String> creatableTypes,
626        Set<String> deactivatedTypes,
627        final List<String> typesForTypeTab) {
628
629        List<CmsResourceTypeBean> result = buildTypesList(resourceTypes, creatableTypes);
630
631        for (CmsResourceTypeBean typeBean : result) {
632            if ((typesForTypeTab != null) && (typesForTypeTab.size() > 0)) {
633                if (!typesForTypeTab.contains(typeBean.getType())) {
634                    if (typeBean.getVisibility() != TypeVisibility.hidden) {
635                        typeBean.setVisibility(TypeVisibility.showOptional);
636                    }
637                }
638            }
639            typeBean.setDeactivated(deactivatedTypes.contains(typeBean.getType()));
640        }
641        if ((typesForTypeTab != null) && (typesForTypeTab.size() > 0)) {
642            Collections.sort(result, new Comparator<CmsResourceTypeBean>() {
643
644                public int compare(CmsResourceTypeBean first, CmsResourceTypeBean second) {
645
646                    return ComparisonChain.start().compare(searchTypeRank(first), searchTypeRank(second)).compare(
647                        first.getTitle(),
648                        second.getTitle(),
649                        Collator.getInstance(getWorkplaceLocale())).compare(first.getType(), second.getType()).result();
650                }
651
652                int searchTypeRank(CmsResourceTypeBean type) {
653
654                    int index = typesForTypeTab.indexOf(type.getType());
655                    if (index == -1) {
656                        return Integer.MAX_VALUE;
657                    } else {
658                        return index;
659                    }
660                }
661            });
662
663        }
664        return result;
665    }
666
667    /**
668     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#deleteResource(java.lang.String)
669     */
670    public void deleteResource(String resourcePath) throws CmsRpcException {
671
672        try {
673            ensureLock(resourcePath);
674            getCmsObject().deleteResource(resourcePath, CmsResource.DELETE_PRESERVE_SIBLINGS);
675        } catch (Exception e) {
676            error(e);
677        }
678    }
679
680    /**
681     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getAdeViewModeConfiguration()
682     */
683    public CmsGalleryConfiguration getAdeViewModeConfiguration() {
684
685        CmsGalleryConfiguration result = new CmsGalleryConfiguration();
686        List<String> typeNames = new ArrayList<String>();
687
688        for (I_CmsResourceType type : OpenCms.getResourceManager().getResourceTypes()) {
689            Class<?> typeClass = type.getClass();
690            if (CmsResourceTypeXmlContent.class.isAssignableFrom(typeClass)
691                || CmsResourceTypeXmlPage.class.isAssignableFrom(typeClass)) {
692                continue;
693            }
694            if (type.getGalleryTypes().size() > 0) {
695                typeNames.add(type.getTypeName());
696            }
697        }
698        result.setSearchTypes(typeNames);
699        result.setResourceTypes(typeNames);
700        result.setGalleryMode(GalleryMode.adeView);
701        result.setGalleryStoragePrefix("" + GalleryMode.adeView);
702        result.setTabConfiguration(CmsGalleryTabConfiguration.resolve("selectDoc"));
703        return result;
704    }
705
706    /**
707     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getGalleries(java.lang.String, java.util.List)
708     */
709    public List<CmsGalleryFolderBean> getGalleries(String context, List<String> resourceTypes) {
710
711        return buildGalleriesList(context, readGalleryInfosByTypeNames(resourceTypes));
712    }
713
714    /**
715     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getGalleryActionInfo(java.lang.String)
716     */
717    public CmsGalleryActionInfo getGalleryActionInfo(String sitePath) throws CmsRpcException {
718
719        try {
720            CmsObject cms = getCmsObject();
721            try {
722                CmsResource folderRes = cms.readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION);
723                I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(folderRes);
724                String action = type.getConfiguration().get("gallery.upload.action");
725                return new CmsGalleryActionInfo(folderRes.getStructureId(), action);
726            } catch (CmsVfsResourceNotFoundException e) {
727                LOG.info(e.getLocalizedMessage(), e);
728                return null;
729            }
730        } catch (Throwable e) {
731            error(e);
732            return null;
733        }
734
735    }
736
737    /**
738     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getInfoForResource(java.lang.String, java.lang.String)
739     */
740    public CmsResultItemBean getInfoForResource(String linkPath, String locale) throws CmsRpcException {
741
742        CmsResultItemBean result = null;
743        CmsObject cms = getCmsObject();
744        CmsMessages messageBundle = Messages.get().getBundle(getWorkplaceLocale());
745        try {
746            if (new CmsUriSplitter(linkPath).getProtocol() != null) {
747                result = new CmsResultItemBean();
748                result.setTitle(messageBundle.key(Messages.GUI_EXTERNAL_LINK_0));
749                result.setSubTitle("");
750                result.setType(CmsResourceTypePointer.getStaticTypeName());
751                result.setBigIconClasses(
752                    CmsIconUtil.getIconClasses(CmsResourceTypePointer.getStaticTypeName(), null, false));
753            } else if (CmsStaticResourceHandler.isStaticResourceUri(linkPath)) {
754                result = new CmsResultItemBean();
755                result.setTitle(messageBundle.key(Messages.GUI_STATIC_RESOURCE_0));
756                result.setSubTitle(CmsStaticResourceHandler.removeStaticResourcePrefix(linkPath));
757                result.setType(CmsResourceTypeBinary.getStaticTypeName());
758                result.setBigIconClasses(
759                    CmsIconUtil.getIconClasses(CmsResourceTypeBinary.getStaticTypeName(), null, false));
760            } else {
761                boolean notFound = false;
762                String path = linkPath;
763                String siteRoot = OpenCms.getSiteManager().getSiteRoot(linkPath);
764                String oldSite = cms.getRequestContext().getSiteRoot();
765                try {
766                    if (siteRoot != null) {
767                        // only switch the site if needed
768                        cms.getRequestContext().setSiteRoot(siteRoot);
769                        // remove the site root, because the link manager call will append it anyway
770                        path = cms.getRequestContext().removeSiteRoot(linkPath);
771                    }
772                    // remove parameters, if not the link manager call might fail
773                    int pos = path.indexOf(CmsRequestUtil.URL_DELIMITER);
774                    int anchorPos = path.indexOf('#');
775                    if ((pos == -1) || ((anchorPos > -1) && (pos > anchorPos))) {
776                        pos = anchorPos;
777                    }
778                    if (pos > -1) {
779                        path = path.substring(0, pos);
780                    }
781                    // get the root path
782                    path = OpenCms.getLinkManager().getRootPath(cms, path);
783
784                } catch (Exception e) {
785                    notFound = true;
786                } finally {
787                    if (siteRoot != null) {
788                        cms.getRequestContext().setSiteRoot(oldSite);
789                    }
790                }
791                notFound = notFound || (path == null);
792                boolean isInTimeRange = true;
793                if (!notFound) {
794                    CmsObject rootCms = OpenCms.initCmsObject(cms);
795                    rootCms.getRequestContext().setSiteRoot("");
796                    try {
797                        CmsResource selectedResource = rootCms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION);
798                        long currentTime = System.currentTimeMillis();
799                        isInTimeRange = selectedResource.isReleasedAndNotExpired(currentTime);
800                        if (selectedResource.isFolder()) {
801                            result = new CmsResultItemBean();
802
803                            CmsJspNavElement folderNav = new CmsJspNavBuilder(rootCms).getNavigationForResource(
804                                selectedResource.getRootPath(),
805                                CmsResourceFilter.IGNORE_EXPIRATION);
806                            CmsResource defaultFileResource = null;
807                            if (folderNav.isInNavigation() && !folderNav.isNavigationLevel()) {
808                                try {
809                                    defaultFileResource = rootCms.readDefaultFile(
810                                        selectedResource,
811                                        CmsResourceFilter.ONLY_VISIBLE);
812                                } catch (Exception e) {
813                                    log(e.getMessage(), e);
814                                }
815                            }
816                            result.setBigIconClasses(
817                                CmsIconUtil.getIconClasses(
818                                    CmsIconUtil.getDisplayType(rootCms, selectedResource),
819                                    path,
820                                    false));
821                            CmsResource resourceForType = defaultFileResource != null
822                            ? defaultFileResource
823                            : selectedResource;
824                            result.setType(OpenCms.getResourceManager().getResourceType(resourceForType).getTypeName());
825                            if (defaultFileResource != null) {
826                                result.setSmallIconClasses(
827                                    CmsIconUtil.getIconClasses(
828                                        CmsIconUtil.getDisplayType(rootCms, defaultFileResource),
829                                        defaultFileResource.getName(),
830                                        true));
831                            }
832                            String title = folderNav.getProperty(CmsPropertyDefinition.PROPERTY_NAVTEXT);
833                            if (CmsStringUtil.isEmptyOrWhitespaceOnly(title)) {
834                                title = folderNav.getTitle();
835                            } else if (CmsStringUtil.isEmptyOrWhitespaceOnly(title)) {
836                                title = CmsResource.getName(path);
837                                if (title.contains("/")) {
838                                    title = title.substring(0, title.indexOf("/"));
839                                }
840                            }
841                            result.setTitle(title);
842                            try {
843                                String userName = cms.readUser(selectedResource.getUserLastModified()).getFullName();
844                                result.setUserLastModified(userName);
845                            } catch (CmsException e) {
846                                log(e.getMessage(), e);
847                            }
848                            Date date = new Date(selectedResource.getDateLastModified());
849                            String formattedDate = CmsDateUtil.getDateTime(
850                                date,
851                                DateFormat.MEDIUM,
852                                getWorkplaceLocale());
853                            result.setDateLastModified(formattedDate);
854
855                        } else {
856                            CmsGallerySearchResult resultItem = null;
857                            try {
858                                resultItem = CmsGallerySearch.searchByPath(
859                                    cms,
860                                    path,
861                                    CmsLocaleManager.getLocale(locale));
862                            } catch (CmsVfsResourceNotFoundException ex) {
863                                // ignore
864                            }
865                            notFound = resultItem == null;
866                            if (!notFound) {
867                                result = buildSingleSearchResultItem(getCmsObject(), resultItem, null, res -> false);
868                            }
869                        }
870                    } catch (CmsException ex) {
871                        notFound = true;
872                    }
873                }
874                if (notFound) {
875                    result = new CmsResultItemBean();
876                    result.setTitle(messageBundle.key(Messages.GUI_RESOURCE_NOT_FOUND_0));
877                    result.setSubTitle("");
878                    result.setType(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND);
879                    result.setBigIconClasses(
880                        CmsIconUtil.getIconClasses(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND, null, false));
881                } else if (!isInTimeRange && (result != null)) {
882                    result.setType(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND);
883                    result.setTitle(messageBundle.key(Messages.GUI_RESOURCE_OUT_OF_TIME_RANGE_1, result.getTitle()));
884                    result.setBigIconClasses(
885                        CmsIconUtil.getIconClasses(CmsIconUtil.TYPE_RESOURCE_NOT_FOUND, null, false));
886                }
887            }
888        } catch (Throwable t) {
889            error(t);
890        }
891        return result;
892    }
893
894    /**
895     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getInitialSettings(org.opencms.ade.galleries.shared.CmsGalleryConfiguration)
896     */
897    public CmsGalleryDataBean getInitialSettings(CmsGalleryConfiguration conf) throws CmsRpcException {
898
899        try {
900            return getInitialSettingsInternal(conf);
901        } catch (Throwable t) {
902            error(t);
903            return null; // will never be reached
904        }
905    }
906
907    /**
908     * Returns the initial gallery data for the container page editor.<p>
909     *
910     * @param types the available resource types
911     * @param uri the page URI
912     * @param locale the content locale
913     *
914     * @return the gallery data
915     */
916    public CmsGalleryDataBean getInitialSettingsForContainerPage(
917        List<CmsResourceTypeBean> types,
918        String uri,
919        String locale) {
920
921        CmsGalleryDataBean data = null;
922        try {
923            data = new CmsGalleryDataBean();
924            boolean galleryShowInvalidDefault = Boolean.parseBoolean(
925                getWorkplaceSettings().getUserSettings().getAdditionalPreference(
926                    PREF_GALLERY_SHOW_INVALID_DEFAULT,
927                    true));
928            data.setIncludeExpiredDefault(galleryShowInvalidDefault);
929            data.setResultViewType(readResultViewType());
930            data.setMode(GalleryMode.ade);
931            data.setGalleryStoragePrefix("");
932            data.setLocales(buildLocalesMap());
933            data.setLocale(locale);
934
935            data.setVfsRootFolders(getRootEntries());
936
937            data.setScope(getWorkplaceSettings().getLastSearchScope());
938            data.setSortOrder(getWorkplaceSettings().getLastGalleryResultOrder());
939
940            data.setTabIds(GalleryMode.ade.getTabs());
941            data.setReferenceSitePath(uri);
942            data.setTypes(types);
943            Map<String, CmsGalleryTypeInfo> adeGalleryTypeInfos = readGalleryInfosByTypeBeans(types);
944            data.setGalleries(buildGalleriesList(uri, adeGalleryTypeInfos));
945            data.setStartTab(GalleryTabId.cms_tab_types);
946            Set<String> folderFilter = readFolderFilters();
947            data.setStartFolderFilter(folderFilter);
948            if ((folderFilter != null) && !folderFilter.isEmpty()) {
949                try {
950                    data.setVfsPreloadData(generateVfsPreloadData(getCmsObject(), null, folderFilter));
951                } catch (Exception e) {
952                    LOG.error(e.getLocalizedMessage(), e);
953                }
954            }
955            CmsSiteSelectorOptionBuilder optionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
956            optionBuilder.addNormalSites(true, getWorkplaceSettings().getUserSettings().getStartFolder());
957            optionBuilder.addSharedSite();
958            data.setVfsSiteSelectorOptions(optionBuilder.getOptions());
959
960            CmsSiteSelectorOptionBuilder sitemapOptionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
961            sitemapOptionBuilder.addNormalSites(false, null);
962            if (data.getReferenceSitePath() != null) {
963                sitemapOptionBuilder.addCurrentSubsite(getCmsObject().addSiteRoot(data.getReferenceSitePath()));
964            }
965            data.setSitemapSiteSelectorOptions(sitemapOptionBuilder.getOptions());
966            data.setDefaultScope(OpenCms.getWorkplaceManager().getGalleryDefaultScope());
967            CmsCoreService service = new CmsCoreService();
968            service.setCms(getCmsObject());
969            data.setCategories(service.getCategoriesForSitePath(data.getReferenceSitePath()));
970        } catch (Exception e) {
971            LOG.error(e.getLocalizedMessage(), e);
972        }
973        return data;
974    }
975
976    /**
977     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSearch(org.opencms.ade.galleries.shared.CmsGalleryDataBean)
978     */
979    public CmsGallerySearchBean getSearch(CmsGalleryDataBean data) {
980
981        CmsGallerySearchBean result = null;
982        // search within all available types
983        List<String> types = getTypeNames(data);
984        switch (data.getMode()) {
985            case editor:
986            case view:
987            case adeView:
988            case widget:
989                String currentelement = data.getCurrentElement();
990                try {
991                    CmsSitemapEntryBean sitemapPreloadData = null;
992                    CmsVfsEntryBean vfsPreloadData = null;
993                    boolean disablePreview = false;
994                    GalleryTabId startTab = null;
995                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(currentelement)) {
996                        log("looking up:" + currentelement);
997                        // removing the servlet context if present
998                        currentelement = CmsLinkManager.removeOpenCmsContext(currentelement);
999                        // get search results given resource path
1000                        result = findResourceInGallery(currentelement, data);
1001                        if (result != null) {
1002                            sitemapPreloadData = result.getSitemapPreloadData();
1003                            vfsPreloadData = result.getVfsPreloadData();
1004                        }
1005                        if ((sitemapPreloadData != null)
1006                            && data.getTabConfiguration().getTabs().contains(GalleryTabId.cms_tab_sitemap)) {
1007                            startTab = GalleryTabId.cms_tab_sitemap;
1008                            disablePreview = true;
1009                        }
1010                    } else {
1011                        CmsTreeOpenState sitemapState = getSitemapTreeState(data.getTreeToken());
1012                        if (sitemapState != null) {
1013                            A_CmsTreeTabDataPreloader<CmsSitemapEntryBean> sitemaploader = new A_CmsTreeTabDataPreloader<CmsSitemapEntryBean>() {
1014
1015                                @Override
1016                                protected CmsSitemapEntryBean createEntry(CmsObject cms, CmsResource resource)
1017                                throws CmsException {
1018
1019                                    return internalCreateSitemapEntryBean(cms, resource);
1020                                }
1021
1022                                /**
1023                                 * @see org.opencms.ade.galleries.A_CmsTreeTabDataPreloader#getChildren(org.opencms.file.CmsResource)
1024                                 */
1025                                @Override
1026                                protected List<CmsResource> getChildren(CmsResource resource) throws CmsException {
1027
1028                                    return getSitemapSubEntryResources(resource.getRootPath());
1029                                }
1030
1031                            };
1032                            // in the case
1033                            sitemapPreloadData = sitemaploader.preloadData(
1034                                getCmsObject(),
1035                                Sets.newHashSet(
1036                                    readAll(sitemapState.getOpenItems(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)),
1037                                null);
1038                        }
1039                    }
1040                    if ((result == null) || (result.getResults() == null) || result.getResults().isEmpty()) {
1041                        result = new CmsGallerySearchBean();
1042                        result.setOriginalGalleryData(data);
1043                        result.setGalleryMode(data.getMode());
1044                        result.setGalleryStoragePrefix(data.getGalleryStoragePrefix());
1045                        result.setIgnoreSearchExclude(true);
1046                        String gallery = data.getStartGallery();
1047                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(gallery)) {
1048                            List<String> galleries = new ArrayList<String>();
1049                            galleries.add(gallery);
1050                            result.setGalleries(galleries);
1051                        }
1052                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(data.getStartFolder())) {
1053                            Set<String> folders = new HashSet<String>();
1054                            folders.add(data.getStartFolder());
1055                            result.setFolders(folders);
1056                        } else if (data.getStartFolderFilter() != null) {
1057                            result.setFolders(data.getStartFolderFilter());
1058                        }
1059                        result.setTypes(types);
1060                        result.setLocale(data.getLocale());
1061                        CmsGallerySearchScope scope = data.getScope();
1062                        if (scope == null) {
1063                            scope = OpenCms.getWorkplaceManager().getGalleryDefaultScope();
1064                        }
1065                        result.setSortOrder(data.getSortOrder().name());
1066                        result.setScope(scope);
1067                        result.setIncludeExpired(data.getIncludeExpiredDefault());
1068                        result = search(result);
1069                    }
1070                    result.setSitemapPreloadData(sitemapPreloadData);
1071                    result.setVfsPreloadData(vfsPreloadData);
1072                    result.setInitialTabId(startTab);
1073                    result.setDisablePreview(disablePreview);
1074                    if (types.size() > 1) {
1075                        // only remove types parameter if there is more than one type available
1076                        result.setTypes(null);
1077                    }
1078                } catch (CmsException e) {
1079                    logError(e);
1080                    result = null;
1081                }
1082                break;
1083            case ade:
1084            default:
1085                break;
1086        }
1087        return result;
1088    }
1089
1090    /**
1091     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSearch(CmsGallerySearchBean)
1092     */
1093    public CmsGallerySearchBean getSearch(CmsGallerySearchBean searchObj) throws CmsRpcException {
1094
1095        CmsGallerySearchBean gSearchObj = null;
1096
1097        try {
1098            gSearchObj = search(searchObj);
1099            getWorkplaceSettings().setLastSearchScope(searchObj.getScope());
1100            getWorkplaceSettings().setLastGalleryResultOrder(SortParams.valueOf(searchObj.getSortOrder()));
1101            setLastOpenedGallery(searchObj);
1102        } catch (Throwable e) {
1103            error(e);
1104        }
1105
1106        return gSearchObj;
1107    }
1108
1109    /**
1110     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSubEntries(java.lang.String, boolean, java.lang.String)
1111     */
1112    public List<CmsSitemapEntryBean> getSubEntries(String rootPath, boolean isRoot, String filter)
1113    throws CmsRpcException {
1114
1115        try {
1116            return getSubEntriesInternal(rootPath, isRoot, filter);
1117        } catch (Throwable e) {
1118            error(e);
1119        }
1120        return null;
1121    }
1122
1123    /**
1124     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#getSubFolders(java.lang.String)
1125     */
1126    public List<CmsVfsEntryBean> getSubFolders(String rootPath) throws CmsRpcException {
1127
1128        try {
1129            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1130            cms.getRequestContext().setSiteRoot("");
1131            List<CmsVfsEntryBean> result = new ArrayList<CmsVfsEntryBean>();
1132            if (cms.existsResource(rootPath, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1133                CmsResource resource = cms.readResource(rootPath, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1134                List<CmsResource> resources = cms.getSubFolders(
1135                    resource.getRootPath(),
1136                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1137                for (CmsResource res : resources) {
1138                    String title = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
1139                    result.add(
1140                        internalCreateVfsEntryBean(
1141                            getCmsObject(),
1142                            res,
1143                            title,
1144                            false,
1145                            isEditable(cms, res),
1146                            null,
1147                            false));
1148                }
1149            }
1150            Collections.<CmsVfsEntryBean> sort(result, VFS_COMPARATOR);
1151            return result;
1152        } catch (Throwable e) {
1153            error(e);
1154        }
1155        return null;
1156    }
1157
1158    /**
1159     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#loadVfsEntryBean(java.lang.String, java.lang.String)
1160     */
1161    public CmsVfsEntryBean loadVfsEntryBean(String path, String filter) throws CmsRpcException {
1162
1163        try {
1164            if (CmsStringUtil.isEmpty(filter)) {
1165
1166                CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1167                cms.getRequestContext().setSiteRoot("");
1168                if (!cms.existsResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1169                    String startFolder = CmsStringUtil.joinPaths(
1170                        path,
1171                        getWorkplaceSettings().getUserSettings().getStartFolder());
1172                    if (cms.existsResource(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1173                        path = startFolder;
1174                    }
1175                }
1176                CmsResource optionRes = cms.readResource(path);
1177                String title = cms.readPropertyObject(
1178                    optionRes,
1179                    CmsPropertyDefinition.PROPERTY_TITLE,
1180                    false).getValue();
1181                if (CmsStringUtil.isEmpty(title)) {
1182                    title = path;
1183                }
1184                CmsVfsEntryBean entryBean = internalCreateVfsEntryBean(
1185                    getCmsObject(),
1186                    optionRes,
1187                    title,
1188                    true,
1189                    isEditable(cms, optionRes),
1190                    null,
1191                    false);
1192                return entryBean;
1193            } else {
1194                filter = filter.toLowerCase();
1195                CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1196                cms.getRequestContext().setSiteRoot("");
1197                if (!cms.existsResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1198                    String startFolder = CmsStringUtil.joinPaths(
1199                        path,
1200                        getWorkplaceSettings().getUserSettings().getStartFolder());
1201                    if (cms.existsResource(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
1202                        path = startFolder;
1203                    }
1204                }
1205                CmsResource optionRes = cms.readResource(path);
1206                List<CmsResource> folders = cms.readResources(
1207                    optionRes.getRootPath(),
1208                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFolder());
1209                folders.add(optionRes);
1210                Set<CmsResource> folderSet = Sets.newHashSet(folders);
1211                List<CmsResource> titleResources = cms.readResourcesWithProperty(
1212                    path,
1213                    CmsPropertyDefinition.PROPERTY_TITLE);
1214                titleResources.retainAll(folderSet);
1215                Set<CmsResource> filterMatches = Sets.newHashSet();
1216                for (CmsResource folder : folderSet) {
1217                    if (folder.getName().toLowerCase().contains(filter)) {
1218                        filterMatches.add(folder);
1219                        titleResources.remove(folder); // we don't need to check the title if the name already matched
1220                    }
1221                }
1222                for (CmsResource titleRes : titleResources) {
1223                    CmsProperty prop = cms.readPropertyObject(titleRes, CmsPropertyDefinition.PROPERTY_TITLE, false);
1224                    String title = prop.getValue();
1225                    if ((title != null) && title.toLowerCase().contains(filter)) {
1226                        filterMatches.add(titleRes);
1227                    }
1228                }
1229                Set<String> filterMatchAncestorPaths = Sets.newHashSet();
1230                if (filterMatches.size() > 0) {
1231                    for (CmsResource filterMatch : filterMatches) {
1232                        String currentPath = filterMatch.getRootPath();
1233                        while (currentPath != null) {
1234                            filterMatchAncestorPaths.add(currentPath);
1235                            currentPath = CmsResource.getParentFolder(currentPath);
1236                        }
1237                    }
1238                    Set<String> allPaths = Sets.newHashSet();
1239                    Set<String> parentPaths = Sets.newHashSet();
1240                    for (CmsResource folder : folderSet) {
1241                        allPaths.add(folder.getRootPath());
1242                        String parent = CmsResource.getParentFolder(folder.getRootPath());
1243                        if (parent != null) {
1244                            parentPaths.add(parent);
1245                        }
1246                    }
1247                    parentPaths.retainAll(allPaths);
1248
1249                    Set<CmsResource> filterMatchAncestors = Sets.newHashSet();
1250                    for (CmsResource folderRes : folderSet) {
1251                        if (filterMatchAncestorPaths.contains(folderRes.getRootPath())) {
1252                            filterMatchAncestors.add(folderRes);
1253                        }
1254                    }
1255                    Map<String, CmsResource> resourcesByPath = Maps.newHashMap();
1256                    for (CmsResource treeRes : filterMatchAncestors) {
1257                        resourcesByPath.put(treeRes.getRootPath(), treeRes);
1258                    }
1259                    Multimap<CmsResource, CmsResource> childMap = ArrayListMultimap.create();
1260                    for (CmsResource res : filterMatchAncestors) {
1261                        CmsResource parent = resourcesByPath.get(CmsResource.getParentFolder(res.getRootPath()));
1262                        if (parent != null) {
1263                            childMap.put(parent, res);
1264                        }
1265                    }
1266                    return buildVfsEntryBeanForQuickSearch(optionRes, childMap, filterMatches, parentPaths, true);
1267                } else {
1268                    return null;
1269                }
1270            }
1271        } catch (Throwable e) {
1272            error(e);
1273            return null;
1274        }
1275    }
1276
1277    /**
1278     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#saveResultViewType(java.lang.String)
1279     */
1280    public void saveResultViewType(String resultViewType) {
1281
1282        CmsUser user = getCmsObject().getRequestContext().getCurrentUser();
1283        user.setAdditionalInfo(RESULT_VIEW_TYPE_ADD_INFO_KEY, resultViewType);
1284        try {
1285            getCmsObject().writeUser(user);
1286        } catch (CmsException e) {
1287            LOG.error(e.getLocalizedMessage(), e);
1288        }
1289    }
1290
1291    /**
1292     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#saveTreeOpenState(java.lang.String, java.lang.String, java.lang.String, java.util.Set)
1293     */
1294    public void saveTreeOpenState(String treeName, String treeToken, String siteRoot, Set<CmsUUID> openItems)
1295    throws CmsRpcException {
1296
1297        try {
1298            HttpServletRequest request = getRequest();
1299            HttpSession session = request.getSession();
1300            String attributeName = getTreeOpenStateAttributeName(treeName, treeToken);
1301            if (openItems.isEmpty()) {
1302                CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1303                cms.getRequestContext().setSiteRoot("");
1304                CmsResource resource = cms.readResource(siteRoot);
1305                openItems = Sets.newHashSet(resource.getStructureId());
1306            }
1307            CmsTreeOpenState treeState = new CmsTreeOpenState(treeName, siteRoot, openItems);
1308            session.setAttribute(attributeName, treeState);
1309        } catch (Throwable e) {
1310            error(e);
1311        }
1312    }
1313
1314    /**
1315     * @see org.opencms.ade.galleries.shared.rpc.I_CmsGalleryService#updateIndex()
1316     */
1317    public void updateIndex() throws CmsRpcException {
1318
1319        try {
1320            OpenCms.getSearchManager().updateOfflineIndexes();
1321        } catch (Throwable e) {
1322            error(e);
1323        }
1324    }
1325
1326    /**
1327     * Gets an initialized CmsObject to be used for the actual search for a given search bean.<p>
1328     *
1329     * @param searchObj the search object
1330     * @return the initialized CmsObject
1331     *
1332     * @throws CmsException if something goes wrong
1333     */
1334    protected CmsObject getSearchCms(CmsGallerySearchBean searchObj) throws CmsException {
1335
1336        CmsObject searchCms = getCmsObject();
1337        if (searchObj.isIncludeExpired()) {
1338            searchCms = OpenCms.initCmsObject(getCmsObject());
1339            searchCms.getRequestContext().setRequestTime(CmsResource.DATE_RELEASED_EXPIRED_IGNORE);
1340        }
1341        return searchCms;
1342    }
1343
1344    /**
1345     * Gets the sitemap sub entries for a given path as resources.<p>
1346     *
1347     * @param rootPath the root path
1348     * @return the sitemap sub entry resources
1349     * @throws CmsException if something goes wrong
1350     */
1351    protected List<CmsResource> getSitemapSubEntryResources(String rootPath) throws CmsException {
1352
1353        CmsObject rootCms = OpenCms.initCmsObject(getCmsObject());
1354        List<CmsResource> result = new ArrayList<CmsResource>();
1355        rootCms.getRequestContext().setSiteRoot("");
1356        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(rootCms);
1357        for (CmsJspNavElement navElement : navBuilder.getNavigationForFolder(
1358            rootPath,
1359            Visibility.all,
1360            CmsResourceFilter.ONLY_VISIBLE)) {
1361            if ((navElement != null) && navElement.isInNavigation()) {
1362                result.add(navElement.getResource());
1363            }
1364        }
1365        return result;
1366    }
1367
1368    /**
1369     * Internal method for getting sitemap sub entries for a given root path.<p>
1370     *
1371     * @param rootPath the root path
1372     * @param isRoot true if this method is used to get the root entries of a sitemap
1373     * @param filter the filter string (only relevant if isRoot is true)
1374     * @return the list of sitemap sub-entry beans
1375     *
1376     * @throws CmsException if something goes wrong
1377     */
1378    protected List<CmsSitemapEntryBean> getSubEntriesInternal(String rootPath, boolean isRoot, String filter)
1379    throws CmsException {
1380
1381        CmsObject rootCms = OpenCms.initCmsObject(getCmsObject());
1382        rootCms.getRequestContext().setSiteRoot("");
1383        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(rootCms);
1384        if (isRoot) {
1385            if (CmsStringUtil.isEmpty(filter)) {
1386                List<CmsSitemapEntryBean> result = new ArrayList<CmsSitemapEntryBean>();
1387                for (CmsJspNavElement navElement : navBuilder.getNavigationForFolder(
1388                    rootPath,
1389                    Visibility.all,
1390                    CmsResourceFilter.ONLY_VISIBLE)) {
1391                    if ((navElement != null) && navElement.isInNavigation()) {
1392                        CmsSitemapEntryBean nextEntry = prepareSitemapEntry(rootCms, navElement, false, true);
1393                        result.add(nextEntry);
1394                    }
1395                }
1396                CmsJspNavElement navElement = navBuilder.getNavigationForResource(
1397                    rootPath,
1398                    CmsResourceFilter.ONLY_VISIBLE);
1399                if (navElement == null) {
1400                    return result;
1401                }
1402                CmsSitemapEntryBean root = prepareSitemapEntry(rootCms, navElement, isRoot, true);
1403                root.setChildren(result);
1404                return Collections.singletonList(root);
1405            } else {
1406                CmsGalleryFilteredNavTreeBuilder navTreeBuilder = new CmsGalleryFilteredNavTreeBuilder(
1407                    rootCms,
1408                    rootPath);
1409                navTreeBuilder.initTree(filter);
1410                if (navTreeBuilder.hasMatches()) {
1411                    return Lists.newArrayList(convertNavigationTreeToBean(rootCms, navTreeBuilder.getRoot(), true));
1412                } else {
1413                    return Lists.newArrayList();
1414                }
1415            }
1416        } else {
1417            List<CmsSitemapEntryBean> result = new ArrayList<CmsSitemapEntryBean>();
1418            for (CmsJspNavElement navElement : navBuilder.getNavigationForFolder(
1419                rootPath,
1420                Visibility.all,
1421                CmsResourceFilter.ONLY_VISIBLE)) {
1422                if ((navElement != null) && navElement.isInNavigation()) {
1423                    CmsSitemapEntryBean nextEntry = prepareSitemapEntry(rootCms, navElement, false, true);
1424                    result.add(nextEntry);
1425                }
1426            }
1427            return result;
1428        }
1429    }
1430
1431    /**
1432     * Gets the type names from the gallery data bean.<p>
1433     *
1434     * @param data the gallery data bean
1435     * @return the type names
1436     */
1437    protected List<String> getTypeNames(CmsGalleryDataBean data) {
1438
1439        List<String> types = new ArrayList<String>();
1440        for (CmsResourceTypeBean info : data.getTypes()) {
1441            types.add(info.getType());
1442        }
1443        return types;
1444    }
1445
1446    /**
1447     * Checks whether a given resource is a sitemap entry.<p>
1448     *
1449     * This is used for preselected entries in the gallery widget.<p>
1450     *
1451     *
1452     * @param cms the current CMS context
1453     * @param resource the resource to check
1454     * @return true if the resource is a sitemap entry
1455     *
1456     * @throws CmsException if something goes wrong
1457     */
1458    protected boolean isSitemapEntry(CmsObject cms, CmsResource resource) throws CmsException {
1459
1460        CmsResourceFilter filter = CmsResourceFilter.ONLY_VISIBLE_NO_DELETED;
1461        List<CmsResource> ancestors = new ArrayList<CmsResource>();
1462        CmsResource currentResource = resource;
1463        String siteRoot = OpenCms.getSiteManager().getSiteRoot(resource.getRootPath());
1464        if (CmsStringUtil.isEmpty(siteRoot)) {
1465            return false;
1466        }
1467        while (true) {
1468            CmsResource parent = cms.readParentFolder(currentResource.getStructureId());
1469            if ((parent == null) || !cms.existsResource(parent.getStructureId(), filter)) {
1470                break;
1471            }
1472            ancestors.add(parent);
1473            if (CmsStringUtil.comparePaths(siteRoot, parent.getRootPath())) {
1474                break;
1475            }
1476            currentResource = parent;
1477        }
1478        Collections.reverse(ancestors);
1479        boolean first = true;
1480        for (CmsResource ancestor : ancestors) {
1481            if (first) {
1482                if (null == OpenCms.getSiteManager().getSiteRoot(ancestor.getRootPath())) {
1483                    return false;
1484                }
1485            } else {
1486                if (!hasNavigationProperty(cms, ancestor)) {
1487                    return false;
1488                }
1489            }
1490            first = false;
1491        }
1492        if (resource.isFile()) {
1493            if (ancestors.isEmpty()) {
1494                return false;
1495            }
1496            CmsResource defaultFile = cms.readDefaultFile(ancestors.get(ancestors.size() - 1), filter);
1497            if (!resource.equals(defaultFile)) {
1498                return false;
1499            }
1500        } else {
1501            if (!hasNavigationProperty(cms, resource)) {
1502                return false;
1503            }
1504        }
1505        return true;
1506    }
1507
1508    /**
1509     * Reads the resources for a collection of structure ids and returns the list of resources which could be read.<p>
1510     *
1511     * @param structureIds the structure ids for which we want to read the resources
1512     * @param filter the filter used to read the resource
1513     *
1514     * @return the list of resources for the given structure id
1515     */
1516    protected List<CmsResource> readAll(Collection<CmsUUID> structureIds, CmsResourceFilter filter) {
1517
1518        List<CmsResource> result = new ArrayList<CmsResource>();
1519        for (CmsUUID id : structureIds) {
1520            try {
1521                result.add(getCmsObject().readResource(id, filter));
1522            } catch (CmsException e) {
1523                LOG.info(e.getLocalizedMessage(), e);
1524            }
1525        }
1526        return result;
1527    }
1528
1529    /**
1530     * Gets the sitemap tree open state.<p>
1531     *
1532     * @param treeToken the tree token to use
1533     *
1534     * @return the sitemap tree open state
1535     */
1536    CmsTreeOpenState getSitemapTreeState(String treeToken) {
1537
1538        return (CmsTreeOpenState)(getRequest().getSession().getAttribute(
1539            getTreeOpenStateAttributeName(I_CmsGalleryProviderConstants.TREE_SITEMAP, treeToken)));
1540    }
1541
1542    /**
1543     * Gets the VFS tree open state.<p>
1544     *
1545     * @param treeToken the tree token
1546     *
1547     * @return the VFS tree open state
1548     */
1549    CmsTreeOpenState getVfsTreeState(String treeToken) {
1550
1551        return (CmsTreeOpenState)(getRequest().getSession().getAttribute(
1552            getTreeOpenStateAttributeName(I_CmsGalleryProviderConstants.TREE_VFS, treeToken)));
1553    }
1554
1555    /**
1556     * Returns the workplace locale from the current user's settings.<p>
1557     *
1558     * @return the workplace locale
1559     */
1560    Locale getWorkplaceLocale() {
1561
1562        if (m_wpLocale == null) {
1563            m_wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
1564        }
1565        return m_wpLocale;
1566    }
1567
1568    /**
1569     * Creates the sitemap entry bean for a resource.<p>
1570     *
1571     * @param cms the current CMS context
1572     * @param resource the resource for which the sitemap entry bean should be created
1573     *
1574     * @return the created sitemap entry bean
1575     *
1576     * @throws CmsException if something goes wrong
1577     */
1578    CmsSitemapEntryBean internalCreateSitemapEntryBean(CmsObject cms, CmsResource resource) throws CmsException {
1579
1580        cms = OpenCms.initCmsObject(cms);
1581        cms.getRequestContext().setSiteRoot("");
1582        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms);
1583        CmsJspNavElement entry = navBuilder.getNavigationForResource(resource.getRootPath());
1584        if (entry == null) {
1585            // may be null for expired resources
1586            return null;
1587        }
1588        return prepareSitemapEntry(cms, entry, false, true);
1589    }
1590
1591    /**
1592     * Checks if the current user has write permissions on the given resource.<p>
1593     *
1594     * @param cms the current cms context
1595     * @param resource the resource to check
1596     *
1597     * @return <code>true</code> if the current user has write permissions on the given resource
1598     */
1599    boolean isEditable(CmsObject cms, CmsResource resource) {
1600
1601        try {
1602            return cms.hasPermissions(resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL);
1603        } catch (CmsException e) {
1604            return false;
1605        }
1606    }
1607
1608    /**
1609     * Adds galleries for a given type.<p>
1610     *
1611     * @param galleryTypeInfos the gallery type infos
1612     * @param typeName the type name
1613     *
1614     * @throws CmsLoaderException if something goes wrong
1615     */
1616    @SuppressWarnings("deprecation")
1617    private void addGalleriesForType(Map<String, CmsGalleryTypeInfo> galleryTypeInfos, String typeName)
1618    throws CmsLoaderException {
1619
1620        I_CmsResourceType contentType = getResourceManager().getResourceType(typeName);
1621        for (I_CmsResourceType galleryType : contentType.getGalleryTypes()) {
1622
1623            if (galleryTypeInfos.containsKey(galleryType.getTypeName())) {
1624                CmsGalleryTypeInfo typeInfo = galleryTypeInfos.get(galleryType.getTypeName());
1625                typeInfo.addContentType(contentType);
1626            } else {
1627                CmsGalleryTypeInfo typeInfo;
1628
1629                typeInfo = new CmsGalleryTypeInfo(
1630                    galleryType,
1631                    contentType,
1632                    getGalleriesByType(galleryType.getTypeId()));
1633
1634                galleryTypeInfos.put(galleryType.getTypeName(), typeInfo);
1635            }
1636
1637        }
1638    }
1639
1640    /**
1641     * Returns the map with the available galleries.<p>
1642     *
1643     * The map uses gallery path as the key and stores the CmsGalleriesListInfoBean as the value.<p>
1644     * @param contextPath the site path used as the current context
1645     * @param galleryTypes the galleries
1646     *
1647     * @return the map with gallery info beans
1648     */
1649    private List<CmsGalleryFolderBean> buildGalleriesList(
1650        String contextPath,
1651        Map<String, CmsGalleryTypeInfo> galleryTypes) {
1652
1653        CmsObject cms = getCmsObject();
1654        Locale wpLocale = getWorkplaceLocale();
1655        String rootPath = cms.getRequestContext().addSiteRoot(contextPath);
1656        CmsADEConfigData sitemapConfig = OpenCms.getADEManager().lookupConfigurationWithCache(cms, rootPath);
1657        String subsitePath = sitemapConfig.getBasePath();
1658        CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(rootPath);
1659
1660        List<CmsGalleryFolderBean> list = new ArrayList<CmsGalleryFolderBean>();
1661        if (galleryTypes == null) {
1662            return list;
1663        }
1664        for (Entry<String, CmsGalleryTypeInfo> ent : galleryTypes.entrySet()) {
1665            CmsGalleryTypeInfo tInfo = ent.getValue();
1666            ArrayList<String> contentTypes = new ArrayList<String>();
1667            Iterator<I_CmsResourceType> it = tInfo.getContentTypes().iterator();
1668            while (it.hasNext()) {
1669                contentTypes.add(String.valueOf(it.next().getTypeName()));
1670            }
1671            for (CmsResource res : tInfo.getGalleries()) {
1672                CmsGalleryFolderBean bean = new CmsGalleryFolderBean();
1673                String sitePath = getCmsObject().getSitePath(res);
1674                String title = "";
1675                try {
1676                    // read the gallery title
1677                    title = getCmsObject().readPropertyObject(
1678                        sitePath,
1679                        CmsPropertyDefinition.PROPERTY_TITLE,
1680                        false,
1681                        getWorkplaceLocale()).getValue("");
1682                } catch (CmsException e) {
1683                    // error reading title property
1684                    logError(e);
1685                }
1686                // sitepath as gallery id
1687                bean.setPath(sitePath);
1688                // content types
1689                bean.setContentTypes(contentTypes);
1690                // title
1691                bean.setTitle(title);
1692                CmsGalleryGroup group = null;
1693                String groupLabel = null;
1694                if ((site != null)
1695                    && (subsitePath != null)
1696                    && CmsStringUtil.isPrefixPath(subsitePath, res.getRootPath())
1697                    && !new CmsPath(subsitePath).equals(new CmsPath(site.getSiteRoot()))) {
1698                    // we are in a proper subsite, not just the site itself
1699                    group = CmsGalleryGroup.subsite;
1700
1701                    String labelSuffix = cms.getRequestContext().removeSiteRoot(subsitePath);
1702                    try {
1703                        Map<String, String> properties = CmsProperty.toMap(
1704                            cms.readPropertyObjects(cms.getRequestContext().removeSiteRoot(subsitePath), false));
1705                        for (String propName : new String[] {
1706                            CmsPropertyDefinition.PROPERTY_TITLE,
1707                            CmsPropertyDefinition.PROPERTY_NAVTEXT}) {
1708                            String propValue = properties.get(propName);
1709                            if (propValue != null) {
1710                                labelSuffix = propValue;
1711                                break;
1712                            }
1713                        }
1714                    } catch (Exception e) {
1715                        LOG.error(e.getLocalizedMessage(), e);
1716                    }
1717                    groupLabel = Messages.get().getBundle(wpLocale).key(
1718                        Messages.GUI_GALLERIES_GROUP_SUBSITE_1,
1719                        labelSuffix);
1720                } else if ((site != null) && CmsStringUtil.isPrefixPath(site.getSiteRoot(), res.getRootPath())) {
1721                    group = CmsGalleryGroup.site;
1722                    String labelSuffix;
1723                    labelSuffix = site.getTitle();
1724                    if (CmsStringUtil.isEmptyOrWhitespaceOnly(labelSuffix)) {
1725                        labelSuffix = site.getSiteRoot();
1726                    }
1727                    groupLabel = Messages.get().getBundle(wpLocale).key(
1728                        Messages.GUI_GALLERIES_GROUP_SITE_1,
1729                        labelSuffix);
1730                } else if (CmsStringUtil.isPrefixPath(CmsResource.VFS_FOLDER_SYSTEM, res.getRootPath())
1731                    || OpenCms.getSiteManager().startsWithShared(res.getRootPath())) {
1732                    group = CmsGalleryGroup.shared;
1733                    groupLabel = Messages.get().getBundle(wpLocale).key(Messages.GUI_GALLERIES_GROUP_SHARED_0);
1734                } else {
1735                    group = CmsGalleryGroup.other;
1736                    groupLabel = Messages.get().getBundle(wpLocale).key(Messages.GUI_GALLERIES_GROUP_OTHER_0);
1737                }
1738                bean.setGroup(group);
1739                bean.setGroupLabel(groupLabel);
1740                bean.setResourceType(tInfo.getResourceType().getTypeName());
1741                bean.setUploadAction(tInfo.getResourceType().getConfiguration().get("gallery.upload.action"));
1742                bean.setEditable(isEditable(getCmsObject(), res));
1743                bean.setBigIconClasses(
1744                    CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(getCmsObject(), res), sitePath, false));
1745                list.add(bean);
1746            }
1747        }
1748        return list;
1749    }
1750
1751    /**
1752     * Returns a map with the available locales.<p>
1753     *
1754     * The map entry key is the current locale and the value the localized nice name.<p>
1755     *
1756     * @return the map representation of all available locales
1757     */
1758    private Map<String, String> buildLocalesMap() {
1759
1760        TreeMap<String, String> localesMap = new TreeMap<String, String>();
1761        Iterator<Locale> it = OpenCms.getLocaleManager().getAvailableLocales().iterator();
1762        while (it.hasNext()) {
1763            Locale locale = it.next();
1764            localesMap.put(locale.toString(), locale.getDisplayName(getWorkplaceLocale()));
1765        }
1766        return localesMap;
1767    }
1768
1769    /**
1770     * Returns the list of beans for the given search results.<p>
1771     *
1772     * @param searchResult the list of search results
1773     * @param presetResult the search result which corresponds to a preset value in the editor
1774     * @param checkDeactivated checks if search results should be shown as deactivated
1775     *
1776     * @return the list with the current search results
1777     */
1778    private List<CmsResultItemBean> buildSearchResultList(
1779        List<CmsGallerySearchResult> searchResult,
1780        CmsGallerySearchResult presetResult,
1781        Predicate<CmsResource> checkDeactivated) {
1782
1783        ArrayList<CmsResultItemBean> list = new ArrayList<CmsResultItemBean>();
1784        if ((searchResult == null) || (searchResult.size() == 0)) {
1785            return list;
1786        }
1787        CmsObject cms = getCmsObject();
1788        for (CmsGallerySearchResult sResult : searchResult) {
1789            try {
1790                CmsResultItemBean bean = buildSingleSearchResultItem(cms, sResult, presetResult, checkDeactivated);
1791                list.add(bean);
1792            } catch (Exception e) {
1793                logError(e);
1794            }
1795        }
1796        return list;
1797    }
1798
1799    /**
1800     * Builds a single search result list item for the client from a server-side search result.<p>
1801     *
1802     * @param cms the current CMS context
1803     * @param sResult the server-side search result
1804     * @param presetResult the preselected result
1805     * @param checkDeactivated checks if search results should be shown as deactivated
1806     *
1807     * @return the client side search result item
1808     *
1809     * @throws CmsException if something goes wrong
1810     * @throws ParseException if date parsing fails
1811     */
1812    private CmsResultItemBean buildSingleSearchResultItem(
1813        CmsObject cms,
1814        CmsGallerySearchResult sResult,
1815        CmsGallerySearchResult presetResult,
1816        Predicate<CmsResource> checkDeactivated)
1817    throws CmsException, ParseException {
1818
1819        Locale wpLocale = getWorkplaceLocale();
1820        CmsResultItemBean bean = new CmsResultItemBean();
1821        if (sResult == presetResult) {
1822            bean.setPreset(true);
1823        }
1824        bean.setReleasedAndNotExpired(sResult.isReleaseAndNotExpired(cms));
1825        String path = sResult.getPath();
1826        path = cms.getRequestContext().removeSiteRoot(path);
1827
1828        // resource path as id
1829        bean.setPath(path);
1830
1831        // title
1832        String rawTitle = CmsStringUtil.isEmptyOrWhitespaceOnly(sResult.getTitle())
1833        ? CmsResource.getName(sResult.getPath())
1834        : sResult.getTitle();
1835        bean.setTitle(rawTitle);
1836        bean.setRawTitle(rawTitle);
1837        // resource type
1838        bean.setType(sResult.getResourceType());
1839        CmsResource resultResource = cms.readResource(
1840            new CmsUUID(sResult.getStructureId()),
1841            CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
1842        bean.setBigIconClasses(
1843            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resultResource), path, false));
1844        String detailType = CmsResourceIcon.getDefaultFileOrDetailType(cms, resultResource);
1845        if (detailType != null) {
1846            bean.setSmallIconClasses(CmsIconUtil.getIconClasses(detailType, null, true));
1847        }
1848        // structured id
1849        bean.setClientId(sResult.getStructureId());
1850
1851        CmsVfsService.addLockInfo(cms, resultResource, bean);
1852
1853        String permalinkId = sResult.getStructureId().toString();
1854        String permalink = CmsStringUtil.joinPaths(
1855            OpenCms.getSystemInfo().getOpenCmsContext(),
1856            CmsPermalinkResourceHandler.PERMALINK_HANDLER,
1857            permalinkId);
1858
1859        bean.setViewLink(permalink);
1860        // set nice resource type name as subtitle
1861        I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(sResult.getResourceType());
1862        String resourceTypeDisplayName = CmsWorkplaceMessages.getResourceTypeName(wpLocale, type.getTypeName());
1863        String description = sResult.getDescription();
1864        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(description)) {
1865            bean.setDescription(description);
1866            bean.addAdditionalInfo(
1867                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DESCRIPTION_0),
1868                description);
1869            if (sResult.getResourceType().equals(CmsResourceTypeFunctionConfig.TYPE_NAME)) {
1870                bean.setSubTitle(description);
1871            }
1872        } else {
1873            bean.setDescription(resourceTypeDisplayName);
1874        }
1875        bean.setUserLastModified(sResult.getUserLastModified());
1876        Date lastModDate = sResult.getDateLastModified();
1877        String formattedDate = lastModDate != null
1878        ? CmsDateUtil.getDateTime(lastModDate, DateFormat.MEDIUM, wpLocale)
1879        : "";
1880        bean.setDateLastModified(formattedDate);
1881        if (!type.getTypeName().equals(CmsResourceTypeImage.getStaticTypeName())) {
1882            bean.addAdditionalInfo(
1883                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_RESOURCE_TYPE_0),
1884                resourceTypeDisplayName);
1885        }
1886        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(sResult.getExcerpt())) {
1887            bean.addAdditionalInfo(
1888                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_EXCERPT_0),
1889                sResult.getExcerpt(),
1890                CmsListInfoBean.CSS_CLASS_MULTI_LINE);
1891        }
1892        if (type instanceof CmsResourceTypeImage) {
1893            CmsProperty copyrightProp = cms.readPropertyObject(
1894                resultResource,
1895                CmsPropertyDefinition.PROPERTY_COPYRIGHT,
1896                false);
1897            if (!copyrightProp.isNullProperty()) {
1898                bean.addAdditionalInfo(
1899                    Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_COPYRIGHT_0),
1900                    copyrightProp.getValue());
1901            }
1902            CmsProperty imageDimensionProp = cms.readPropertyObject(
1903                resultResource,
1904                CmsPropertyDefinition.PROPERTY_IMAGE_SIZE,
1905                false);
1906            if (!imageDimensionProp.isNullProperty()) {
1907                String dimensions = imageDimensionProp.getValue();
1908                dimensions = dimensions.substring(2).replace(",h:", " x ");
1909                bean.setDimension(dimensions);
1910                bean.addAdditionalInfo(
1911                    Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DIMENSION_0),
1912                    dimensions);
1913            }
1914        }
1915
1916        if (type instanceof CmsResourceTypeXmlContent) {
1917            CmsProperty elementModelProperty = cms.readPropertyObject(
1918                resultResource,
1919                CmsPropertyDefinition.PROPERTY_ELEMENT_MODEL,
1920                true);
1921            if (!elementModelProperty.isNullProperty()) {
1922                if (Boolean.valueOf(elementModelProperty.getValue()).booleanValue()) {
1923                    bean.setIsCopyModel(true);
1924                }
1925            }
1926        }
1927        bean.setResourceState(resultResource.getState());
1928        bean.addAdditionalInfo(
1929            Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_SIZE_0),
1930            (sResult.getLength() / 1000) + " kb");
1931        if (lastModDate != null) {
1932            bean.addAdditionalInfo(
1933                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DATE_CHANGED_0),
1934                CmsDateUtil.getDate(lastModDate, DateFormat.SHORT, getWorkplaceLocale()));
1935        }
1936        if ((sResult.getDateExpired().getTime() != CmsResource.DATE_EXPIRED_DEFAULT)
1937            && !sResult.getDateExpired().equals(CmsSearchFieldMapping.getDefaultDateExpired())) {
1938            bean.addAdditionalInfo(
1939                Messages.get().getBundle(getWorkplaceLocale()).key(Messages.GUI_RESULT_LABEL_DATE_EXPIRED_0),
1940                CmsDateUtil.getDate(sResult.getDateExpired(), DateFormat.SHORT, getWorkplaceLocale()));
1941        }
1942
1943        bean.setNoEditReson(
1944            new CmsResourceUtil(cms, resultResource).getNoEditReason(
1945                OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)));
1946        bean.setMarkChangedState(true);
1947        if (checkDeactivated.test(resultResource)) {
1948            bean.setDeactivated(true);
1949        }
1950        return bean;
1951    }
1952
1953    /**
1954     * Generates a map with all available content types.<p>
1955     *
1956     * The map uses resource type name as the key and stores the CmsTypesListInfoBean as the value.
1957     *
1958     * @param types the resource types
1959     * @param creatableTypes the creatable types
1960     *
1961     * @return the map containing the available resource types
1962     */
1963    private List<CmsResourceTypeBean> buildTypesList(List<I_CmsResourceType> types, Set<String> creatableTypes) {
1964
1965        ArrayList<CmsResourceTypeBean> list = new ArrayList<CmsResourceTypeBean>();
1966        if (types == null) {
1967            return list;
1968        }
1969        Map<I_CmsResourceType, I_CmsPreviewProvider> typeProviderMapping = getPreviewProviderForTypes(types);
1970        Iterator<I_CmsResourceType> it = types.iterator();
1971        while (it.hasNext()) {
1972
1973            I_CmsResourceType type = it.next();
1974            try {
1975                CmsResourceTypeBean bean = createTypeBean(
1976                    type,
1977                    typeProviderMapping.get(type),
1978                    creatableTypes.contains(type.getTypeName()));
1979                list.add(bean);
1980            } catch (Exception e) {
1981                if (type != null) {
1982                    log(
1983                        Messages.get().getBundle(getWorkplaceLocale()).key(
1984                            Messages.ERR_BUILD_TYPE_LIST_1,
1985                            type.getTypeName()),
1986                        e);
1987                }
1988            }
1989        }
1990        return list;
1991    }
1992
1993    /**
1994     * Recursively builds the VFS entry bean for the quick filtering function in the folder tab.<p<
1995     *
1996     * @param resource the resource
1997     * @param childMap map from parent to child resources
1998     * @param filterMatches the resources matching the filter
1999     * @param parentPaths root paths of resources which are not leaves
2000     * @param isRoot true if this the root node
2001     *
2002     * @return the VFS entry bean for the client
2003     *
2004     * @throws CmsException if something goes wrong
2005     */
2006    private CmsVfsEntryBean buildVfsEntryBeanForQuickSearch(
2007        CmsResource resource,
2008        Multimap<CmsResource, CmsResource> childMap,
2009        Set<CmsResource> filterMatches,
2010        Set<String> parentPaths,
2011        boolean isRoot)
2012    throws CmsException {
2013
2014        CmsObject cms = getCmsObject();
2015        String title = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
2016        boolean isMatch = filterMatches.contains(resource);
2017        List<CmsVfsEntryBean> childBeans = Lists.newArrayList();
2018
2019        Collection<CmsResource> children = childMap.get(resource);
2020        if (!children.isEmpty()) {
2021            for (CmsResource child : children) {
2022                CmsVfsEntryBean childBean = buildVfsEntryBeanForQuickSearch(
2023                    child,
2024                    childMap,
2025                    filterMatches,
2026                    parentPaths,
2027                    false);
2028                childBeans.add(childBean);
2029            }
2030        } else if (filterMatches.contains(resource)) {
2031            if (parentPaths.contains(resource.getRootPath())) {
2032                childBeans = null;
2033            }
2034            // otherwise childBeans remains an empty list
2035        }
2036
2037        String rootPath = resource.getRootPath();
2038        CmsVfsEntryBean result = new CmsVfsEntryBean(
2039            rootPath,
2040            resource.getStructureId(),
2041            title,
2042            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resource), resource.getName(), true),
2043            isRoot,
2044            isEditable(cms, resource),
2045            childBeans,
2046            isMatch);
2047        String siteRoot = null;
2048        if (OpenCms.getSiteManager().startsWithShared(rootPath)) {
2049            siteRoot = OpenCms.getSiteManager().getSharedFolder();
2050        } else {
2051            String tempSiteRoot = OpenCms.getSiteManager().getSiteRoot(rootPath);
2052            if (tempSiteRoot != null) {
2053                siteRoot = tempSiteRoot;
2054            } else {
2055                siteRoot = "";
2056            }
2057        }
2058        result.setSiteRoot(siteRoot);
2059        return result;
2060    }
2061
2062    /**
2063     * Helper method to construct a sitemap entry bean for the sitemap tab filter functionality.<p>
2064     *
2065     * @param cms the CMS context
2066     * @param node the root node of the filtered tree
2067     * @param isRoot true if this is the root node
2068     *
2069     * @return the sitemap entry bean
2070     */
2071    private CmsSitemapEntryBean convertNavigationTreeToBean(CmsObject cms, NavigationNode node, boolean isRoot) {
2072
2073        CmsSitemapEntryBean bean = null;
2074        try {
2075            bean = prepareSitemapEntry(cms, node.getNavElement(), isRoot, false);
2076            bean.setSearchMatch(node.isMatch());
2077            List<NavigationNode> children = node.getChildren();
2078            List<CmsSitemapEntryBean> childBeans = Lists.newArrayList();
2079            if (children.size() > 0) {
2080                for (NavigationNode child : children) {
2081                    childBeans.add(convertNavigationTreeToBean(cms, child, false));
2082                }
2083            } else if (node.isLeaf()) {
2084                childBeans = Lists.newArrayList();
2085            } else {
2086                // no children in filter result, but can still load children by clicking on tree item
2087                childBeans = null;
2088            }
2089            bean.setChildren(childBeans);
2090
2091        } catch (CmsException e) {
2092            LOG.error(e.getLocalizedMessage(), e);
2093        }
2094        return bean;
2095    }
2096
2097    /**
2098     * Returns a list of resource types by a request parameter.<p>
2099     *
2100     * @param resourceTypes the resource types parameter
2101     *
2102     * @return the resource types
2103     */
2104    private List<I_CmsResourceType> convertTypeNamesToTypes(List<String> resourceTypes) {
2105
2106        List<I_CmsResourceType> result = new ArrayList<I_CmsResourceType>();
2107        if (resourceTypes != null) {
2108            for (String type : resourceTypes) {
2109                try {
2110                    result.add(getResourceManager().getResourceType(type.trim()));
2111                } catch (Exception e) {
2112                    logError(e);
2113                }
2114            }
2115        }
2116
2117        return result;
2118    }
2119
2120    /**
2121     * Creates a resource type bean for the given type.<p>
2122     *
2123     * @param type the resource type
2124     * @param preview the preview provider
2125     * @param creatable if the type may be created by the current user
2126     *
2127     * @return the resource type bean
2128     */
2129    @SuppressWarnings("deprecation")
2130    private CmsResourceTypeBean createTypeBean(
2131        I_CmsResourceType type,
2132        I_CmsPreviewProvider preview,
2133        boolean creatable) {
2134
2135        CmsResourceTypeBean result = new CmsResourceTypeBean();
2136
2137        result.setResourceType(type.getTypeName());
2138        result.setTypeId(type.getTypeId());
2139        Locale wpLocale = getWorkplaceLocale();
2140        // type title and subtitle
2141        result.setTitle(CmsWorkplaceMessages.getResourceTypeName(wpLocale, type.getTypeName()));
2142        result.setSubTitle(CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, type.getTypeName()));
2143        result.setBigIconClasses(CmsIconUtil.getIconClasses(type.getTypeName(), null, false));
2144        // gallery id of corresponding galleries
2145        ArrayList<String> galleryNames = new ArrayList<String>();
2146        Iterator<I_CmsResourceType> galleryTypes = type.getGalleryTypes().iterator();
2147        while (galleryTypes.hasNext()) {
2148            I_CmsResourceType galleryType = galleryTypes.next();
2149            galleryNames.add(galleryType.getTypeName());
2150        }
2151        result.setGalleryTypeNames(galleryNames);
2152        if (preview != null) {
2153            result.setPreviewProviderName(preview.getPreviewName());
2154        }
2155        if (type.isFolder()) {
2156            result.setVisibility(TypeVisibility.hidden);
2157        }
2158        result.setCreatableType(creatable);
2159        return result;
2160    }
2161
2162    /**
2163     * Returns the search object containing the list with search results and the path to the specified resource.<p>
2164     *
2165     * @param resourceName the given resource
2166     * @param data the gallery data bean
2167     *
2168     * @return the gallery search object containing the current search parameter and the search result list
2169     *
2170     * @throws CmsException if the search fails
2171     */
2172    private CmsGallerySearchBean findResourceInGallery(String resourceName, CmsGalleryDataBean data)
2173    throws CmsException {
2174
2175        CmsResource resource = null;
2176        int pos = resourceName.indexOf("?");
2177        String resName = resourceName;
2178        String query = "";
2179        if (pos > -1) {
2180            query = resourceName.substring(pos);
2181            resName = resourceName.substring(0, pos);
2182        }
2183        String resNameWithoutServer = OpenCms.getLinkManager().getRootPath(getCmsObject(), resName);
2184        if (resNameWithoutServer != null) {
2185            // also cut off fragment if it has one
2186            resName = resNameWithoutServer.replaceFirst("#.*$", "");
2187        }
2188        CmsObject cms = getCmsObject();
2189        try {
2190            log("reading resource: " + resName);
2191            resource = cms.readResource(resName, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2192        } catch (CmsException e) {
2193            String originalSiteRoot = cms.getRequestContext().getSiteRoot();
2194            try {
2195                cms.getRequestContext().setSiteRoot("");
2196                resource = cms.readResource(resName, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2197            } catch (CmsException e2) {
2198                logError(e);
2199                return null;
2200            } finally {
2201                cms.getRequestContext().setSiteRoot(originalSiteRoot);
2202            }
2203        }
2204        boolean typeOk = true;
2205        if ((data.getTypes() != null) && !data.getTypes().isEmpty()) {
2206            typeOk = false;
2207            for (CmsResourceTypeBean type : data.getTypes()) {
2208                if (OpenCms.getResourceManager().matchResourceType(type.getType(), resource.getTypeId())) {
2209                    typeOk = true;
2210                }
2211            }
2212        }
2213        if (!typeOk) {
2214            LOG.debug(
2215                "Selected resource " + resource.getRootPath() + " has invalid type for configured gallery widget.");
2216            return null;
2217        }
2218        ArrayList<String> types = new ArrayList<String>();
2219        String resType = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
2220        types.add(resType);
2221        Set<String> folders = null;
2222        if (data.getStartFolderFilter() != null) {
2223            for (String folder : data.getStartFolderFilter()) {
2224                if (resource.getRootPath().startsWith(folder)) {
2225                    folders = data.getStartFolderFilter();
2226                    break;
2227                }
2228            }
2229        }
2230        CmsGallerySearchBean initialSearchObj = new CmsGallerySearchBean();
2231        initialSearchObj.setGalleryMode(data.getMode());
2232        initialSearchObj.setGalleryStoragePrefix(data.getGalleryStoragePrefix());
2233        initialSearchObj.setIncludeExpired(data.getIncludeExpiredDefault());
2234        initialSearchObj.setIgnoreSearchExclude(true);
2235        initialSearchObj.setTypes(types);
2236        if (folders != null) {
2237            initialSearchObj.setFolders(folders);
2238        }
2239        ArrayList<String> galleries = new ArrayList<String>();
2240        for (CmsGalleryFolderBean gallery : data.getGalleries()) {
2241            String galleryPath = gallery.getPath();
2242            String galleryRootPath = cms.addSiteRoot(galleryPath);
2243            String folderPath = CmsResource.getFolderPath(resName);
2244            if (galleryPath.equals(folderPath) || galleryRootPath.equals(folderPath)) {
2245                galleries.add(gallery.getPath());
2246                initialSearchObj.setGalleries(galleries);
2247                break;
2248            }
2249        }
2250        if (galleries.isEmpty()) {
2251            ArrayList<String> vfsFolders = new ArrayList<String>();
2252            vfsFolders.add(CmsResource.getFolderPath(resource.getRootPath()));
2253            initialSearchObj.setFolders(new HashSet<String>(vfsFolders));
2254        }
2255        initialSearchObj.setLocale(data.getLocale());
2256        CmsGallerySearchBean searchObj = new CmsGallerySearchBean(initialSearchObj);
2257        searchObj.setSortOrder(CmsGallerySearchParameters.CmsGallerySortParam.DEFAULT.toString());
2258        int currentPage = 1;
2259        boolean found = false;
2260        searchObj.setPage(currentPage);
2261        CmsGallerySearchParameters params = prepareSearchParams(searchObj, CmsAddContentRestriction.EMPTY);
2262        CmsObject searchCms = getSearchCms(searchObj);
2263        org.opencms.search.galleries.CmsGallerySearch searchBean = new org.opencms.search.galleries.CmsGallerySearch();
2264        searchBean.init(searchCms);
2265        searchBean.setIndexForProject(searchCms);
2266        CmsGallerySearchResultList searchResults = null;
2267        CmsGallerySearchResultList totalResults = new CmsGallerySearchResultList();
2268        CmsGallerySearchResult foundItem = null;
2269        while (!found) {
2270            params.setResultPage(currentPage);
2271            searchResults = searchBean.getResult(params);
2272            totalResults.append(searchResults);
2273            Iterator<CmsGallerySearchResult> resultsIt = searchResults.listIterator();
2274            while (resultsIt.hasNext()) {
2275                CmsGallerySearchResult searchResult = resultsIt.next();
2276                if (searchResult.getPath().equals(resource.getRootPath())) {
2277                    found = true;
2278                    foundItem = searchResult;
2279                    break;
2280                }
2281            }
2282            if (!found && ((searchResults.getHitCount() / (currentPage * params.getMatchesPerPage())) >= 1)) {
2283                currentPage++;
2284            } else {
2285                break;
2286            }
2287            if (searchResults.getHitCount() > INITIAL_SEARCH_MAX_RESULTS) {
2288                // in case the hit count is too large, don't continue the search to avoid slow load times
2289                break;
2290            }
2291        }
2292        boolean hasResults = searchResults != null;
2293        searchResults = totalResults;
2294        if (hasResults) {
2295            initialSearchObj.setSortOrder(params.getSortOrder().name());
2296            initialSearchObj.setResultCount(searchResults.getHitCount());
2297            initialSearchObj.setPage(params.getResultPage());
2298            initialSearchObj.setResults(buildSearchResultList(searchResults, foundItem, res -> false));
2299            initialSearchObj.setPage(1);
2300            initialSearchObj.setLastPage(currentPage);
2301            initialSearchObj.setTabId(I_CmsGalleryProviderConstants.GalleryTabId.cms_tab_results.name());
2302            initialSearchObj.setResourcePath(resName + query);
2303            initialSearchObj.setResourceType(resType);
2304            updateNoUploadReason(searchCms, searchObj);
2305        } else {
2306            log("could not find selected resource");
2307        }
2308        if ((resource != null)) {
2309            if (isSitemapEntry(cms, resource)) {
2310                A_CmsTreeTabDataPreloader<CmsSitemapEntryBean> loader = new A_CmsTreeTabDataPreloader<CmsSitemapEntryBean>() {
2311
2312                    @Override
2313                    protected CmsSitemapEntryBean createEntry(CmsObject innerCms, CmsResource innerResource)
2314                    throws CmsException {
2315
2316                        return internalCreateSitemapEntryBean(innerCms, innerResource);
2317                    }
2318
2319                    /**
2320                     * @see org.opencms.ade.galleries.A_CmsTreeTabDataPreloader#getChildren(org.opencms.file.CmsResource)
2321                     */
2322                    @Override
2323                    protected List<CmsResource> getChildren(CmsResource parent) throws CmsException {
2324
2325                        return getSitemapSubEntryResources(parent.getRootPath());
2326                    }
2327                };
2328                CmsSitemapEntryBean entryBean = loader.preloadData(
2329                    cms,
2330                    Sets.newHashSet(Collections.singletonList(resource)),
2331                    null);
2332                initialSearchObj.setSitemapPreloadData(entryBean);
2333            } else if (resource.isFolder()) {
2334                A_CmsTreeTabDataPreloader<CmsVfsEntryBean> loader = new A_CmsTreeTabDataPreloader<CmsVfsEntryBean>() {
2335
2336                    @Override
2337                    protected CmsVfsEntryBean createEntry(CmsObject innerCms, CmsResource innerResource)
2338                    throws CmsException {
2339
2340                        String title = innerCms.readPropertyObject(
2341                            innerResource,
2342                            CmsPropertyDefinition.PROPERTY_TITLE,
2343                            false).getValue();
2344                        return internalCreateVfsEntryBean(
2345                            getCmsObject(),
2346                            innerResource,
2347                            title,
2348                            true,
2349                            isEditable(innerCms, innerResource),
2350                            null,
2351                            false);
2352                    }
2353                };
2354                CmsVfsEntryBean entryBean = loader.preloadData(
2355                    cms,
2356                    Sets.newHashSet(Collections.singletonList(resource)),
2357                    null);
2358                initialSearchObj.setVfsPreloadData(entryBean);
2359            }
2360        }
2361
2362        return initialSearchObj;
2363    }
2364
2365    /**
2366     * Get default types for gallery together with visibility.<p>
2367     *
2368     * @return the default types
2369     */
2370    private List<I_CmsResourceType> getDefaultTypesForGallery() {
2371
2372        return OpenCms.getResourceManager().getResourceTypes();
2373    }
2374
2375    /**
2376     * Generates a list of available galleries for the given gallery-type.<p>
2377     *
2378     * @param galleryTypeId the gallery-type
2379     *
2380     * @return the list of galleries
2381     *
2382     */
2383    @SuppressWarnings("deprecation")
2384    private List<CmsResource> getGalleriesByType(int galleryTypeId) {
2385
2386        Set<CmsResource> galleries = new HashSet<CmsResource>();
2387
2388        // We swallow errors in this method because we don't  want a failure to read some folders (e.g. because of permission problems) to
2389        // cause an empty gallery list as a result
2390
2391        try {
2392            galleries.addAll(
2393                getCmsObject().readResources(
2394                    "/",
2395                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryTypeId)));
2396        } catch (Exception e) {
2397            LOG.error("Could not read site galleries: " + e.getLocalizedMessage(), e);
2398        }
2399
2400        String siteRoot = getCmsObject().getRequestContext().getSiteRoot();
2401        // if the current site is NOT the root site - add all other galleries from the system path
2402
2403        try {
2404            if (!siteRoot.equals("")) {
2405                List<CmsResource> systemGalleries = null;
2406                // get the galleries in the /system/ folder
2407                systemGalleries = getCmsObject().readResources(
2408                    CmsWorkplace.VFS_PATH_SYSTEM,
2409                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryTypeId));
2410                if (systemGalleries != null) {
2411                    // add the found system galleries to the result
2412                    galleries.addAll(systemGalleries);
2413                }
2414            }
2415        } catch (Exception e) {
2416            LOG.info("Could not read system galleries: " + e.getLocalizedMessage(), e);
2417        }
2418
2419        try {
2420            if (!OpenCms.getSiteManager().isSharedFolder(siteRoot)) {
2421                String shared = OpenCms.getSiteManager().getSharedFolder();
2422                List<CmsResource> sharedGalleries = getCmsObject().readResources(
2423                    shared,
2424                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireType(galleryTypeId));
2425                if (sharedGalleries != null) {
2426                    galleries.addAll(sharedGalleries);
2427                }
2428            }
2429        } catch (Exception e) {
2430            LOG.info("Could not read shared galleries: " + e.getLocalizedMessage(), e);
2431        }
2432        List<CmsResource> galleriesList = new ArrayList<>(galleries);
2433        Collections.sort(
2434            galleriesList,
2435            (a, b) -> ComparisonChain.start().compare(a.getRootPath(), b.getRootPath()).result());
2436        return galleriesList;
2437    }
2438
2439    /**
2440     * Helper method for getting the initial gallery settings.<p>
2441     *
2442     * @param conf the gallery configration
2443     * @return the gallery settings
2444     *
2445     * @throws CmsRpcException if something goes wrong
2446     */
2447    private CmsGalleryDataBean getInitialSettingsInternal(CmsGalleryConfiguration conf) throws CmsRpcException {
2448
2449        CmsObject cms = getCmsObject();
2450        CmsGalleryDataBean data = new CmsGalleryDataBean();
2451        data.setMode(conf.getGalleryMode());
2452        data.setResultViewType(readResultViewType());
2453        boolean galleryShowInvalidDefault = Boolean.parseBoolean(
2454            getWorkplaceSettings().getUserSettings().getAdditionalPreference(PREF_GALLERY_SHOW_INVALID_DEFAULT, true));
2455        data.setIncludeExpiredDefault(galleryShowInvalidDefault);
2456
2457        data.setGalleryStoragePrefix(conf.getGalleryStoragePrefix());
2458        data.setLocales(buildLocalesMap());
2459        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(conf.getLocale())) {
2460            data.setLocale(conf.getLocale());
2461        } else {
2462            data.setLocale(getCmsObject().getRequestContext().getLocale().toString());
2463        }
2464        data.setVfsRootFolders(getRootEntries());
2465        data.setScope(getWorkplaceSettings().getLastSearchScope());
2466        data.setSortOrder(getWorkplaceSettings().getLastGalleryResultOrder());
2467
2468        List<CmsResourceTypeBean> types = null;
2469        data.setTabIds(conf.getGalleryMode().getTabs());
2470        switch (conf.getGalleryMode()) {
2471            case editor:
2472            case view:
2473            case adeView:
2474            case widget:
2475                if (conf.getTabIds() != null) {
2476                    data.setTabIds(conf.getTabIds());
2477                }
2478                data.setCurrentElement(conf.getCurrentElement());
2479                String referencePath = conf.getReferencePath();
2480                if (CmsStringUtil.isEmptyOrWhitespaceOnly(referencePath)) {
2481                    referencePath = conf.getGalleryPath();
2482                }
2483                data.setReferenceSitePath(referencePath);
2484                types = getResourceTypeBeans(
2485                    conf.getGalleryMode(),
2486                    data.getReferenceSitePath(),
2487                    conf.getResourceTypes(),
2488                    conf.getSearchTypes());
2489                data.setTypes(types);
2490                Map<String, CmsGalleryTypeInfo> galleryTypeInfos = readGalleryInfosByTypeBeans(types);
2491                // in case the 'gallerytypes' parameter is set, allow only the given galleries
2492                if (conf.getGalleryTypes() != null) {
2493                    Map<String, CmsGalleryTypeInfo> infos = new HashMap<String, CmsGalleryTypeInfo>();
2494                    for (int i = 0; i < conf.getGalleryTypes().length; i++) {
2495                        CmsGalleryTypeInfo typeInfo = galleryTypeInfos.get(conf.getGalleryTypes()[i]);
2496                        if (typeInfo != null) {
2497                            infos.put(conf.getGalleryTypes()[i], typeInfo);
2498                        }
2499                    }
2500                    galleryTypeInfos = infos;
2501                }
2502
2503                String uri = cms.getRequestContext().getUri();
2504                String galleryContext = referencePath;
2505                if (conf.getPageId() != null) {
2506                    // This covers the case where the user is in the page editor,
2507                    // then edits an element of the page with the content editor, and then
2508                    // opens the gallery from a WYSIWYG field in the content editor.
2509                    try {
2510                        CmsResource page = cms.readResource(
2511                            new CmsUUID(conf.getPageId()),
2512                            CmsResourceFilter.IGNORE_EXPIRATION);
2513                        galleryContext = cms.getSitePath(page);
2514                    } catch (Exception e) {
2515                        LOG.error(e.getLocalizedMessage(), e);
2516                    }
2517                } else if (!uri.endsWith(".gwt") && !uri.endsWith(".jsp")) {
2518                    galleryContext = uri;
2519                }
2520                if (galleryContext == null) {
2521                    galleryContext = "/";
2522                }
2523                data.setGalleries(buildGalleriesList(galleryContext, galleryTypeInfos));
2524                String startGallery = conf.getGalleryPath();
2525                // check if the configured gallery path really is an existing gallery
2526                boolean galleryAvailable = false;
2527                for (CmsGalleryFolderBean folderBean : data.getGalleries()) {
2528                    if (folderBean.getPath().equals(startGallery)) {
2529                        galleryAvailable = true;
2530                        break;
2531                    }
2532                }
2533                data.setStartGallery(galleryAvailable ? startGallery : null);
2534                if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(conf.getStartFolder())) {
2535                    try {
2536                        CmsObject cloneCms = OpenCms.initCmsObject(getCmsObject());
2537                        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(conf.getStartSite())) {
2538                            cloneCms.getRequestContext().setSiteRoot(conf.getStartSite());
2539                        }
2540                        if (cloneCms.existsResource(conf.getStartFolder(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
2541                            data.setStartFolder(cloneCms.getRequestContext().addSiteRoot(conf.getStartFolder()));
2542                        }
2543                    } catch (CmsException e) {
2544                        log(e.getMessage(), e);
2545                    }
2546                }
2547
2548                if (CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartGallery()) && !data.getGalleries().isEmpty()) {
2549
2550                    String key = "";
2551                    if (!types.isEmpty() && !CmsStringUtil.isEmptyOrWhitespaceOnly(conf.getReferencePath())) {
2552                        key = types.get(0).getType();
2553                        try {
2554                            CmsResource refResource = getCmsObject().readResource(conf.getReferencePath());
2555                            String referenceType = OpenCms.getResourceManager().getResourceType(
2556                                refResource).getTypeName();
2557                            key = CmsGallerySearchBean.getGalleryStorageKey(
2558                                data.getGalleryStoragePrefix(),
2559                                referenceType);
2560                        } catch (Exception e) {
2561                            LOG.error("Could not read reference resource: " + conf.getReferencePath());
2562                        }
2563                    }
2564
2565                    if (!data.getGalleries().isEmpty()) {
2566                        startGallery = getWorkplaceSettings().getLastUsedGallery(key);
2567                        if (CmsStringUtil.isEmptyOrWhitespaceOnly(startGallery)) {
2568                            // check the user preferences for any configured start gallery
2569                            String galleryTypeName = data.getGalleries().get(0).getType();
2570                            startGallery = getWorkplaceSettings().getUserSettings().getStartGallery(
2571                                galleryTypeName,
2572                                getCmsObject());
2573                            if (CmsWorkplace.INPUT_DEFAULT.equals(startGallery)) {
2574                                startGallery = OpenCms.getWorkplaceManager().getDefaultUserSettings().getStartGallery(
2575                                    galleryTypeName);
2576                            }
2577                            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(startGallery)) {
2578                                startGallery = getCmsObject().getRequestContext().removeSiteRoot(startGallery);
2579                            }
2580                        }
2581                    }
2582                    // check if the gallery is available in this site and still exists
2583                    if (!conf.isResultsSelectable()) {
2584                        // if selecting results is explicitly disabled, opening the start gallery does not make much sense
2585                        data.setStartGallery(null);
2586                    } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(startGallery)) {
2587                        boolean galleryExists = getCmsObject().existsResource(startGallery);
2588                        if (galleryExists) {
2589                            data.setStartGallery(startGallery);
2590                        } else {
2591                            LOG.error("Could not read start gallery: " + startGallery);
2592                            data.setStartGallery(null);
2593                        }
2594                    } else {
2595                        data.setStartGallery(null);
2596                    }
2597                }
2598
2599                GalleryTabId defaultTab = conf.getTabConfiguration().getDefaultTab();
2600                data.setTabConfiguration(conf.getTabConfiguration());
2601                if (CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartGallery())
2602                    && CmsStringUtil.isEmptyOrWhitespaceOnly(data.getCurrentElement())
2603                    && CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartFolder())) {
2604                    data.setStartTab(defaultTab);
2605                } else {
2606                    data.setStartTab(GalleryTabId.cms_tab_results);
2607                }
2608                break;
2609            case ade:
2610                data.setReferenceSitePath(getCmsObject().getRequestContext().getUri());
2611                types = getResourceTypeBeans(
2612                    conf.getGalleryMode(),
2613                    data.getReferenceSitePath(),
2614                    conf.getResourceTypes(),
2615                    conf.getSearchTypes());
2616                data.setTypes(types);
2617                Map<String, CmsGalleryTypeInfo> adeGalleryTypeInfos = readGalleryInfosByTypeBeans(types);
2618                data.setGalleries(buildGalleriesList(data.getReferenceSitePath(), adeGalleryTypeInfos));
2619                data.setStartTab(GalleryTabId.cms_tab_types);
2620                break;
2621            default:
2622                break;
2623        }
2624
2625        if (CmsStringUtil.isEmptyOrWhitespaceOnly(data.getStartGallery())) {
2626            Set<String> folderFilter = readFolderFilters();
2627            data.setStartFolderFilter(folderFilter);
2628            if ((folderFilter != null) && !folderFilter.isEmpty()) {
2629                try {
2630                    data.setVfsPreloadData(
2631                        generateVfsPreloadData(
2632                            getCmsObject(),
2633                            CmsGalleryService.getVfsTreeState(getRequest(), conf.getTreeToken()),
2634                            folderFilter));
2635                } catch (Exception e) {
2636                    LOG.error(e.getLocalizedMessage(), e);
2637                }
2638            }
2639        }
2640
2641        CmsSiteSelectorOptionBuilder optionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
2642        optionBuilder.addNormalSites(true, getWorkplaceSettings().getUserSettings().getStartFolder());
2643        optionBuilder.addSharedSite();
2644        data.setVfsSiteSelectorOptions(optionBuilder.getOptions());
2645
2646        CmsSiteSelectorOptionBuilder sitemapOptionBuilder = new CmsSiteSelectorOptionBuilder(getCmsObject());
2647        sitemapOptionBuilder.addNormalSites(false, null);
2648        if (data.getReferenceSitePath() != null) {
2649            sitemapOptionBuilder.addCurrentSubsite(getCmsObject().addSiteRoot(data.getReferenceSitePath()));
2650        }
2651        data.setSitemapSiteSelectorOptions(sitemapOptionBuilder.getOptions());
2652        data.setDefaultScope(OpenCms.getWorkplaceManager().getGalleryDefaultScope());
2653        return data;
2654    }
2655
2656    /**
2657     * Reads the preview provider configuration and generates needed type-provider mappings.<p>
2658     *
2659     * @param types the resource types
2660     *
2661     * @return a map from resource types to preview providers
2662     */
2663    private Map<I_CmsResourceType, I_CmsPreviewProvider> getPreviewProviderForTypes(List<I_CmsResourceType> types) {
2664
2665        Map<String, I_CmsPreviewProvider> previewProviderMap = new HashMap<String, I_CmsPreviewProvider>();
2666        Map<I_CmsResourceType, I_CmsPreviewProvider> typeProviderMapping = new HashMap<I_CmsResourceType, I_CmsPreviewProvider>();
2667        for (I_CmsResourceType type : types) {
2668            String providerClass = type.getGalleryPreviewProvider();
2669            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(providerClass)) {
2670                providerClass = providerClass.trim();
2671                try {
2672                    if (previewProviderMap.containsKey(providerClass)) {
2673                        typeProviderMapping.put(type, previewProviderMap.get(providerClass));
2674                    } else {
2675                        I_CmsPreviewProvider previewProvider = (I_CmsPreviewProvider)Class.forName(
2676                            providerClass).newInstance();
2677                        previewProviderMap.put(providerClass, previewProvider);
2678                        typeProviderMapping.put(type, previewProvider);
2679                    }
2680                } catch (Exception e) {
2681                    logError(
2682                        new CmsException(
2683                            Messages.get().container(
2684                                Messages.ERR_INSTANCING_PREVIEW_PROVIDER_2,
2685                                providerClass,
2686                                type.getTypeName()),
2687                            e));
2688                }
2689            }
2690        }
2691        return typeProviderMapping;
2692    }
2693
2694    /**
2695     * Returns the resourceManager.<p>
2696     *
2697     * @return the resourceManager
2698     */
2699    private CmsResourceManager getResourceManager() {
2700
2701        if (m_resourceManager == null) {
2702            m_resourceManager = OpenCms.getResourceManager();
2703        }
2704        return m_resourceManager;
2705    }
2706
2707    /**
2708     * Returns the resource types configured to be used within the given gallery mode.<p>
2709     *
2710     * @param galleryMode the gallery mode
2711     * @param referenceSitePath the reference site-path to check permissions for
2712     * @param resourceTypesList the resource types parameter
2713     * @param typesForTypeTab the types which should be shown in the types tab according to the gallery configuration
2714     *
2715     * @return the resource types
2716     */
2717    private List<CmsResourceTypeBean> getResourceTypeBeans(
2718        GalleryMode galleryMode,
2719        String referenceSitePath,
2720        List<String> resourceTypesList,
2721        final List<String> typesForTypeTab) {
2722
2723        List<I_CmsResourceType> resourceTypes = null;
2724        Set<String> creatableTypes = null;
2725        switch (galleryMode) {
2726            case editor:
2727            case view:
2728            case adeView:
2729            case widget:
2730                resourceTypes = convertTypeNamesToTypes(resourceTypesList);
2731                if (resourceTypes.size() == 0) {
2732                    resourceTypes = Lists.newArrayList(getDefaultTypesForGallery());
2733                }
2734                creatableTypes = Collections.<String> emptySet();
2735                break;
2736            case ade:
2737                throw new IllegalStateException("This code should never be called");
2738            // ADE case is handled by container page service
2739            default:
2740                resourceTypes = Collections.<I_CmsResourceType> emptyList();
2741                creatableTypes = Collections.<String> emptySet();
2742        }
2743        return buildTypesList(resourceTypes, creatableTypes, Collections.<String> emptySet(), typesForTypeTab);
2744    }
2745
2746    /**
2747     * Returns the VFS root entries.<p>
2748     *
2749     * @return the VFS root entries
2750     *
2751     * @throws CmsRpcException if something goes wrong
2752     */
2753    private List<CmsVfsEntryBean> getRootEntries() throws CmsRpcException {
2754
2755        List<CmsVfsEntryBean> rootFolders = new ArrayList<CmsVfsEntryBean>();
2756        CmsObject cms = getCmsObject();
2757        try {
2758            String path = "/";
2759            if (!cms.existsResource(path, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
2760                String startFolder = getWorkplaceSettings().getUserSettings().getStartFolder();
2761                if (cms.existsResource(startFolder, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
2762                    path = startFolder;
2763                } else {
2764                    path = null;
2765                }
2766            }
2767            if (path != null) {
2768                CmsResource rootFolderResource = getCmsObject().readResource(
2769                    path,
2770                    CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2771                String title = cms.readPropertyObject(path, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue();
2772                rootFolders.add(
2773                    internalCreateVfsEntryBean(
2774                        getCmsObject(),
2775                        rootFolderResource,
2776                        title,
2777                        true,
2778                        isEditable(getCmsObject(), rootFolderResource),
2779                        null,
2780                        false));
2781            }
2782
2783        } catch (CmsException e) {
2784            error(e);
2785        }
2786        return rootFolders;
2787    }
2788
2789    /**
2790     * Returns the workplace settings of the current user.<p>
2791     *
2792     * @return the workplace settings
2793     */
2794    private CmsWorkplaceSettings getWorkplaceSettings() {
2795
2796        if (m_workplaceSettings == null) {
2797            m_workplaceSettings = CmsWorkplace.getWorkplaceSettings(getCmsObject(), getRequest());
2798        }
2799        return m_workplaceSettings;
2800    }
2801
2802    /**
2803     * Checks whether a resource has a navigation property.<p>
2804     *
2805     * @param cms the current CMS context
2806     * @param resource the resource to use
2807     *
2808     * @return true if the resource has a navigation property
2809     *
2810     * @throws CmsException if something goes wrong
2811     */
2812    private boolean hasNavigationProperty(CmsObject cms, CmsResource resource) throws CmsException {
2813
2814        List<CmsProperty> props = cms.readPropertyObjects(resource, false);
2815        Map<String, String> propMap = CmsProperty.toMap(props);
2816        return propMap.containsKey(CmsPropertyDefinition.PROPERTY_NAVPOS)
2817            || propMap.containsKey(CmsPropertyDefinition.PROPERTY_NAVTEXT);
2818    }
2819
2820    /**
2821     * Returns the search parameters for the given query data.<p>
2822     *
2823     * @param searchData the query data
2824     * @param replacementConfig the replacement configuration
2825     *
2826     * @return the prepared search parameters
2827     */
2828    private CmsGallerySearchParameters prepareSearchParams(
2829        CmsGallerySearchBean searchData,
2830        CmsAddContentRestriction replacementConfig) {
2831
2832        // create a new search parameter object
2833        CmsGallerySearchParameters params = new CmsGallerySearchParameters();
2834        CmsObject cms = getCmsObject();
2835
2836        // set the selected types to the parameters
2837        if (searchData.getServerSearchTypes() != null) {
2838            params.setResourceTypes(searchData.getServerSearchTypes());
2839        }
2840
2841        // set the selected galleries to the parameters
2842        if (searchData.getGalleries() != null) {
2843            List<String> paramGalleries = new ArrayList<String>();
2844            for (String gallerySitePath : searchData.getGalleries()) {
2845                paramGalleries.add(cms.getRequestContext().addSiteRoot(gallerySitePath));
2846            }
2847            params.setGalleries(paramGalleries);
2848        }
2849
2850        // set the sort order for the galleries to the parameters
2851        CmsGallerySearchParameters.CmsGallerySortParam sortOrder;
2852        String temp = searchData.getSortOrder();
2853        try {
2854            sortOrder = CmsGallerySearchParameters.CmsGallerySortParam.valueOf(temp);
2855        } catch (Exception e) {
2856            sortOrder = CmsGallerySearchParameters.CmsGallerySortParam.DEFAULT;
2857        }
2858        params.setSortOrder(sortOrder);
2859        if (searchData.getScope() == null) {
2860            params.setScope(OpenCms.getWorkplaceManager().getGalleryDefaultScope());
2861        } else {
2862            params.setScope(searchData.getScope());
2863        }
2864        params.setReferencePath(searchData.getReferencePath());
2865
2866        // set the selected folders to the parameters
2867        params.setFolders(new ArrayList<String>(searchData.getFolders()));
2868
2869        // set the categories to the parameters
2870        if (searchData.getCategories() != null) {
2871            params.setCategories(searchData.getCategories());
2872        }
2873
2874        // set the search query to the parameters
2875        if (!CmsStringUtil.isEmptyOrWhitespaceOnly(searchData.getQuery())) {
2876            params.setSearchWords(searchData.getQuery());
2877        }
2878
2879        // set the result page to the parameters
2880        int page = searchData.getPage();
2881        params.setResultPage(page);
2882
2883        // set the locale to the parameters
2884        String locale = searchData.getLocale();
2885        if (CmsStringUtil.isEmptyOrWhitespaceOnly(locale)) {
2886            locale = getCmsObject().getRequestContext().getLocale().toString();
2887        }
2888        params.setSearchLocale(locale);
2889
2890        // set the matches per page to the parameters
2891        params.setMatchesPerPage(searchData.getMatchesPerPage());
2892
2893        // get the date range input
2894        long dateCreatedStart = searchData.getDateCreatedStart();
2895        long dateCreatedEnd = searchData.getDateCreatedEnd();
2896        long dateModifiedStart = searchData.getDateModifiedStart();
2897        long dateModifiedEnd = searchData.getDateModifiedEnd();
2898
2899        // set the date created range to the parameters
2900        if ((dateCreatedStart != -1L) && (dateCreatedEnd != -1L)) {
2901            params.setDateCreatedTimeRange(dateCreatedStart, dateCreatedEnd);
2902        } else if (dateCreatedStart != -1L) {
2903            params.setDateCreatedTimeRange(dateCreatedStart, Long.MAX_VALUE);
2904        } else if (dateCreatedEnd != -1L) {
2905            params.setDateCreatedTimeRange(Long.MIN_VALUE, dateCreatedEnd);
2906        }
2907
2908        // set the date modified range to the parameters
2909        if ((dateModifiedStart != -1L) && (dateModifiedEnd != -1L)) {
2910            params.setDateLastModifiedTimeRange(dateModifiedStart, dateModifiedEnd);
2911        } else if (dateModifiedStart != -1L) {
2912            params.setDateLastModifiedTimeRange(dateModifiedStart, Long.MAX_VALUE);
2913        } else if (dateModifiedEnd != -1L) {
2914            params.setDateLastModifiedTimeRange(Long.MIN_VALUE, dateModifiedEnd);
2915        }
2916        params.setIgnoreSearchExclude(searchData.isIgnoreSearchExclude());
2917        if (GalleryMode.ade.equals(searchData.getGalleryMode())) {
2918            if (searchData.getTypes().isEmpty() || !Collections.disjoint(FUNCTION_TYPES, searchData.getTypes())) {
2919                CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
2920                    cms,
2921                    cms.getRequestContext().addSiteRoot(searchData.getReferencePath()));
2922                CmsFormatterConfigurationCacheState formatterState = OpenCms.getADEManager().getCachedFormatters(
2923                    cms.getRequestContext().getCurrentProject().isOnlineProject());
2924                params.setFunctionAvailability(config.getDynamicFunctionAvailability(formatterState));
2925                if (config.isHideNonMatchingFunctions()) {
2926                    if (searchData.getContainerInfo() != null) {
2927                        Set<CmsUUID> excludedFunctions = getExcludedFunctionsForContainerInfo(
2928                            cms,
2929                            config,
2930                            searchData.getContainerInfo());
2931                        params.setExcludedFunctions(excludedFunctions);
2932                    }
2933                }
2934            }
2935            CmsTemplateContextInfo templateContextInfo = searchData.getTemplateContextInfo();
2936            if ((templateContextInfo != null)
2937                && (templateContextInfo.getContextProvider() != null)
2938                && (templateContextInfo.getCurrentContext() != null)) {
2939                I_CmsTemplateContextProvider provider = OpenCms.getTemplateContextManager().getTemplateContextProvider(
2940                    templateContextInfo.getContextProvider());
2941                if (provider != null) {
2942                    Set<CmsUUID> allowedFunctions = provider.getFunctionsForGallery(
2943                        cms,
2944                        templateContextInfo.getCurrentContext());
2945                    // allowed functions may be null - this is fine
2946                    params.setIncludedFunctions(allowedFunctions);
2947                    String compatibility = provider.getTemplateCompatibility(templateContextInfo.getCurrentContext());
2948                    params.setTemplateCompatibility(compatibility);
2949                }
2950            }
2951            if (replacementConfig != null) {
2952                // if the search replacement configuration didn't already handle the replacement,
2953                // exclude the type from search results (this happens when searching for multiple types).
2954                Set<String> excludedTypes = replacementConfig.getTypes();
2955                if ((excludedTypes.size() > 0) && (params.getResourceTypes() != null)) {
2956                    List<String> types = new ArrayList<>(params.getResourceTypes());
2957                    boolean removed = types.removeAll(excludedTypes);
2958                    if (removed && (types.size() == 0)) {
2959                        params.setForceEmptyResult(true);
2960                    }
2961                    params.setResourceTypes(types);
2962                }
2963            }
2964        }
2965
2966        // set include expired/unreleased
2967        if (searchData.isIncludeExpired()) {
2968            params.setIncludeExpired(true);
2969        }
2970        return params;
2971    }
2972
2973    /**
2974     * Prepares a sitemap entry bean from the given navigation element.<p>
2975     *
2976     * @param cms the cms context
2977     * @param navElement the navigation element
2978     * @param isRoot <code>true</code> if this is a site root entry
2979     * @param checkHasChildren if true, check if the entry has any children; set to false if you want to handle the list of children manually
2980     *
2981     * @return the sitemap entry
2982     *
2983     * @throws CmsException if something goes wrong reading types and resources
2984     */
2985    private CmsSitemapEntryBean prepareSitemapEntry(
2986        CmsObject cms,
2987        CmsJspNavElement navElement,
2988        boolean isRoot,
2989        boolean checkHasChildren)
2990    throws CmsException {
2991
2992        CmsResource ownResource = navElement.getResource();
2993        CmsResource defaultFileResource = null;
2994        CmsJspNavBuilder navBuilder = new CmsJspNavBuilder(cms);
2995        if (ownResource.isFolder() && !navElement.isNavigationLevel()) {
2996            try {
2997                defaultFileResource = cms.readDefaultFile(ownResource, CmsResourceFilter.ONLY_VISIBLE);
2998            } catch (CmsPermissionViolationException e) {
2999                // user has insufficient rights, can be ignored
3000            }
3001        }
3002        String type;
3003        if (defaultFileResource != null) {
3004            type = OpenCms.getResourceManager().getResourceType(defaultFileResource.getTypeId()).getTypeName();
3005        } else {
3006            type = OpenCms.getResourceManager().getResourceType(ownResource.getTypeId()).getTypeName();
3007        }
3008        // make sure not to show ??? NavText ???
3009        String title = null;
3010        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(navElement.getProperty(CmsPropertyDefinition.PROPERTY_NAVTEXT))) {
3011            title = navElement.getProperty(CmsPropertyDefinition.PROPERTY_NAVTEXT);
3012        } else if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(
3013            navElement.getProperty(CmsPropertyDefinition.PROPERTY_TITLE))) {
3014            title = navElement.getProperty(CmsPropertyDefinition.PROPERTY_TITLE);
3015        } else {
3016            title = navElement.getFileName();
3017            if (title.contains("/")) {
3018                title = title.substring(0, title.indexOf("/"));
3019            }
3020        }
3021        String childPath = navElement.getResource().getRootPath();
3022        boolean noChildren = true;
3023
3024        if (checkHasChildren) {
3025            List<CmsJspNavElement> childNav = navBuilder.getNavigationForFolder(
3026                childPath,
3027                Visibility.all,
3028                CmsResourceFilter.ONLY_VISIBLE);
3029            for (CmsJspNavElement childNavEntry : childNav) {
3030                if (childNavEntry.isInNavigation()) {
3031                    noChildren = false;
3032                    break;
3033                }
3034            }
3035        }
3036
3037        CmsSitemapEntryBean result = new CmsSitemapEntryBean(
3038            navElement.getResource().getRootPath(),
3039            navElement.getResourceName(),
3040            ownResource.getStructureId(),
3041            title,
3042            type,
3043            ownResource.isFolder(),
3044            isRoot,
3045            navElement.isHiddenNavigationEntry());
3046        result.setSiteRoot(OpenCms.getSiteManager().getSiteRoot(ownResource.getRootPath()));
3047        String displayType = CmsIconUtil.getDisplayType(
3048            cms,
3049            defaultFileResource != null ? defaultFileResource : ownResource);
3050        result.setBigIconClasses(
3051            CmsIconUtil.getIconClasses(
3052                displayType,
3053                defaultFileResource != null ? defaultFileResource.getName() : ownResource.getName(),
3054                false));
3055        result.setSmallIconClasses(
3056            CmsIconUtil.getIconClasses(
3057                displayType,
3058                defaultFileResource != null ? defaultFileResource.getName() : ownResource.getName(),
3059                true));
3060        if (checkHasChildren && noChildren) {
3061            result.setChildren(new ArrayList<CmsSitemapEntryBean>());
3062        }
3063
3064        return result;
3065    }
3066
3067    /**
3068     * Reads the folder filters for the current site.<p>
3069     *
3070     * @return the folder filters
3071     */
3072    private Set<String> readFolderFilters() {
3073
3074        JSONObject storedFilters = readUserFolderFilters();
3075        Set<String> result = null;
3076        if (storedFilters.has(getCmsObject().getRequestContext().getSiteRoot())) {
3077            try {
3078                org.opencms.json.JSONArray folders = storedFilters.getJSONArray(
3079                    getCmsObject().getRequestContext().getSiteRoot());
3080                result = new HashSet<String>();
3081                for (int i = 0; i < folders.length(); i++) {
3082                    result.add(folders.getString(i));
3083                }
3084            } catch (JSONException e) {
3085                LOG.error(e.getLocalizedMessage(), e);
3086            }
3087        }
3088        return result;
3089    }
3090
3091    /**
3092     * Returns a map with gallery type names associated with the list of available galleries for this type.<p>
3093     *
3094     * @param resourceTypes the resources types to collect the galleries for
3095     *
3096     * @return a map with gallery type and  the associated galleries
3097     */
3098    private Map<String, CmsGalleryTypeInfo> readGalleryInfosByTypeBeans(List<CmsResourceTypeBean> resourceTypes) {
3099
3100        Map<String, CmsGalleryTypeInfo> galleryTypeInfos = new HashMap<String, CmsGalleryTypeInfo>();
3101        for (CmsResourceTypeBean typeBean : resourceTypes) {
3102            try {
3103                if (!typeBean.isDeactivated()) {
3104                    addGalleriesForType(galleryTypeInfos, typeBean.getType());
3105                }
3106            } catch (CmsLoaderException e1) {
3107                logError(e1);
3108            }
3109        }
3110        return galleryTypeInfos;
3111    }
3112
3113    /**
3114     * Returns a map with gallery type names associated with the list of available galleries for this type.<p>
3115     *
3116     * @param resourceTypes the resources types to collect the galleries for
3117     *
3118     * @return a map with gallery type and  the associated galleries
3119     */
3120    private Map<String, CmsGalleryTypeInfo> readGalleryInfosByTypeNames(List<String> resourceTypes) {
3121
3122        Map<String, CmsGalleryTypeInfo> galleryTypeInfos = new HashMap<String, CmsGalleryTypeInfo>();
3123        for (String typeName : resourceTypes) {
3124            try {
3125                addGalleriesForType(galleryTypeInfos, typeName);
3126            } catch (CmsLoaderException e1) {
3127                logError(e1);
3128            }
3129        }
3130        return galleryTypeInfos;
3131    }
3132
3133    /**
3134     * Reads the result view type from the current user.<p>
3135     *
3136     * @return the result view type
3137     */
3138    private String readResultViewType() {
3139
3140        return (String)getCmsObject().getRequestContext().getCurrentUser().getAdditionalInfo(
3141            RESULT_VIEW_TYPE_ADD_INFO_KEY);
3142    }
3143
3144    /**
3145     * Reads the users folder filters from the additional info.<p>
3146     *
3147     * @return the folder filters
3148     */
3149    private JSONObject readUserFolderFilters() {
3150
3151        CmsUser user = getCmsObject().getRequestContext().getCurrentUser();
3152        String addInfo = (String)user.getAdditionalInfo(FOLDER_FILTER_ADD_INFO_KEY);
3153        JSONObject result = null;
3154        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(addInfo)) {
3155            try {
3156                result = new JSONObject(addInfo);
3157            } catch (JSONException e) {
3158                LOG.error(e.getLocalizedMessage(), e);
3159            }
3160        }
3161        if (result == null) {
3162            result = new JSONObject();
3163        }
3164        return result;
3165    }
3166
3167    /**
3168     * Returns the gallery search object containing the results for the current parameter.<p>
3169     *
3170     * @param searchObj the current search object
3171     *
3172     * @return the search result
3173     *
3174     * @throws CmsException if the search fails
3175     */
3176    private CmsGallerySearchBean search(CmsGallerySearchBean searchObj) throws CmsException {
3177
3178        CmsGallerySearchBean searchObjBean = new CmsGallerySearchBean(searchObj);
3179        if (searchObj == null) {
3180            return searchObjBean;
3181        }
3182        // store folder filter
3183        storeFolderFilter(searchObj.getFolders());
3184        CmsObject cms = getCmsObject();
3185        CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache(
3186            cms,
3187            cms.getRequestContext().addSiteRoot(cms.getRequestContext().getUri()));
3188        CmsAddContentRestriction replacementConfig = config.getAddContentRestriction();
3189        CmsGallerySearchResultList searchResults = null;
3190        List<String> types = searchObj.getTypes();
3191        Predicate<CmsResource> deactivatedCheck = res -> false;
3192        if (searchObj.getGalleryMode().equals(GalleryMode.ade)
3193            && types.contains(CmsResourceTypeFunctionConfig.TYPE_NAME)
3194            && !config.isHideNonMatchingFunctions()
3195            && (searchObj.getContainerInfo() != null)) {
3196            final Set<CmsUUID> excludedFunctions = getExcludedFunctionsForContainerInfo(
3197                cms,
3198                config,
3199                searchObj.getContainerInfo());
3200            deactivatedCheck = res -> excludedFunctions.contains(res.getStructureId());
3201        }
3202
3203        searchObjBean.setReplacedResults(false);
3204        if (searchObj.getGalleryMode().equals(GalleryMode.ade)
3205            && (types.size() == 1)
3206            && replacementConfig.getTypes().contains(types.iterator().next())) {
3207
3208            List<CmsGallerySearchResult> items = replacementConfig.getResult(cms, types.iterator().next());
3209            searchResults = new CmsGallerySearchResultList();
3210            searchResults.addAll(items);
3211            searchObjBean.setReplacedResults(true);
3212            searchObjBean.setPage(1);
3213            searchObjBean.setFolders(new HashSet<>());
3214            searchObjBean.setGalleries(new ArrayList<>());
3215            searchObjBean.setCategories(new ArrayList<>());
3216            // searchObjBean.setMatchesPerPage(searchResults.size());
3217            searchObjBean.setNoUploadReason(
3218                Messages.get().getBundle(m_wpLocale).key(Messages.GUI_NO_UPLOAD_FOR_REPLACED_SEARCH_RESULTS_0));
3219            searchObjBean.setResults(buildSearchResultList(searchResults, null, deactivatedCheck));
3220            searchObjBean.setResultCount(searchResults.size());
3221            if (searchObjBean.getResultCount() > 0) {
3222                CmsADESessionCache cache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3223                cache.setLastPageEditorGallerySearch(searchObj);
3224            }
3225
3226        } else {
3227            // search
3228            CmsGallerySearchParameters params = prepareSearchParams(searchObj, replacementConfig);
3229            CmsObject searchCms = getSearchCms(searchObj);
3230            searchResults = OpenCms.getSearchManager().getIndexSolr("Solr Offline").gallerySearch(searchCms, params);
3231            searchResults.calculatePages(params.getResultPage(), params.getMatchesPerPage());
3232
3233            // set only the result dependent search params for this search
3234            // the user dependent params(galleries, types etc.) remain unchanged
3235            searchObjBean.setSortOrder(params.getSortOrder().name());
3236            searchObjBean.setScope(params.getScope());
3237            searchObjBean.setResultCount(searchResults.getHitCount());
3238            searchObjBean.setPage(params.getResultPage());
3239            searchObjBean.setLastPage(params.getResultPage());
3240            searchObjBean.setResults(buildSearchResultList(searchResults, null, deactivatedCheck));
3241            if (searchObj.getGalleryMode().equals(GalleryMode.ade)) {
3242                if (searchObjBean.getResultCount() > 0) {
3243                    CmsADESessionCache cache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3244                    cache.setLastPageEditorGallerySearch(searchObj);
3245                }
3246            }
3247            updateNoUploadReason(searchCms, searchObjBean);
3248        }
3249        return searchObjBean;
3250    }
3251
3252    /**
3253     * Sets the last opened gallery information for the current user.<p>
3254     *
3255     * @param searchObject the current search
3256     */
3257    private void setLastOpenedGallery(CmsGallerySearchBean searchObject) {
3258
3259        if ((searchObject.getGalleries() != null)
3260            && (searchObject.getGalleries().size() <= 1) // if the size is 0, the user has actively deselected the galleries, so we want to handle this case too
3261            && searchObject.haveGalleriesChanged()) {
3262            String galleryPath = searchObject.getGalleries().isEmpty() ? null : searchObject.getGalleries().get(0);
3263            CmsWorkplaceSettings settings = getWorkplaceSettings();
3264            if (searchObject.getGalleryMode() == GalleryMode.adeView) {
3265                settings.setLastUsedGallery("" + GalleryMode.adeView, galleryPath);
3266            } else {
3267                String referencePath = searchObject.getReferencePath();
3268
3269                String referenceTypeName = "";
3270
3271                try {
3272                    CmsObject cms = getCmsObject();
3273                    CmsResource referenceResource = cms.readResource(referencePath);
3274                    I_CmsResourceType referenceType = OpenCms.getResourceManager().getResourceType(referenceResource);
3275                    referenceTypeName = referenceType.getTypeName();
3276                } catch (CmsException e) {
3277                    LOG.error(e.getLocalizedMessage(), e);
3278                }
3279                settings.setLastUsedGallery(
3280                    CmsGallerySearchBean.getGalleryStorageKey(
3281                        searchObject.getGalleryStoragePrefix(),
3282                        referenceTypeName),
3283                    galleryPath);
3284            }
3285        }
3286    }
3287
3288    /**
3289     * Stores the folder filters for the current site.<p>
3290     *
3291     * @param folders the folder filters
3292     */
3293    private void storeFolderFilter(Set<String> folders) {
3294
3295        JSONObject storedFilters = readUserFolderFilters();
3296        try {
3297            storedFilters.put(getCmsObject().getRequestContext().getSiteRoot(), folders);
3298            CmsUser user = getCmsObject().getRequestContext().getCurrentUser();
3299            user.setAdditionalInfo(FOLDER_FILTER_ADD_INFO_KEY, storedFilters.toString());
3300            getCmsObject().writeUser(user);
3301        } catch (Exception e) {
3302            LOG.error(e.getLocalizedMessage(), e);
3303        }
3304    }
3305
3306    /**
3307     * Checks the current users permissions on the upload target folder to update the no upload reason.<p>
3308     *
3309     * @param searchCms the cms context
3310     * @param searchObj the search data
3311     */
3312    private void updateNoUploadReason(CmsObject searchCms, CmsGallerySearchBean searchObj) {
3313
3314        if ((searchObj.getGalleries().size() + searchObj.getFolders().size()) == 1) {
3315            String target = !searchObj.getGalleries().isEmpty()
3316            ? searchObj.getGalleries().get(0)
3317            : searchObj.getFolders().iterator().next();
3318            try {
3319                CmsResource targetRes;
3320                if (searchCms.existsResource(target, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
3321                    targetRes = searchCms.readResource(target, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3322                } else {
3323                    CmsObject rootCms = OpenCms.initCmsObject(searchCms);
3324                    rootCms.getRequestContext().setSiteRoot("");
3325                    targetRes = rootCms.readResource(target, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3326                }
3327                searchObj.setNoUploadReason(
3328                    new CmsResourceUtil(searchCms, targetRes).getNoEditReason(getWorkplaceLocale(), true));
3329            } catch (CmsException e) {
3330                searchObj.setNoUploadReason(e.getLocalizedMessage(getWorkplaceLocale()));
3331            }
3332        } else {
3333            searchObj.setNoUploadReason(null);
3334        }
3335    }
3336}