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.configuration;
029
030import org.opencms.db.CmsOnlineFolderOptions;
031import org.opencms.file.CmsProperty;
032import org.opencms.file.collectors.I_CmsResourceCollector;
033import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
034import org.opencms.file.types.CmsResourceTypeXmlContent;
035import org.opencms.file.types.I_CmsResourceType;
036import org.opencms.loader.CmsDefaultFileNameGenerator;
037import org.opencms.loader.CmsMimeType;
038import org.opencms.loader.CmsResourceManager;
039import org.opencms.loader.I_CmsResourceLoader;
040import org.opencms.main.CmsLog;
041import org.opencms.main.OpenCms;
042import org.opencms.relations.CmsRelationType;
043import org.opencms.util.CmsHtmlConverterOption;
044import org.opencms.util.CmsResourceTranslator;
045import org.opencms.util.CmsStringUtil;
046import org.opencms.widgets.I_CmsWidget;
047import org.opencms.xml.CmsXmlContentTypeManager;
048import org.opencms.xml.types.I_CmsXmlSchemaType;
049
050import java.util.ArrayList;
051import java.util.Collections;
052import java.util.Iterator;
053import java.util.List;
054
055import org.apache.commons.digester3.Digester;
056import org.apache.commons.digester3.Rule;
057
058import org.dom4j.Element;
059import org.xml.sax.Attributes;
060
061/**
062 * VFS master configuration class.<p>
063 *
064 * @since 6.0.0
065 */
066public class CmsVfsConfiguration extends A_CmsXmlConfiguration {
067
068    /** The adjust-links-folder attribute. */
069    public static final String A_ADJUST_LINKS_FOLDER = "adjust-links-folder";
070
071    /** The widget configuration attribute. */
072    public static final String A_CONFIGURATION = "configuration";
073
074    /** The widget attribute. */
075    public static final String A_DEFAULTWIDGET = "defaultwidget";
076
077    /** The extension attribute name. */
078    public static final String A_EXTENSION = "extension";
079
080    /** The source attribute name. */
081    public static final String A_SOURCE = "source";
082
083    /** The target attribute name. */
084    public static final String A_TARGET = "target";
085
086    /** The name of the DTD for this configuration. */
087    public static final String CONFIGURATION_DTD_NAME = "opencms-vfs.dtd";
088
089    /** The name of the default XML file for this configuration. */
090    public static final String DEFAULT_XML_FILE_NAME = "opencms-vfs.xml";
091
092    /** The collector node name. */
093    public static final String N_COLLECTOR = "collector";
094
095    /** The collectors node name. */
096    public static final String N_COLLECTORS = "collectors";
097
098    public static final String N_PATH = "path";
099
100    /** The copy-resource node name.*/
101    public static final String N_COPY_RESOURCE = "copy-resource";
102
103    /** The copy-resources node name.*/
104    public static final String N_COPY_RESOURCES = "copy-resources";
105
106    /** The defaultfile node name. */
107    public static final String N_DEFAULTFILE = "defaultfile";
108
109    /** The defaultfiles node name. */
110    public static final String N_DEFAULTFILES = "defaultfiles";
111
112    /** File translations node name. */
113    public static final String N_FILETRANSLATIONS = "filetranslations";
114
115    /** Folder translations node name. */
116    public static final String N_FOLDERTRANSLATIONS = "foldertranslations";
117
118    /** The html-converter node name.*/
119    public static final String N_HTML_CONVERTER = "html-converter";
120
121    /** The html-converters node name.*/
122    public static final String N_HTML_CONVERTERS = "html-converters";
123
124    /** The node name of an individual resource loader. */
125    public static final String N_LOADER = "loader";
126
127    /** The mapping node name. */
128    public static final String N_MAPPING = "mapping";
129
130    /** The mappings node name. */
131    public static final String N_MAPPINGS = "mappings";
132
133    /** The mimetype node name. */
134    public static final String N_MIMETYPE = "mimetype";
135
136    /** The mimetypes node name. */
137    public static final String N_MIMETYPES = "mimetypes";
138
139    /** The properties node name. */
140    public static final String N_PROPERTIES = "properties";
141
142    /** The relation type node name. */
143    public static final String N_RELATIONTYPE = "relationtype";
144
145    /** The relation types node name. */
146    public static final String N_RELATIONTYPES = "relationtypes";
147
148    /** The resource loaders node name. */
149    public static final String N_RESOURCELOADERS = "resourceloaders";
150
151    /** The main resource node name. */
152    public static final String N_RESOURCES = "resources";
153
154    /** The resource types node name. */
155    public static final String N_RESOURCETYPES = "resourcetypes";
156
157    /** The schematype node name. */
158    public static final String N_SCHEMATYPE = "schematype";
159
160    /** The storage-policy node name. */
161    public static final String N_STORAGE_POLICY = "storage-policy";
162
163    /** The online-folders node name. */
164    public static final String N_ONLINE_FOLDERS = "online-folders";
165
166    /** The schematypes node name. */
167    public static final String N_SCHEMATYPES = "schematypes";
168
169    /** Individual translation node name. */
170    public static final String N_TRANSLATION = "translation";
171
172    /** The translations master node name. */
173    public static final String N_TRANSLATIONS = "translations";
174
175    /** The node name of an individual resource type. */
176    public static final String N_TYPE = "type";
177
178    /** The node name for the version history. */
179    public static final String N_VERSIONHISTORY = "versionhistory";
180
181    /** The main vfs configuration node name. */
182    public static final String N_VFS = "vfs";
183
184    /** The widget node name. */
185    public static final String N_WIDGET = "widget";
186
187    /** The widget alias node name. */
188    public static final String N_WIDGET_ALIAS = "widget-alias";
189
190    /** The widgets node name. */
191    public static final String N_WIDGETS = "widgets";
192
193    /** The xmlcontent node name. */
194    public static final String N_XMLCONTENT = "xmlcontent";
195
196    /** The xmlcontents node name. */
197    public static final String N_XMLCONTENTS = "xmlcontents";
198
199    /** XSD translations node name. */
200    public static final String N_XSDTRANSLATIONS = "xsdtranslations";
201
202    /** The namegenerator node name. */
203    private static final String N_NAMEGENERATOR = "namegenerator";
204
205    private CmsOnlineFolderOptions m_onlineFolderOptions = new CmsOnlineFolderOptions(
206        new ArrayList<>(),
207        new CmsParameterConfiguration());
208
209    /** The configured XML content type manager. */
210    CmsXmlContentTypeManager m_xmlContentTypeManager;
211
212    /** The list of configured default files. */
213    private List<String> m_defaultFiles;
214
215    /** Controls if file translation is enabled. */
216    private boolean m_fileTranslationEnabled;
217
218    /** The list of file translations. */
219    private List<String> m_fileTranslations;
220
221    /** Controls if folder translation is enabled. */
222    private boolean m_folderTranslationEnabled;
223
224    /** The list of folder translations. */
225    private List<String> m_folderTranslations;
226
227    /** The configured resource manager. */
228    private CmsResourceManager m_resourceManager;
229
230    /** The configured storage policy. */
231    private CmsStoragePolicyConfiguration m_storagePolicyConfiguration;
232
233    /** Controls if XSD translation is enabled. */
234    private boolean m_xsdTranslationEnabled;
235
236    /** The list of XSD translations. */
237    private List<String> m_xsdTranslations;
238
239    /**
240     * Adds the resource type rules to the given digester.<p>
241     *
242     * @param digester the digester to add the rules to
243     */
244    public static void addResourceTypeXmlRules(Digester digester) {
245
246        // add rules for resource types
247        digester.addFactoryCreate("*/" + N_RESOURCETYPES + "/" + N_TYPE, CmsDigesterResourceTypeCreationFactory.class);
248        digester.addSetNext("*/" + N_RESOURCETYPES + "/" + N_TYPE, I_CmsResourceType.ADD_RESOURCE_TYPE_METHOD);
249
250        // please note: the order of the rules is very important here,
251        // the "set next" rule (above) must be added _before_ the "call method" rule (below)!
252        // reason is digester will call the rule that was last added first
253        // here we must make sure that the resource type is initialized first (with the "call method" rule)
254        // before it is actually added to the resource type container (with the "set next" rule)
255        // otherwise there will be an empty resource type added to the container, and validation will not work
256        digester.addCallMethod(
257            "*/" + N_RESOURCETYPES + "/" + N_TYPE,
258            I_CmsConfigurationParameterHandler.INIT_CONFIGURATION_METHOD,
259            3);
260        // please note: the resource types use a special version of the init method with 3 parameters
261        digester.addCallParam("*/" + N_RESOURCETYPES + "/" + N_TYPE, 0, A_NAME);
262        digester.addCallParam("*/" + N_RESOURCETYPES + "/" + N_TYPE, 1, A_ID);
263        digester.addCallParam("*/" + N_RESOURCETYPES + "/" + N_TYPE, 2, A_CLASS);
264
265        // add rules for default properties
266        digester.addObjectCreate(
267            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY,
268            CmsProperty.class);
269        digester.addCallMethod(
270            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY + "/" + N_NAME,
271            "setName",
272            1);
273        digester.addCallParam(
274            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY + "/" + N_NAME,
275            0);
276
277        digester.addCallMethod(
278            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY + "/" + N_VALUE,
279            "setValue",
280            2);
281        digester.addCallParam(
282            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY + "/" + N_VALUE,
283            0);
284        digester.addCallParam(
285            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY + "/" + N_VALUE,
286            1,
287            A_TYPE);
288
289        digester.addSetNext(
290            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_PROPERTIES + "/" + N_PROPERTY,
291            "addDefaultProperty");
292
293        // extension mapping rules
294        digester.addCallMethod(
295            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_MAPPINGS + "/" + N_MAPPING,
296            I_CmsResourceType.ADD_MAPPING_METHOD,
297            1);
298        digester.addCallParam("*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_MAPPINGS + "/" + N_MAPPING, 0, A_SUFFIX);
299
300        digester.addCallMethod(
301            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_COPY_RESOURCES,
302            "setAdjustLinksFolder",
303            1);
304        digester.addCallParam("*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_COPY_RESOURCES, 0, A_ADJUST_LINKS_FOLDER);
305
306        // copy resource rules
307        digester.addCallMethod(
308            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_COPY_RESOURCES + "/" + N_COPY_RESOURCE,
309            "addCopyResource",
310            3);
311        digester.addCallParam(
312            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_COPY_RESOURCES + "/" + N_COPY_RESOURCE,
313            0,
314            A_SOURCE);
315        digester.addCallParam(
316            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_COPY_RESOURCES + "/" + N_COPY_RESOURCE,
317            1,
318            A_TARGET);
319        digester.addCallParam(
320            "*/" + N_RESOURCETYPES + "/" + N_TYPE + "/" + N_COPY_RESOURCES + "/" + N_COPY_RESOURCE,
321            2,
322            A_TYPE);
323
324    }
325
326    /**
327     * Creates the xml output for resourcetype nodes.<p>
328     *
329     * @param startNode the startnode to add all rescource types to
330     * @param resourceTypes the list of resource types
331     * @param module flag, signaling to add them module resource types or not
332     */
333    public static void generateResourceTypeXml(
334        Element startNode,
335        List<I_CmsResourceType> resourceTypes,
336        boolean module) {
337
338        for (int i = 0; i < resourceTypes.size(); i++) {
339            I_CmsResourceType resType = resourceTypes.get(i);
340            // only add this resource type to the xml output, if it is no additional type defined
341            // in a module
342            if (resType.isAdditionalModuleResourceType() == module) {
343                Element resourceType = startNode.addElement(N_TYPE).addAttribute(A_CLASS, resType.getClassName());
344                // add type id and type name
345                resourceType.addAttribute(A_NAME, resType.getTypeName());
346                resourceType.addAttribute(A_ID, String.valueOf(resType.getTypeId()));
347                // add resource mappings
348                List<String> mappings = resType.getConfiguredMappings();
349                if ((mappings != null) && (mappings.size() > 0)) {
350                    Element mappingsNode = resourceType.addElement(N_MAPPINGS);
351                    for (int j = 0; j < mappings.size(); j++) {
352                        Element mapping = mappingsNode.addElement(N_MAPPING);
353                        mapping.addAttribute(A_SUFFIX, mappings.get(j));
354                    }
355                }
356                // add default properties
357                List<CmsProperty> properties = resType.getConfiguredDefaultProperties();
358                if (properties != null) {
359                    if (properties.size() > 0) {
360                        Element propertiesNode = resourceType.addElement(N_PROPERTIES);
361                        Iterator<CmsProperty> p = properties.iterator();
362                        while (p.hasNext()) {
363                            CmsProperty property = p.next();
364                            Element propertyNode = propertiesNode.addElement(N_PROPERTY);
365                            propertyNode.addElement(N_NAME).addText(property.getName());
366                            if (property.getStructureValue() != null) {
367                                propertyNode.addElement(N_VALUE).addCDATA(property.getStructureValue());
368                            }
369                            if (property.getResourceValue() != null) {
370                                propertyNode.addElement(N_VALUE).addAttribute(A_TYPE, CmsProperty.TYPE_SHARED).addCDATA(
371                                    property.getResourceValue());
372                            }
373                        }
374                    }
375                }
376                // add copy resources
377                List<CmsConfigurationCopyResource> copyRes = resType.getConfiguredCopyResources();
378                if ((copyRes != null) && (copyRes.size() > 0)) {
379                    Element copyResNode = resourceType.addElement(N_COPY_RESOURCES);
380                    Iterator<CmsConfigurationCopyResource> p = copyRes.iterator();
381                    String adjustLinksFolder = resType.getAdjustLinksFolder();
382                    if (adjustLinksFolder != null) {
383                        copyResNode.addAttribute(A_ADJUST_LINKS_FOLDER, adjustLinksFolder);
384                    }
385                    while (p.hasNext()) {
386                        CmsConfigurationCopyResource cRes = p.next();
387                        Element cNode = copyResNode.addElement(N_COPY_RESOURCE);
388                        cNode.addAttribute(A_SOURCE, cRes.getSource());
389                        if (!cRes.isTargetWasNull()) {
390                            cNode.addAttribute(A_TARGET, cRes.getTarget());
391                        }
392                        if (!cRes.isTypeWasNull()) {
393                            cNode.addAttribute(A_TYPE, cRes.getTypeString());
394                        }
395                    }
396                }
397                // add optional parameters
398                CmsParameterConfiguration configuration = resType.getConfiguration();
399                if (configuration != null) {
400                    List<String> ignore = null;
401                    if ((resType instanceof CmsResourceTypeXmlContainerPage)) {
402                        ignore = new ArrayList<String>(1);
403                        ignore.add(CmsResourceTypeXmlContent.CONFIGURATION_SCHEMA);
404                    }
405                    configuration.appendToXml(resourceType, ignore);
406                }
407            }
408        }
409    }
410
411    /**
412     * Adds a directory default file.<p>
413     *
414     * @param defaultFile the directory default file to add
415     */
416    public void addDefaultFile(String defaultFile) {
417
418        m_defaultFiles.add(defaultFile);
419        if (CmsLog.INIT.isInfoEnabled()) {
420            CmsLog.INIT.info(
421                Messages.get().getBundle().key(
422                    Messages.INIT_VFS_DEFAULT_FILE_2,
423                    Integer.valueOf(m_defaultFiles.size()),
424                    defaultFile));
425        }
426    }
427
428    /**
429     * Adds one file translation rule.<p>
430     *
431     * @param translation the file translation rule to add
432     */
433    public void addFileTranslation(String translation) {
434
435        m_fileTranslations.add(translation);
436        if (CmsLog.INIT.isInfoEnabled()) {
437            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_ADD_FILE_TRANSLATION_1, translation));
438        }
439    }
440
441    /**
442     * Adds one folder translation rule.<p>
443     *
444     * @param translation the folder translation rule to add
445     */
446    public void addFolderTranslation(String translation) {
447
448        m_folderTranslations.add(translation);
449        if (CmsLog.INIT.isInfoEnabled()) {
450            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_ADD_FOLDER_TRANSLATION_1, translation));
451        }
452    }
453
454    /**
455     * @see org.opencms.configuration.I_CmsXmlConfiguration#addXmlDigesterRules(org.apache.commons.digester3.Digester)
456     */
457    public void addXmlDigesterRules(Digester digester) {
458
459        // add finish rule
460        digester.addCallMethod("*/" + N_VFS, "initializeFinished");
461
462        // creation of the resource manager
463        digester.addObjectCreate("*/" + N_VFS + "/" + N_RESOURCES, CmsResourceManager.class);
464        digester.addCallMethod(
465            "*/" + N_VFS + "/" + N_RESOURCES,
466            I_CmsConfigurationParameterHandler.INIT_CONFIGURATION_METHOD);
467        digester.addSetNext("*/" + N_VFS + "/" + N_RESOURCES, "setResourceManager");
468
469        // add rules for resource loaders
470        digester.addObjectCreate(
471            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_RESOURCELOADERS + "/" + N_LOADER,
472            CmsConfigurationException.class.getName(),
473            A_CLASS);
474        digester.addCallMethod(
475            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_RESOURCELOADERS + "/" + N_LOADER,
476            I_CmsConfigurationParameterHandler.INIT_CONFIGURATION_METHOD);
477        digester.addSetNext("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_RESOURCELOADERS + "/" + N_LOADER, "addLoader");
478
479        // add rules for resource types
480        addResourceTypeXmlRules(digester);
481
482        // add rules for storage policy
483        digester.addRule("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_STORAGE_POLICY, new Rule() {
484
485            @Override
486            public void begin(String namespace, String name, Attributes attributes) throws Exception {
487
488                CmsStoragePolicyConfiguration configuration = new CmsStoragePolicyConfiguration();
489                configuration.setClassName(attributes.getValue(A_CLASS));
490                getDigester().push(configuration);
491            }
492
493            @Override
494            public void end(String namespace, String name) throws Exception {
495
496                CmsStoragePolicyConfiguration configuration = getDigester().pop();
497                configuration.initConfiguration();
498                setStoragePolicyConfiguration(configuration);
499            }
500        });
501
502        // add rules for VFS content collectors
503        digester.addCallMethod(
504            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_COLLECTORS + "/" + N_COLLECTOR,
505            "addContentCollector",
506            2);
507        digester.addCallParam("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_COLLECTORS + "/" + N_COLLECTOR, 0, A_CLASS);
508        digester.addCallParam("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_COLLECTORS + "/" + N_COLLECTOR, 1, A_ORDER);
509
510        // add the name generator
511        digester.addObjectCreate(
512            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_NAMEGENERATOR,
513            CmsDefaultFileNameGenerator.class.getName(),
514            A_CLASS);
515        digester.addSetNext("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_NAMEGENERATOR, "setNameGenerator");
516
517        // add MIME type rules
518        digester.addCallMethod(
519            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_MIMETYPES + "/" + N_MIMETYPE,
520            "addMimeType",
521            2);
522        digester.addCallParam("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_MIMETYPES + "/" + N_MIMETYPE, 0, A_EXTENSION);
523        digester.addCallParam("*/" + N_VFS + "/" + N_RESOURCES + "/" + N_MIMETYPES + "/" + N_MIMETYPE, 1, A_TYPE);
524
525        // add relation type rules
526        digester.addCallMethod(
527            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_RELATIONTYPES + "/" + N_RELATIONTYPE,
528            "addRelationType",
529            2);
530        digester.addCallParam(
531            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_RELATIONTYPES + "/" + N_RELATIONTYPE,
532            0,
533            A_NAME);
534        digester.addCallParam(
535            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_RELATIONTYPES + "/" + N_RELATIONTYPE,
536            1,
537            A_TYPE);
538
539        // add html converter rules
540        digester.addCallMethod(
541            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_HTML_CONVERTERS + "/" + N_HTML_CONVERTER,
542            "addHtmlConverter",
543            2);
544        digester.addCallParam(
545            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_HTML_CONVERTERS + "/" + N_HTML_CONVERTER,
546            0,
547            A_NAME);
548        digester.addCallParam(
549            "*/" + N_VFS + "/" + N_RESOURCES + "/" + N_HTML_CONVERTERS + "/" + N_HTML_CONVERTER,
550            1,
551            A_CLASS);
552
553        // generic <param> parameter rules
554        digester.addCallMethod(
555            "*/" + I_CmsXmlConfiguration.N_PARAM,
556            I_CmsConfigurationParameterHandler.ADD_PARAMETER_METHOD,
557            2);
558        digester.addCallParam("*/" + I_CmsXmlConfiguration.N_PARAM, 0, I_CmsXmlConfiguration.A_NAME);
559        digester.addCallParam("*/" + I_CmsXmlConfiguration.N_PARAM, 1);
560
561        // add rule for default files
562        digester.addCallMethod("*/" + N_VFS + "/" + N_DEFAULTFILES + "/" + N_DEFAULTFILE, "addDefaultFile", 1);
563        digester.addCallParam("*/" + N_VFS + "/" + N_DEFAULTFILES + "/" + N_DEFAULTFILE, 0, A_NAME);
564
565        // add rules for file translations
566        digester.addCallMethod(
567            "*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_FILETRANSLATIONS + "/" + N_TRANSLATION,
568            "addFileTranslation",
569            0);
570        digester.addCallMethod(
571            "*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_FILETRANSLATIONS,
572            "setFileTranslationEnabled",
573            1);
574        digester.addCallParam("*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_FILETRANSLATIONS, 0, A_ENABLED);
575
576        // add rules for file translations
577        digester.addCallMethod(
578            "*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_FOLDERTRANSLATIONS + "/" + N_TRANSLATION,
579            "addFolderTranslation",
580            0);
581        digester.addCallMethod(
582            "*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_FOLDERTRANSLATIONS,
583            "setFolderTranslationEnabled",
584            1);
585        digester.addCallParam("*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_FOLDERTRANSLATIONS, 0, A_ENABLED);
586
587        // add rules for file translations
588        digester.addCallMethod(
589            "*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_XSDTRANSLATIONS + "/" + N_TRANSLATION,
590            "addXsdTranslation",
591            0);
592        digester.addCallMethod(
593            "*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_XSDTRANSLATIONS,
594            "setXsdTranslationEnabled",
595            1);
596        digester.addCallParam("*/" + N_VFS + "/" + N_TRANSLATIONS + "/" + N_XSDTRANSLATIONS, 0, A_ENABLED);
597
598        // XML content type manager creation rules
599        digester.addObjectCreate("*/" + N_VFS + "/" + N_XMLCONTENT, CmsXmlContentTypeManager.class);
600        digester.addSetNext("*/" + N_VFS + "/" + N_XMLCONTENT, "setXmlContentTypeManager");
601
602        // XML content widgets add rules
603
604        // Widget definitions.
605        // 'aliases' list is used/reset by the rule for widgets, and filled by the rule for aliases.
606        final List<String> aliases = new ArrayList<>();
607        digester.addRule("*/" + N_VFS + "/" + N_XMLCONTENT + "/" + N_WIDGETS + "/" + N_WIDGET, new Rule() {
608
609            private String m_className;
610            private String m_config;
611
612            @Override
613            public void begin(String namespace, String name, Attributes attributes) throws Exception {
614
615                m_className = attributes.getValue(A_CLASS);
616                m_config = attributes.getValue(A_CONFIGURATION);
617                String alias = attributes.getValue(A_ALIAS);
618
619                aliases.clear();
620                if (alias != null) {
621                    aliases.add(alias.trim());
622                }
623            }
624
625            @Override
626            public void end(String namespace, String name) throws Exception {
627
628                CmsXmlContentTypeManager manager = getDigester().peek();
629                List<String> aliasesCopy = new ArrayList<>(aliases);
630                manager.addWidget(m_className, aliasesCopy, m_config);
631            }
632        });
633
634        digester.addRule(
635            "*/" + N_VFS + "/" + N_XMLCONTENT + "/" + N_WIDGETS + "/" + N_WIDGET + "/" + N_WIDGET_ALIAS,
636            new Rule() {
637
638                @Override
639                public void body(String namespace, String name, String text) throws Exception {
640
641                    aliases.add(text.trim());
642                }
643
644            });
645
646        // XML content schema type add rules
647        digester.addCallMethod(
648            "*/" + N_VFS + "/" + N_XMLCONTENT + "/" + N_SCHEMATYPES + "/" + N_SCHEMATYPE,
649            "addSchemaType",
650            2);
651        digester.addCallParam("*/" + N_VFS + "/" + N_XMLCONTENT + "/" + N_SCHEMATYPES + "/" + N_SCHEMATYPE, 0, A_CLASS);
652        digester.addCallParam(
653            "*/" + N_VFS + "/" + N_XMLCONTENT + "/" + N_SCHEMATYPES + "/" + N_SCHEMATYPE,
654            1,
655            A_DEFAULTWIDGET);
656
657        final CmsParameterConfiguration onlineFolderParams = new CmsParameterConfiguration();
658        final List<String> onlineFolderPaths = new ArrayList<>();
659        digester.addRule("*/" + N_ONLINE_FOLDERS, new Rule() {
660
661            @Override
662            public void begin(String namespace, String name, Attributes attributes) throws Exception {
663
664                super.begin(namespace, name, attributes);
665                getDigester().push(new I_CmsConfigurationParameterHandler() {
666
667                    @Override
668                    public void addConfigurationParameter(String paramName, String paramValue) {
669
670                        onlineFolderParams.add(paramName, paramValue);
671                    }
672
673                    @Override
674                    public CmsParameterConfiguration getConfiguration() {
675
676                        return onlineFolderParams;
677
678                    }
679
680                    @Override
681                    public void initConfiguration() throws CmsConfigurationException {
682
683                        // TODO Auto-generated method stub
684
685                    }
686                });
687            }
688
689            @Override
690            public void end(String namespace, String name) throws Exception {
691
692                getDigester().pop();
693                m_onlineFolderOptions = new CmsOnlineFolderOptions(onlineFolderPaths, onlineFolderParams);
694            }
695        });
696        digester.addRule("*/" + N_ONLINE_FOLDERS + "/" + N_PATH, new Rule() {
697
698            public void body(String namespace, String name, String text) throws Exception {
699
700                if (!CmsStringUtil.isEmptyOrWhitespaceOnly(text)) {
701                    onlineFolderPaths.add(text);
702                }
703            }
704        });
705    }
706
707    /**
708     * Adds one XSD translation rule.<p>
709     *
710     * @param translation the XSD translation rule to add
711     */
712    public void addXsdTranslation(String translation) {
713
714        m_xsdTranslations.add(translation);
715        if (CmsLog.INIT.isInfoEnabled()) {
716            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_ADD_XSD_TRANSLATION_1, translation));
717        }
718    }
719
720    /**
721     * @see org.opencms.configuration.I_CmsXmlConfiguration#generateXml(org.dom4j.Element)
722     */
723    public Element generateXml(Element parent) {
724
725        if (OpenCms.getRunLevel() >= OpenCms.RUNLEVEL_3_SHELL_ACCESS) {
726            m_resourceManager = OpenCms.getResourceManager();
727            m_xmlContentTypeManager = OpenCms.getXmlContentTypeManager();
728            m_defaultFiles = OpenCms.getDefaultFiles();
729        }
730
731        // generate vfs node and subnodes
732        Element vfs = parent.addElement(N_VFS);
733
734        // add resources main element
735        Element resources = vfs.addElement(N_RESOURCES);
736
737        // add resource loader
738        Element resourceloadersElement = resources.addElement(N_RESOURCELOADERS);
739        for (I_CmsResourceLoader loader : m_resourceManager.getLoaders()) {
740            // add the loader node
741            Element loaderNode = resourceloadersElement.addElement(N_LOADER);
742            loaderNode.addAttribute(A_CLASS, loader.getClass().getName());
743            CmsParameterConfiguration loaderConfiguration = loader.getConfiguration();
744            if (loaderConfiguration != null) {
745                loaderConfiguration.appendToXml(loaderNode);
746            }
747        }
748
749        // add resource types
750        Element resourcetypesElement = resources.addElement(N_RESOURCETYPES);
751        List<I_CmsResourceType> resourceTypes = new ArrayList<I_CmsResourceType>();
752        if (m_resourceManager.getResTypeUnknownFolder() != null) {
753            resourceTypes.add(m_resourceManager.getResTypeUnknownFolder());
754        }
755        if (m_resourceManager.getResTypeUnknownFile() != null) {
756            resourceTypes.add(m_resourceManager.getResTypeUnknownFile());
757        }
758        resourceTypes.addAll(m_resourceManager.getResourceTypes());
759        generateResourceTypeXml(resourcetypesElement, resourceTypes, false);
760
761        if (m_storagePolicyConfiguration != null) {
762            Element storagePolicyElement = resources.addElement(N_STORAGE_POLICY);
763            storagePolicyElement.addAttribute(A_CLASS, m_storagePolicyConfiguration.getClassName());
764            m_storagePolicyConfiguration.getConfiguration().appendToXml(storagePolicyElement);
765        }
766
767        // add VFS content collectors
768        Element collectorsElement = resources.addElement(N_COLLECTORS);
769        for (I_CmsResourceCollector collector : m_resourceManager.getRegisteredContentCollectors()) {
770            collectorsElement.addElement(N_COLLECTOR).addAttribute(
771                A_CLASS,
772                collector.getClass().getName()).addAttribute(A_ORDER, String.valueOf(collector.getOrder()));
773        }
774
775        Element namegeneratorElement = resources.addElement(N_NAMEGENERATOR);
776        String nameGeneratorClass = m_resourceManager.getNameGenerator().getClass().getName();
777        namegeneratorElement.addAttribute(A_CLASS, nameGeneratorClass);
778
779        // add MIME types
780        Element mimeTypesElement = resources.addElement(N_MIMETYPES);
781        for (CmsMimeType type : m_resourceManager.getMimeTypes()) {
782            mimeTypesElement.addElement(N_MIMETYPE).addAttribute(A_EXTENSION, type.getExtension()).addAttribute(
783                A_TYPE,
784                type.getType());
785        }
786
787        // add relation types
788        Element relationTypesElement = resources.addElement(N_RELATIONTYPES);
789        for (CmsRelationType type : m_resourceManager.getRelationTypes()) {
790            relationTypesElement.addElement(N_RELATIONTYPE).addAttribute(A_NAME, type.getName()).addAttribute(
791                A_TYPE,
792                type.getType());
793        }
794
795        // HTML converter configuration
796        boolean writeConfig = false;
797        for (CmsHtmlConverterOption converter : m_resourceManager.getHtmlConverters()) {
798            if (!converter.isDefault()) {
799                // found a non default converter configuration, set flag to write configuration
800                writeConfig = true;
801                break;
802            }
803        }
804        if (writeConfig) {
805            // configuration is written because non default options were found
806            Element htmlConvertersElement = resources.addElement(N_HTML_CONVERTERS);
807            for (CmsHtmlConverterOption converter : m_resourceManager.getHtmlConverters()) {
808                Element converterElement = htmlConvertersElement.addElement(N_HTML_CONVERTER).addAttribute(
809                    A_NAME,
810                    converter.getName());
811                converterElement.addAttribute(A_CLASS, converter.getClassName());
812            }
813        }
814
815        // add default file names
816        Element defaultFileElement = vfs.addElement(N_DEFAULTFILES);
817        for (String element : m_defaultFiles) {
818            defaultFileElement.addElement(N_DEFAULTFILE).addAttribute(A_NAME, element);
819        }
820
821        // add translation rules
822        Element translationsElement = vfs.addElement(N_TRANSLATIONS);
823
824        // file translation rules
825        Element fileTransElement = translationsElement.addElement(N_FILETRANSLATIONS).addAttribute(
826            A_ENABLED,
827            String.valueOf(m_fileTranslationEnabled));
828        for (String translation : m_fileTranslations) {
829            fileTransElement.addElement(N_TRANSLATION).setText(translation);
830        }
831
832        // folder translation rules
833        Element folderTransElement = translationsElement.addElement(N_FOLDERTRANSLATIONS).addAttribute(
834            A_ENABLED,
835            String.valueOf(m_folderTranslationEnabled));
836        for (String translation : m_folderTranslations) {
837            folderTransElement.addElement(N_TRANSLATION).setText(translation);
838        }
839
840        // XSD translation rules
841        Element xsdTransElement = translationsElement.addElement(N_XSDTRANSLATIONS).addAttribute(
842            A_ENABLED,
843            String.valueOf(m_xsdTranslationEnabled));
844        for (String translation : m_xsdTranslations) {
845            xsdTransElement.addElement(N_TRANSLATION).setText(translation);
846        }
847
848        Element onlineFoldersElement = vfs.addElement(N_ONLINE_FOLDERS);
849        for (String path : m_onlineFolderOptions.getPaths()) {
850            Element pathElem = onlineFoldersElement.addElement(N_PATH);
851            pathElem.setText(path);
852        }
853        for (String key : m_onlineFolderOptions.getParams().keySet()) {
854            Element paramElem = onlineFoldersElement.addElement(N_PARAM);
855            paramElem.addAttribute(A_NAME, key);
856            paramElem.setText(m_onlineFolderOptions.getParams().get(key));
857        }
858
859        // XML content configuration
860        Element xmlContentsElement = vfs.addElement(N_XMLCONTENT);
861
862        // XML widgets
863        Element xmlWidgetsElement = xmlContentsElement.addElement(N_WIDGETS);
864        for (String widget : m_xmlContentTypeManager.getRegisteredWidgetNames()) {
865            Element widgetElement = xmlWidgetsElement.addElement(N_WIDGET).addAttribute(A_CLASS, widget);
866            for (String alias : m_xmlContentTypeManager.getRegisteredWidgetAliases(widget)) {
867                widgetElement.addElement(N_WIDGET_ALIAS).addText(alias);
868            }
869            String defaultConfiguration = m_xmlContentTypeManager.getWidgetDefaultConfiguration(widget);
870            if (CmsStringUtil.isNotEmpty(defaultConfiguration)) {
871                widgetElement.addAttribute(A_CONFIGURATION, defaultConfiguration);
872            }
873        }
874
875        // XML content types
876        Element xmlSchemaTypesElement = xmlContentsElement.addElement(N_SCHEMATYPES);
877        for (I_CmsXmlSchemaType type : m_xmlContentTypeManager.getRegisteredSchemaTypes()) {
878            I_CmsWidget widget = m_xmlContentTypeManager.getWidgetDefault(type.getTypeName());
879            xmlSchemaTypesElement.addElement(N_SCHEMATYPE).addAttribute(
880                A_CLASS,
881                type.getClass().getName()).addAttribute(A_DEFAULTWIDGET, widget.getClass().getName());
882        }
883
884        // return the vfs node
885        return vfs;
886    }
887
888    /**
889     * Returns the (unmodifiable) list of configured directory default files.<p>
890     *
891     * @return the (unmodifiable) list of configured directory default files
892     */
893    public List<String> getDefaultFiles() {
894
895        return Collections.unmodifiableList(m_defaultFiles);
896    }
897
898    /**
899     * @see org.opencms.configuration.I_CmsXmlConfiguration#getDtdFilename()
900     */
901    public String getDtdFilename() {
902
903        return CONFIGURATION_DTD_NAME;
904    }
905
906    /**
907     * Returns the file resource translator that has been initialized
908     * with the configured file translation rules.<p>
909     *
910     * @return the file resource translator
911     */
912    public CmsResourceTranslator getFileTranslator() {
913
914        String[] array = new String[0];
915        if (m_fileTranslationEnabled) {
916            array = new String[m_fileTranslations.size()];
917            for (int i = 0; i < m_fileTranslations.size(); i++) {
918                array[i] = m_fileTranslations.get(i);
919            }
920        }
921        return new CmsResourceTranslator(array, true);
922    }
923
924    /**
925     * Returns the folder resource translator that has been initialized
926     * with the configured folder translation rules.<p>
927     *
928     * @return the folder resource translator
929     */
930    public CmsResourceTranslator getFolderTranslator() {
931
932        String[] array = new String[0];
933        if (m_folderTranslationEnabled) {
934            array = new String[m_folderTranslations.size()];
935            for (int i = 0; i < m_folderTranslations.size(); i++) {
936                array[i] = m_folderTranslations.get(i);
937            }
938        }
939        return new CmsResourceTranslator(array, false);
940    }
941
942    /**
943     * Gets the configured online folder options.
944     *
945     * @return the online folder options
946     */
947    public CmsOnlineFolderOptions getOnlineFolderOptions() {
948
949        return m_onlineFolderOptions;
950    }
951
952    /**
953     * Returns the initialized resource manager.<p>
954     *
955     * @return the initialized resource manager
956     */
957    public CmsResourceManager getResourceManager() {
958
959        return m_resourceManager;
960    }
961
962    /**
963     * Returns the configured storage policy configuration.<p>
964     *
965     * @return the configured storage policy configuration
966     */
967    public CmsStoragePolicyConfiguration getStoragePolicyConfiguration() {
968
969        return m_storagePolicyConfiguration;
970    }
971
972    /**
973     * Returns the configured XML content type manager.<p>
974     *
975     * @return the configured XML content type manager
976     */
977    public CmsXmlContentTypeManager getXmlContentTypeManager() {
978
979        return m_xmlContentTypeManager;
980    }
981
982    /**
983     * Returns the XSD translator that has been initialized
984     * with the configured XSD translation rules.<p>
985     *
986     * @return the XSD translator
987     */
988    public CmsResourceTranslator getXsdTranslator() {
989
990        String[] array = m_xsdTranslationEnabled ? new String[m_xsdTranslations.size()] : new String[0];
991        for (int i = 0; i < m_xsdTranslations.size(); i++) {
992            array[i] = m_xsdTranslations.get(i);
993        }
994        return new CmsResourceTranslator(array, true);
995    }
996
997    /**
998     * Will be called when configuration of this object is finished.<p>
999     */
1000    public void initializeFinished() {
1001
1002        if (CmsLog.INIT.isInfoEnabled()) {
1003            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_CONFIG_FINISHED_0));
1004        }
1005    }
1006
1007    /**
1008     * Enables or disables the file translation rules.<p>
1009     *
1010     * @param value if <code>"true"</code>, file translation is enabled, otherwise it is disabled
1011     */
1012    public void setFileTranslationEnabled(String value) {
1013
1014        m_fileTranslationEnabled = Boolean.valueOf(value).booleanValue();
1015        if (CmsLog.INIT.isInfoEnabled()) {
1016            if (m_fileTranslationEnabled) {
1017                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_FILE_TRANSLATION_ENABLE_0));
1018            } else {
1019                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_FILE_TRANSLATION_DISABLE_0));
1020            }
1021        }
1022    }
1023
1024    /**
1025     * Enables or disables the folder translation rules.<p>
1026     *
1027     * @param value if <code>"true"</code>, folder translation is enabled, otherwise it is disabled
1028     */
1029    public void setFolderTranslationEnabled(String value) {
1030
1031        m_folderTranslationEnabled = Boolean.valueOf(value).booleanValue();
1032        if (CmsLog.INIT.isInfoEnabled()) {
1033            if (m_folderTranslationEnabled) {
1034                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_FOLDER_TRANSLATION_ENABLE_0));
1035            } else {
1036                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_FOLDER_TRANSLATION_DISABLE_0));
1037            }
1038        }
1039    }
1040
1041    /**
1042     * Sets the generated resource manager.<p>
1043     *
1044     * @param manager the resource manager to set
1045     */
1046    public void setResourceManager(CmsResourceManager manager) {
1047
1048        m_resourceManager = manager;
1049    }
1050
1051    /**
1052     * Sets the configured storage policy configuration.<p>
1053     *
1054     * @param storagePolicyConfiguration the storage policy configuration
1055     */
1056    public void setStoragePolicyConfiguration(CmsStoragePolicyConfiguration storagePolicyConfiguration) {
1057
1058        m_storagePolicyConfiguration = storagePolicyConfiguration;
1059    }
1060
1061    /**
1062     * Sets the generated XML content type manager.<p>
1063     *
1064     * @param manager the generated XML content type manager to set
1065     */
1066    public void setXmlContentTypeManager(CmsXmlContentTypeManager manager) {
1067
1068        if (CmsLog.INIT.isInfoEnabled()) {
1069            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_XML_CONTENT_FINISHED_0));
1070        }
1071        m_xmlContentTypeManager = manager;
1072    }
1073
1074    /**
1075     * Enables or disables the XSD translation rules.<p>
1076     *
1077     * @param value if <code>"true"</code>, XSD translation is enabled, otherwise it is disabled
1078     */
1079    public void setXsdTranslationEnabled(String value) {
1080
1081        m_xsdTranslationEnabled = Boolean.valueOf(value).booleanValue();
1082        if (CmsLog.INIT.isInfoEnabled()) {
1083            if (m_xsdTranslationEnabled) {
1084                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_XSD_TRANSLATION_ENABLE_0));
1085            } else {
1086                CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_XSD_TRANSLATION_DISABLE_0));
1087            }
1088        }
1089    }
1090
1091    /**
1092     * @see org.opencms.configuration.A_CmsXmlConfiguration#initMembers()
1093     */
1094    @Override
1095    protected void initMembers() {
1096
1097        setXmlFileName(DEFAULT_XML_FILE_NAME);
1098        m_fileTranslations = new ArrayList<String>();
1099        m_folderTranslations = new ArrayList<String>();
1100        m_xsdTranslations = new ArrayList<String>();
1101        m_defaultFiles = new ArrayList<String>();
1102        if (CmsLog.INIT.isInfoEnabled()) {
1103            CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_VFS_CONFIG_INIT_0));
1104        }
1105    }
1106}