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.module;
029
030import org.opencms.db.CmsExportPoint;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsResource;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.file.types.I_CmsResourceType;
035import org.opencms.main.CmsException;
036import org.opencms.main.CmsIllegalArgumentException;
037import org.opencms.main.CmsLog;
038import org.opencms.main.OpenCms;
039import org.opencms.security.CmsRole;
040import org.opencms.security.CmsRoleViolationException;
041import org.opencms.util.CmsFileUtil;
042import org.opencms.util.CmsStringUtil;
043import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
044
045import java.io.Serializable;
046import java.util.ArrayList;
047import java.util.Collections;
048import java.util.List;
049import java.util.Map;
050import java.util.SortedMap;
051import java.util.StringTokenizer;
052import java.util.TreeMap;
053
054import org.apache.commons.logging.Log;
055
056import com.google.common.collect.Lists;
057
058/**
059 * Describes an OpenCms module.<p>
060 *
061 * OpenCms modules provide a standard mechanism to extend the OpenCms functionality.
062 * Modules can contain VFS data, Java classes and a number of configuration options.<p>
063 *
064 * @since 6.0.0
065 *
066 * @see org.opencms.module.I_CmsModuleAction
067 * @see org.opencms.module.A_CmsModuleAction
068 */
069public class CmsModule implements Comparable<CmsModule>, Serializable {
070
071    /** The available module export modes. */
072    public enum ExportMode {
073
074        /** Default export mode. */
075        DEFAULT,
076        /** Reduced export, that omits last modification information (dates and users). */
077        REDUCED;
078
079        /**
080         * @see java.lang.Enum#toString()
081         */
082        @Override
083        public String toString() {
084
085            return super.toString().toLowerCase();
086        }
087    }
088
089    /** The default date for module created / installed if not provided. */
090    public static final long DEFAULT_DATE = 0L;
091
092    /** The log object for this class. */
093    private static final Log LOG = CmsLog.getLog(CmsModule.class);
094
095    /**
096     * The module property key name to specifiy additional resources which are
097     * part of a module outside of {system/modules}.
098     */
099    private static final String MODULE_PROPERTY_ADDITIONAL_RESOURCES = "additionalresources";
100
101    /** Character to separate additional resources specified in the module properties.  */
102    private static final String MODULE_PROPERTY_ADDITIONAL_RESOURCES_SEPARATOR = ";";
103
104    /** The serial version id. */
105    private static final long serialVersionUID = -2639349161445831665L;
106
107    /** The module action class name. */
108    private String m_actionClass;
109
110    /** Initialized module action instance. */
111    private transient I_CmsModuleAction m_actionInstance;
112
113    /** The email of the author of this module. */
114    private String m_authorEmail;
115
116    /** The name of the author of this module. */
117    private String m_authorName;
118
119    /** True if the module's version should be auto-incremented based on module resource changes in the VFS. */
120    private boolean m_autoIncrement;
121
122    /** Timestamp used for version auto-incrementing: if module resources have been modified after this timestamp, increment the version. */
123    private long m_checkpointTime;
124
125    /** Flag to create the classes folders when creating the module. */
126    private transient boolean m_createClassesFolder;
127
128    /** Flag to create the elements folder when creating the module. */
129    private transient boolean m_createElementsFolder;
130
131    /** Flag to create the formatters folder when creating the module. */
132    private transient boolean m_createFormattersFolder;
133
134    /** Flag to create the i18n folder when creating the module. */
135    private transient boolean m_createI18NFolder;
136
137    /** Flag to create the lib folder when creating the module. */
138    private transient boolean m_createLibFolder;
139
140    /** Flag to create the module folder when creating the module. */
141    private transient boolean m_createModuleFolder;
142
143    /** Flag to create the resources folder when creating the module. */
144    private transient boolean m_createResourcesFolder;
145
146    /** Flag to create the schemas folder when creating the module. */
147    private transient boolean m_createSchemasFolder;
148
149    /** Flag to create the template folder when creating the module. */
150    private transient boolean m_createTemplateFolder;
151
152    /** The date this module was created by the author. */
153    private long m_dateCreated;
154
155    /** The date this module was installed. */
156    private long m_dateInstalled;
157
158    /** List of dependencies of this module. */
159    private List<CmsModuleDependency> m_dependencies;
160
161    /** The description of this module. */
162    private String m_description;
163
164    /** List of VFS resources that do not belong to this module.
165     *  In particular used for files / folders in folders that belong to the module.
166     */
167    private List<String> m_excluderesources;
168
169    /** The explorer type settings. */
170    private List<CmsExplorerTypeSettings> m_explorerTypeSettings;
171
172    /** The export mode to use for the module. */
173    private ExportMode m_exportMode;
174
175    /** List of export points added by this module. */
176    private List<CmsExportPoint> m_exportPoints;
177
178    /** The export version (this is only used for module objects which have been read from a zip file). */
179    private String m_exportVersion;
180
181    /** Indicates if this modules configuration has already been frozen. */
182    private transient boolean m_frozen;
183
184    /** The group of the module. */
185    private String m_group;
186
187    /** True if the module has a fixed import site. */
188    private boolean m_hasImportSite;
189
190    /** The script to execute when the module is imported. */
191    private String m_importScript;
192
193    /** The name of this module, must be a valid Java package name. */
194    private String m_name;
195
196    /** The "nice" display name of this module. */
197    private String m_niceName;
198
199    /** A timestamp from the time this object was created. */
200    private long m_objectCreateTime = System.currentTimeMillis();
201
202    /** The additional configuration parameters of this module. */
203    private SortedMap<String, String> m_parameters;
204
205    /** List of VFS resources that belong to this module. */
206    private List<String> m_resources;
207
208    /** The list of additional resource types. */
209    private transient List<I_CmsResourceType> m_resourceTypes;
210
211    /** The module site. */
212    private String m_site;
213
214    /** The name of the user who installed this module. */
215    private String m_userInstalled;
216
217    /** The version of this module. */
218    private CmsModuleVersion m_version;
219
220    /**
221     * Creates a new, empty CmsModule object.<p>
222     */
223    public CmsModule() {
224
225        m_version = new CmsModuleVersion(CmsModuleVersion.DEFAULT_VERSION);
226        m_resources = Collections.emptyList();
227        m_excluderesources = Collections.emptyList();
228        m_exportPoints = Collections.emptyList();
229        m_dependencies = Collections.emptyList();
230        m_resourceTypes = Collections.emptyList();
231        m_explorerTypeSettings = Collections.emptyList();
232        m_parameters = new TreeMap<String, String>();
233        m_exportMode = ExportMode.DEFAULT;
234    }
235
236    /**
237     * Creates a new module description with the specified values.<p>
238     *
239     * @param name the name of this module, must be a valid Java package name
240     * @param niceName the "nice" display name of this module
241     * @param group the group of this module
242     * @param actionClass the (optional) module class name
243     * @param importScript the script to execute when the module is imported
244     * @param site the site the module belongs to
245     * @param isImportSite true if the module site should be used as a fixed import site
246     * @param exportMode the export mode that should be used for the module
247     * @param description the description of this module
248     * @param version the version of this module
249     * @param authorName the name of the author of this module
250     * @param authorEmail the email of the author of this module
251     * @param dateCreated the date this module was created by the author
252     * @param userInstalled the name of the user who uploaded this module
253     * @param dateInstalled the date this module was uploaded
254     * @param dependencies a list of dependencies of this module
255     * @param exportPoints a list of export point added by this module
256     * @param resources a list of VFS resources that belong to this module
257     * @param excluderesources a list of VFS resources that are exclude from the module's resources
258     * @param parameters the parameters for this module
259     */
260    public CmsModule(
261        String name,
262        String niceName,
263        String group,
264        String actionClass,
265        String importScript,
266        String site,
267        boolean isImportSite,
268        ExportMode exportMode,
269        String description,
270        CmsModuleVersion version,
271        String authorName,
272        String authorEmail,
273        long dateCreated,
274        String userInstalled,
275        long dateInstalled,
276        List<CmsModuleDependency> dependencies,
277        List<CmsExportPoint> exportPoints,
278        List<String> resources,
279        List<String> excluderesources,
280        Map<String, String> parameters) {
281
282        super();
283        m_name = name;
284        setNiceName(niceName);
285        setActionClass(actionClass);
286        setGroup(group);
287
288        m_exportMode = null == exportMode ? ExportMode.DEFAULT : exportMode;
289
290        if (CmsStringUtil.isEmpty(description)) {
291            m_description = "";
292        } else {
293            m_description = description;
294        }
295        m_version = version;
296        if (CmsStringUtil.isEmpty(authorName)) {
297            m_authorName = "";
298        } else {
299            m_authorName = authorName;
300        }
301        if (CmsStringUtil.isEmpty(authorEmail)) {
302            m_authorEmail = "";
303        } else {
304            m_authorEmail = authorEmail;
305        }
306        // remove milisecounds
307        m_dateCreated = (dateCreated / 1000L) * 1000L;
308        if (CmsStringUtil.isEmpty(userInstalled)) {
309            m_userInstalled = "";
310        } else {
311            m_userInstalled = userInstalled;
312        }
313        m_dateInstalled = (dateInstalled / 1000L) * 1000L;
314        if (dependencies == null) {
315            m_dependencies = Collections.emptyList();
316        } else {
317            m_dependencies = Collections.unmodifiableList(dependencies);
318        }
319        if (exportPoints == null) {
320            m_exportPoints = Collections.emptyList();
321        } else {
322            m_exportPoints = Collections.unmodifiableList(exportPoints);
323        }
324        if (resources == null) {
325            m_resources = Collections.emptyList();
326        } else {
327            m_resources = Collections.unmodifiableList(resources);
328        }
329        if (excluderesources == null) {
330            m_excluderesources = Collections.emptyList();
331        } else {
332            m_excluderesources = Collections.unmodifiableList(excluderesources);
333        }
334        if (parameters == null) {
335            m_parameters = new TreeMap<String, String>();
336        } else {
337            m_parameters = new TreeMap<String, String>(parameters);
338        }
339
340        m_site = site;
341
342        m_hasImportSite = isImportSite;
343
344        m_importScript = importScript;
345
346        initOldAdditionalResources();
347
348        if (LOG.isDebugEnabled()) {
349            LOG.debug(Messages.get().getBundle().key(Messages.LOG_MODULE_INSTANCE_CREATED_1, m_name));
350        }
351        m_resourceTypes = Collections.emptyList();
352        m_explorerTypeSettings = Collections.emptyList();
353    }
354
355    /** Determines the resources that are:
356     * <ul>
357     *  <li>accessible with the provided {@link CmsObject},</li>
358     *  <li>part of the <code>moduleResources</code> (or in a folder of these resources) and</li>
359     *  <li><em>not</em> contained in <code>excludedResources</code> (or a folder of these resources).</li>
360     * </ul>
361     * and adds the to <code>result</code>
362     *
363     * @param result the resource list, that gets extended by the calculated resources.
364     * @param cms the {@link CmsObject} used to read resources.
365     * @param moduleResources the resources to include.
366     * @param excludeResources the site paths of the resources to exclude.
367     * @throws CmsException thrown if reading resources fails.
368     */
369    public static void addCalculatedModuleResources(
370        List<CmsResource> result,
371        final CmsObject cms,
372        final List<CmsResource> moduleResources,
373        final List<String> excludeResources)
374    throws CmsException {
375
376        for (CmsResource resource : moduleResources) {
377
378            String sitePath = cms.getSitePath(resource);
379
380            List<String> excludedSubResources = getExcludedForResource(sitePath, excludeResources);
381
382            // check if resources have to be excluded
383            if (excludedSubResources.isEmpty()) {
384                // no resource has to be excluded - add the whole resource
385                // (that is, also all resources in the folder, if the resource is a folder)
386                result.add(resource);
387            } else {
388                // cannot add the complete resource (i.e., including the whole sub-tree)
389                if (CmsStringUtil.comparePaths(sitePath, excludedSubResources.get(0))) {
390                    // the resource itself is excluded -> do not add it and check the next resource
391                    continue;
392                }
393                // try to include sub-resources.
394                List<CmsResource> subResources = cms.readResources(sitePath, CmsResourceFilter.ALL, false);
395                addCalculatedModuleResources(result, cms, subResources, excludedSubResources);
396            }
397        }
398
399    }
400
401    /** Calculates the resources belonging to the module, taking excluded resources and readability of resources into account,
402     *  and returns site paths of the module resources.<p>
403     *  For more details of the returned resource, see {@link #calculateModuleResources(CmsObject, CmsModule)}.
404     *
405     * @param cms the {@link CmsObject} used to read the resources.
406     * @param module the module, for which the resources should be calculated
407     * @return the calculated module resources
408     * @throws CmsException thrown if reading resources fails.
409     */
410    public static List<String> calculateModuleResourceNames(final CmsObject cms, final CmsModule module)
411    throws CmsException {
412
413        // adjust the site root, if necessary
414        CmsObject cmsClone = adjustSiteRootIfNecessary(cms, module);
415
416        // calculate the module resources
417        List<CmsResource> moduleResources = calculateModuleResources(cmsClone, module);
418
419        // get the site paths
420        List<String> moduleResouceNames = new ArrayList<String>(moduleResources.size());
421        for (CmsResource resource : moduleResources) {
422            moduleResouceNames.add(cmsClone.getSitePath(resource));
423        }
424        return moduleResouceNames;
425    }
426
427    /** Calculates and returns the resources belonging to the module, taking excluded resources and readability of resources into account.
428     * The list of returned resources contains:
429     * <ul>
430     *  <li>Only resources that are readable (present at the system and accessible with the provided {@link CmsObject}</li>
431     *  <li>Only the resource for a folder, if <em>all</em> resources in the folder belong to the module.</li>
432     *  <li>Only resources that are specified as module resources and <em>not</em> excluded by the module's exclude resources.</li>
433     * </ul>
434     *
435     * @param cms the {@link CmsObject} used to read the resources.
436     * @param module the module, for which the resources should be calculated
437     * @return the calculated module resources
438     * @throws CmsException thrown if reading resources fails.
439     */
440    public static List<CmsResource> calculateModuleResources(final CmsObject cms, final CmsModule module)
441    throws CmsException {
442
443        CmsObject cmsClone = adjustSiteRootIfNecessary(cms, module);
444        List<CmsResource> result = null;
445        List<String> excluded = CmsFileUtil.removeRedundancies(module.getExcludeResources());
446        excluded = removeNonAccessible(cmsClone, excluded);
447        List<String> resourceSitePaths = CmsFileUtil.removeRedundancies(module.getResources());
448        resourceSitePaths = removeNonAccessible(cmsClone, resourceSitePaths);
449
450        List<CmsResource> moduleResources = new ArrayList<CmsResource>(resourceSitePaths.size());
451        for (String resourceSitePath : resourceSitePaths) {
452            // assumes resources are accessible - already checked aboveremoveNonAccessible
453            CmsResource resource = cmsClone.readResource(resourceSitePath, CmsResourceFilter.IGNORE_EXPIRATION);
454            moduleResources.add(resource);
455        }
456
457        if (excluded.isEmpty()) {
458            result = moduleResources;
459        } else {
460            result = new ArrayList<CmsResource>();
461
462            addCalculatedModuleResources(result, cmsClone, moduleResources, excluded);
463
464        }
465        return result;
466
467    }
468
469    /** Adjusts the site root and returns a cloned CmsObject, iff the module has set an import site that differs
470     * from the site root of the CmsObject provided as argument. Otherwise returns the provided CmsObject unchanged.
471     * @param cms The original CmsObject.
472     * @param module The module where the import site is read from.
473     * @return The original CmsObject, or, if necessary, a clone with adjusted site root
474     * @throws CmsException see {@link OpenCms#initCmsObject(CmsObject)}
475     */
476    private static CmsObject adjustSiteRootIfNecessary(final CmsObject cms, final CmsModule module)
477    throws CmsException {
478
479        CmsObject cmsClone;
480        if ((null == module.getSite()) || cms.getRequestContext().getSiteRoot().equals(module.getSite())) {
481            cmsClone = cms;
482        } else {
483            cmsClone = OpenCms.initCmsObject(cms);
484            cmsClone.getRequestContext().setSiteRoot(module.getSite());
485        }
486
487        return cmsClone;
488    }
489
490    /** Returns only the resource names starting with the provided <code>sitePath</code>.
491     *
492     * @param sitePath the site relative path, all paths should start with.
493     * @param excluded the paths to filter.
494     * @return the paths from <code>excluded</code>, that start with <code>sitePath</code>.
495     */
496    private static List<String> getExcludedForResource(final String sitePath, final List<String> excluded) {
497
498        List<String> result = new ArrayList<String>();
499        for (String exclude : excluded) {
500            if (CmsStringUtil.isPrefixPath(sitePath, exclude)) {
501                result.add(exclude);
502            }
503        }
504        return result;
505    }
506
507    /** Removes the resources not accessible with the provided {@link CmsObject}.
508     *
509     * @param cms the {@link CmsObject} used to read the resources.
510     * @param sitePaths site relative paths of the resources that should be checked for accessibility.
511     * @return site paths of the accessible resources.
512     */
513    private static List<String> removeNonAccessible(CmsObject cms, List<String> sitePaths) {
514
515        List<String> result = new ArrayList<String>(sitePaths.size());
516        for (String sitePath : sitePaths) {
517            if (cms.existsResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION)) {
518                result.add(sitePath);
519            }
520        }
521        return result;
522    }
523
524    /**
525     * Checks if this module depends on another given module,
526     * will return the dependency, or <code>null</code> if no dependency was found.<p>
527     *
528     * @param module the other module to check against
529     * @return the dependency, or null if no dependency was found
530     */
531    public CmsModuleDependency checkDependency(CmsModule module) {
532
533        CmsModuleDependency otherDepdendency = new CmsModuleDependency(module.getName(), module.getVersion());
534
535        // loop through all the dependencies
536        for (int i = 0; i < m_dependencies.size(); i++) {
537            CmsModuleDependency dependency = m_dependencies.get(i);
538            if (dependency.dependesOn(otherDepdendency)) {
539                // short circuit here
540                return dependency;
541            }
542        }
543
544        // no dependency was found
545        return null;
546    }
547
548    /**
549     * Checks if all resources of the module are present.<p>
550     *
551     * @param cms an initialized OpenCms user context which must have read access to all module resources
552     *
553     * @throws CmsIllegalArgumentException in case not all module resources exist or can be read with the given OpenCms user context
554     */
555    public void checkResources(CmsObject cms) throws CmsIllegalArgumentException {
556
557        CmsFileUtil.checkResources(cms, getResources());
558    }
559
560    /**
561     * Clones a CmsModule which is not set to frozen.<p>
562     * This clones module can be used to be update the module information.
563     *
564     * @see java.lang.Object#clone()
565     */
566    @Override
567    public CmsModule clone() {
568
569        // create a copy of the module
570        CmsModule result = new CmsModule(
571            m_name,
572            m_niceName,
573            m_group,
574            m_actionClass,
575            m_importScript,
576            m_site,
577            m_hasImportSite,
578            m_exportMode,
579            m_description,
580            m_version,
581            m_authorName,
582            m_authorEmail,
583            m_dateCreated,
584            m_userInstalled,
585            m_dateInstalled,
586            m_dependencies,
587            m_exportPoints,
588            m_resources,
589            m_excluderesources,
590            m_parameters);
591        // and set its frozen state to false
592        result.m_frozen = false;
593
594        if (getExplorerTypes() != null) {
595            List<CmsExplorerTypeSettings> settings = new ArrayList<CmsExplorerTypeSettings>();
596            for (CmsExplorerTypeSettings setting : getExplorerTypes()) {
597                settings.add((CmsExplorerTypeSettings)setting.clone());
598            }
599            result.setExplorerTypes(settings);
600        }
601        if (getResourceTypes() != null) {
602            // TODO: The resource types must be cloned also, otherwise modification will effect the origin also
603            result.setResourceTypes(new ArrayList<I_CmsResourceType>(getResourceTypes()));
604        }
605        if (getDependencies() != null) {
606            List<CmsModuleDependency> deps = new ArrayList<CmsModuleDependency>();
607            for (CmsModuleDependency dep : getDependencies()) {
608                deps.add((CmsModuleDependency)dep.clone());
609            }
610            result.setDependencies(new ArrayList<CmsModuleDependency>(getDependencies()));
611        }
612        if (getExportPoints() != null) {
613            List<CmsExportPoint> exps = new ArrayList<CmsExportPoint>();
614            for (CmsExportPoint exp : getExportPoints()) {
615                exps.add((CmsExportPoint)exp.clone());
616            }
617            result.setExportPoints(exps);
618        }
619
620        result.setAutoIncrement(m_autoIncrement);
621        result.setCheckpointTime(m_checkpointTime);
622
623        result.setCreateClassesFolder(m_createClassesFolder);
624        result.setCreateElementsFolder(m_createElementsFolder);
625        result.setCreateLibFolder(m_createLibFolder);
626        result.setCreateModuleFolder(m_createModuleFolder);
627        result.setCreateResourcesFolder(m_createResourcesFolder);
628        result.setCreateSchemasFolder(m_createSchemasFolder);
629        result.setCreateTemplateFolder(m_createTemplateFolder);
630        result.setCreateFormattersFolder(m_createFormattersFolder);
631
632        result.setResources(new ArrayList<String>(m_resources));
633        result.setExcludeResources(new ArrayList<String>(m_excluderesources));
634
635        return result;
636    }
637
638    /**
639     * @see java.lang.Comparable#compareTo(java.lang.Object)
640     */
641    public int compareTo(CmsModule obj) {
642
643        if (obj == this) {
644            return 0;
645        }
646        return m_name.compareTo(obj.m_name);
647    }
648
649    /**
650     * Two instances of a module are considered equal if their name is equal.<p>
651     *
652     * @param obj the object to compare
653     *
654     * @return true if the objects are equal
655     *
656     * @see java.lang.Object#equals(java.lang.Object)
657     * @see #isIdentical(CmsModule)
658     */
659    @Override
660    public boolean equals(Object obj) {
661
662        if (obj == this) {
663            return true;
664        }
665        if (obj instanceof CmsModule) {
666            return ((CmsModule)obj).m_name.equals(m_name);
667        }
668        return false;
669    }
670
671    /**
672     * Returns the class name of this modules (optional) action class.<p>
673     *
674     * If this module does not use an action class,
675     * <code>null</code> is returned.<p>
676     *
677     * @return the class name of this modules (optional) action class
678     */
679    public String getActionClass() {
680
681        return m_actionClass;
682    }
683
684    /**
685     * Returns the module action instance of this module, or <code>null</code>
686     * if no module action instance is configured.<p>
687     *
688     * @return the module action instance of this module
689     */
690    public I_CmsModuleAction getActionInstance() {
691
692        return m_actionInstance;
693    }
694
695    /**
696     * Returns the email of the module author.<p>
697     *
698     * @return the email of the module author
699     */
700    public String getAuthorEmail() {
701
702        return m_authorEmail;
703    }
704
705    /**
706     * Returns the name of the author of this module.<p>
707     *
708     * @return the name of the author of this module
709     */
710    public String getAuthorName() {
711
712        return m_authorName;
713    }
714
715    /**
716     * Gets the module checkpoint time.<p>
717     *
718     * This timestamp is used for auto-incrementing the version: if module resources have been modified in the VFS after this timestamp, increment
719     * the version.<p>
720     *
721     * Note: This is not exported in the manifest.    *
722     *
723     * @return the checkpoint timestamp
724     */
725    public long getCheckpointTime() {
726
727        return m_checkpointTime;
728    }
729
730    /**
731     * Gets the module configuration path.<p>
732     *
733     * @return the module configuration path
734     */
735    public String getConfigurationPath() {
736
737        String parameter = getParameter("config.sitemap");
738        if (parameter != null) {
739            return parameter;
740        } else {
741            return "/system/modules/" + getName() + "/.config";
742        }
743    }
744
745    /**
746     * Returns the date this module was created by the author.<p>
747     *
748     * @return the date this module was created by the author
749     */
750    public long getDateCreated() {
751
752        return m_dateCreated;
753    }
754
755    /**
756     * Returns the date this module was uploaded.<p>
757     *
758     * @return the date this module was uploaded
759     */
760    public long getDateInstalled() {
761
762        return m_dateInstalled;
763    }
764
765    /**
766     * Returns the list of dependencies of this module.<p>
767     *
768     * @return the list of dependencies of this module
769     */
770    public List<CmsModuleDependency> getDependencies() {
771
772        return m_dependencies;
773    }
774
775    /**
776     * Returns the description of this module.<p>
777     *
778     * @return the description of this module
779     */
780    public String getDescription() {
781
782        return m_description;
783    }
784
785    /**
786     * Returns the list of VFS resources that do not belong to this module.<p>
787     * In particular, files / folders that would be included otherwise,
788     * considering the module resources.<p>
789     *
790     * @return the list of VFS resources that do not belong to this module
791     */
792    public List<String> getExcludeResources() {
793
794        return m_excluderesources;
795    }
796
797    /**
798     * Returns the list of explorer resource types that belong to this module.<p>
799     *
800     * @return the list of explorer resource types that belong to this module
801     */
802    public List<CmsExplorerTypeSettings> getExplorerTypes() {
803
804        return m_explorerTypeSettings;
805    }
806
807    /** Returns the export mode specified for the module.
808     * @return the module's export mode.
809     */
810    public ExportMode getExportMode() {
811
812        return m_exportMode;
813    }
814
815    /**
816     * Returns the list of export point added by this module.<p>
817     *
818     * @return the list of export point added by this module
819     */
820    public List<CmsExportPoint> getExportPoints() {
821
822        return m_exportPoints;
823    }
824
825    /**
826     * Gets the export version.<p>
827     *
828     * This is only used for module objects which have been read from a zip file.
829     *
830     * @return the export version
831     */
832    public String getExportVersion() {
833
834        return m_exportVersion;
835    }
836
837    /**
838     * Returns the group name of this module.<p>
839     *
840     * @return the group name of this module
841     */
842    public String getGroup() {
843
844        return m_group;
845    }
846
847    /**
848     * Returns true if the module has an import site set.<p>
849     *
850     * @return true if the module has an import site set
851     */
852    public boolean getHasImportSite() {
853
854        return hasImportSite();
855    }
856
857    /**
858     * Returns the importScript.<p>
859     *
860     * @return the importScript
861     */
862    public String getImportScript() {
863
864        return m_importScript;
865    }
866
867    /**
868     * Gets the import site.<p>
869     *
870     * If this is not empty, then it will be used as the site root for importing and exporting this module.<p>
871     *
872     * @return the import site
873     */
874    public String getImportSite() {
875
876        if (m_hasImportSite) {
877            return m_site;
878        } else {
879            return null;
880        }
881
882    }
883
884    /**
885     * Returns the name of this module.<p>
886     *
887     * The module name must be a valid java package name.<p>
888     *
889     * @return the name of this module
890     */
891    public String getName() {
892
893        return m_name;
894    }
895
896    /**
897     * Returns the "nice" display name of this module.<p>
898     *
899     * @return the "nice" display name of this module
900     */
901    public String getNiceName() {
902
903        return m_niceName;
904    }
905
906    /**
907     * Gets the timestamp of this object's creation time.<p>
908     *
909     * @return the object creation timestamp
910     */
911    public long getObjectCreateTime() {
912
913        return m_objectCreateTime;
914    }
915
916    /**
917     * Returns a parameter value from the module parameters.<p>
918     *
919     * @param key the parameter to return the value for
920     * @return the parameter value from the module parameters
921     */
922    public String getParameter(String key) {
923
924        return m_parameters.get(key);
925    }
926
927    /**
928     * Returns a parameter value from the module parameters,
929     * or a given default value in case the parameter is not set.<p>
930     *
931     * @param key the parameter to return the value for
932     * @param defaultValue the default value in case there is no value stored for this key
933     * @return the parameter value from the module parameters
934     */
935    public String getParameter(String key, String defaultValue) {
936
937        String value = m_parameters.get(key);
938        return (value != null) ? value : defaultValue;
939    }
940
941    /**
942     * Returns the configured (immutable) module parameters.<p>
943     *
944     * @return the configured (immutable) module parameters
945     */
946    public SortedMap<String, String> getParameters() {
947
948        return m_parameters;
949    }
950
951    /**
952     * Returns the list of VFS resources that belong to this module.<p>
953     *
954     * @return the list of VFS resources that belong to this module
955     */
956    public List<String> getResources() {
957
958        return m_resources;
959    }
960
961    /**
962     * Returns the list of additional resource types that belong to this module.<p>
963     *
964     * @return the list of additional resource types that belong to this module
965     */
966    public List<I_CmsResourceType> getResourceTypes() {
967
968        return m_resourceTypes;
969    }
970
971    /**
972     * Gets the module's site.<p>
973     *
974     * @return the site of the module
975     */
976    public String getSite() {
977
978        return m_site;
979    }
980
981    /**
982     * Returns the name of the user who uploaded this module.<p>
983     *
984     * @return the name of the user who uploaded this module
985     */
986    public String getUserInstalled() {
987
988        return m_userInstalled;
989    }
990
991    /**
992     * Returns the version of this module.<p>
993     *
994     * @return the version of this module
995     */
996    public CmsModuleVersion getVersion() {
997
998        return m_version;
999    }
1000
1001    /**
1002     * Gets the version number as a string.<p>
1003     *
1004     * @return the version number as a string
1005     */
1006    public String getVersionStr() {
1007
1008        return m_version.toString();
1009    }
1010
1011    /**
1012     * @see java.lang.Object#hashCode()
1013     */
1014    @Override
1015    public int hashCode() {
1016
1017        return m_name.hashCode();
1018    }
1019
1020    /**
1021     * Returns true if the module has a fixed import site.<p>
1022     *
1023     * @return true if the module has a fixed import site
1024     */
1025    public boolean hasImportSite() {
1026
1027        return m_hasImportSite;
1028    }
1029
1030    /**
1031     * Determines if the module haas resources whose site is undefined.<p>
1032     *
1033     * @return true if there are module resources with an undefined site
1034     */
1035    public boolean hasModuleResourcesWithUndefinedSite() {
1036
1037        if (getSite() == null) {
1038            for (String modRes : getResources()) {
1039                if (!CmsStringUtil.isPrefixPath("/system/", modRes)
1040                    && !OpenCms.getSiteManager().startsWithShared(modRes)) {
1041                    return true;
1042                }
1043
1044            }
1045        }
1046        return false;
1047    }
1048
1049    /**
1050     * Check if all module resources are under /system or the shared folder.<p>
1051     *
1052     * @return true if the module only has resources under system or the shared folder
1053     */
1054    public boolean hasOnlySystemAndSharedResources() {
1055
1056        for (String modRes : getResources()) {
1057            if (!CmsStringUtil.isPrefixPath("/system/", modRes) && !OpenCms.getSiteManager().startsWithShared(modRes)) {
1058                return false;
1059            }
1060        }
1061        return true;
1062    }
1063
1064    /**
1065     * Returns true if version auto-incrementation is enabled for this module.
1066     *
1067     * @return true if version auto-incrementation is enabled for this module
1068     */
1069    public boolean isAutoIncrement() {
1070
1071        return m_autoIncrement;
1072    }
1073
1074    /**
1075     * Returns the createClassesFolder flag.<p>
1076     *
1077     * @return the createClassesFolder flag
1078     */
1079    public boolean isCreateClassesFolder() {
1080
1081        return m_createClassesFolder;
1082    }
1083
1084    /**
1085     * Returns the createElementsFolder flag.<p>
1086     *
1087     * @return the createElementsFolder flag
1088     */
1089    public boolean isCreateElementsFolder() {
1090
1091        return m_createElementsFolder;
1092    }
1093
1094    /**
1095     * Returns the createFormattersFolder flag.<p>
1096     *
1097     * @return the createFormattersFolder flag
1098     */
1099    public boolean isCreateFormattersFolder() {
1100
1101        return m_createFormattersFolder;
1102    }
1103
1104    /**
1105     * Returns the createI18NFolder flag.<p>
1106     *
1107     * @return boolean
1108     */
1109    public boolean isCreateI18NFolder() {
1110
1111        return m_createI18NFolder;
1112    }
1113
1114    /**
1115     * Returns the createLibFolder flag.<p>
1116     *
1117     * @return the createLibFolder flag
1118     */
1119    public boolean isCreateLibFolder() {
1120
1121        return m_createLibFolder;
1122    }
1123
1124    /**
1125     * Returns the createModuleFolder flag.<p>
1126     *
1127     * @return the createModuleFolder flag
1128     */
1129    public boolean isCreateModuleFolder() {
1130
1131        return m_createModuleFolder;
1132    }
1133
1134    /**
1135     * Returns the createResourcesFolder flag.<p>
1136     *
1137     * @return the createResourcesFolder flag
1138     */
1139    public boolean isCreateResourcesFolder() {
1140
1141        return m_createResourcesFolder;
1142    }
1143
1144    /**
1145     * Returns the createSchemasFolder flag.<p>
1146     *
1147     * @return the createSchemasFolder flag
1148     */
1149    public boolean isCreateSchemasFolder() {
1150
1151        return m_createSchemasFolder;
1152    }
1153
1154    /**
1155     * Returns the createTemplateFolder flag.<p>
1156     *
1157     * @return the createTemplateFolder flag
1158     */
1159    public boolean isCreateTemplateFolder() {
1160
1161        return m_createTemplateFolder;
1162    }
1163
1164    /**
1165     * Checks if this module is identical with another module.<p>
1166     *
1167     * Modules A, B are <b>identical</b> if <i>all</i> values of A are equal to B.
1168     * The values from {@link #getUserInstalled()} and {@link #getDateInstalled()}
1169     * are ignored for this test.<p>
1170     *
1171     * Modules A, B are <b>equal</b> if just the name of A is equal to the name of B.<p>
1172     *
1173     * @param other the module to compare with
1174     *
1175     * @return if the modules are identical
1176     *
1177     * @see #equals(Object)
1178     */
1179    public boolean isIdentical(CmsModule other) {
1180
1181        // some code redundancy here but this is easier to debug
1182        if (!isEqual(m_name, other.m_name)) {
1183            return false;
1184        }
1185        if (!isEqual(m_niceName, other.m_niceName)) {
1186            return false;
1187        }
1188        if (!isEqual(m_version, other.m_version)) {
1189            return false;
1190        }
1191        if (!isEqual(m_actionClass, other.m_actionClass)) {
1192            return false;
1193        }
1194        if (!isEqual(m_description, other.m_description)) {
1195            return false;
1196        }
1197        if (!isEqual(m_authorName, other.m_authorName)) {
1198            return false;
1199        }
1200        if (!isEqual(m_authorEmail, other.m_authorEmail)) {
1201            return false;
1202        }
1203        if (m_dateCreated != other.m_dateCreated) {
1204            return false;
1205        }
1206        return true;
1207    }
1208
1209    /** Checks, if the module should use the reduced export mode.
1210     * @return if reduce export mode should be used <code>true</code>, otherwise <code>false</code>.
1211     */
1212    public boolean isReducedExportMode() {
1213
1214        return ExportMode.REDUCED.equals(m_exportMode);
1215    }
1216
1217    /**
1218     * Sets the class name of this modules (optional) action class.<p>
1219     *
1220     * Providing <code>null</code> as a value indicates that this module does not use an action class.<p>
1221     *
1222     * <i>Please note:</i>It's not possible to set the action class name once the module
1223     * configuration has been frozen.<p>
1224     *
1225     * @param value the class name of this modules (optional) action class to set
1226     */
1227    public void setActionClass(String value) {
1228
1229        checkFrozen();
1230        if (CmsStringUtil.isEmpty(value)) {
1231            m_actionClass = null;
1232        } else {
1233            if (!CmsStringUtil.isValidJavaClassName(value)) {
1234                throw new CmsIllegalArgumentException(
1235                    Messages.get().container(Messages.ERR_MODULE_ACTION_CLASS_2, value, getName()));
1236            }
1237            m_actionClass = value;
1238        }
1239    }
1240
1241    /**
1242     * Sets the author email of this module.<p>
1243     *
1244     *
1245     * <i>Please note:</i>It's not possible to set the modules author email once the module
1246     * configuration has been frozen.<p>
1247     *
1248     * @param value the module description to set
1249     */
1250    public void setAuthorEmail(String value) {
1251
1252        checkFrozen();
1253        m_authorEmail = value.trim();
1254    }
1255
1256    /**
1257     * Sets the author name of this module.<p>
1258     *
1259     *
1260     * <i>Please note:</i>It's not possible to set the modules author name once the module
1261     * configuration has been frozen.<p>
1262     *
1263     * @param value the module description to set
1264     */
1265    public void setAuthorName(String value) {
1266
1267        checkFrozen();
1268        m_authorName = value.trim();
1269    }
1270
1271    /**
1272     * Sets auto-increment mode.
1273     *
1274     * @param autoIncrement true if version auto-incrementation should be enabled
1275     */
1276    public void setAutoIncrement(boolean autoIncrement) {
1277
1278        m_autoIncrement = autoIncrement;
1279    }
1280
1281    /**
1282     * Sets the module checkpoint time.
1283     *
1284     * @param checkpointTime the module checkpoint time
1285     */
1286    public void setCheckpointTime(long checkpointTime) {
1287
1288        m_checkpointTime = checkpointTime;
1289    }
1290
1291    /**
1292     * Sets the createClassesFolder flag.<p>
1293     *
1294     * @param createClassesFolder the createClassesFolder flag to set
1295     */
1296    public void setCreateClassesFolder(boolean createClassesFolder) {
1297
1298        m_createClassesFolder = createClassesFolder;
1299    }
1300
1301    /**
1302     * Sets the createElementsFolder flag.<p>
1303     *
1304     * @param createElementsFolder the createElementsFolder flag to set
1305     */
1306    public void setCreateElementsFolder(boolean createElementsFolder) {
1307
1308        m_createElementsFolder = createElementsFolder;
1309    }
1310
1311    /**
1312     * Sets the createFormattersFolder flag.<p>
1313     *
1314     * @param createFormattersFolder the createFormattersFolder flag to set
1315     */
1316    public void setCreateFormattersFolder(boolean createFormattersFolder) {
1317
1318        m_createFormattersFolder = createFormattersFolder;
1319    }
1320
1321    /**
1322     * Sets the createI18NFolder flag.<p>
1323     *
1324     * @param createI18NFolder boolean
1325     */
1326    public void setCreateI18NFolder(boolean createI18NFolder) {
1327
1328        m_createI18NFolder = createI18NFolder;
1329    }
1330
1331    /**
1332     * Sets the createLibFolder flag.<p>
1333     *
1334     * @param createLibFolder the createLibFolder flag to set
1335     */
1336    public void setCreateLibFolder(boolean createLibFolder) {
1337
1338        m_createLibFolder = createLibFolder;
1339    }
1340
1341    /**
1342     * Sets the createModuleFolder flag.<p>
1343     *
1344     * @param createModuleFolder the createModuleFolder flag to set
1345     */
1346    public void setCreateModuleFolder(boolean createModuleFolder) {
1347
1348        m_createModuleFolder = createModuleFolder;
1349    }
1350
1351    /**
1352     * Sets the createResourcesFolder flag.<p>
1353     *
1354     * @param createResourcesFolder the createResourcesFolder flag to set
1355     */
1356    public void setCreateResourcesFolder(boolean createResourcesFolder) {
1357
1358        m_createResourcesFolder = createResourcesFolder;
1359    }
1360
1361    /**
1362     * Sets the createSchemasFolder flag .<p>
1363     *
1364     * @param createSchemasFolder the createSchemasFolder flag to set
1365     */
1366    public void setCreateSchemasFolder(boolean createSchemasFolder) {
1367
1368        m_createSchemasFolder = createSchemasFolder;
1369    }
1370
1371    /**
1372     * Sets the createTemplateFolder flag .<p>
1373     *
1374     * @param createTemplateFolder the createTemplateFolder flag to set
1375     */
1376    public void setCreateTemplateFolder(boolean createTemplateFolder) {
1377
1378        m_createTemplateFolder = createTemplateFolder;
1379    }
1380
1381    /**
1382     * Sets the date created of this module.<p>
1383     *
1384     *
1385     * <i>Please note:</i>It's not possible to set the module date created once the module
1386     * configuration has been frozen.<p>
1387     *
1388     * @param value the date created to set
1389     */
1390    public void setDateCreated(long value) {
1391
1392        checkFrozen();
1393        m_dateCreated = value;
1394    }
1395
1396    /**
1397     * Sets the installation date of this module.<p>
1398     *
1399     *
1400     * <i>Please note:</i>It's not possible to set the installation date once the module
1401     * configuration has been frozen.<p>
1402     *
1403     * @param value the installation date this module
1404     */
1405    public void setDateInstalled(long value) {
1406
1407        checkFrozen();
1408        m_dateInstalled = value;
1409    }
1410
1411    /**
1412     * Sets the list of module dependencies.<p>
1413     *
1414     * @param dependencies list of module dependencies
1415     */
1416    public void setDependencies(List<CmsModuleDependency> dependencies) {
1417
1418        checkFrozen();
1419        m_dependencies = dependencies;
1420    }
1421
1422    /**
1423     * Sets the description of this module.<p>
1424     *
1425     *
1426     * <i>Please note:</i>It's not possible to set the modules description once the module
1427     * configuration has been frozen.<p>
1428     *
1429     * @param value the module description to set
1430     */
1431    public void setDescription(String value) {
1432
1433        checkFrozen();
1434        m_description = value.trim();
1435    }
1436
1437    /**
1438     * Sets the resources excluded from this module.<p>
1439     *
1440     *
1441     * <i>Please note:</i>It's not possible to set the module resources once the module
1442     * configuration has been frozen.<p>
1443     *
1444     * @param value the resources to exclude from the module
1445     */
1446    public void setExcludeResources(List<String> value) {
1447
1448        checkFrozen();
1449        m_excluderesources = value;
1450    }
1451
1452    /**
1453     * Sets the additional explorer types that belong to this module.<p>
1454     *
1455     * @param explorerTypeSettings the explorer type settings.
1456     */
1457    public void setExplorerTypes(List<CmsExplorerTypeSettings> explorerTypeSettings) {
1458
1459        m_explorerTypeSettings = explorerTypeSettings;
1460    }
1461
1462    /**
1463     * Sets the export points of this module.<p>
1464     *
1465     * @param exportPoints the export points of this module.
1466     */
1467    public void setExportPoints(List<CmsExportPoint> exportPoints) {
1468
1469        m_exportPoints = exportPoints;
1470    }
1471
1472    /**
1473     * Sets the export version.<p>
1474     *
1475     * @param exportVersion the export version
1476     */
1477    public void setExportVersion(String exportVersion) {
1478
1479        m_exportVersion = exportVersion;
1480
1481    }
1482
1483    /**
1484     * Sets the group name of this module.<p>
1485     *
1486     *
1487     * <i>Please note:</i>It's not possible to set the modules group name once the module
1488     * configuration has been frozen.<p>
1489     *
1490     * @param value the module group name to set
1491     */
1492    public void setGroup(String value) {
1493
1494        checkFrozen();
1495        m_group = value;
1496    }
1497
1498    /**
1499     * Sets the hasImportSite flag, which determines whether the module site should be used as a fixed import site.
1500     *
1501     * @param isImportSite true if the module site should be treated as a fixed import site
1502     */
1503    public void setHasImportSite(boolean isImportSite) {
1504
1505        checkFrozen();
1506        m_hasImportSite = isImportSite;
1507    }
1508
1509    /**
1510     * Sets the importScript.<p>
1511     *
1512     * @param importScript the importScript to set
1513     */
1514    public void setImportScript(String importScript) {
1515
1516        checkFrozen();
1517        m_importScript = importScript;
1518    }
1519
1520    /**
1521     * Sets the import site.<p>
1522     *
1523     * @param importSite the import site
1524     */
1525    public void setImportSite(String importSite) {
1526
1527        checkFrozen();
1528        if (importSite != null) {
1529            importSite = importSite.trim();
1530        }
1531        m_site = importSite;
1532        m_hasImportSite = true;
1533    }
1534
1535    /**
1536     * Sets the name of this module.<p>
1537     *
1538     * The module name must be a valid java package name.<p>
1539     *
1540     * <i>Please note:</i>It's not possible to set the modules name once the module
1541     * configuration has been frozen.<p>
1542     *
1543     * @param value the module name to set
1544     */
1545    public void setName(String value) {
1546
1547        checkFrozen();
1548        if (!CmsStringUtil.isValidJavaClassName(value)) {
1549            throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_MODULE_NAME_1, value));
1550        }
1551        m_name = value;
1552    }
1553
1554    /**
1555     * Sets the "nice" display name of this module.<p>
1556     *
1557     * <i>Please note:</i>It's not possible to set the modules "nice" name once the module
1558     * configuration has been frozen.<p>
1559     *
1560     * @param value the "nice" display name of this module to set
1561     */
1562    public void setNiceName(String value) {
1563
1564        checkFrozen();
1565        if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) {
1566            m_niceName = getName();
1567        } else {
1568            m_niceName = value.trim();
1569        }
1570    }
1571
1572    /**
1573     * Sets the parameters of this module.<p>
1574     *
1575     *
1576     * <i>Please note:</i>It's not possible to set the module parameters once the module
1577     * configuration has been frozen.<p>
1578     *
1579     * @param parameters the module parameters to set
1580     */
1581    public void setParameters(SortedMap<String, String> parameters) {
1582
1583        checkFrozen();
1584        m_parameters = parameters;
1585    }
1586
1587    /** Set/unset the reduced export mode.
1588     * @param reducedExportMode if <code>true</code>, the export mode is set to {@link ExportMode#REDUCED}, otherwise to {@link ExportMode#DEFAULT}.
1589     */
1590    public void setReducedExportMode(boolean reducedExportMode) {
1591
1592        m_exportMode = reducedExportMode ? ExportMode.REDUCED : ExportMode.DEFAULT;
1593    }
1594
1595    /**
1596     * Sets the resources of this module.<p>
1597     *
1598     *
1599     * <i>Please note:</i>It's not possible to set the module resources once the module
1600     * configuration has been frozen.<p>
1601     *
1602     * @param value the module resources to set
1603     */
1604    public void setResources(List<String> value) {
1605
1606        checkFrozen();
1607        m_resources = value;
1608    }
1609
1610    /**
1611     * Sets the list of additional resource types that belong to this module.<p>
1612     *
1613     * @param resourceTypes list of additional resource types that belong to this module
1614     */
1615    public void setResourceTypes(List<I_CmsResourceType> resourceTypes) {
1616
1617        m_resourceTypes = Collections.unmodifiableList(resourceTypes);
1618    }
1619
1620    /**
1621     * Sets the module site.
1622     *
1623     * @param siteRoot the module site root
1624     */
1625    public void setSite(String siteRoot) {
1626
1627        if (siteRoot == null) {
1628            m_hasImportSite = false;
1629        }
1630        m_site = siteRoot;
1631    }
1632
1633    /**
1634     * Sets the user who installed of this module.<p>
1635     *
1636     *
1637     * <i>Please note:</i>It's not possible to set the user installed once the module
1638     * configuration has been frozen.<p>
1639     *
1640     * @param value the user who installed this module
1641     */
1642    public void setUserInstalled(String value) {
1643
1644        checkFrozen();
1645        m_userInstalled = value.trim();
1646    }
1647
1648    /**
1649     * Sets the version number as a string.
1650     *
1651     * @param versionString the version number string
1652     */
1653    public void setVersionStr(String versionString) {
1654
1655        checkFrozen();
1656        m_version = new CmsModuleVersion(versionString);
1657
1658    }
1659
1660    /**
1661     * Determines if the version should be incremented based on the module resources' modification dates.
1662     *
1663     * @param cms the CMS context
1664     * @return true if the version number should be incremented
1665     *
1666     * @throws CmsException if something goes wrong
1667     */
1668    public boolean shouldIncrementVersionBasedOnResources(CmsObject cms) throws CmsException {
1669
1670        if (m_checkpointTime == 0) {
1671            return true;
1672        }
1673
1674        // adjust the site root, if necessary
1675        CmsObject cmsClone = adjustSiteRootIfNecessary(cms, this);
1676
1677        // calculate the module resources
1678        List<CmsResource> moduleResources = calculateModuleResources(cmsClone, this);
1679
1680        for (CmsResource resource : moduleResources) {
1681            try {
1682                List<CmsResource> resourcesToCheck = Lists.newArrayList();
1683                resourcesToCheck.add(resource);
1684                if (resource.isFolder()) {
1685                    resourcesToCheck.addAll(cms.readResources(resource, CmsResourceFilter.IGNORE_EXPIRATION, true));
1686                }
1687                for (CmsResource resourceToCheck : resourcesToCheck) {
1688                    if (resourceToCheck.getDateLastModified() > m_checkpointTime) {
1689                        return true;
1690                    }
1691                }
1692            } catch (CmsException e) {
1693                LOG.warn(e.getLocalizedMessage(), e);
1694                continue;
1695            }
1696        }
1697        return false;
1698    }
1699
1700    /**
1701     * @see java.lang.Object#toString()
1702     */
1703    @Override
1704    public String toString() {
1705
1706        if (m_name != null) {
1707            return "[CmsModule: " + m_name + "]";
1708        }
1709        return super.toString();
1710    }
1711
1712    /**
1713     * Checks if this modules configuration is frozen.<p>
1714     *
1715     * @throws CmsIllegalArgumentException in case the configuration is already frozen
1716     */
1717    protected void checkFrozen() throws CmsIllegalArgumentException {
1718
1719        if (m_frozen) {
1720            throw new CmsIllegalArgumentException(Messages.get().container(Messages.ERR_MODULE_FROZEN_1, getName()));
1721        }
1722    }
1723
1724    /**
1725     * Initializes this module, also freezing the module configuration.<p>
1726     *
1727     * @param cms an initialized OpenCms user context
1728     *
1729     * @throws CmsRoleViolationException if the given users does not have the <code>{@link CmsRole#DATABASE_MANAGER}</code> role
1730     */
1731    protected void initialize(CmsObject cms) throws CmsRoleViolationException {
1732
1733        checkFrozen();
1734        // check if the user has the required permissions
1735        OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER);
1736
1737        m_frozen = true;
1738        m_resources = Collections.unmodifiableList(m_resources);
1739        m_excluderesources = Collections.unmodifiableList(m_excluderesources);
1740    }
1741
1742    /**
1743     * Sets the module action instance for this module.<p>
1744     *
1745     * @param actionInstance the module action instance for this module
1746     */
1747    /*package*/void setActionInstance(I_CmsModuleAction actionInstance) {
1748
1749        m_actionInstance = actionInstance;
1750
1751    }
1752
1753    /**
1754     * Resolves the module property "additionalresources" to the resource list and
1755     * vice versa.<p>
1756     *
1757     * This "special" module property is required as long as we do not have a new
1758     * GUI for editing of module resource entries. Once we have the new GUI, the
1759     * handling of "additionalresources" will be moved to the import of the module
1760     * and done only if the imported module is a 5.0 module.<p>
1761     */
1762    private void initOldAdditionalResources() {
1763
1764        SortedMap<String, String> parameters = new TreeMap<String, String>(m_parameters);
1765        List<String> resources = new ArrayList<String>(m_resources);
1766
1767        String additionalResources;
1768        additionalResources = parameters.get(MODULE_PROPERTY_ADDITIONAL_RESOURCES);
1769        if (additionalResources != null) {
1770            StringTokenizer tok = new StringTokenizer(
1771                additionalResources,
1772                MODULE_PROPERTY_ADDITIONAL_RESOURCES_SEPARATOR);
1773            while (tok.hasMoreTokens()) {
1774                String resource = tok.nextToken().trim();
1775                if ((!"-".equals(resource)) && (!resources.contains(resource))) {
1776                    resources.add(resource);
1777                }
1778            }
1779        }
1780
1781        m_resources = resources;
1782    }
1783
1784    /**
1785     * Checks if two objects are either both null, or equal.<p>
1786     *
1787     * @param a the first object to check
1788     * @param b the second object to check
1789     * @return true if the two object are either both null, or equal
1790     */
1791    private boolean isEqual(Object a, Object b) {
1792
1793        if (a == null) {
1794            return (b == null);
1795        }
1796        if (b == null) {
1797            return false;
1798        }
1799        return a.equals(b);
1800    }
1801
1802}