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