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