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