001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software GmbH & Co. KG, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.file.types;
029
030import org.opencms.configuration.CmsConfigurationCopyResource;
031import org.opencms.configuration.CmsConfigurationException;
032import org.opencms.configuration.CmsParameterConfiguration;
033import org.opencms.db.CmsSecurityManager;
034import org.opencms.file.CmsFile;
035import org.opencms.file.CmsObject;
036import org.opencms.file.CmsProperty;
037import org.opencms.file.CmsResource;
038import org.opencms.file.CmsResourceFilter;
039import org.opencms.file.CmsVfsException;
040import org.opencms.file.CmsVfsResourceNotFoundException;
041import org.opencms.loader.CmsLoaderException;
042import org.opencms.loader.CmsResourceManager;
043import org.opencms.lock.CmsLockType;
044import org.opencms.main.CmsException;
045import org.opencms.main.CmsIllegalArgumentException;
046import org.opencms.main.CmsLog;
047import org.opencms.main.CmsRuntimeException;
048import org.opencms.main.OpenCms;
049import org.opencms.relations.CmsLink;
050import org.opencms.relations.I_CmsLinkParseable;
051import org.opencms.report.I_CmsReport;
052import org.opencms.staticexport.CmsLinkManager;
053import org.opencms.util.CmsFileUtil;
054import org.opencms.util.CmsMacroResolver;
055import org.opencms.util.CmsStringUtil;
056import org.opencms.xml.containerpage.CmsFormatterConfiguration;
057
058import java.util.ArrayList;
059import java.util.Collections;
060import java.util.HashMap;
061import java.util.Iterator;
062import java.util.List;
063import java.util.Map;
064
065import org.apache.commons.logging.Log;
066
067/**
068 * Base implementation for resource type classes.<p>
069 *
070 * @since 6.0.0
071 */
072public abstract class A_CmsResourceType implements I_CmsResourceType {
073
074    /** Configuration key for optional javascript in galleries. */
075    public static final String CONFIGURATION_GALLERY_JAVASCRIPT_PATH = "gallery.javascript.path";
076
077    /** Configuration key for optional preview provider in galleries. */
078    public static final String CONFIGURATION_GALLERY_PREVIEW_PROVIDER = "gallery.preview.provider";
079
080    /** Configuration key for the optional folder class name. */
081    public static final String CONFIGURATION_GALLERY_TYPE_NAMES = "gallery.type.names";
082
083    /** Configuration key for the (optional) internal flag. */
084    public static final String CONFIGURATION_INTERNAL = "resource.flag.internal";
085
086    /** The default gallery preview provider. */
087    public static final String DEFAULT_GALLERY_PREVIEW_PROVIDER = "org.opencms.ade.galleries.preview.CmsBinaryPreviewProvider";
088
089    /** Macro for the folder path of the current resource. */
090    public static final String MACRO_RESOURCE_FOLDER_PATH = "resource.folder.path";
091
092    /** Macro for the folder path of the current resource, with touch enabled for the copied resources. */
093    public static final String MACRO_RESOURCE_FOLDER_PATH_TOUCH = "resource.folder.path.touch";
094
095    /** Macro for the name of the current resource. */
096    public static final String MACRO_RESOURCE_NAME = "resource.name";
097
098    /** Macro for the parent folder path of the current resource. */
099    public static final String MACRO_RESOURCE_PARENT_PATH = "resource.parent.path";
100
101    /** Macro for the root path of the current resource. */
102    public static final String MACRO_RESOURCE_ROOT_PATH = "resource.root.path";
103
104    /** Macro for the site path of the current resource. */
105    public static final String MACRO_RESOURCE_SITE_PATH = "resource.site.path";
106
107    /** The log object for this class. */
108    private static final Log LOG = CmsLog.getLog(A_CmsResourceType.class);
109
110    /** The serial version id. */
111    private static final long serialVersionUID = 2131071233840674874L;
112
113    /** Flag for showing that this is an additional resource type which is defined in a module. */
114    protected boolean m_addititionalModuleResourceType;
115
116    /** The configured class name of this resource type. */
117    protected String m_className;
118
119    /** Configuration parameters. */
120    protected CmsParameterConfiguration m_configuration;
121
122    /** The list of resources to copy. */
123    protected List<CmsConfigurationCopyResource> m_copyResources;
124
125    /** The list of configured default properties. */
126    protected List<CmsProperty> m_defaultProperties;
127
128    /** Indicates that the configuration of the resource type has been frozen. */
129    protected boolean m_frozen;
130
131    /** The gallery preview provider. */
132    protected String m_galleryPreviewProvider;
133
134    /**  Contains the file extensions mapped to this resource type. */
135    protected List<String> m_mappings;
136
137    /** The module name if this is an additional resource type which is defined in a module. */
138    protected String m_moduleName;
139
140    /** The configured id of this resource type. */
141    protected int m_typeId;
142
143    /** The configured name of this resource type. */
144    protected String m_typeName;
145
146    /** The folder for which links should be adjusted after copying the copy-resources. */
147    private String m_adjustLinksFolder;
148
149    /** The gallery type name for this resource type. */
150    private String m_galleryTypeNames;
151
152    /** The gallery type for this resource type. */
153    private List<I_CmsResourceType> m_galleryTypes;
154
155    /** The optional internal parameter value. */
156    private Boolean m_internal;
157
158    /**
159     * Default constructor, used to initialize some member variables.<p>
160     */
161    public A_CmsResourceType() {
162
163        m_typeId = -1;
164        m_mappings = new ArrayList<String>();
165        m_defaultProperties = new ArrayList<CmsProperty>();
166        m_copyResources = new ArrayList<CmsConfigurationCopyResource>();
167        m_configuration = new CmsParameterConfiguration();
168    }
169
170    /**
171     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#addConfigurationParameter(java.lang.String, java.lang.String)
172     */
173    public void addConfigurationParameter(String paramName, String paramValue) {
174
175        m_configuration.add(paramName, paramValue);
176        if (CmsStringUtil.isNotEmpty(paramName) && CmsStringUtil.isNotEmpty(paramValue)) {
177            if (CONFIGURATION_INTERNAL.equalsIgnoreCase(paramName)) {
178                m_internal = Boolean.valueOf(paramValue.trim());
179            }
180            if (CONFIGURATION_GALLERY_TYPE_NAMES.equalsIgnoreCase(paramName)) {
181                m_galleryTypeNames = paramValue.trim();
182            }
183        }
184    }
185
186    /**
187     * Adds a new "copy resource" to this resource type,
188     * allowed only during the configuration phase.<p>
189     *
190     * The "copy resources" are copied to the specified location after
191     * a new resource of this type is created. Usually this feature is used to
192     * populate a newly created folder with some default resources.<p>
193     *
194     * If target is <code>null</code>, the macro {@link #MACRO_RESOURCE_FOLDER_PATH} is used as default.
195     * If type is <code>null</code>, the copy type {@link CmsResource#COPY_AS_NEW} is used as default.<p>
196     *
197     * @param source the source resource
198     * @param target the target resource (may contain macros)
199     * @param type the type of the copy, for example "as new", "as sibling" etc
200     *
201     * @throws CmsConfigurationException if the configuration is already frozen
202     */
203    public void addCopyResource(String source, String target, String type) throws CmsConfigurationException {
204
205        if (LOG.isDebugEnabled()) {
206            LOG.debug(
207                Messages.get().getBundle().key(
208                    Messages.LOG_ADD_COPY_RESOURCE_4,
209                    new Object[] {this, source, target, type}));
210        }
211
212        if (m_frozen) {
213            // configuration already frozen
214            throw new CmsConfigurationException(
215                Messages.get().container(
216                    Messages.ERR_CONFIG_FROZEN_3,
217                    this.getClass().getName(),
218                    getTypeName(),
219                    Integer.valueOf(getTypeId())));
220        }
221
222        // create the copy resource object an add it to the list
223        CmsConfigurationCopyResource copyResource = new CmsConfigurationCopyResource(source, target, type);
224        m_copyResources.add(copyResource);
225    }
226
227    /**
228     * Adds a default property to this resource type,
229     * allowed only during the configuration phase.<p>
230     *
231     * @param property the default property to add
232     *
233     * @throws CmsConfigurationException if the configuration is already frozen
234     */
235    public void addDefaultProperty(CmsProperty property) throws CmsConfigurationException {
236
237        if (LOG.isDebugEnabled()) {
238            LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_DFLT_PROP_2, this, property));
239        }
240
241        if (m_frozen) {
242            // configuration already frozen
243            throw new CmsConfigurationException(
244                Messages.get().container(
245                    Messages.ERR_CONFIG_FROZEN_3,
246                    this.getClass().getName(),
247                    getTypeName(),
248                    Integer.valueOf(getTypeId())));
249        }
250
251        m_defaultProperties.add(property);
252    }
253
254    /**
255     * @see org.opencms.file.types.I_CmsResourceType#addMappingType(java.lang.String)
256     */
257    public void addMappingType(String mapping) {
258
259        // this configuration does not support parameters
260        if (LOG.isDebugEnabled()) {
261            LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_MAPPING_TYPE_2, mapping, this));
262        }
263        if (m_mappings == null) {
264            m_mappings = new ArrayList<String>();
265        }
266        m_mappings.add(mapping);
267    }
268
269    /**
270     * @see org.opencms.file.types.I_CmsResourceType#changeLock(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource)
271     */
272    public void changeLock(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
273    throws CmsException {
274
275        securityManager.changeLock(cms.getRequestContext(), resource);
276    }
277
278    /**
279     * @see org.opencms.file.types.I_CmsResourceType#chflags(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int)
280     */
281    public void chflags(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, int flags)
282    throws CmsException {
283
284        securityManager.chflags(cms.getRequestContext(), resource, flags);
285    }
286
287    /**
288     * @see org.opencms.file.types.I_CmsResourceType#chtype(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, org.opencms.file.types.I_CmsResourceType)
289     */
290    public void chtype(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, I_CmsResourceType type)
291    throws CmsException {
292
293        // TODO: Refactor driver layer to use resource type id classes (or names) instead of int
294        chtype(cms, securityManager, resource, type.getTypeId());
295    }
296
297    /**
298     * @see org.opencms.file.types.I_CmsResourceType#chtype(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int)
299     *
300     * @deprecated
301     * Use {@link #chtype(CmsObject, CmsSecurityManager, CmsResource, I_CmsResourceType)} instead.
302     * Resource types should always be referenced either by its type class (preferred) or by type name.
303     * Use of int based resource type references will be discontinued in a future OpenCms release.
304     */
305    @Deprecated
306    public void chtype(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, int type)
307    throws CmsException {
308
309        // change type
310        securityManager.chtype(cms.getRequestContext(), resource, type);
311        // type may have changed from non link parseable to link parseable
312        createRelations(cms, securityManager, resource.getRootPath());
313    }
314
315    /**
316     * @see org.opencms.file.types.I_CmsResourceType#copyResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, java.lang.String, CmsResource.CmsResourceCopyMode)
317     */
318    public void copyResource(
319        CmsObject cms,
320        CmsSecurityManager securityManager,
321        CmsResource source,
322        String destination,
323        CmsResource.CmsResourceCopyMode siblingMode)
324    throws CmsException {
325
326        securityManager.copyResource(
327            cms.getRequestContext(),
328            source,
329            cms.getRequestContext().addSiteRoot(destination),
330            siblingMode);
331        // create the relations for the new resource, this could be improved by an sql query for copying relations
332        createRelations(cms, securityManager, cms.getRequestContext().addSiteRoot(destination));
333    }
334
335    /**
336     * @see org.opencms.file.types.I_CmsResourceType#copyResourceToProject(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource)
337     */
338    public void copyResourceToProject(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
339    throws CmsException {
340
341        securityManager.copyResourceToProject(cms.getRequestContext(), resource);
342    }
343
344    /**
345     * @see org.opencms.file.types.I_CmsResourceType#createResource(org.opencms.file.CmsObject, CmsSecurityManager, java.lang.String, byte[], List)
346     */
347    public CmsResource createResource(
348        CmsObject cms,
349        CmsSecurityManager securityManager,
350        String resourcename,
351        byte[] content,
352        List<CmsProperty> properties)
353    throws CmsException {
354
355        // initialize a macro resolver with the current user OpenCms context
356        CmsMacroResolver resolver = getMacroResolver(cms, resourcename);
357
358        // add the predefined property values from the XML configuration to the resource
359        List<CmsProperty> newProperties = processDefaultProperties(properties, resolver);
360
361        CmsResource result = securityManager.createResource(
362            cms.getRequestContext(),
363            cms.getRequestContext().addSiteRoot(resourcename),
364            getTypeId(),
365            content,
366            newProperties);
367
368        if ((m_internal != null) && m_internal.booleanValue()) {
369            securityManager.chflags(cms.getRequestContext(), result, result.getFlags() ^ CmsResource.FLAG_INTERNAL);
370        }
371
372        // process the (optional) copy resources from the configuration
373        processCopyResources(cms, resourcename, resolver);
374
375        // create the relations for the new resource
376        createRelations(cms, securityManager, cms.getRequestContext().addSiteRoot(resourcename));
377
378        // return the created resource
379        return result;
380    }
381
382    /**
383     * @see org.opencms.file.types.I_CmsResourceType#createSibling(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, CmsResource, java.lang.String, java.util.List)
384     */
385    public CmsResource createSibling(
386        CmsObject cms,
387        CmsSecurityManager securityManager,
388        CmsResource source,
389        String destination,
390        List<CmsProperty> properties)
391    throws CmsException {
392
393        CmsResource sibling = securityManager.createSibling(
394            cms.getRequestContext(),
395            source,
396            cms.getRequestContext().addSiteRoot(destination),
397            properties);
398        // create the relations for the new resource, this could be improved by an sql query for copying relations
399        createRelations(cms, securityManager, sibling.getRootPath());
400        return sibling;
401    }
402
403    /**
404     * @see org.opencms.file.types.I_CmsResourceType#deleteResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceDeleteMode)
405     */
406    public void deleteResource(
407        CmsObject cms,
408        CmsSecurityManager securityManager,
409        CmsResource resource,
410        CmsResource.CmsResourceDeleteMode siblingMode)
411    throws CmsException {
412
413        securityManager.deleteResource(cms.getRequestContext(), resource, siblingMode);
414    }
415
416    /**
417     * Returns <code>true</code>, if this resource type is equal to the given Object.<p>
418     *
419     * Please note: A resource type is identified by it's id {@link #getTypeId()} and it's name {@link #getTypeName()}.
420     * Two resource types are considered equal, if either their id or their name is equal.
421     * This is to prevent issues in the configuration with multiple occurrences of the same name or id.<p>
422     *
423     * @param obj the Object to compare this resource type with
424     *
425     * @return <code>true</code>, if this resource type is equal to the given Object
426     *
427     * @see #getTypeId()
428     * @see #getTypeName()
429     * @see #isIdentical(I_CmsResourceType)
430     * @see java.lang.Object#equals(java.lang.Object)
431     */
432    @Override
433    public boolean equals(Object obj) {
434
435        if (obj == this) {
436            return true;
437        }
438        if (obj instanceof I_CmsResourceType) {
439            I_CmsResourceType other = (I_CmsResourceType)obj;
440            if ((getTypeName() != null) && (getTypeName().equals(other.getTypeName()))) {
441                return true;
442            }
443            if (getTypeId() == other.getTypeId()) {
444                return true;
445            }
446        }
447        return false;
448    }
449
450    /**
451     * @see org.opencms.file.types.I_CmsResourceType#getAdjustLinksFolder()
452     */
453    public String getAdjustLinksFolder() {
454
455        return m_adjustLinksFolder;
456    }
457
458    /**
459     * @see org.opencms.file.types.I_CmsResourceType#getCachePropertyDefault()
460     */
461    public String getCachePropertyDefault() {
462
463        return null;
464    }
465
466    /**
467     * Returns the configured class name of this resource type.<p>
468     *
469     * @see org.opencms.file.types.I_CmsResourceType#getClassName()
470     */
471    public String getClassName() {
472
473        return m_className;
474    }
475
476    /**
477     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#getConfiguration()
478     */
479    public CmsParameterConfiguration getConfiguration() {
480
481        if (LOG.isDebugEnabled()) {
482            LOG.debug(Messages.get().getBundle().key(Messages.LOG_GET_CONFIGURATION_1, this));
483        }
484
485        return m_configuration;
486    }
487
488    /**
489     * Returns the (unmodifiable) list of copy resources.<p>
490     *
491     * @return the (unmodifiable) list of copy resources
492     */
493    public List<CmsConfigurationCopyResource> getConfiguredCopyResources() {
494
495        return m_copyResources;
496    }
497
498    /**
499     * Returns the default properties for this resource type in an unmodifiable List.<p>
500     *
501     * @return the default properties for this resource type in an unmodifiable List
502     */
503    public List<CmsProperty> getConfiguredDefaultProperties() {
504
505        return m_defaultProperties;
506    }
507
508    /**
509     * @see org.opencms.file.types.I_CmsResourceType#getConfiguredMappings()
510     */
511    public List<String> getConfiguredMappings() {
512
513        return m_mappings;
514    }
515
516    /**
517     *
518     * @see org.opencms.file.types.I_CmsResourceType#getFormattersForResource(org.opencms.file.CmsObject, org.opencms.file.CmsResource)
519     */
520    public CmsFormatterConfiguration getFormattersForResource(CmsObject cms, CmsResource res) {
521
522        return CmsFormatterConfiguration.EMPTY_CONFIGURATION;
523    }
524
525    /**
526     * @see org.opencms.file.types.I_CmsResourceType#getGalleryPreviewProvider()
527     */
528    public String getGalleryPreviewProvider() {
529
530        if (m_galleryPreviewProvider == null) {
531            m_galleryPreviewProvider = getConfiguration().getString(CONFIGURATION_GALLERY_PREVIEW_PROVIDER, null);
532        }
533        return m_galleryPreviewProvider;
534    }
535
536    /**
537     * @see org.opencms.file.types.I_CmsResourceType#getGalleryTypes()
538     */
539    public List<I_CmsResourceType> getGalleryTypes() {
540
541        if (m_galleryTypes == null) {
542            m_galleryTypes = new ArrayList<I_CmsResourceType>();
543            if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_galleryTypeNames)) {
544                CmsResourceManager rm = OpenCms.getResourceManager();
545                Iterator<String> iTypeNames = CmsStringUtil.splitAsList(
546                    m_galleryTypeNames,
547                    CmsProperty.VALUE_LIST_DELIMITER).iterator();
548                while (iTypeNames.hasNext()) {
549                    String typeName = iTypeNames.next();
550                    try {
551                        m_galleryTypes.add(rm.getResourceType(typeName));
552                    } catch (CmsLoaderException e) {
553                        if (LOG.isWarnEnabled()) {
554                            LOG.warn(Messages.get().container(Messages.ERR_COULD_NOT_READ_RESOURCE_TYPE_1, typeName));
555                        }
556                    }
557                }
558            }
559
560        }
561        return m_galleryTypes;
562    }
563
564    /**
565     * @see org.opencms.file.types.I_CmsResourceType#getLoaderId()
566     */
567    public abstract int getLoaderId();
568
569    /**
570     * @see org.opencms.file.types.I_CmsResourceType#getModuleName()
571     */
572    public String getModuleName() {
573
574        return m_moduleName;
575    }
576
577    /**
578     * @see org.opencms.file.types.I_CmsResourceType#getTypeId()
579     *
580     * @deprecated
581     * Use this class or {@link #getTypeName()} instead.
582     * Resource types should always be referenced either by its type class (preferred) or by type name.
583     * Use of int based resource type references will be discontinued in a future OpenCms release.
584     */
585    @Deprecated
586    public int getTypeId() {
587
588        return m_typeId;
589    }
590
591    /**
592     * @see org.opencms.file.types.I_CmsResourceType#getTypeName()
593     */
594    public String getTypeName() {
595
596        return m_typeName;
597    }
598
599    /**
600     * The hash code implementation uses the type name to generate a hash code.<p>
601     *
602     * @see #getTypeId()
603     * @see java.lang.Object#hashCode()
604     */
605    @Override
606    public int hashCode() {
607
608        return getTypeName().hashCode();
609    }
610
611    /**
612     * @see org.opencms.file.types.I_CmsResourceType#importResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.report.I_CmsReport, java.lang.String, org.opencms.file.CmsResource, byte[], java.util.List)
613     */
614    public CmsResource importResource(
615        CmsObject cms,
616        CmsSecurityManager securityManager,
617        I_CmsReport report,
618        String resourcename,
619        CmsResource resource,
620        byte[] content,
621        List<CmsProperty> properties)
622    throws CmsException {
623
624        // this triggers the internal "is touched" state
625        // and prevents the security manager from inserting the current time
626        resource.setDateLastModified(resource.getDateLastModified());
627        // ensure resource record is updated
628        resource.setState(CmsResource.STATE_NEW);
629        return securityManager.importResource(
630            cms.getRequestContext(),
631            cms.getRequestContext().addSiteRoot(resourcename),
632            resource,
633            content,
634            properties,
635            true);
636    }
637
638    /**
639     * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration()
640     */
641    public final void initConfiguration() {
642
643        // final since subclasses should NOT implement this, but rather the version with 3 String parameters (see below)
644        if (LOG.isDebugEnabled()) {
645            LOG.debug(Messages.get().getBundle().key(Messages.LOG_INIT_CONFIGURATION_1, this));
646        }
647    }
648
649    /**
650     * @see org.opencms.file.types.I_CmsResourceType#initConfiguration(java.lang.String, java.lang.String, java.lang.String)
651     */
652    public void initConfiguration(String name, String id, String className) throws CmsConfigurationException {
653
654        if (LOG.isDebugEnabled()) {
655            LOG.debug(Messages.get().getBundle().key(Messages.LOG_INIT_CONFIGURATION_3, this, name, id));
656        }
657
658        if (m_frozen) {
659            // configuration already frozen
660            throw new CmsConfigurationException(
661                org.opencms.configuration.Messages.get().container(
662                    org.opencms.file.types.Messages.ERR_CONFIG_FROZEN_3,
663                    className,
664                    getTypeName(),
665                    Integer.valueOf(getTypeId())));
666        }
667
668        // freeze the configuration
669        m_frozen = true;
670
671        // set type name and id (please note that some resource types have a fixed type / id)
672        if (name != null) {
673            m_typeName = name;
674        }
675        if (id != null) {
676            m_typeId = Integer.valueOf(id).intValue();
677        }
678        if (className != null) {
679            m_className = className;
680        }
681
682        // check type id, type name and class name
683        if ((getTypeName() == null)
684            || (getClassName() == null)
685            || ((getTypeId() < 0)
686                && (!m_typeName.equals(CmsResourceTypeUnknownFile.getStaticTypeName()))
687                && (!m_typeName.equals(CmsResourceTypeUnknownFolder.getStaticTypeName())))) {
688            throw new CmsConfigurationException(
689                Messages.get().container(
690                    Messages.ERR_INVALID_RESTYPE_CONFIG_3,
691                    className,
692                    m_typeName,
693                    Integer.valueOf(m_typeId)));
694        }
695
696        m_defaultProperties = Collections.unmodifiableList(m_defaultProperties);
697        m_copyResources = Collections.unmodifiableList(m_copyResources);
698        m_mappings = Collections.unmodifiableList(m_mappings);
699        m_configuration = CmsParameterConfiguration.unmodifiableVersion(m_configuration);
700    }
701
702    /**
703     * @see org.opencms.file.types.I_CmsResourceType#initialize(org.opencms.file.CmsObject)
704     */
705    public void initialize(CmsObject cms) {
706
707        // most resource type do not require any runtime information
708        if (LOG.isDebugEnabled()) {
709            LOG.debug(Messages.get().getBundle().key(Messages.LOG_INITIALIZE_1, this));
710        }
711    }
712
713    /**
714     * @see org.opencms.file.types.I_CmsResourceType#isAdditionalModuleResourceType()
715     */
716    public boolean isAdditionalModuleResourceType() {
717
718        return m_addititionalModuleResourceType;
719    }
720
721    /**
722     * @see org.opencms.file.types.I_CmsResourceType#isDirectEditable()
723     */
724    public boolean isDirectEditable() {
725
726        return false;
727    }
728
729    /**
730     * @see org.opencms.file.types.I_CmsResourceType#isFolder()
731     */
732    public boolean isFolder() {
733
734        return false;
735    }
736
737    /**
738     * @see org.opencms.file.types.I_CmsResourceType#isIdentical(org.opencms.file.types.I_CmsResourceType)
739     */
740    public boolean isIdentical(I_CmsResourceType type) {
741
742        if (type == null) {
743            return false;
744        }
745
746        return (getTypeId() == type.getTypeId()) && (getTypeName().equals(type.getTypeName()));
747    }
748
749    /**
750     * @see org.opencms.file.types.I_CmsResourceType#lockResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, org.opencms.lock.CmsLockType)
751     */
752    public void lockResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, CmsLockType type)
753    throws CmsException {
754
755        securityManager.lockResource(cms.getRequestContext(), resource, type);
756    }
757
758    /**
759     * @see org.opencms.file.types.I_CmsResourceType#moveResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, java.lang.String)
760     */
761    public void moveResource(
762        CmsObject cms,
763        CmsSecurityManager securityManager,
764        CmsResource resource,
765        String destination)
766    throws CmsException, CmsIllegalArgumentException {
767
768        String dest = cms.getRequestContext().addSiteRoot(destination);
769        if (resource.getRootPath().equals(dest)) {
770            // move to target with same name is not allowed
771            throw new CmsVfsException(
772                org.opencms.file.Messages.get().container(org.opencms.file.Messages.ERR_MOVE_SAME_NAME_1, destination));
773        }
774        // check the destination
775        try {
776            securityManager.readResource(cms.getRequestContext(), dest, CmsResourceFilter.ALL);
777            throw new CmsVfsException(
778                org.opencms.file.Messages.get().container(
779                    org.opencms.file.Messages.ERR_OVERWRITE_RESOURCE_2,
780                    cms.getRequestContext().removeSiteRoot(resource.getRootPath()),
781                    destination));
782        } catch (CmsVfsResourceNotFoundException e) {
783            // ok
784        }
785        String targetName = CmsResource.getName(destination).replace("/", "");
786        CmsResource.checkResourceName(targetName);
787        // move
788        securityManager.moveResource(cms.getRequestContext(), resource, dest);
789    }
790
791    /**
792     * @see org.opencms.file.types.I_CmsResourceType#removeResourceFromProject(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource)
793     */
794    public void removeResourceFromProject(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
795    throws CmsException {
796
797        securityManager.removeResourceFromProject(cms.getRequestContext(), resource);
798    }
799
800    /**
801     * @see org.opencms.file.types.I_CmsResourceType#replaceResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsResource, org.opencms.file.types.I_CmsResourceType, byte[], java.util.List)
802     */
803    public void replaceResource(
804        CmsObject cms,
805        CmsSecurityManager securityManager,
806        CmsResource resource,
807        I_CmsResourceType type,
808        byte[] content,
809        List<CmsProperty> properties)
810    throws CmsException {
811
812        // TODO: Refactor driver layer to use resource type id classes (or names) instead of int
813        replaceResource(cms, securityManager, resource, type.getTypeId(), content, properties);
814    }
815
816    /**
817     * @see org.opencms.file.types.I_CmsResourceType#replaceResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int, byte[], List)
818     *
819     * @deprecated
820     * Use {@link #replaceResource(CmsObject, CmsSecurityManager, CmsResource, I_CmsResourceType, byte[], List)} instead.
821     * Resource types should always be referenced either by its type class (preferred) or by type name.
822     * Use of int based resource type references will be discontinued in a future OpenCms release.
823     */
824    @Deprecated
825    public void replaceResource(
826        CmsObject cms,
827        CmsSecurityManager securityManager,
828        CmsResource resource,
829        int type,
830        byte[] content,
831        List<CmsProperty> properties)
832    throws CmsException {
833
834        securityManager.replaceResource(cms.getRequestContext(), resource, type, content, properties);
835        // type may have changed from non link parseable to link parseable
836        createRelations(cms, securityManager, resource.getRootPath());
837    }
838
839    /**
840     * @see org.opencms.file.types.I_CmsResourceType#restoreResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, int)
841     */
842    public void restoreResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, int version)
843    throws CmsException {
844
845        securityManager.restoreResource(cms.getRequestContext(), resource, version);
846        // type may have changed from non link parseable to link parseable
847        createRelations(cms, securityManager, resource.getRootPath());
848    }
849
850    /**
851     * @see org.opencms.file.types.I_CmsResourceType#setAdditionalModuleResourceType(boolean)
852     */
853    public void setAdditionalModuleResourceType(boolean additionalType) {
854
855        m_addititionalModuleResourceType = additionalType;
856    }
857
858    /**
859     * @see org.opencms.file.types.I_CmsResourceType#setAdjustLinksFolder(String)
860     */
861    public void setAdjustLinksFolder(String adjustLinksFolder) {
862
863        m_adjustLinksFolder = adjustLinksFolder;
864    }
865
866    /**
867     * @see org.opencms.file.types.I_CmsResourceType#setDateExpired(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean)
868     */
869    public void setDateExpired(
870        CmsObject cms,
871        CmsSecurityManager securityManager,
872        CmsResource resource,
873        long dateExpired,
874        boolean recursive)
875    throws CmsException {
876
877        securityManager.setDateExpired(cms.getRequestContext(), resource, dateExpired);
878    }
879
880    /**
881     * @see org.opencms.file.types.I_CmsResourceType#setDateLastModified(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean)
882     */
883    public void setDateLastModified(
884        CmsObject cms,
885        CmsSecurityManager securityManager,
886        CmsResource resource,
887        long dateLastModified,
888        boolean recursive)
889    throws CmsException {
890
891        securityManager.setDateLastModified(cms.getRequestContext(), resource, dateLastModified);
892    }
893
894    /**
895     * @see org.opencms.file.types.I_CmsResourceType#setDateReleased(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, long, boolean)
896     */
897    public void setDateReleased(
898        CmsObject cms,
899        CmsSecurityManager securityManager,
900        CmsResource resource,
901        long dateReleased,
902        boolean recursive)
903    throws CmsException {
904
905        securityManager.setDateReleased(cms.getRequestContext(), resource, dateReleased);
906    }
907
908    /**
909     * @see org.opencms.file.types.I_CmsResourceType#setModuleName(java.lang.String)
910     */
911    public void setModuleName(String moduleName) {
912
913        m_moduleName = moduleName;
914    }
915
916    /**
917     * @see java.lang.Object#toString()
918     */
919    @Override
920    public String toString() {
921
922        StringBuffer output = new StringBuffer();
923        output.append("[ResourceType] class=");
924        output.append(getClass().getName());
925        output.append(" name=");
926        output.append(getTypeName());
927        output.append(" id=");
928        output.append(getTypeId());
929        output.append(" loaderId=");
930        output.append(getLoaderId());
931        return output.toString();
932    }
933
934    /**
935     * @see org.opencms.file.types.I_CmsResourceType#undelete(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, boolean)
936     */
937    public void undelete(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource, boolean recursive)
938    throws CmsException {
939
940        securityManager.undelete(cms.getRequestContext(), resource);
941    }
942
943    /**
944     * @see org.opencms.file.types.I_CmsResourceType#undoChanges(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource, CmsResource.CmsResourceUndoMode)
945     */
946    public void undoChanges(
947        CmsObject cms,
948        CmsSecurityManager securityManager,
949        CmsResource resource,
950        CmsResource.CmsResourceUndoMode mode)
951    throws CmsException {
952
953        securityManager.undoChanges(cms.getRequestContext(), resource, mode);
954        updateRelationForUndo(cms, securityManager, resource);
955    }
956
957    /**
958     * @see org.opencms.file.types.I_CmsResourceType#unlockResource(org.opencms.file.CmsObject, CmsSecurityManager, CmsResource)
959     */
960    public void unlockResource(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
961    throws CmsException {
962
963        securityManager.unlockResource(cms.getRequestContext(), resource);
964    }
965
966    /**
967     * @see org.opencms.file.types.I_CmsResourceType#writeFile(org.opencms.file.CmsObject, CmsSecurityManager, CmsFile)
968     */
969    public CmsFile writeFile(CmsObject cms, CmsSecurityManager securityManager, CmsFile resource) throws CmsException {
970
971        if (resource.isFile()) {
972            CmsFile file = securityManager.writeFile(cms.getRequestContext(), resource);
973            I_CmsResourceType type = getResourceType(file);
974            // update the relations after writing!!
975            List<CmsLink> links = null;
976            if (type instanceof I_CmsLinkParseable) { // this check is needed because of type change
977                // if the new type is link parseable
978                links = ((I_CmsLinkParseable)type).parseLinks(cms, file);
979            }
980            // this has to be always executed, even if not link parseable to remove old links
981            securityManager.updateRelationsForResource(cms.getRequestContext(), file, links);
982            return file;
983        }
984        // folders can never be written like a file
985        throw new CmsVfsException(
986            Messages.get().container(Messages.ERR_WRITE_FILE_IS_FOLDER_1, cms.getSitePath(resource)));
987    }
988
989    /**
990     * @see org.opencms.file.types.I_CmsResourceType#writePropertyObject(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, CmsResource, org.opencms.file.CmsProperty)
991     */
992    public void writePropertyObject(
993        CmsObject cms,
994        CmsSecurityManager securityManager,
995        CmsResource resource,
996        CmsProperty property)
997    throws CmsException {
998
999        securityManager.writePropertyObject(cms.getRequestContext(), resource, property);
1000    }
1001
1002    /**
1003     * @see org.opencms.file.types.I_CmsResourceType#writePropertyObjects(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, CmsResource, java.util.List)
1004     */
1005    public void writePropertyObjects(
1006        CmsObject cms,
1007        CmsSecurityManager securityManager,
1008        CmsResource resource,
1009        List<CmsProperty> properties)
1010    throws CmsException {
1011
1012        securityManager.writePropertyObjects(cms.getRequestContext(), resource, properties);
1013    }
1014
1015    /**
1016     * Creates the relation information for the resource with the given resource name.<p>
1017     *
1018     * @param cms the cms context
1019     * @param securityManager the security manager
1020     * @param resourceName the resource name of the resource to update the relations for
1021     *
1022     * @return the fresh read resource
1023     *
1024     * @throws CmsException if something goes wrong
1025     */
1026    protected CmsResource createRelations(CmsObject cms, CmsSecurityManager securityManager, String resourceName)
1027    throws CmsException {
1028
1029        CmsResource resource = securityManager.readResource(
1030            cms.getRequestContext(),
1031            resourceName,
1032            CmsResourceFilter.ALL);
1033        I_CmsResourceType resourceType = getResourceType(resource);
1034        List<CmsLink> links = null;
1035        if (resourceType instanceof I_CmsLinkParseable) {
1036            I_CmsLinkParseable linkParseable = (I_CmsLinkParseable)resourceType;
1037            links = linkParseable.parseLinks(cms, cms.readFile(resource));
1038        }
1039        securityManager.updateRelationsForResource(cms.getRequestContext(), resource, links);
1040        return resource;
1041    }
1042
1043    /**
1044     * Gets the actual copy resources to use when creating a resource.
1045     *
1046     * @param cms the CMS context
1047     * @param resourcename the path of the resource to create
1048     * @param resolver the macro resolver to use
1049     *
1050     * @return the copy resources to use
1051     */
1052    protected List<CmsConfigurationCopyResource> getCopyResources(
1053        CmsObject cms,
1054        String resourcename,
1055        CmsMacroResolver resolver) {
1056
1057        return m_copyResources;
1058    }
1059
1060    /**
1061     * Creates a macro resolver based on the current users OpenCms context and the provided resource name.<p>
1062     *
1063     * @param cms the current OpenCms user context
1064     * @param resourcename the resource name for macros like {@link A_CmsResourceType#MACRO_RESOURCE_FOLDER_PATH}
1065     *
1066     * @return a macro resolver based on the current users OpenCms context and the provided resource name
1067     */
1068    protected CmsMacroResolver getMacroResolver(CmsObject cms, String resourcename) {
1069
1070        CmsMacroResolver result = CmsMacroResolver.newInstance().setCmsObject(cms);
1071        if (isFolder() && (!CmsResource.isFolder(resourcename))) {
1072            // ensure folder ends with "/" so
1073            resourcename = resourcename.concat("/");
1074        }
1075        // add special mappings for macros in default properties
1076        result.addMacro(MACRO_RESOURCE_ROOT_PATH, cms.getRequestContext().addSiteRoot(resourcename));
1077        result.addMacro(MACRO_RESOURCE_SITE_PATH, resourcename);
1078        result.addMacro(MACRO_RESOURCE_FOLDER_PATH, CmsResource.getFolderPath(resourcename));
1079        result.addMacro(MACRO_RESOURCE_FOLDER_PATH_TOUCH, CmsResource.getFolderPath(resourcename));
1080        result.addMacro(MACRO_RESOURCE_PARENT_PATH, CmsResource.getParentFolder(resourcename));
1081        result.addMacro(MACRO_RESOURCE_NAME, CmsResource.getName(resourcename));
1082
1083        return result;
1084    }
1085
1086    /**
1087     * Convenience method to get the initialized resource type instance for the given resource,
1088     * with a fall back to special "unknown" resource types in case the resource type is not configured.<p>
1089     *
1090     * @param resource the resource to get the type for
1091     *
1092     * @return the initialized resource type instance for the given resource
1093     *
1094     * @see org.opencms.loader.CmsResourceManager#getResourceType(int)
1095     */
1096    protected I_CmsResourceType getResourceType(CmsResource resource) {
1097
1098        return OpenCms.getResourceManager().getResourceType(resource);
1099    }
1100
1101    /**
1102     * Processes the copy resources of this resource type.<p>
1103     *
1104     * @param cms the current OpenCms user context
1105     * @param resourcename the name of the base resource
1106     * @param resolver the resolver used for resolving target macro names
1107     */
1108    protected void processCopyResources(CmsObject cms, String resourcename, CmsMacroResolver resolver) {
1109
1110        Map<String, String> copiedResources = new HashMap<String, String>();
1111        for (CmsConfigurationCopyResource oriCopyResource : getCopyResources(cms, resourcename, resolver)) {
1112
1113            // store original copy target
1114            String oriTarget = oriCopyResource.getTarget();
1115            String target = oriTarget;
1116
1117            List<CmsConfigurationCopyResource> copyResources = new ArrayList<CmsConfigurationCopyResource>();
1118            try {
1119                // determine if source definition has a wild card character at the end
1120                if (oriCopyResource.getSource().endsWith("*")) {
1121                    // add all sub resources of the specified source folder to the set of resources to copy
1122                    String source = oriCopyResource.getSource().substring(0, oriCopyResource.getSource().length() - 1);
1123                    List<CmsResource> sources = cms.readResources(source, CmsResourceFilter.IGNORE_EXPIRATION, false);
1124                    for (CmsResource sourceRes : sources) {
1125                        copyResources.add(
1126                            new CmsConfigurationCopyResource(
1127                                cms.getSitePath(sourceRes),
1128                                oriCopyResource.getTarget(),
1129                                oriCopyResource.getTypeString()));
1130                    }
1131                    copiedResources.put(source, resolver.resolveMacros(target));
1132                } else {
1133                    // just add the single specified source
1134                    copyResources.add(oriCopyResource);
1135                }
1136
1137                // loop the calculated resources to copy
1138                for (CmsConfigurationCopyResource copyResource : copyResources) {
1139
1140                    target = copyResource.getTarget();
1141                    if (copyResource.isTargetWasNull()
1142                        || CmsMacroResolver.isMacro(target, MACRO_RESOURCE_FOLDER_PATH)
1143                        || CmsMacroResolver.isMacro(target, MACRO_RESOURCE_FOLDER_PATH_TOUCH)) {
1144                        // target is just the resource folder, must add source file name to target
1145                        target = target.concat(CmsResource.getName(copyResource.getSource()));
1146                    }
1147                    // now resolve the macros in the target name
1148                    target = resolver.resolveMacros(target);
1149                    // now resolve possible relative paths in the target
1150                    target = CmsFileUtil.normalizePath(CmsLinkManager.getAbsoluteUri(target, resourcename), '/');
1151
1152                    // copy the resource
1153                    cms.copyResource(copyResource.getSource(), target, copyResource.getType());
1154                    copiedResources.put(copyResource.getSource(), target);
1155                    if (CmsMacroResolver.isMacro(oriTarget, MACRO_RESOURCE_FOLDER_PATH_TOUCH)) {
1156                        // copied resources should be touched in order to be able to do additional stuff
1157                        CmsResource res = cms.readResource(target);
1158                        if (res.isFile()) {
1159                            // single file, just rewrite it
1160                            CmsFile file = cms.readFile(res);
1161                            cms.writeFile(file);
1162                        } else {
1163                            // folder, get all sub resources that are files
1164                            Iterator<CmsResource> it = cms.readResources(
1165                                target,
1166                                CmsResourceFilter.DEFAULT_FILES,
1167                                true).iterator();
1168                            while (it.hasNext()) {
1169                                // rewrite the sub resource
1170                                CmsResource subRes = it.next();
1171                                CmsFile file = cms.readFile(subRes);
1172                                cms.writeFile(file);
1173                            }
1174                        }
1175                    }
1176
1177                }
1178            } catch (Exception e) {
1179                // CmsIllegalArgumentException as well as CmsException
1180                // log the error and continue with the other copy resources
1181                if (LOG.isDebugEnabled()) {
1182                    // log stack trace in debug level only
1183                    LOG.debug(
1184                        Messages.get().getBundle().key(
1185                            Messages.LOG_PROCESS_COPY_RESOURCES_3,
1186                            resourcename,
1187                            oriCopyResource,
1188                            target),
1189                        e);
1190                } else {
1191                    LOG.error(
1192                        Messages.get().getBundle().key(
1193                            Messages.LOG_PROCESS_COPY_RESOURCES_3,
1194                            resourcename,
1195                            oriCopyResource,
1196                            target));
1197                }
1198            }
1199        }
1200        // only adjust links for successfully copied resources and if the feature is enabled
1201        try {
1202            if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_adjustLinksFolder) && !copiedResources.isEmpty()) {
1203                String realAdjustFolderPath = resolver.resolveMacros(m_adjustLinksFolder);
1204                cms.adjustLinks(copiedResources, realAdjustFolderPath);
1205            }
1206        } catch (CmsException e) {
1207            LOG.error(e.getLocalizedMessage(), e);
1208        } catch (CmsIllegalArgumentException e) {
1209            LOG.error(e.getLocalizedMessage(), e);
1210        }
1211    }
1212
1213    /**
1214     * Returns a list of property objects that are attached to the resource on creation.<p>
1215     *
1216     * It's possible to use OpenCms macros for the property values.
1217     * Please see {@link CmsMacroResolver} for allowed macro values.<p>
1218     *
1219     * @param properties the (optional) properties provided by the user
1220     * @param resolver the resolver used to resolve the macro values
1221     *
1222     * @return a list of property objects that are attached to the resource on creation
1223     */
1224    protected List<CmsProperty> processDefaultProperties(List<CmsProperty> properties, CmsMacroResolver resolver) {
1225
1226        if ((m_defaultProperties == null) || (m_defaultProperties.size() == 0)) {
1227            // no default properties are defined
1228            return properties;
1229        }
1230
1231        // the properties must be copied since the macros could contain macros that are
1232        // resolved differently for every user / context
1233        ArrayList<CmsProperty> result = new ArrayList<CmsProperty>();
1234        Iterator<CmsProperty> i = m_defaultProperties.iterator();
1235
1236        while (i.hasNext()) {
1237            // create a clone of the next property
1238            CmsProperty property = (i.next()).clone();
1239
1240            // resolve possible macros in the property values
1241            if (property.getResourceValue() != null) {
1242                property.setResourceValue(resolver.resolveMacros(property.getResourceValue()));
1243            }
1244            if (property.getStructureValue() != null) {
1245                property.setStructureValue(resolver.resolveMacros(property.getStructureValue()));
1246            }
1247
1248            // save the new property in the result list
1249            result.add(property);
1250        }
1251
1252        // add the original properties
1253        if (properties != null) {
1254            result.addAll(properties);
1255        }
1256
1257        // return the result
1258        return result;
1259    }
1260
1261    /**
1262     * Update the relations after an undo changes operation.<p>
1263     *
1264     * @param cms the cms context
1265     * @param securityManager the security manager
1266     * @param resource the resource that has been undone
1267     *
1268     * @throws CmsException if something goes wrong
1269     */
1270    protected void updateRelationForUndo(CmsObject cms, CmsSecurityManager securityManager, CmsResource resource)
1271    throws CmsException {
1272
1273        // type may have changed from non link parseable to link parseable
1274        CmsResource undoneResource1 = null;
1275        try {
1276            // first try to locate the resource by path
1277            undoneResource1 = createRelations(cms, securityManager, resource.getRootPath());
1278        } catch (CmsVfsResourceNotFoundException e) {
1279            // ignore, undone move operation
1280        }
1281        // now, in case a move operation has been undone, locate the resource by id
1282        CmsResource undoneResource2 = securityManager.readResource(
1283            cms.getRequestContext(),
1284            resource.getStructureId(),
1285            CmsResourceFilter.ALL);
1286        if (!undoneResource2.equals(undoneResource1)) {
1287            I_CmsResourceType resourceType = getResourceType(resource);
1288            List<CmsLink> links = null;
1289            if (resourceType instanceof I_CmsLinkParseable) {
1290                I_CmsLinkParseable linkParseable = (I_CmsLinkParseable)resourceType;
1291                if ((undoneResource1 == null) || !undoneResource2.getRootPath().equals(undoneResource1.getRootPath())) {
1292                    try {
1293                        links = linkParseable.parseLinks(cms, cms.readFile(undoneResource2));
1294                    } catch (CmsException e) {
1295                        if (LOG.isWarnEnabled()) {
1296                            LOG.warn(e.getLocalizedMessage(), e);
1297                        }
1298                    } catch (CmsRuntimeException e) {
1299                        if (LOG.isWarnEnabled()) {
1300                            LOG.warn(e.getLocalizedMessage(), e);
1301                        }
1302                    }
1303                }
1304            }
1305            securityManager.updateRelationsForResource(cms.getRequestContext(), undoneResource2, links);
1306        }
1307    }
1308}