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.xml.containerpage;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.CmsADEManager;
032import org.opencms.ade.containerpage.shared.CmsContainerElement;
033import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
034import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
035import org.opencms.ade.containerpage.shared.CmsInheritanceInfo;
036import org.opencms.file.CmsFile;
037import org.opencms.file.CmsObject;
038import org.opencms.file.CmsResource;
039import org.opencms.file.CmsResourceFilter;
040import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
041import org.opencms.file.types.CmsResourceTypeXmlContent;
042import org.opencms.file.types.I_CmsResourceType;
043import org.opencms.main.CmsException;
044import org.opencms.main.OpenCms;
045import org.opencms.util.CmsNullIgnoringConcurrentMap;
046import org.opencms.util.CmsUUID;
047import org.opencms.xml.CmsXmlContentDefinition;
048import org.opencms.xml.content.CmsXmlContent;
049import org.opencms.xml.content.CmsXmlContentFactory;
050import org.opencms.xml.content.CmsXmlContentPropertyHelper;
051
052import java.util.Collections;
053import java.util.HashMap;
054import java.util.Locale;
055import java.util.Map;
056
057import javax.servlet.ServletRequest;
058
059/**
060 * One element of a container in a container page.<p>
061 *
062 * @since 8.0
063 */
064public class CmsContainerElementBean implements Cloneable {
065
066    /** Prevent caching in ADE session cache. */
067    private boolean m_doNotCache;
068
069    /** Flag indicating if a new element should be created replacing the given one on first edit of a container-page. */
070    private final boolean m_createNew;
071
072    /** The client ADE editor hash. */
073    private transient String m_editorHash;
074
075    /** The element's structure id. */
076    private CmsUUID m_elementId;
077
078    /** The formatter's structure id. */
079    private CmsUUID m_formatterId;
080
081    /** The configured properties. */
082    private Map<String, String> m_individualSettings;
083
084    /** The inheritance info of this element. */
085    private CmsInheritanceInfo m_inheritanceInfo;
086
087    /** Indicates whether the represented resource is in memory only and not in the VFS. */
088    private boolean m_inMemoryOnly;
089
090    /** True if the element is used for a historical content. */
091    private boolean m_isHistory;
092
093    /** Indicating if the element resource is released and not expired. */
094    private boolean m_releasedAndNotExpired;
095
096    /** The resource of this element. */
097    private transient CmsResource m_resource;
098
099    /** The settings of this element containing also default values. */
100    private transient Map<String, String> m_settings;
101
102    /** The element site path, only set while rendering. */
103    private String m_sitePath;
104
105    /** Indicates the element bean has a temporary file content set. */
106    private boolean m_temporaryContent;
107
108    /**
109     * Creates a new container page element bean.<p>
110     *
111     * @param file the element's file
112     * @param formatterId the formatter's structure id, could be <code>null</code>
113     * @param individualSettings the element settings as a map of name/value pairs
114     * @param inMemoryOnly the in memory flag
115     * @param editorHash the editor hash to use
116     * @param createNew <code>true</code> if a new element should be created replacing the given one on first edit of a container-page
117     **/
118    public CmsContainerElementBean(
119        CmsFile file,
120        CmsUUID formatterId,
121        Map<String, String> individualSettings,
122        boolean inMemoryOnly,
123        String editorHash,
124        boolean createNew) {
125
126        this(file.getStructureId(), formatterId, individualSettings, createNew);
127        m_inMemoryOnly = inMemoryOnly;
128        m_editorHash = editorHash;
129        m_resource = file;
130    }
131
132    /**
133     * Creates a new container page element bean.<p>
134     *
135     * @param elementId the element's structure id
136     * @param formatterId the formatter's structure id, could be <code>null</code>
137     * @param individualSettings the element settings as a map of name/value pairs
138     * @param createNew <code>true</code> if a new element should be created replacing the given one on first edit of a container-page
139     **/
140    public CmsContainerElementBean(
141        CmsUUID elementId,
142        CmsUUID formatterId,
143        Map<String, String> individualSettings,
144        boolean createNew) {
145
146        m_elementId = elementId;
147        m_formatterId = formatterId;
148        Map<String, String> newSettings = (individualSettings == null
149        ? new HashMap<String, String>()
150        : new HashMap<String, String>(individualSettings));
151        if (!newSettings.containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)) {
152            newSettings.put(CmsContainerElement.ELEMENT_INSTANCE_ID, new CmsUUID().toString());
153        }
154        newSettings.values().removeAll(Collections.singletonList(null));
155        m_individualSettings = Collections.unmodifiableMap(newSettings);
156        m_editorHash = m_elementId.toString() + getSettingsHash();
157        m_createNew = createNew;
158    }
159
160    /**
161     * Constructor to enable wrapped elements.<p>
162     */
163    protected CmsContainerElementBean() {
164
165        m_elementId = null;
166        m_createNew = false;
167    }
168
169    /**
170     * Cloning constructor.<p>
171     *
172     * @param createNew create new flag
173     * @param elementId element id
174     * @param formatterId formatter id
175     * @param individualSettings individual settings
176     * @param inheritanceInfo inheritance info
177     * @param inMemoryOnly in memory only flag
178     * @param temporaryContent temporary content flag
179     * @param releasedAndNotExpired released and not expired flag
180     * @param resource the resource/file object
181     * @param settings the settings
182     * @param sitePath the site path
183     */
184    private CmsContainerElementBean(
185        boolean createNew,
186        CmsUUID elementId,
187        CmsUUID formatterId,
188        Map<String, String> individualSettings,
189        CmsInheritanceInfo inheritanceInfo,
190        boolean inMemoryOnly,
191        boolean temporaryContent,
192        boolean releasedAndNotExpired,
193        CmsResource resource,
194        Map<String, String> settings,
195        String sitePath) {
196
197        m_createNew = createNew;
198        m_elementId = elementId;
199        m_formatterId = formatterId;
200        m_individualSettings = Collections.unmodifiableMap(individualSettings);
201        m_inheritanceInfo = inheritanceInfo;
202        m_inMemoryOnly = inMemoryOnly;
203        m_releasedAndNotExpired = releasedAndNotExpired;
204        m_resource = resource;
205        setSettings(settings);
206        m_sitePath = sitePath;
207        m_temporaryContent = temporaryContent;
208    }
209
210    /**
211     * Clones the given element bean with a different formatter.<p>
212     *
213     * @param source the element to clone
214     * @param formatterId the new formatter id
215     *
216     * @return the element bean
217     */
218    public static CmsContainerElementBean cloneWithFormatter(CmsContainerElementBean source, CmsUUID formatterId) {
219
220        CmsContainerElementBean result = source.clone();
221        result.m_formatterId = formatterId;
222        return result;
223    }
224
225    /**
226     * Clones the given element bean with a different set of settings.<p>
227     *
228     * @param source the element to clone
229     * @param settings the new settings
230     *
231     * @return the element bean
232     */
233    public static CmsContainerElementBean cloneWithSettings(
234        CmsContainerElementBean source,
235        Map<String, String> settings) {
236
237        boolean createNew = source.m_createNew;
238        if (settings.containsKey(CmsContainerElement.CREATE_AS_NEW)) {
239            createNew = Boolean.valueOf(settings.get(CmsContainerElement.CREATE_AS_NEW)).booleanValue();
240            settings = new HashMap<String, String>(settings);
241            settings.remove(CmsContainerElement.CREATE_AS_NEW);
242        }
243        CmsContainerElementBean result = new CmsContainerElementBean(
244            source.m_elementId,
245            source.m_formatterId,
246            settings,
247            createNew);
248        result.m_resource = source.m_resource;
249        result.m_sitePath = source.m_sitePath;
250        result.m_inMemoryOnly = source.m_inMemoryOnly;
251        result.m_inheritanceInfo = source.m_inheritanceInfo;
252        if (result.m_inMemoryOnly) {
253            String editorHash = source.m_editorHash;
254            if (editorHash.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) {
255                editorHash = editorHash.substring(0, editorHash.indexOf(CmsADEManager.CLIENT_ID_SEPERATOR));
256            }
257            editorHash += result.getSettingsHash();
258            result.m_editorHash = editorHash;
259        }
260        return result;
261    }
262
263    /**
264     * Creates an element bean for the given resource type.<p>
265     * <b>The represented resource will be in memory only and not in the VFS!!!.</b><p>
266     *
267     * @param cms the CMS context
268     * @param resourceType the resource type
269     * @param targetFolder the parent folder of the resource
270     * @param individualSettings the element settings as a map of name/value pairs
271     * @param isCopyModels if this element when used in models should be copied instead of reused
272     * @param locale the locale to use
273     *
274     * @return the created element bean
275     * @throws CmsException if something goes wrong creating the element
276     * @throws IllegalArgumentException if the resource type not instance of {@link org.opencms.file.types.CmsResourceTypeXmlContent}
277     */
278    public static CmsContainerElementBean createElementForResourceType(
279        CmsObject cms,
280        I_CmsResourceType resourceType,
281        String targetFolder,
282        Map<String, String> individualSettings,
283        boolean isCopyModels,
284        Locale locale)
285    throws CmsException {
286
287        if (!(resourceType instanceof CmsResourceTypeXmlContent)) {
288            throw new IllegalArgumentException();
289        }
290
291        byte[] content = new byte[0];
292        String schema = ((CmsResourceTypeXmlContent)resourceType).getSchema();
293        if (schema != null) {
294            // must set URI of OpenCms user context to parent folder of created resource,
295            // in order to allow reading of properties for default values
296            CmsObject newCms = OpenCms.initCmsObject(cms);
297            newCms.getRequestContext().setUri(targetFolder);
298            // unmarshal the content definition for the new resource
299            CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema);
300            CmsXmlContent xmlContent = CmsXmlContentFactory.createDocument(
301                newCms,
302                locale,
303                OpenCms.getSystemInfo().getDefaultEncoding(),
304                contentDefinition);
305            // adding all other available locales
306            for (Locale otherLocale : OpenCms.getLocaleManager().getAvailableLocales()) {
307                if (!locale.equals(otherLocale)) {
308                    xmlContent.addLocale(newCms, otherLocale);
309                }
310            }
311            content = xmlContent.marshal();
312        }
313        @SuppressWarnings("deprecation")
314        CmsFile file = new CmsFile(
315            CmsUUID.getNullUUID(),
316            CmsUUID.getNullUUID(),
317            targetFolder + "~",
318            resourceType.getTypeId(),
319            0,
320            cms.getRequestContext().getCurrentProject().getUuid(),
321            CmsResource.STATE_NEW,
322            0,
323            cms.getRequestContext().getCurrentUser().getId(),
324            0,
325            cms.getRequestContext().getCurrentUser().getId(),
326            CmsResource.DATE_RELEASED_DEFAULT,
327            CmsResource.DATE_EXPIRED_DEFAULT,
328            1,
329            content.length,
330            0,
331            0,
332            content);
333        CmsContainerElementBean elementBean = new CmsContainerElementBean(
334            file,
335            null,
336            individualSettings,
337            true,
338            resourceType.getTypeName() + getSettingsHash(individualSettings, isCopyModels),
339            isCopyModels);
340        return elementBean;
341    }
342
343    /**
344     * Gets the hash code for the element settings.<p>
345     *
346     * @param individualSettings the individual settings
347     * @param createNew the create new flag
348     *
349     * @return the hash code for the element settings
350     */
351    private static String getSettingsHash(Map<String, String> individualSettings, boolean createNew) {
352
353        if (!individualSettings.isEmpty() || createNew) {
354            int hash = (individualSettings.toString() + createNew).hashCode();
355            return CmsADEManager.CLIENT_ID_SEPERATOR + hash;
356        }
357        return "";
358    }
359
360    /**
361     * Adds a formatter setting.<p>
362     *
363     * @param containerName the container name
364     * @param formatterId the formatter id
365     */
366    public void addFormatterSetting(String containerName, String formatterId) {
367
368        Map<String, String> newSettings = new HashMap<String, String>(m_individualSettings);
369        newSettings.put(CmsFormatterConfig.getSettingsKeyForContainer(containerName), formatterId);
370        m_individualSettings = Collections.unmodifiableMap(newSettings);
371        if (m_inMemoryOnly) {
372            String editorHash = m_editorHash;
373            if (editorHash.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) {
374                editorHash = editorHash.substring(0, editorHash.indexOf(CmsADEManager.CLIENT_ID_SEPERATOR));
375            }
376            editorHash += getSettingsHash();
377            m_editorHash = editorHash;
378        } else {
379            m_editorHash = m_elementId.toString() + getSettingsHash();
380        }
381    }
382
383    /**
384     * @see java.lang.Object#clone()
385     */
386    @Override
387    public CmsContainerElementBean clone() {
388
389        return new CmsContainerElementBean(
390            m_createNew,
391            m_elementId,
392            m_formatterId,
393            m_individualSettings,
394            m_inheritanceInfo,
395            m_inMemoryOnly,
396            m_temporaryContent,
397            m_releasedAndNotExpired,
398            m_resource,
399            m_settings,
400            m_sitePath);
401    }
402
403    /**
404     * Returns the ADE client editor has value.<p>
405     *
406     * @return the ADE client editor has value
407     */
408    public String editorHash() {
409
410        if (m_editorHash == null) {
411            m_editorHash = m_elementId.toString() + getSettingsHash();
412        }
413        return m_editorHash;
414    }
415
416    /**
417     * Ensures the element has a new element instance id.<p>
418     */
419    public void ensureNewInstanceId() {
420
421        Map<String, String> newSettings = new HashMap<String, String>(m_individualSettings);
422        newSettings.put(CmsContainerElement.ELEMENT_INSTANCE_ID, new CmsUUID().toString());
423        m_individualSettings = Collections.unmodifiableMap(newSettings);
424        m_editorHash = m_elementId.toString() + getSettingsHash();
425    }
426
427    /**
428     * @see java.lang.Object#equals(java.lang.Object)
429     */
430    @Override
431    public boolean equals(Object obj) {
432
433        if (!(obj instanceof CmsContainerElementBean)) {
434            return false;
435        }
436        return editorHash().equals(((CmsContainerElementBean)obj).editorHash());
437    }
438
439    /**
440     * Returns the structure id of the formatter of this element.<p>
441     *
442     * @return the structure id of the formatter of this element
443     */
444    public CmsUUID getFormatterId() {
445
446        return m_formatterId;
447    }
448
449    /**
450     * Returns the structure id of the resource of this element.<p>
451     *
452     * @return the structure id of the resource of this element
453     */
454    public CmsUUID getId() {
455
456        return m_elementId;
457    }
458
459    /**
460     * Returns the settings of this element.<p>
461     *
462     * @return the settings of this element
463     */
464    public Map<String, String> getIndividualSettings() {
465
466        return m_individualSettings;
467    }
468
469    /**
470     * Returns the inheritance info.<p>
471     *
472     * @return the inheritance info or <code>null</code> if not available
473     */
474    public CmsInheritanceInfo getInheritanceInfo() {
475
476        return m_inheritanceInfo;
477    }
478
479    /**
480     * Returns the element instance id.<p>
481     *
482     * @return the element instance id
483     */
484    public String getInstanceId() {
485
486        return getIndividualSettings().get(CmsContainerElement.ELEMENT_INSTANCE_ID);
487    }
488
489    /**
490     * Returns the resource of this element.<p>
491     *
492     * It is required to call {@link #initResource(CmsObject)} before this method can be used.<p>
493     *
494     * @return the resource of this element
495     *
496     * @see #initResource(CmsObject)
497     */
498    public CmsResource getResource() {
499
500        return m_resource;
501    }
502
503    /**
504     * Returns the element settings including default values for settings not set.<p>
505     * Will return <code>null</code> if the element bean has not been initialized with {@link #initResource(org.opencms.file.CmsObject)}.<p>
506     *
507     * @return the element settings
508     */
509    public Map<String, String> getSettings() {
510
511        return m_settings;
512    }
513
514    /**
515     * Returns the site path of the resource of this element.<p>
516     *
517     * It is required to call {@link #initResource(CmsObject)} before this method can be used.<p>
518     *
519     * @return the site path of the resource of this element
520     *
521     * @see #initResource(CmsObject)
522     */
523    public String getSitePath() {
524
525        return m_sitePath;
526    }
527
528    /**
529     * Returns the resource type name.<p>
530     *
531     * @return the type name
532     */
533    public String getTypeName() {
534
535        if (getResource() != null) {
536            return OpenCms.getResourceManager().getResourceType(getResource()).getTypeName();
537        } else {
538            return "unknown";
539        }
540    }
541
542    /**
543     * @see java.lang.Object#hashCode()
544     */
545    @Override
546    public int hashCode() {
547
548        return m_editorHash.hashCode();
549    }
550
551    /**
552     * Initializes the resource and the site path of this element.<p>
553     *
554     * @param cms the CMS context
555     *
556     * @throws CmsException if something goes wrong reading the element resource
557     */
558    public void initResource(CmsObject cms) throws CmsException {
559
560        if (m_resource == null) {
561            m_resource = cms.readResource(getId(), CmsResourceFilter.IGNORE_EXPIRATION);
562            m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime());
563        } else if (!isInMemoryOnly()) {
564            CmsUUID id = m_resource.getStructureId();
565            if (id == null) {
566                id = getId();
567            }
568            // the resource object may have a wrong root path, e.g. if it was created before the resource was moved
569            if (cms.getRequestContext().getCurrentProject().isOnlineProject()) {
570                m_resource = cms.readResource(id, CmsResourceFilter.IGNORE_EXPIRATION);
571                m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime());
572            } else {
573                if (!isTemporaryContent()) {
574                    m_resource = cms.readResource(getId(), CmsResourceFilter.IGNORE_EXPIRATION);
575                }
576                m_releasedAndNotExpired = m_resource.isReleasedAndNotExpired(cms.getRequestContext().getRequestTime());
577            }
578        }
579        if (m_settings == null) {
580            setSettings(new HashMap<String, String>(getIndividualSettings()));
581        }
582        // redo on every init call to ensure sitepath is calculated for current site
583        m_sitePath = cms.getSitePath(m_resource);
584    }
585
586    /**
587     * Initializes the element settings.<p>
588     *
589     * @param cms the CMS context
590     * @param formatterBean the formatter configuration bean
591     * @param locale the content locale
592     * @param request the current request, if available
593     * @param presets the presets for container element settings
594     */
595    public void initSettings(
596        CmsObject cms,
597        CmsADEConfigData config,
598        I_CmsFormatterBean formatterBean,
599        Locale locale,
600        ServletRequest request,
601        Map<String, String> presets) {
602
603        Map<String, String> mergedSettings;
604        if (formatterBean == null) {
605            mergedSettings = CmsXmlContentPropertyHelper.mergeDefaults(
606                cms,
607                config,
608                m_resource,
609                getIndividualSettings(),
610                locale,
611                request);
612        } else {
613            mergedSettings = CmsXmlContentPropertyHelper.mergeDefaults(
614                cms,
615                OpenCms.getADEManager().getFormatterSettings(
616                    cms,
617                    config,
618                    formatterBean,
619                    getResource(),
620                    locale,
621                    request),
622                getIndividualSettings());
623        }
624        if ((presets != null) && (presets.size() > 0)) {
625            mergedSettings.putAll(presets);
626        }
627        if (m_settings == null) {
628            setSettings(mergedSettings);
629        } else {
630            m_settings.putAll(mergedSettings);
631        }
632    }
633
634    /**
635     * Returns if the given element should be used as a copy model.<p>
636     *
637     * @return <code>true</code> if the given element should be used as a copy model
638     */
639    public boolean isCopyModel() {
640
641        return Boolean.valueOf(getIndividualSettings().get(CmsContainerElement.USE_AS_COPY_MODEL)).booleanValue();
642    }
643
644    /**
645     * Returns if a new element should be created replacing the given one on first edit of a container-page.<p>
646     *
647     * @return <code>true</code> if a new element should be created replacing the given one on first edit of a container-page
648     */
649    public boolean isCreateNew() {
650
651        return m_createNew;
652    }
653
654    /**
655     * Checks if the element is uncacheable.
656     *
657     * @return true if the element is uncacheable
658     */
659    public boolean isDoNotCache() {
660
661        return m_doNotCache;
662    }
663
664    /**
665     * Tests whether this element refers to a group container.<p>
666     *
667     * @param cms the CmsObject used for VFS operations
668     *
669     * @return <code>true</code> if the container element refers to a group container
670     *
671     * @throws CmsException if something goes wrong
672     */
673    public boolean isGroupContainer(CmsObject cms) throws CmsException {
674
675        if (m_resource == null) {
676            initResource(cms);
677        }
678        return CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME.equals(
679            OpenCms.getResourceManager().getResourceType(m_resource).getTypeName());
680    }
681
682    /**
683     * Checks if the element is used for displaying a historical content (usually from the history dialog).
684     *
685     * @return true if the element is used for displaying a historical content
686     */
687    public boolean isHistoryContent() {
688
689        return m_isHistory;
690    }
691
692    /**
693     * Returns whether this element refers to an inherited container element.<p>
694     *
695     * @param cms the CmsObject used for VFS operations
696     *
697     * @return <code>true</code> if the container element refers to an inherited container
698     *
699     * @throws CmsException if something goes wrong
700     */
701    @SuppressWarnings("deprecation")
702    public boolean isInheritedContainer(CmsObject cms) throws CmsException {
703
704        if (m_resource == null) {
705            initResource(cms);
706        }
707        return OpenCms.getResourceManager().getResourceType(
708            CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_TYPE_NAME).getTypeId() == m_resource.getTypeId();
709    }
710
711    /**
712     * Returns if the represented resource is in memory only and not persisted in the VFS.<p>
713     *
714     * @return <code>true</code> if the represented resource is in memory only and not persisted in the VFS
715     */
716    public boolean isInMemoryOnly() {
717
718        return m_inMemoryOnly;
719    }
720
721    /**
722     * Returns if the given element is a model group.<p>
723     *
724     * @return <code>true</code> if the given element is a model group
725     */
726    public boolean isModelGroup() {
727
728        ModelGroupState state = ModelGroupState.evaluate(
729            getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE));
730        return state == ModelGroupState.isModelGroup;
731    }
732
733    /**
734     * Returns if all instances of this element should be replaced within a copy model.<p>
735     *
736     * @return <code>true</code> if all instances of this element should be replaced within a copy model
737     */
738    public boolean isModelGroupAlwaysReplace() {
739
740        return Boolean.parseBoolean(getIndividualSettings().get(CmsContainerElement.IS_MODEL_GROUP_ALWAYS_REPLACE));
741    }
742
743    /**
744     * Returns if the element resource is released and not expired.<p>
745     *
746     * @return <code>true</code> if the element resource is released and not expired
747     */
748    public boolean isReleasedAndNotExpired() {
749
750        return isInMemoryOnly() || m_releasedAndNotExpired;
751    }
752
753    /**
754     * Returns if the element resource contains temporary file content.<p>
755     *
756     * @return <code>true</code> if the element resource contains temporary file content
757     */
758    public boolean isTemporaryContent() {
759
760        return m_temporaryContent;
761    }
762
763    /**
764     * Enables / disables 'do not cache' status, which prevents the element from being cached in the session cache.
765     *
766     * @param doNotCache the new value
767     */
768    public void setDoNotCache(boolean doNotCache) {
769
770        m_doNotCache = doNotCache;
771    }
772
773    /**
774     * Sets the formatter id.<p>
775     *
776     * @param formatterId the formatter id
777     */
778    public void setFormatterId(CmsUUID formatterId) {
779
780        m_formatterId = formatterId;
781    }
782
783    /**
784     * Sets a historical file.<p>
785     *
786     * @param file the historical file
787     */
788    public void setHistoryFile(CmsFile file) {
789
790        m_resource = file;
791        m_inMemoryOnly = true;
792        m_isHistory = true;
793    }
794
795    /**
796     * Sets the inheritance info for this element.<p>
797     *
798     * @param inheritanceInfo the inheritance info
799     */
800    public void setInheritanceInfo(CmsInheritanceInfo inheritanceInfo) {
801
802        m_inheritanceInfo = inheritanceInfo;
803    }
804
805    /**
806     * Sets the element resource as a temporary file.<p>
807     *
808     * @param elementFile the temporary file
809     */
810    public void setTemporaryFile(CmsFile elementFile) {
811
812        m_resource = elementFile;
813        m_temporaryContent = true;
814    }
815
816    /**
817     * @see java.lang.Object#toString()
818     */
819    @Override
820    public String toString() {
821
822        return editorHash();
823    }
824
825    /**
826     * Updates the individual settings.<p>
827     *
828     * This causes all merged settings (from defaults etc.) to be lost.
829     *
830     * @param newSettings the new settings
831     */
832    public void updateIndividualSettings(Map<String, String> newSettings) {
833
834        m_individualSettings = Collections.unmodifiableMap(newSettings);
835        setSettings(getIndividualSettings());
836    }
837
838    /**
839     * Gets the hash code for the element settings.<p>
840     *
841     * @return the hash code for the element settings
842     */
843    private String getSettingsHash() {
844
845        String instanceId = getInstanceId();
846        if (instanceId == null) {
847            throw new RuntimeException("Missing instance id");
848        }
849        return CmsADEManager.CLIENT_ID_SEPERATOR
850            + getInstanceId()
851            + "_"
852            + getIndividualSettings().get(CmsContainerElement.SETTING_PAGE_ID);
853    }
854
855    /**
856     * Sets the settings map.<p>
857     *
858     * @param settings the settings
859     */
860    private void setSettings(Map<String, String> settings) {
861
862        if (settings == null) {
863            m_settings = null;
864        } else {
865            m_settings = new CmsNullIgnoringConcurrentMap<String, String>(settings);
866        }
867    }
868}