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