001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (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.configuration;
029
030import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProperty;
033import org.opencms.file.CmsRequestContext;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.CmsVfsResourceNotFoundException;
037import org.opencms.file.types.CmsResourceTypeFunctionConfig;
038import org.opencms.file.types.I_CmsResourceType;
039import org.opencms.lock.CmsLock;
040import org.opencms.lock.CmsLockException;
041import org.opencms.main.CmsException;
042import org.opencms.main.CmsLog;
043import org.opencms.main.OpenCms;
044import org.opencms.relations.CmsCategoryService;
045import org.opencms.security.CmsPermissionSet;
046import org.opencms.security.CmsRole;
047import org.opencms.ui.util.CmsNewResourceBuilder;
048import org.opencms.util.CmsStringUtil;
049import org.opencms.util.CmsUUID;
050import org.opencms.util.CmsVfsUtil;
051import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
052import org.opencms.xml.containerpage.CmsXmlDynamicFunctionHandler;
053
054import java.util.ArrayList;
055import java.util.HashSet;
056import java.util.Locale;
057import java.util.Set;
058
059import org.apache.commons.logging.Log;
060
061/**
062 * The configuration for a single resource type.<p>
063 */
064public class CmsResourceTypeConfig implements I_CmsConfigurationObject<CmsResourceTypeConfig>, Cloneable {
065
066    /**
067     * Enum used to distinguish the type of menu in which a configured resource type can be displayed.
068     */
069    public enum AddMenuType {
070        /** ADE add menu. */
071        ade,
072
073        /** Workplace dialogs. */
074        workplace
075    }
076
077    /**
078     * Represents the visibility status of a resource type  in  the 'Add' menu of the container page editor.<p>
079     */
080    public enum AddMenuVisibility {
081
082        /** Type should not be creatable. */
083        createDisabled,
084
085        /** Type not visible. */
086        disabled,
087
088        /** Type does not belong to current view, but has been configured to be still visible in it. */
089        fromOtherView,
090
091        /** Type is normally visible. */
092        visible
093    }
094
095    /** The log instance for this class. */
096    private static final Log LOG = CmsLog.getLog(CmsResourceTypeConfig.class);
097
098    /** The parameter for setting the default value for 'check reuse'. */
099    private static final Object PARAM_CHECK_REUSE_DEFAULT = "checkReuseDefault";
100
101    /** The CMS object used for VFS operations. */
102    protected CmsObject m_cms;
103
104    /** Flag which controls whether adding elements of this type using ADE is disabled. */
105    private boolean m_addDisabled;
106
107    /** True if availability has not been set in the configuration file.*/
108    private boolean m_availabilityNotSet;
109
110    /** 'Check reuse' value (may be null). */
111    private Boolean m_checkReuse;
112
113    /** Elements of this type when used in models should be copied instead of reused. */
114    private Boolean m_copyInModels;
115
116    /** Flag which controls whether creating elements of this type using ADE is disabled. */
117    private boolean m_createDisabled;
118
119    /** The flag for disabling detail pages. */
120    private boolean m_detailPagesDisabled;
121
122    /** True if this is a disabled configuration. */
123    private boolean m_disabled;
124
125    /** True if editing is disabled for container elements of this type. */
126    private boolean m_editDisabled;
127
128    /** The element delete mode. */
129    private ElementDeleteMode m_elementDeleteMode;
130
131    /** The element view id. */
132    private CmsUUID m_elementView;
133
134    /** True if this creating/editing for this type should be enabled in lists (e.g. search or contentload tags). */
135    private boolean m_enableInLists;
136
137    /** A reference to a folder of folder name. */
138    private CmsContentFolderDescriptor m_folderOrName;
139
140    /** The bundle to add as workplace bundle for the resource type. */
141    private String m_localization;
142
143    /** The name pattern .*/
144    private String m_namePattern;
145
146    /** The number used for sorting the resource type configurations. */
147    private Integer m_order;
148
149    /** Flag which controls whether this type should be shown in the 'add' menu in the default view. */
150    private Boolean m_showInDefaultView;
151
152    /** The set of template context keys associated with this type via the template=... parameter in master configuration links. */
153    private Set<String> m_templates = new HashSet<>();
154
155    /** The name of the resource type. */
156    private String m_typeName;
157
158    /**
159     * Creates a new resource type configuration.<p>
160     *
161     * @param typeName the resource type name
162     * @param disabled true if this is a disabled configuration
163     * @param folder the folder reference
164     * @param pattern the name pattern
165     */
166    public CmsResourceTypeConfig(String typeName, boolean disabled, CmsContentFolderDescriptor folder, String pattern) {
167
168        this(
169            typeName,
170            disabled,
171            folder,
172            pattern,
173            false,
174            false,
175            false,
176            false,
177            false,
178            false,
179            CmsElementView.DEFAULT_ELEMENT_VIEW.getId(),
180            null,
181            null,
182            null,
183            Integer.valueOf(I_CmsConfigurationObject.DEFAULT_ORDER),
184            null,
185            null);
186    }
187
188    /**
189     * Creates a new resource type configuration.<p>
190     *
191     * @param typeName the resource type name
192     * @param disabled true if this is a disabled configuration
193     * @param folder the folder reference
194     * @param pattern the name pattern
195     * @param detailPagesDisabled true if detail page creation should be disabled for this type
196     * @param addDisabled true if adding elements of this type via ADE should be disabled
197     * @param editDisabled true if editing container elements of the type should be disabled
198     * @param enableInLists true if the type should be enabled, but only for the direct edit buttons in lists and not ADE/drag/drop.
199     * @param createDisabled true if creating elements of this type via ADE should be disabled
200     * @param availabilityNotSet true if the availability has not been set
201     * @param elementView the element view id
202     * @param localization the base name of the bundle to add as workplace bundle for the resource type
203     * @param showInDefaultView if true, the element type should be shown in the default element view even if it doesn't belong to it
204     * @param copyInModels if elements of this type when used in models should be copied instead of reused
205     * @param order the display order
206     * @param elementDeleteMode the element delete mode
207     * @param checkReuse indicates whether element reuse should be checked for this type
208     */
209    public CmsResourceTypeConfig(
210        String typeName,
211        boolean disabled,
212        CmsContentFolderDescriptor folder,
213        String pattern,
214        boolean detailPagesDisabled,
215        boolean addDisabled,
216        boolean createDisabled,
217        boolean editDisabled,
218        boolean enableInLists,
219        boolean availabilityNotSet,
220        CmsUUID elementView,
221        String localization,
222        Boolean showInDefaultView,
223        Boolean copyInModels,
224        Integer order,
225        ElementDeleteMode elementDeleteMode,
226        Boolean checkReuse) {
227
228        m_typeName = typeName;
229        m_disabled = disabled;
230        m_folderOrName = folder;
231        m_namePattern = pattern;
232        m_detailPagesDisabled = detailPagesDisabled;
233        m_addDisabled = addDisabled;
234        m_createDisabled = createDisabled;
235        m_availabilityNotSet = availabilityNotSet;
236        m_elementView = elementView;
237        m_editDisabled = editDisabled;
238        m_enableInLists = enableInLists;
239        m_localization = localization;
240        m_showInDefaultView = showInDefaultView;
241        m_copyInModels = copyInModels;
242        m_order = order;
243        m_elementDeleteMode = elementDeleteMode;
244        m_checkReuse = checkReuse;
245    }
246
247    /**
248     * Checks if this resource type is creatable.<p>
249     *
250     * @param cms the current CMS context
251     * @param pageFolderRootPath the root path of the folder containing the current container page
252     *
253     * @return <code>true</code> if the resource type is creatable
254     *
255     * @throws CmsException if something goes wrong
256     */
257    public boolean checkCreatable(CmsObject cms, String pageFolderRootPath) throws CmsException {
258
259        if (cms.getRequestContext().getCurrentProject().isOnlineProject()) {
260            return false;
261        }
262        if (OpenCms.getRoleManager().hasRole(cms, CmsRole.ROOT_ADMIN)) {
263            return true;
264        }
265        if (CmsXmlDynamicFunctionHandler.TYPE_FUNCTION.equals(m_typeName)
266            || CmsResourceTypeFunctionConfig.TYPE_NAME.equals(m_typeName)) {
267            return OpenCms.getRoleManager().hasRole(cms, CmsRole.DEVELOPER);
268        }
269        checkInitialized();
270        if ((m_folderOrName != null) && m_folderOrName.isPageRelative() && (pageFolderRootPath == null)) {
271            LOG.info(
272                "type "
273                    + m_typeName
274                    + " not creatable for pageFolderRootPath=null because it is configured to be page-relative");
275            return false;
276        }
277        String folderPath = getFolderPath(cms, pageFolderRootPath);
278        String oldSiteRoot = cms.getRequestContext().getSiteRoot();
279        cms.getRequestContext().setSiteRoot("");
280        //tryToUnlock(cms, folderPath);
281        CmsResource permissionCheckFolder = null;
282        for (String currentPath = folderPath; currentPath != null; currentPath = CmsResource.getParentFolder(
283            currentPath)) {
284            try {
285                permissionCheckFolder = cms.readResource(currentPath);
286                break;
287            } catch (CmsVfsResourceNotFoundException e) {
288                // ignore
289            }
290        }
291        try {
292            if (permissionCheckFolder == null) {
293                return false;
294            }
295            LOG.info("Using " + permissionCheckFolder + " as a permission check folder for " + folderPath);
296            CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(m_typeName);
297            if (settings == null) {
298                return false;
299            }
300            boolean editable = settings.isEditable(cms, permissionCheckFolder);
301            boolean controlPermission = settings.getAccess().getPermissions(
302                cms,
303                permissionCheckFolder).requiresControlPermission();
304            boolean hasWritePermission = cms.hasPermissions(
305                permissionCheckFolder,
306                CmsPermissionSet.ACCESS_WRITE,
307                false,
308                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
309            return editable && controlPermission && hasWritePermission;
310        } catch (CmsVfsResourceNotFoundException e) {
311            return false;
312        } catch (CmsException e) {
313            LOG.error(e.getLocalizedMessage(), e);
314            return false;
315        } finally {
316            cms.getRequestContext().setSiteRoot(oldSiteRoot);
317        }
318    }
319
320    /**
321     * Checks whether the object is initialized and throws an exception otherwise.<p>
322    */
323    public void checkInitialized() {
324
325        if (m_cms == null) {
326            throw new IllegalStateException();
327        }
328    }
329
330    /**
331     * Checks whether the cms context is in the offline project and throws an exception otherwise.<p>
332     *
333     * @param cms the cms context
334     */
335    public void checkOffline(CmsObject cms) {
336
337        if (cms.getRequestContext().getCurrentProject().isOnlineProject()) {
338            throw new IllegalStateException();
339        }
340    }
341
342    /**
343     * Checks if a resource type is viewable for the current user.
344     * If not, this resource type should not be available at all within the ADE 'add-wizard'.<p>
345     *
346     * @param cms the current CMS context
347     * @param referenceUri the resource URI to check permissions for
348     *
349     * @return <code>true</code> if the resource type is viewable
350     */
351    public boolean checkViewable(CmsObject cms, String referenceUri) {
352
353        try {
354            CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(m_typeName);
355            CmsResource referenceResource = cms.readResource(
356                referenceUri,
357                CmsResourceFilter.ignoreExpirationOffline(cms));
358            if (settings == null) {
359                // no explorer type
360                return false;
361            }
362            return settings.getAccess().getPermissions(cms, referenceResource).requiresViewPermission();
363        } catch (CmsException e) {
364            LOG.error(e.getLocalizedMessage(), e);
365            return false;
366        }
367    }
368
369    /**
370     * Similar to createNewElement, but just sets parameters on a resource builder instead of actually creating the resource.<p>
371     *
372     * @param cms the CMS context
373     * @param pageFolderRootPath the page folder root path
374     * @param builder the resource builder
375     *
376     * @throws CmsException if something goes wrong
377     */
378    public void configureCreateNewElement(CmsObject cms, String pageFolderRootPath, CmsNewResourceBuilder builder)
379    throws CmsException {
380
381        checkOffline(cms);
382        checkInitialized();
383        String folderPath = getFolderPath(cms, pageFolderRootPath);
384        CmsVfsUtil.createFolder(cms, folderPath);
385        String destination = CmsStringUtil.joinPaths(folderPath, getNamePattern(true));
386        builder.setSiteRoot("");
387        builder.setPatternPath(destination);
388        builder.setType(getTypeName());
389        builder.setLocale(cms.getRequestContext().getLocale());
390    }
391
392    /**
393     * Creates a new element.<p>
394     *
395     * @param userCms the CMS context to use
396     * @param modelResource the model resource to use
397     * @param pageFolderRootPath the root path of the folder containing the current container page
398     *
399     * @return the created resource
400     *
401     * @throws CmsException if something goes wrong
402     */
403    public CmsResource createNewElement(CmsObject userCms, CmsResource modelResource, String pageFolderRootPath)
404    throws CmsException {
405
406        checkOffline(userCms);
407        checkInitialized();
408        CmsObject rootCms = rootCms(userCms);
409        String folderPath = getFolderPath(userCms, pageFolderRootPath);
410        CmsVfsUtil.createFolder(userCms, folderPath);
411        String destination = CmsStringUtil.joinPaths(folderPath, getNamePattern(true));
412        String creationPath = OpenCms.getResourceManager().getNameGenerator().getNewFileName(rootCms, destination, 5);
413        // set the content locale
414        Locale contentLocale = userCms.getRequestContext().getLocale();
415        if (!OpenCms.getLocaleManager().getAvailableLocales(rootCms, folderPath).contains(contentLocale)) {
416            contentLocale = OpenCms.getLocaleManager().getDefaultLocale(rootCms, folderPath);
417        }
418        rootCms.getRequestContext().setAttribute(CmsRequestContext.ATTRIBUTE_NEW_RESOURCE_LOCALE, contentLocale);
419        if (modelResource != null) {
420            // set the model resource
421            rootCms.getRequestContext().setAttribute(CmsRequestContext.ATTRIBUTE_MODEL, modelResource.getRootPath());
422        }
423        CmsResource createdResource = rootCms.createResource(
424            creationPath,
425            getType(),
426            null,
427            new ArrayList<CmsProperty>(0));
428        if (modelResource != null) {
429            // set the model resource
430            CmsCategoryService.getInstance().copyCategories(rootCms, modelResource, creationPath);
431        }
432        try {
433            rootCms.unlockResource(creationPath);
434        } catch (CmsLockException e) {
435            // probably the parent folder is locked
436            LOG.info(e.getLocalizedMessage(), e);
437        }
438        return createdResource;
439    }
440
441    /**
442     * Creates a new element.<p>
443     *
444     * @param userCms the CMS context to use
445     * @param pageFolderRootPath root path of the folder containing the current container page
446     *
447     * @return the created resource
448     *
449     * @throws CmsException if something goes wrong
450     */
451    public CmsResource createNewElement(CmsObject userCms, String pageFolderRootPath) throws CmsException {
452
453        return createNewElement(userCms, null, pageFolderRootPath);
454    }
455
456    /**
457     * Gets the visibility status in the 'add' menu for this type and the given element view.<p>
458     *
459     * @param elementViewId the id of the view for which to compute the visibility status
460     * @param menuType the menu type for which we want to evaluate the visibility
461     *
462     * @return the visibility status
463     */
464    public AddMenuVisibility getAddMenuVisibility(CmsUUID elementViewId, AddMenuType menuType) {
465
466        if (isAddDisabled()) {
467            return AddMenuVisibility.disabled;
468        }
469
470        if (elementViewId.equals(getElementView())) {
471            if (isCreateDisabled() && (menuType == AddMenuType.ade)) {
472                return AddMenuVisibility.createDisabled;
473            }
474            return AddMenuVisibility.visible;
475        }
476
477        if (isShowInDefaultView() && elementViewId.equals(CmsElementView.DEFAULT_ELEMENT_VIEW.getId())) {
478            return AddMenuVisibility.fromOtherView;
479        }
480
481        return AddMenuVisibility.disabled;
482    }
483
484    /**
485     * Gets the 'check reuse' value, without applying the default value.
486     *
487     * <p>The return value may be null if this is not set.
488     *
489     * @return the value of the 'check reuse' option
490     */
491    public Boolean getCheckReuseObj() {
492
493        return m_checkReuse;
494    }
495
496    /**
497     * Returns the bundle that is configured as workplace bundle for the resource type, or <code>null</code> if none is configured.
498     * @return the bundle that is configured as workplace bundle for the resource type, or <code>null</code> if none is configured.
499     */
500    public String getConfiguredWorkplaceBundle() {
501
502        return m_localization;
503    }
504
505    /**
506     * Gets the element delete mode.<p>
507     *
508     * @return the element delete mode
509     */
510    public ElementDeleteMode getElementDeleteMode() {
511
512        return m_elementDeleteMode;
513    }
514
515    /**
516     * Returns the element view id.<p>
517     *
518     * @return the element view id
519     */
520    public CmsUUID getElementView() {
521
522        return m_elementView == null ? CmsElementView.DEFAULT_ELEMENT_VIEW.getId() : m_elementView;
523    }
524
525    /**
526     * Computes the folder path for this resource type.<p>
527     *
528     * @param cms the cms context to use
529     * @param pageFolderRootPath root path of the folder containing the current container page
530     *
531     * @return the folder root path for this resource type
532     */
533    public String getFolderPath(CmsObject cms, String pageFolderRootPath) {
534
535        checkInitialized();
536        if (m_folderOrName != null) {
537            return m_folderOrName.getFolderPath(cms, pageFolderRootPath);
538        } else {
539            String siteRoot = null;
540            if (pageFolderRootPath != null) {
541                siteRoot = OpenCms.getSiteManager().getSiteRoot(pageFolderRootPath);
542            }
543            if (siteRoot == null) {
544                siteRoot = cms.getRequestContext().getSiteRoot();
545            }
546            return CmsStringUtil.joinPaths(siteRoot, CmsADEManager.CONTENT_FOLDER_NAME, m_typeName);
547        }
548    }
549
550    /**
551     * @see org.opencms.ade.configuration.I_CmsConfigurationObject#getKey()
552     */
553    public String getKey() {
554
555        return m_typeName;
556    }
557
558    /**
559     * Gets the name pattern.<p>
560     *
561     * @param useDefaultIfEmpty if true, uses a default value if the name pattern isn't set directly
562     *
563     * @return the name pattern
564     */
565    public String getNamePattern(boolean useDefaultIfEmpty) {
566
567        if (m_namePattern != null) {
568            return m_namePattern;
569        }
570        if (useDefaultIfEmpty) {
571            return m_typeName + "-%(number).xml";
572        }
573        return null;
574    }
575
576    /**
577     * Returns the number used for sorting module resource types.<p>
578     *
579     * @return the number used for sorting module resource types
580     */
581    public int getOrder() {
582
583        if (m_order == null) {
584            return I_CmsConfigurationObject.DEFAULT_ORDER;
585        }
586
587        return m_order.intValue();
588    }
589
590    /**
591     * Returns the order as an object (or null if it's not set).
592     *
593     * @return the order
594     */
595    public Integer getOrderObject() {
596
597        return m_order;
598    }
599
600    /**
601     * Gets the actual resource type for which this is a configuration.<p>
602     *
603     * @return the actual resource type
604     *
605     * @throws CmsException if something goes wrong
606     */
607    public I_CmsResourceType getType() throws CmsException {
608
609        return OpenCms.getResourceManager().getResourceType(m_typeName);
610    }
611
612    /**
613     * Returns the type name.<p>
614     *
615     * @return the type name
616     */
617    public String getTypeName() {
618
619        return m_typeName;
620    }
621
622    /**
623     * Initializes this instance.<p>
624     *
625     * @param cms the CMS context to use
626     */
627    public void initialize(CmsObject cms) {
628
629        m_cms = cms;
630
631    }
632
633    /**
634     * Returns true if adding elements of this type via ADE should be disabled.<p>
635     *
636     * @return true if elements of this type shouldn't be added to the page
637     */
638    public boolean isAddDisabled() {
639
640        return m_addDisabled;
641    }
642
643    /**
644     * Checks if the type can be used for the given template context key.
645     *
646     * <p>If this type isn't specifically associated with one or more template keys, this returns true,
647     * otherwise it will check if the 'template' argument is among the template keys
648     *
649     * @param template the template key to check
650     * @return true if the type should be available for the template
651     */
652    public boolean isAvailableInTemplate(String template) {
653
654        return (template == null) || (m_templates.size() == 0) || m_templates.contains(template);
655    }
656
657    /**
658     * Returns true if reuse should be checked for elements of this type.
659     *
660     * <p>This tries to use the value configured for this type first, and if it doesn't have one, returns the global default.
661     *
662     * @return true if reuse should be checked for this type
663     */
664    public boolean isCheckReuse() {
665
666        if (m_checkReuse != null) {
667            return m_checkReuse.booleanValue();
668        }
669        String defaultStr = OpenCms.getADEManager().getParameters(null).get(PARAM_CHECK_REUSE_DEFAULT);
670        return Boolean.parseBoolean(defaultStr);
671    }
672
673    /**
674     * Returns if elements of this type when used in models should be copied instead of reused.<p>
675     *
676     * @return if elements of this type when used in models should be copied instead of reused
677     */
678    public boolean isCopyInModels() {
679
680        return (m_copyInModels == null) || m_copyInModels.booleanValue();
681    }
682
683    /**
684     * Returns whether creating elements of this type via ADE should be disabled.<p>
685     *
686     * @return <code>true</code> if creating elements of this type via ADE should be disabled
687     */
688    public boolean isCreateDisabled() {
689
690        return m_createDisabled;
691    }
692
693    /**
694     * True if the detail page creation should be disabled for this resource type.<p>
695     *
696     * @return true if detail page creation should be disabled for this type
697     */
698    public boolean isDetailPagesDisabled() {
699
700        return m_detailPagesDisabled;
701    }
702
703    /**
704     * @see org.opencms.ade.configuration.I_CmsConfigurationObject#isDisabled()
705     */
706    public boolean isDisabled() {
707
708        return m_disabled;
709    }
710
711    /**
712     * Checks if editing should be disabled for container elements of this type.
713     *
714     * @return true if editing should be disabled for container elements of this type
715     */
716    public boolean isEditDisabled() {
717
718        return m_editDisabled;
719    }
720
721    /**
722     * Checks if creating and editing resources of this type should be possible via the edit buttons generated by lists.
723     *
724     * @return true if creating/editing resources of this type in lists should be possible
725     */
726    public boolean isEnabledInLists() {
727
728        return m_enableInLists;
729    }
730
731    /**
732     * Returns true if this resource type is configured as 'page relative', i.e. elements of this type are to be stored
733     * with the container page on which they were created.<p>
734     *
735     * @return true if this is a page relative type configuration
736     */
737    public boolean isPageRelative() {
738
739        return (m_folderOrName != null) && m_folderOrName.isPageRelative();
740    }
741
742    /**
743     * Returns true if the type should be shown in the default view if it is not assigned to it.<p>
744     *
745     * This defaults to 'false' if not set.
746     *
747     * @return true if the type should be shown in the default view event if  it doens't belong to that element view
748     */
749    public boolean isShowInDefaultView() {
750
751        return (m_showInDefaultView != null) && m_showInDefaultView.booleanValue();
752    }
753
754    /**
755     * If 'template' is not null, returns a copy of this type bean, but adds 'template' to the
756     * set of supported templates in the copy.
757     *
758     * @param template a template context key
759     * @return a new copy associated with the given template key
760     */
761    public CmsResourceTypeConfig markWithTemplate(String template) {
762
763        try {
764            if (template == null) {
765                return this;
766            }
767            CmsResourceTypeConfig result = (CmsResourceTypeConfig)super.clone();
768            HashSet<String> templates = new HashSet<>();
769            templates.add(template);
770            result.m_templates = templates;
771            return result;
772
773        } catch (CloneNotSupportedException e) {
774            return null;
775        }
776    }
777
778    /**
779     * @see org.opencms.ade.configuration.I_CmsConfigurationObject#merge(org.opencms.ade.configuration.I_CmsConfigurationObject)
780     */
781    public CmsResourceTypeConfig merge(CmsResourceTypeConfig childConfig) {
782
783        CmsContentFolderDescriptor folderOrName = childConfig.m_folderOrName != null
784        ? childConfig.m_folderOrName
785        : m_folderOrName;
786        String namePattern = childConfig.m_namePattern != null ? childConfig.m_namePattern : m_namePattern;
787        CmsUUID elementView = childConfig.m_elementView != null ? childConfig.m_elementView : m_elementView;
788        Boolean showInDefaultView = childConfig.m_showInDefaultView != null
789        ? childConfig.m_showInDefaultView
790        : m_showInDefaultView;
791        Boolean copyInModels = childConfig.m_copyInModels != null ? childConfig.m_copyInModels : m_copyInModels;
792        ElementDeleteMode deleteMode = childConfig.m_elementDeleteMode != null
793        ? childConfig.m_elementDeleteMode
794        : m_elementDeleteMode;
795        Integer order = childConfig.m_order != null ? childConfig.m_order : m_order;
796
797        boolean mergedDisabled = childConfig.m_availabilityNotSet ? isDisabled() : childConfig.isDisabled();
798        boolean mergedAddDisabled = childConfig.m_availabilityNotSet ? isAddDisabled() : childConfig.isAddDisabled();
799        boolean mergedCreateDisabled = childConfig.m_availabilityNotSet
800        ? isCreateDisabled()
801        : (isCreateDisabled() || childConfig.isCreateDisabled());
802
803        boolean mergedEnableInLists = childConfig.m_availabilityNotSet ? m_enableInLists : childConfig.m_enableInLists;
804        boolean mergedDisableEdit = childConfig.m_availabilityNotSet ? m_editDisabled : childConfig.m_editDisabled;
805        Boolean checkReuse = childConfig.m_checkReuse != null ? childConfig.m_checkReuse : m_checkReuse;
806
807        CmsResourceTypeConfig result = new CmsResourceTypeConfig(
808            m_typeName,
809            mergedDisabled,
810            folderOrName,
811            namePattern,
812            isDetailPagesDisabled() || childConfig.isDetailPagesDisabled(),
813            mergedAddDisabled,
814            // a type marked as not creatable, should not be creatable in any sub site
815            mergedCreateDisabled,
816            mergedDisableEdit,
817            mergedEnableInLists,
818            false /* availabilityNotSet - doesn't matter what we use here, because we do not use the return value of this method as a child for configuration merging (which is the only way this attribute is used) */,
819            elementView,
820            m_localization,
821            showInDefaultView,
822            copyInModels,
823            order,
824            deleteMode,
825            checkReuse);
826        result.m_templates = new HashSet<>(this.m_templates);
827        result.m_templates.addAll(childConfig.m_templates);
828        return result;
829    }
830
831    /**
832     * @see java.lang.Object#toString()
833     */
834    @Override
835    public String toString() {
836
837        return getClass().getSimpleName() + "[" + m_typeName + "]";
838    }
839
840    /**
841     * Creates a shallow copy of this resource type configuration object.<p>
842     *
843     * @return a copy of the resource type configuration object
844     */
845    protected CmsResourceTypeConfig copy() {
846
847        return copy(false);
848    }
849
850    /**
851     * Creates a shallow copy of this resource type configuration object.<p>
852     *
853     * @param disabled true if the copy should be disabled regardless of whether the original is disabled
854     *
855     * @return a copy of the resource type configuration object
856     */
857    protected CmsResourceTypeConfig copy(boolean disabled) {
858
859        CmsResourceTypeConfig result = new CmsResourceTypeConfig(
860            m_typeName,
861            m_disabled || disabled,
862            getFolderOrName(),
863            m_namePattern,
864            m_detailPagesDisabled,
865            isAddDisabled(),
866            isCreateDisabled(),
867            m_editDisabled,
868            m_enableInLists,
869            m_availabilityNotSet,
870            m_elementView,
871            m_localization,
872            m_showInDefaultView,
873            m_copyInModels,
874            m_order,
875            m_elementDeleteMode,
876            m_checkReuse);
877        result.m_templates = m_templates;
878        return result;
879    }
880
881    /**
882     * Returns the folder bean from the configuration.<p>
883     *
884     * Normally, you should use getFolderPath() instead.<p>
885     *
886     * @return the folder bean from the configuration
887     */
888    protected CmsContentFolderDescriptor getFolderOrName() {
889
890        return m_folderOrName;
891    }
892
893    /**
894     * Gets the configured name pattern.<p>
895     *
896     * @return the configured name pattern
897     */
898    protected String getNamePattern() {
899
900        return m_namePattern;
901    }
902
903    /**
904     * Creates a new CMS object based on existing one and changes its site root to the site root.<p>
905     *
906     * @param cms the CMS context
907     * @return the root site CMS context
908     * @throws CmsException if something goes wrong
909     */
910    protected CmsObject rootCms(CmsObject cms) throws CmsException {
911
912        CmsObject result = OpenCms.initCmsObject(cms);
913        result.getRequestContext().setSiteRoot("");
914        return result;
915    }
916
917    /**
918     * Tries to remove a lock on an ancestor of a given path owned by the current user.<p>
919     *
920     * @param cms the CMS context
921     * @param folderPath the path for which the lock should be removed
922     *
923     * @throws CmsException if something goes wrong
924     */
925    protected void tryToUnlock(CmsObject cms, String folderPath) throws CmsException {
926
927        // Get path of first ancestor that actually exists
928        while (!cms.existsResource(folderPath)) {
929            folderPath = CmsResource.getParentFolder(folderPath);
930        }
931        CmsResource resource = cms.readResource(folderPath);
932        CmsLock lock = cms.getLock(resource);
933        // we are only interested in locks we can safely unlock, i.e. locks by the current user
934        if (lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) {
935            // walk up the tree until we get to the location from which the lock is inherited
936            while (lock.isInherited()) {
937                folderPath = CmsResource.getParentFolder(folderPath);
938                resource = cms.readResource(folderPath);
939                lock = cms.getLock(resource);
940            }
941            cms.unlockResource(folderPath);
942        }
943    }
944
945    /**
946     * Updates the base path for the folder information.<p>
947     *
948     * @param basePath the new base path
949     */
950    protected void updateBasePath(String basePath) {
951
952        if (m_folderOrName != null) {
953            if (m_folderOrName.isName()) {
954                m_folderOrName = new CmsContentFolderDescriptor(basePath, m_folderOrName.getFolderName());
955            }
956        } else {
957            m_folderOrName = new CmsContentFolderDescriptor(basePath, m_typeName);
958        }
959    }
960}