Source Code Cross Referenced for CmsDefaultXmlContentHandler.java in  » Content-Management-System » opencms » org » opencms » xml » content » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » opencms » org.opencms.xml.content 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * File   : $Source: /usr/local/cvs/opencms/src/org/opencms/xml/content/CmsDefaultXmlContentHandler.java,v $
0003:         * Date   : $Date: 2008-02-27 12:05:36 $
0004:         * Version: $Revision: 1.58 $
0005:         *
0006:         * This library is part of OpenCms -
0007:         * the Open Source Content Management System
0008:         *
0009:         * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
0010:         *
0011:         * This library is free software; you can redistribute it and/or
0012:         * modify it under the terms of the GNU Lesser General Public
0013:         * License as published by the Free Software Foundation; either
0014:         * version 2.1 of the License, or (at your option) any later version.
0015:         *
0016:         * This library is distributed in the hope that it will be useful,
0017:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0018:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0019:         * Lesser General Public License for more details.
0020:         *
0021:         * For further information about Alkacon Software GmbH, please see the
0022:         * company website: http://www.alkacon.com
0023:         *
0024:         * For further information about OpenCms, please see the
0025:         * project website: http://www.opencms.org
0026:         * 
0027:         * You should have received a copy of the GNU Lesser General Public
0028:         * License along with this library; if not, write to the Free Software
0029:         * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
0030:         */
0031:
0032:        package org.opencms.xml.content;
0033:
0034:        import org.opencms.configuration.CmsConfigurationManager;
0035:        import org.opencms.file.CmsFile;
0036:        import org.opencms.file.CmsObject;
0037:        import org.opencms.file.CmsProperty;
0038:        import org.opencms.file.CmsResource;
0039:        import org.opencms.file.CmsResourceFilter;
0040:        import org.opencms.i18n.CmsEncoder;
0041:        import org.opencms.i18n.CmsMessages;
0042:        import org.opencms.lock.CmsLock;
0043:        import org.opencms.main.CmsException;
0044:        import org.opencms.main.CmsLog;
0045:        import org.opencms.main.CmsRuntimeException;
0046:        import org.opencms.main.OpenCms;
0047:        import org.opencms.relations.CmsLink;
0048:        import org.opencms.relations.CmsRelationType;
0049:        import org.opencms.site.CmsSite;
0050:        import org.opencms.util.CmsFileUtil;
0051:        import org.opencms.util.CmsHtmlConverter;
0052:        import org.opencms.util.CmsMacroResolver;
0053:        import org.opencms.util.CmsStringUtil;
0054:        import org.opencms.widgets.CmsDisplayWidget;
0055:        import org.opencms.widgets.I_CmsWidget;
0056:        import org.opencms.xml.CmsXmlContentDefinition;
0057:        import org.opencms.xml.CmsXmlEntityResolver;
0058:        import org.opencms.xml.CmsXmlException;
0059:        import org.opencms.xml.CmsXmlUtils;
0060:        import org.opencms.xml.types.CmsXmlNestedContentDefinition;
0061:        import org.opencms.xml.types.CmsXmlVarLinkValue;
0062:        import org.opencms.xml.types.CmsXmlVfsFileValue;
0063:        import org.opencms.xml.types.I_CmsXmlContentValue;
0064:        import org.opencms.xml.types.I_CmsXmlSchemaType;
0065:
0066:        import java.util.ArrayList;
0067:        import java.util.HashMap;
0068:        import java.util.Iterator;
0069:        import java.util.List;
0070:        import java.util.Locale;
0071:        import java.util.Map;
0072:        import java.util.regex.Pattern;
0073:
0074:        import org.apache.commons.logging.Log;
0075:
0076:        import org.dom4j.Document;
0077:        import org.dom4j.DocumentHelper;
0078:        import org.dom4j.Element;
0079:
0080:        /**
0081:         * Default implementation for the XML content handler, will be used by all XML contents that do not
0082:         * provide their own handler.<p>
0083:         * 
0084:         * @author Alexander Kandzior 
0085:         * @author Michael Moossen
0086:         * 
0087:         * @version $Revision: 1.58 $ 
0088:         * 
0089:         * @since 6.0.0 
0090:         */
0091:        public class CmsDefaultXmlContentHandler implements 
0092:                I_CmsXmlContentHandler {
0093:
0094:            /** Constant for the "appinfo" element name itself. */
0095:            public static final String APPINFO_APPINFO = "appinfo";
0096:
0097:            /** Constant for the "configuration" appinfo attribute name. */
0098:            public static final String APPINFO_ATTR_CONFIGURATION = "configuration";
0099:
0100:            /** Constant for the "element" appinfo attribute name. */
0101:            public static final String APPINFO_ATTR_ELEMENT = "element";
0102:
0103:            /** Constant for the "invalidate" appinfo attribute name. */
0104:            public static final String APPINFO_ATTR_INVALIDATE = "invalidate";
0105:
0106:            /** Constant for the "mapto" appinfo attribute name. */
0107:            public static final String APPINFO_ATTR_MAPTO = "mapto";
0108:
0109:            /** Constant for the "message" appinfo attribute name. */
0110:            public static final String APPINFO_ATTR_MESSAGE = "message";
0111:
0112:            /** Constant for the "name" appinfo attribute name. */
0113:            public static final String APPINFO_ATTR_NAME = "name";
0114:
0115:            /** Constant for the "regex" appinfo attribute name. */
0116:            public static final String APPINFO_ATTR_REGEX = "regex";
0117:
0118:            /** Constant for the "searchcontent" appinfo attribute name. */
0119:            public static final String APPINFO_ATTR_SEARCHCONTENT = "searchcontent";
0120:
0121:            /** Constant for the "type" appinfo attribute name. */
0122:            public static final String APPINFO_ATTR_TYPE = "type";
0123:
0124:            /** Constant for the "node" appinfo attribute value. */
0125:            public static final String APPINFO_ATTR_TYPE_NODE = "node";
0126:
0127:            /** Constant for the "parent" appinfo attribute value. */
0128:            public static final String APPINFO_ATTR_TYPE_PARENT = "parent";
0129:
0130:            /** Constant for the "warning" appinfo attribute value. */
0131:            public static final String APPINFO_ATTR_TYPE_WARNING = "warning";
0132:
0133:            /** Constant for the "uri" appinfo attribute name. */
0134:            public static final String APPINFO_ATTR_URI = "uri";
0135:
0136:            /** Constant for the "value" appinfo attribute name. */
0137:            public static final String APPINFO_ATTR_VALUE = "value";
0138:
0139:            /** Constant for the "widget" appinfo attribute name. */
0140:            public static final String APPINFO_ATTR_WIDGET = "widget";
0141:
0142:            /** Constant for the "default" appinfo element name. */
0143:            public static final String APPINFO_DEFAULT = "default";
0144:
0145:            /** Constant for the "defaults" appinfo element name. */
0146:            public static final String APPINFO_DEFAULTS = "defaults";
0147:
0148:            /** Constant for the "layout" appinfo element name. */
0149:            public static final String APPINFO_LAYOUT = "layout";
0150:
0151:            /** Constant for the "layouts" appinfo element name. */
0152:            public static final String APPINFO_LAYOUTS = "layouts";
0153:
0154:            /** Constant for the "mapping" appinfo element name. */
0155:            public static final String APPINFO_MAPPING = "mapping";
0156:
0157:            /** Constant for the "mappings" appinfo element name. */
0158:            public static final String APPINFO_MAPPINGS = "mappings";
0159:
0160:            /** Constant for the "modelfolder" appinfo element name. */
0161:            public static final String APPINFO_MODELFOLDER = "modelfolder";
0162:
0163:            /** Constant for the "preview" appinfo element name. */
0164:            public static final String APPINFO_PREVIEW = "preview";
0165:
0166:            /** Constant for the "relation" appinfo element name. */
0167:            public static final String APPINFO_RELATION = "relation";
0168:
0169:            /** Constant for the "relations" appinfo element name. */
0170:            public static final String APPINFO_RELATIONS = "relations";
0171:
0172:            /** Constant for the "searchexclusions" appinfo element name. */
0173:            public static final String APPINFO_RESOURCEBUNDLE = "resourcebundle";
0174:
0175:            /** Constant for the "rule" appinfo element name. */
0176:            public static final String APPINFO_RULE = "rule";
0177:
0178:            /** The file where the default appinfo schema is located. */
0179:            public static final String APPINFO_SCHEMA_FILE = "org/opencms/xml/content/DefaultAppinfo.xsd";
0180:
0181:            /** The file where the default appinfo schema types are located. */
0182:            public static final String APPINFO_SCHEMA_FILE_TYPES = "org/opencms/xml/content/DefaultAppinfoTypes.xsd";
0183:
0184:            /** The XML system id for the default appinfo schema types. */
0185:            public static final String APPINFO_SCHEMA_SYSTEM_ID = CmsConfigurationManager.DEFAULT_DTD_PREFIX
0186:                    + APPINFO_SCHEMA_FILE;
0187:
0188:            /** The XML system id for the default appinfo schema types. */
0189:            public static final String APPINFO_SCHEMA_TYPES_SYSTEM_ID = CmsConfigurationManager.DEFAULT_DTD_PREFIX
0190:                    + APPINFO_SCHEMA_FILE_TYPES;
0191:
0192:            /** Constant for the "searchsetting" appinfo element name. */
0193:            public static final String APPINFO_SEARCHSETTING = "searchsetting";
0194:
0195:            /** Constant for the "searchsettings" appinfo element name. */
0196:            public static final String APPINFO_SEARCHSETTINGS = "searchsettings";
0197:
0198:            /** Constant for the "validationrule" appinfo element name. */
0199:            public static final String APPINFO_VALIDATIONRULE = "validationrule";
0200:
0201:            /** Constant for the "validationrules" appinfo element name. */
0202:            public static final String APPINFO_VALIDATIONRULES = "validationrules";
0203:
0204:            /** Macro for resolving the preview URI. */
0205:            public static final String MACRO_PREVIEW_TEMPFILE = "previewtempfile";
0206:
0207:            /** Default message for validation errors. */
0208:            protected static final String MESSAGE_VALIDATION_DEFAULT_ERROR = "${validation.path}: "
0209:                    + "${key."
0210:                    + Messages.GUI_EDITOR_XMLCONTENT_VALIDATION_ERROR_2
0211:                    + "|${validation.value}|[${validation.regex}]}";
0212:
0213:            /** Default message for validation warnings. */
0214:            protected static final String MESSAGE_VALIDATION_DEFAULT_WARNING = "${validation.path}: "
0215:                    + "${key."
0216:                    + Messages.GUI_EDITOR_XMLCONTENT_VALIDATION_WARNING_2
0217:                    + "|${validation.value}|[${validation.regex}]}";
0218:
0219:            /** The log object for this class. */
0220:            private static final Log LOG = CmsLog
0221:                    .getLog(CmsDefaultXmlContentHandler.class);
0222:
0223:            /** Prefix to cache the checkrule relation types. */
0224:            private static final String RELATION_TYPE_PREFIX = "rt_";
0225:
0226:            /** The configuration values for the element widgets (as defined in the annotations). */
0227:            protected Map m_configurationValues;
0228:
0229:            /** The default values for the elements (as defined in the annotations). */
0230:            protected Map m_defaultValues;
0231:
0232:            /** The element mappings (as defined in the annotations). */
0233:            protected Map m_elementMappings;
0234:
0235:            /** The widgets used for the elements (as defined in the annotations). */
0236:            protected Map m_elementWidgets;
0237:
0238:            /** The resource bundle name to be used for localization of this content handler. */
0239:            protected String m_messageBundleName;
0240:
0241:            /** The folder containing the model file(s) for the content. */
0242:            protected String m_modelFolder;
0243:
0244:            /** The preview location (as defined in the annotations). */
0245:            protected String m_previewLocation;
0246:
0247:            /** The relation check rules. */
0248:            protected Map m_relations;
0249:
0250:            /** The search settings. */
0251:            protected Map m_searchSettings;
0252:
0253:            /** The messages for the error validation rules. */
0254:            protected Map m_validationErrorMessages;
0255:
0256:            /** The validation rules that cause an error (as defined in the annotations). */
0257:            protected Map m_validationErrorRules;
0258:
0259:            /** The messages for the warning validation rules. */
0260:            protected Map m_validationWarningMessages;
0261:
0262:            /** The validation rules that cause a warning (as defined in the annotations). */
0263:            protected Map m_validationWarningRules;
0264:
0265:            /**
0266:             * Creates a new instance of the default XML content handler.<p>  
0267:             */
0268:            public CmsDefaultXmlContentHandler() {
0269:
0270:                init();
0271:            }
0272:
0273:            /**
0274:             * Static initializer for caching the default appinfo validation schema.<p>
0275:             */
0276:            static {
0277:
0278:                // the schema definition is located in 2 separates file for easier editing
0279:                // 2 files are required in case an extended schema want to use the default definitions,
0280:                // but with an extended "appinfo" node 
0281:                byte[] appinfoSchemaTypes;
0282:                try {
0283:                    // first read the default types
0284:                    appinfoSchemaTypes = CmsFileUtil
0285:                            .readFile(APPINFO_SCHEMA_FILE_TYPES);
0286:                } catch (Exception e) {
0287:                    throw new CmsRuntimeException(
0288:                            Messages
0289:                                    .get()
0290:                                    .container(
0291:                                            org.opencms.xml.types.Messages.ERR_XMLCONTENT_LOAD_SCHEMA_1,
0292:                                            APPINFO_SCHEMA_FILE_TYPES), e);
0293:                }
0294:                CmsXmlEntityResolver.cacheSystemId(
0295:                        APPINFO_SCHEMA_TYPES_SYSTEM_ID, appinfoSchemaTypes);
0296:                byte[] appinfoSchema;
0297:                try {
0298:                    // now read the default base schema
0299:                    appinfoSchema = CmsFileUtil.readFile(APPINFO_SCHEMA_FILE);
0300:                } catch (Exception e) {
0301:                    throw new CmsRuntimeException(
0302:                            Messages
0303:                                    .get()
0304:                                    .container(
0305:                                            org.opencms.xml.types.Messages.ERR_XMLCONTENT_LOAD_SCHEMA_1,
0306:                                            APPINFO_SCHEMA_FILE), e);
0307:                }
0308:                CmsXmlEntityResolver.cacheSystemId(APPINFO_SCHEMA_SYSTEM_ID,
0309:                        appinfoSchema);
0310:            }
0311:
0312:            /**
0313:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#getConfiguration(org.opencms.xml.types.I_CmsXmlSchemaType)
0314:             */
0315:            public String getConfiguration(I_CmsXmlSchemaType type) {
0316:
0317:                String elementName = type.getName();
0318:                return (String) m_configurationValues.get(elementName);
0319:            }
0320:
0321:            /**
0322:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#getDefault(org.opencms.file.CmsObject, I_CmsXmlContentValue, java.util.Locale)
0323:             */
0324:            public String getDefault(CmsObject cms, I_CmsXmlContentValue value,
0325:                    Locale locale) {
0326:
0327:                String defaultValue;
0328:                if (value.getElement() == null) {
0329:                    // use the "getDefault" method of the given value, will use value from standard XML schema
0330:                    defaultValue = value.getDefault(locale);
0331:                } else {
0332:                    String xpath = value.getPath();
0333:                    // look up the default from the configured mappings
0334:                    defaultValue = (String) m_defaultValues.get(xpath);
0335:                    if (defaultValue == null) {
0336:                        // no value found, try default xpath
0337:                        xpath = CmsXmlUtils.removeXpath(xpath);
0338:                        xpath = CmsXmlUtils.createXpath(xpath, 1);
0339:                        // look up the default value again with default index of 1 in all path elements
0340:                        defaultValue = (String) m_defaultValues.get(xpath);
0341:                    }
0342:                }
0343:                if (defaultValue != null) {
0344:                    CmsObject newCms = cms;
0345:                    try {
0346:                        // switch the current URI to the XML document resource so that properties can be read
0347:                        CmsResource file = value.getDocument().getFile();
0348:                        CmsSite site = OpenCms.getSiteManager()
0349:                                .getSiteForRootPath(file.getRootPath());
0350:                        if (site != null) {
0351:                            newCms = OpenCms.initCmsObject(cms);
0352:                            newCms.getRequestContext().setSiteRoot(
0353:                                    site.getSiteRoot());
0354:                            newCms.getRequestContext().setUri(
0355:                                    newCms.getSitePath(file));
0356:                        }
0357:                    } catch (Exception e) {
0358:                        // on any error just use the default input OpenCms context
0359:                    }
0360:                    // return the default value with processed macros
0361:                    CmsMacroResolver resolver = CmsMacroResolver.newInstance()
0362:                            .setCmsObject(newCms).setMessages(
0363:                                    getMessages(locale));
0364:                    return resolver.resolveMacros(defaultValue);
0365:                }
0366:                // no default value is available
0367:                return null;
0368:            }
0369:
0370:            /**
0371:             * Returns the first mapping defined for the given element xpath.<p>
0372:             * 
0373:             * Since OpenCms version 7.0.2, multiple mappings for an element are possible, so 
0374:             * use {@link #getMapping(String)} instead.<p>
0375:             * 
0376:             * @param elementName the element xpath to look up the mapping for
0377:             * 
0378:             * @return the mapping defined for the given element xpath
0379:             * 
0380:             * @deprecated use {@link #getMappings(String)} instead to recieve all mappings
0381:             */
0382:            public String getMapping(String elementName) {
0383:
0384:                String[] mappings = getMappings(elementName);
0385:                return (mappings == null) ? null : mappings[0];
0386:            }
0387:
0388:            /**
0389:             * Returns the all mappings defined for the given element xpath.<p>
0390:             * 
0391:             * @since 7.0.2
0392:             * 
0393:             * @param elementName the element xpath to look up the mapping for
0394:             * 
0395:             * @return the mapping defined for the given element xpath
0396:             */
0397:            public String[] getMappings(String elementName) {
0398:
0399:                return (String[]) m_elementMappings.get(elementName);
0400:            }
0401:
0402:            /**
0403:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#getMessages(java.util.Locale)
0404:             */
0405:            public CmsMessages getMessages(Locale locale) {
0406:
0407:                if (m_messageBundleName == null) {
0408:                    // no message bundle was initialized
0409:                    return null;
0410:                }
0411:
0412:                return new CmsMessages(m_messageBundleName, locale);
0413:            }
0414:
0415:            /**
0416:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#getModelFolder(org.opencms.file.CmsObject, java.lang.String)
0417:             */
0418:            public String getModelFolder(CmsObject cms, String currentFolder) {
0419:
0420:                String result = m_modelFolder;
0421:                // store the original uri
0422:                String uri = cms.getRequestContext().getUri();
0423:                try {
0424:                    // set uri to current folder
0425:                    cms.getRequestContext().setUri(currentFolder);
0426:                    CmsMacroResolver resolver = CmsMacroResolver.newInstance()
0427:                            .setCmsObject(cms);
0428:                    // resolve eventual macros
0429:                    result = resolver.resolveMacros(m_modelFolder);
0430:                } finally {
0431:                    // switch back to stored uri
0432:                    cms.getRequestContext().setUri(uri);
0433:                }
0434:                return result;
0435:            }
0436:
0437:            /**
0438:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#getPreview(org.opencms.file.CmsObject, org.opencms.xml.content.CmsXmlContent, java.lang.String)
0439:             */
0440:            public String getPreview(CmsObject cms, CmsXmlContent content,
0441:                    String resourcename) {
0442:
0443:                CmsMacroResolver resolver = CmsMacroResolver.newInstance()
0444:                        .setCmsObject(cms);
0445:                resolver.addMacro(MACRO_PREVIEW_TEMPFILE, resourcename);
0446:
0447:                return resolver.resolveMacros(m_previewLocation);
0448:            }
0449:
0450:            /**
0451:             * @see I_CmsXmlContentHandler#getRelationType(I_CmsXmlContentValue)
0452:             */
0453:            public CmsRelationType getRelationType(I_CmsXmlContentValue value) {
0454:
0455:                if (value == null) {
0456:                    return null;
0457:                }
0458:                String xpath = value.getPath();
0459:                CmsRelationType relationType = null;
0460:                // look up the default from the configured mappings
0461:                relationType = (CmsRelationType) m_relations
0462:                        .get(RELATION_TYPE_PREFIX + xpath);
0463:                if (relationType == null) {
0464:                    // no value found, try default xpath
0465:                    String path = CmsXmlUtils.removeXpathIndex(xpath);
0466:                    // look up the default value again without indexes
0467:                    relationType = (CmsRelationType) m_relations
0468:                            .get(RELATION_TYPE_PREFIX + path);
0469:                }
0470:                if (relationType == null) {
0471:                    // no value found, try the last simple type path
0472:                    String path = CmsXmlUtils.getLastXpathElement(xpath);
0473:                    // look up the default value again for the last simple type
0474:                    relationType = (CmsRelationType) m_relations
0475:                            .get(RELATION_TYPE_PREFIX + path);
0476:                }
0477:                if (relationType == null) {
0478:                    return CmsRelationType.XML_WEAK;
0479:                }
0480:                return relationType;
0481:            }
0482:
0483:            /**
0484:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#getWidget(org.opencms.xml.types.I_CmsXmlContentValue)
0485:             */
0486:            public I_CmsWidget getWidget(I_CmsXmlContentValue value) {
0487:
0488:                // try the specific widget settings first
0489:                I_CmsWidget result = (I_CmsWidget) m_elementWidgets.get(value
0490:                        .getName());
0491:                if (result == null) {
0492:                    // use default widget mappings
0493:                    result = OpenCms.getXmlContentTypeManager()
0494:                            .getWidgetDefault(value.getTypeName());
0495:                } else {
0496:                    result = result.newInstance();
0497:                }
0498:                // set the configuration value for this widget
0499:                result.setConfiguration(getConfiguration(value));
0500:
0501:                return result;
0502:            }
0503:
0504:            /**
0505:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#initialize(org.dom4j.Element, org.opencms.xml.CmsXmlContentDefinition)
0506:             */
0507:            public synchronized void initialize(Element appInfoElement,
0508:                    CmsXmlContentDefinition contentDefinition)
0509:                    throws CmsXmlException {
0510:
0511:                if (appInfoElement != null) {
0512:                    // validate the appinfo element XML content with the default appinfo handler schema
0513:                    validateAppinfoElement(appInfoElement);
0514:
0515:                    // re-initialize the local variables
0516:                    init();
0517:
0518:                    Iterator i = appInfoElement.elements().iterator();
0519:                    while (i.hasNext()) {
0520:                        // iterate all elements in the appinfo node
0521:                        Element element = (Element) i.next();
0522:                        String nodeName = element.getName();
0523:                        if (nodeName.equals(APPINFO_MAPPINGS)) {
0524:                            initMappings(element, contentDefinition);
0525:                        } else if (nodeName.equals(APPINFO_LAYOUTS)) {
0526:                            initLayouts(element, contentDefinition);
0527:                        } else if (nodeName.equals(APPINFO_VALIDATIONRULES)) {
0528:                            initValidationRules(element, contentDefinition);
0529:                        } else if (nodeName.equals(APPINFO_RELATIONS)) {
0530:                            initRelations(element, contentDefinition);
0531:                        } else if (nodeName.equals(APPINFO_DEFAULTS)) {
0532:                            initDefaultValues(element, contentDefinition);
0533:                        } else if (nodeName.equals(APPINFO_MODELFOLDER)) {
0534:                            initModelFolder(element, contentDefinition);
0535:                        } else if (nodeName.equals(APPINFO_PREVIEW)) {
0536:                            initPreview(element, contentDefinition);
0537:                        } else if (nodeName.equals(APPINFO_RESOURCEBUNDLE)) {
0538:                            initResourceBundle(element, contentDefinition);
0539:                        } else if (nodeName.equals(APPINFO_SEARCHSETTINGS)) {
0540:                            initSearchSettings(element, contentDefinition);
0541:                        }
0542:                    }
0543:                }
0544:
0545:                // at the end, add default check rules for optional file references
0546:                addDefaultCheckRules(contentDefinition, null, null);
0547:            }
0548:
0549:            /**
0550:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#invalidateBrokenLinks(CmsObject, CmsXmlContent)
0551:             */
0552:            public void invalidateBrokenLinks(CmsObject cms,
0553:                    CmsXmlContent document) {
0554:
0555:                if ((cms == null)
0556:                        || (cms.getRequestContext().getRequestTime() == CmsResource.DATE_RELEASED_EXPIRED_IGNORE)) {
0557:                    // do not check if the request comes the editor
0558:                    return;
0559:                }
0560:                boolean needReinitialization = false;
0561:                // iterate the locales
0562:                Iterator itLocales = document.getLocales().iterator();
0563:                while (itLocales.hasNext()) {
0564:                    Locale locale = (Locale) itLocales.next();
0565:                    List removedNodes = new ArrayList();
0566:                    // iterate the values
0567:                    Iterator itValues = document.getValues(locale).iterator();
0568:                    while (itValues.hasNext()) {
0569:                        I_CmsXmlContentValue value = (I_CmsXmlContentValue) itValues
0570:                                .next();
0571:                        String path = value.getPath();
0572:                        // check if this value has already been deleted by parent rules 
0573:                        boolean alreadyRemoved = false;
0574:                        Iterator itRemNodes = removedNodes.iterator();
0575:                        while (itRemNodes.hasNext()) {
0576:                            String remNode = (String) itRemNodes.next();
0577:                            if (path.startsWith(remNode)) {
0578:                                alreadyRemoved = true;
0579:                                break;
0580:                            }
0581:                        }
0582:                        // only continue if not already removed and if a rule match
0583:                        if (alreadyRemoved
0584:                                || ((m_relations.get(path) == null) && (m_relations
0585:                                        .get(CmsXmlUtils.removeXpath(path)) == null))) {
0586:                            continue;
0587:                        }
0588:
0589:                        // check rule matched
0590:                        if (LOG.isDebugEnabled()) {
0591:                            LOG.debug(Messages.get().getBundle().key(
0592:                                    Messages.LOG_XMLCONTENT_CHECK_RULE_MATCH_1,
0593:                                    path));
0594:                        }
0595:                        if (validateLink(cms, value, null)) {
0596:                            // invalid link
0597:                            if (LOG.isDebugEnabled()) {
0598:                                LOG
0599:                                        .debug(Messages
0600:                                                .get()
0601:                                                .getBundle()
0602:                                                .key(
0603:                                                        Messages.LOG_XMLCONTENT_CHECK_WARNING_2,
0604:                                                        path,
0605:                                                        value
0606:                                                                .getStringValue(cms)));
0607:                            }
0608:                            // find the node to remove
0609:                            String parentPath = path;
0610:                            while (isInvalidateParent(parentPath)) {
0611:                                // check parent
0612:                                parentPath = CmsXmlUtils
0613:                                        .removeLastXpathElement(parentPath);
0614:                                // log info
0615:                                if (LOG.isDebugEnabled()) {
0616:                                    LOG
0617:                                            .debug(Messages
0618:                                                    .get()
0619:                                                    .getBundle()
0620:                                                    .key(
0621:                                                            Messages.LOG_XMLCONTENT_CHECK_PARENT_2,
0622:                                                            path, parentPath));
0623:                                }
0624:                            }
0625:                            value = document.getValue(parentPath, locale);
0626:                            // detach the value node from the XML document
0627:                            value.getElement().detach();
0628:                            // mark node as deleted
0629:                            removedNodes.add(parentPath);
0630:                        }
0631:                    }
0632:                    if (!removedNodes.isEmpty()) {
0633:                        needReinitialization = true;
0634:                    }
0635:                }
0636:                if (needReinitialization) {
0637:                    // re-initialize the XML content 
0638:                    document.initDocument();
0639:                }
0640:            }
0641:
0642:            /**
0643:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#isSearchable(org.opencms.xml.types.I_CmsXmlContentValue)
0644:             */
0645:            public boolean isSearchable(I_CmsXmlContentValue value) {
0646:
0647:                // check for name configured in the annotations
0648:                Boolean anno = (Boolean) m_searchSettings.get(value.getName());
0649:                // if no annotation has been found, use default for value
0650:                return (anno == null) ? value.isSearchable() : anno
0651:                        .booleanValue();
0652:            }
0653:
0654:            /**
0655:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#prepareForUse(org.opencms.file.CmsObject, org.opencms.xml.content.CmsXmlContent)
0656:             */
0657:            public CmsXmlContent prepareForUse(CmsObject cms,
0658:                    CmsXmlContent content) {
0659:
0660:                // NOOP, just return the unmodified content
0661:                return content;
0662:            }
0663:
0664:            /**
0665:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#prepareForWrite(org.opencms.file.CmsObject, org.opencms.xml.content.CmsXmlContent, org.opencms.file.CmsFile)
0666:             */
0667:            public CmsFile prepareForWrite(CmsObject cms,
0668:                    CmsXmlContent content, CmsFile file) throws CmsException {
0669:
0670:                if (!content.isAutoCorrectionEnabled()) {
0671:                    // check if the XML should be corrected automatically (if not already set)
0672:                    Object attribute = cms.getRequestContext().getAttribute(
0673:                            CmsXmlContent.AUTO_CORRECTION_ATTRIBUTE);
0674:                    // set the auto correction mode as required
0675:                    boolean autoCorrectionEnabled = (attribute != null)
0676:                            && ((Boolean) attribute).booleanValue();
0677:                    content.setAutoCorrectionEnabled(autoCorrectionEnabled);
0678:                }
0679:                // validate the XML structure before writing the file if required                 
0680:                if (!content.isAutoCorrectionEnabled()) {
0681:                    // an exception will be thrown if the structure is invalid
0682:                    content.validateXmlStructure(new CmsXmlEntityResolver(cms));
0683:                }
0684:                // read the content-conversion property
0685:                String contentConversion = CmsHtmlConverter
0686:                        .getConversionSettings(cms, file);
0687:                if (CmsStringUtil.isEmptyOrWhitespaceOnly(contentConversion)) {
0688:                    // enable pretty printing and XHTML conversion of XML content html fields by default
0689:                    contentConversion = CmsHtmlConverter.PARAM_XHTML;
0690:                }
0691:                content.setConversion(contentConversion);
0692:                // correct the HTML structure
0693:                file = content.correctXmlStructure(cms);
0694:                content.setFile(file);
0695:                // resolve the file mappings
0696:                content.resolveMappings(cms);
0697:                // ensure all property mappings of deleted optional values are removed
0698:                removeEmptyMappings(cms, content);
0699:                // return the result
0700:                return file;
0701:            }
0702:
0703:            /**
0704:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#resolveMapping(org.opencms.file.CmsObject, org.opencms.xml.content.CmsXmlContent, org.opencms.xml.types.I_CmsXmlContentValue)
0705:             */
0706:            public void resolveMapping(CmsObject cms, CmsXmlContent content,
0707:                    I_CmsXmlContentValue value) throws CmsException {
0708:
0709:                if (!value.isSimpleType()) {
0710:                    // no mappings for a nested schema are possible
0711:                    // note that the sub-elements of the nested schema ARE mapped by the node visitor,
0712:                    // it's just the nested schema value itself that does not support mapping
0713:                    return;
0714:                }
0715:
0716:                // get the original VFS file from the content
0717:                CmsFile file = content.getFile();
0718:                if (file == null) {
0719:                    throw new CmsXmlException(Messages.get().container(
0720:                            Messages.ERR_XMLCONTENT_RESOLVE_FILE_NOT_FOUND_0));
0721:                }
0722:
0723:                // get the mappings for the element name        
0724:                String[] mappings = getMappings(value.getPath());
0725:                if (mappings == null) {
0726:                    // nothing to do if we have no mappings at all
0727:                    return;
0728:                }
0729:                // create OpenCms user context initialized with "/" as site root to read all siblings
0730:                CmsObject rootCms = OpenCms.initCmsObject(cms);
0731:                rootCms.getRequestContext().setSiteRoot("/");
0732:                // read all siblings of the file
0733:                List siblings = rootCms.readSiblings(content.getFile()
0734:                        .getRootPath(), CmsResourceFilter.IGNORE_EXPIRATION);
0735:
0736:                // since 7.0.2 multiple mappings are possible
0737:                for (int m = mappings.length - 1; m >= 0; m--) {
0738:
0739:                    // for multiple language mappings, we need to ensure 
0740:                    // a) all siblings are handled
0741:                    // b) only the "right" locale is mapped to a sibling
0742:                    String mapping = mappings[m];
0743:                    if (CmsStringUtil.isNotEmpty(mapping)) {
0744:                        for (int i = (siblings.size() - 1); i >= 0; i--) {
0745:                            // get filename
0746:                            String filename = ((CmsResource) siblings.get(i))
0747:                                    .getRootPath();
0748:                            Locale locale = OpenCms.getLocaleManager()
0749:                                    .getDefaultLocale(rootCms, filename);
0750:
0751:                            if (!locale.equals(value.getLocale())) {
0752:                                // only map property if the locale fits
0753:                                continue;
0754:                            }
0755:
0756:                            // make sure the file is locked
0757:                            CmsLock lock = rootCms.getLock(filename);
0758:                            if (lock.isUnlocked()) {
0759:                                rootCms.lockResource(filename);
0760:                            } else if (!lock.isExclusiveOwnedBy(rootCms
0761:                                    .getRequestContext().currentUser())) {
0762:                                rootCms.changeLock(filename);
0763:                            }
0764:
0765:                            // get the string value of the current node
0766:                            String stringValue = value.getStringValue(rootCms);
0767:                            if (mapping.startsWith(MAPTO_PROPERTY_LIST)
0768:                                    && (value.getIndex() == 0)) {
0769:
0770:                                boolean mapToShared;
0771:                                int prefixLength;
0772:                                // check which mapping is used (shared or individual)
0773:                                if (mapping
0774:                                        .startsWith(MAPTO_PROPERTY_LIST_SHARED)) {
0775:                                    mapToShared = true;
0776:                                    prefixLength = MAPTO_PROPERTY_LIST_SHARED
0777:                                            .length();
0778:                                } else if (mapping
0779:                                        .startsWith(MAPTO_PROPERTY_LIST_INDIVIDUAL)) {
0780:                                    mapToShared = false;
0781:                                    prefixLength = MAPTO_PROPERTY_LIST_INDIVIDUAL
0782:                                            .length();
0783:                                } else {
0784:                                    mapToShared = false;
0785:                                    prefixLength = MAPTO_PROPERTY_LIST.length();
0786:                                }
0787:
0788:                                // this is a property list mapping
0789:                                String property = mapping
0790:                                        .substring(prefixLength);
0791:
0792:                                String path = CmsXmlUtils
0793:                                        .removeXpathIndex(value.getPath());
0794:                                List values = content.getValues(path, locale);
0795:                                Iterator j = values.iterator();
0796:                                StringBuffer result = new StringBuffer(values
0797:                                        .size() * 64);
0798:                                while (j.hasNext()) {
0799:                                    I_CmsXmlContentValue val = (I_CmsXmlContentValue) j
0800:                                            .next();
0801:                                    result.append(val.getStringValue(rootCms));
0802:                                    if (j.hasNext()) {
0803:                                        result
0804:                                                .append(CmsProperty.VALUE_LIST_DELIMITER);
0805:                                    }
0806:                                }
0807:
0808:                                CmsProperty p;
0809:                                if (mapToShared) {
0810:                                    // map to shared value
0811:                                    p = new CmsProperty(property, null, result
0812:                                            .toString());
0813:                                } else {
0814:                                    // map to individual value
0815:                                    p = new CmsProperty(property, result
0816:                                            .toString(), null);
0817:                                }
0818:                                // write the created list string value in the selected property
0819:                                rootCms.writePropertyObject(filename, p);
0820:                                if (mapToShared) {
0821:                                    // special case: shared mappings must be written only to one sibling, end loop
0822:                                    i = 0;
0823:                                }
0824:
0825:                            } else if (mapping.startsWith(MAPTO_PROPERTY)) {
0826:
0827:                                boolean mapToShared;
0828:                                int prefixLength;
0829:                                // check which mapping is used (shared or individual)                        
0830:                                if (mapping.startsWith(MAPTO_PROPERTY_SHARED)) {
0831:                                    mapToShared = true;
0832:                                    prefixLength = MAPTO_PROPERTY_SHARED
0833:                                            .length();
0834:                                } else if (mapping
0835:                                        .startsWith(MAPTO_PROPERTY_INDIVIDUAL)) {
0836:                                    mapToShared = false;
0837:                                    prefixLength = MAPTO_PROPERTY_INDIVIDUAL
0838:                                            .length();
0839:                                } else {
0840:                                    mapToShared = false;
0841:                                    prefixLength = MAPTO_PROPERTY.length();
0842:                                }
0843:
0844:                                // this is a property mapping
0845:                                String property = mapping
0846:                                        .substring(prefixLength);
0847:
0848:                                CmsProperty p;
0849:                                if (mapToShared) {
0850:                                    // map to shared value
0851:                                    p = new CmsProperty(property, null,
0852:                                            stringValue);
0853:                                } else {
0854:                                    // map to individual value
0855:                                    p = new CmsProperty(property, stringValue,
0856:                                            null);
0857:                                }
0858:                                // just store the string value in the selected property
0859:                                rootCms.writePropertyObject(filename, p);
0860:                                if (mapToShared) {
0861:                                    // special case: shared mappings must be written only to one sibling, end loop
0862:                                    i = 0;
0863:                                }
0864:
0865:                            } else if (mapping.startsWith(MAPTO_ATTRIBUTE)) {
0866:
0867:                                // this is an attribute mapping                        
0868:                                String attribute = mapping
0869:                                        .substring(MAPTO_ATTRIBUTE.length());
0870:                                switch (ATTRIBUTES.indexOf(attribute)) {
0871:                                case 0: // date released
0872:                                    long date = 0;
0873:                                    try {
0874:                                        date = Long.valueOf(stringValue)
0875:                                                .longValue();
0876:                                    } catch (NumberFormatException e) {
0877:                                        // ignore, value can be a macro
0878:                                    }
0879:                                    if (date == 0) {
0880:                                        date = CmsResource.DATE_RELEASED_DEFAULT;
0881:                                    }
0882:                                    // set the sibling release date
0883:                                    rootCms.setDateReleased(filename, date,
0884:                                            false);
0885:                                    // set current file release date
0886:                                    if (filename.equals(rootCms
0887:                                            .getSitePath(file))) {
0888:                                        file.setDateReleased(date);
0889:                                    }
0890:                                    break;
0891:                                case 1: // date expired
0892:                                    date = 0;
0893:                                    try {
0894:                                        date = Long.valueOf(stringValue)
0895:                                                .longValue();
0896:                                    } catch (NumberFormatException e) {
0897:                                        // ignore, value can be a macro
0898:                                    }
0899:                                    if (date == 0) {
0900:                                        date = CmsResource.DATE_EXPIRED_DEFAULT;
0901:                                    }
0902:                                    // set the sibling expired date
0903:                                    rootCms.setDateExpired(filename, date,
0904:                                            false);
0905:                                    // set current file expired date
0906:                                    if (filename.equals(rootCms
0907:                                            .getSitePath(file))) {
0908:                                        file.setDateExpired(date);
0909:                                    }
0910:                                    break;
0911:                                default:
0912:                                    // ignore invalid / other mappings                                
0913:                                }
0914:                            }
0915:                        }
0916:                    }
0917:                }
0918:                // make sure the original is locked
0919:                CmsLock lock = rootCms.getLock(file);
0920:                if (lock.isUnlocked()) {
0921:                    rootCms.lockResource(file.getRootPath());
0922:                } else if (!lock.isExclusiveOwnedBy(rootCms.getRequestContext()
0923:                        .currentUser())) {
0924:                    rootCms.changeLock(file.getRootPath());
0925:                }
0926:            }
0927:
0928:            /**
0929:             * @see org.opencms.xml.content.I_CmsXmlContentHandler#resolveValidation(org.opencms.file.CmsObject, org.opencms.xml.types.I_CmsXmlContentValue, org.opencms.xml.content.CmsXmlContentErrorHandler)
0930:             */
0931:            public CmsXmlContentErrorHandler resolveValidation(CmsObject cms,
0932:                    I_CmsXmlContentValue value,
0933:                    CmsXmlContentErrorHandler errorHandler) {
0934:
0935:                if (errorHandler == null) {
0936:                    // init a new error handler if required
0937:                    errorHandler = new CmsXmlContentErrorHandler();
0938:                }
0939:
0940:                if (!value.isSimpleType()) {
0941:                    // no validation for a nested schema is possible
0942:                    // note that the sub-elements of the nested schema ARE validated by the node visitor,
0943:                    // it's just the nested schema value itself that does not support validation
0944:                    return errorHandler;
0945:                }
0946:
0947:                // validate the error rules
0948:                errorHandler = validateValue(cms, value, errorHandler,
0949:                        m_validationErrorRules, false);
0950:                // validate the warning rules
0951:                errorHandler = validateValue(cms, value, errorHandler,
0952:                        m_validationWarningRules, true);
0953:
0954:                // return the result
0955:                return errorHandler;
0956:            }
0957:
0958:            /**
0959:             * Adds a check rule for a specified element.<p> 
0960:             * 
0961:             * @param contentDefinition the XML content definition this XML content handler belongs to
0962:             * @param elementName the element name to add the rule to 
0963:             * @param invalidate 
0964:             *              <code>false</code>, to disable link check
0965:             *              <code>true</code> or <code>node</code>, to invalidate just the single node if the link is broken 
0966:             *              <code>parent</code>, if this rule will invalidate the whole parent node in nested content
0967:             * @param type the relation type
0968:             * 
0969:             * @throws CmsXmlException in case an unknown element name is used
0970:             */
0971:            protected void addCheckRule(
0972:                    CmsXmlContentDefinition contentDefinition,
0973:                    String elementName, String invalidate, String type)
0974:                    throws CmsXmlException {
0975:
0976:                I_CmsXmlSchemaType schemaType = contentDefinition
0977:                        .getSchemaType(elementName);
0978:                if (schemaType == null) {
0979:                    // no element with the given name
0980:                    throw new CmsXmlException(Messages.get().container(
0981:                            Messages.ERR_XMLCONTENT_CHECK_INVALID_ELEM_1,
0982:                            elementName));
0983:                }
0984:                if (!CmsXmlVfsFileValue.TYPE_NAME.equals(schemaType
0985:                        .getTypeName())
0986:                        && !CmsXmlVarLinkValue.TYPE_NAME.equals(schemaType
0987:                                .getTypeName())) {
0988:                    // element is not a OpenCmsVfsFile
0989:                    throw new CmsXmlException(Messages.get().container(
0990:                            Messages.ERR_XMLCONTENT_CHECK_INVALID_TYPE_1,
0991:                            elementName));
0992:                }
0993:
0994:                // cache the check rule data
0995:                Boolean invalidateParent = null;
0996:                if ((invalidate == null)
0997:                        || invalidate.equalsIgnoreCase(Boolean.TRUE.toString())
0998:                        || invalidate.equalsIgnoreCase(APPINFO_ATTR_TYPE_NODE)) {
0999:                    invalidateParent = Boolean.FALSE;
1000:                } else if (invalidate
1001:                        .equalsIgnoreCase(APPINFO_ATTR_TYPE_PARENT)) {
1002:                    invalidateParent = Boolean.TRUE;
1003:                }
1004:                if (invalidateParent != null) {
1005:                    m_relations.put(elementName, invalidateParent);
1006:                }
1007:                CmsRelationType relationType = (type == null ? CmsRelationType.XML_WEAK
1008:                        : CmsRelationType.valueOfXml(type));
1009:                m_relations.put(RELATION_TYPE_PREFIX + elementName,
1010:                        relationType);
1011:
1012:                if (invalidateParent != null) {
1013:                    // check the whole xpath hierarchy
1014:                    String path = elementName;
1015:                    while (CmsStringUtil.isNotEmptyOrWhitespaceOnly(path)) {
1016:                        if (!isInvalidateParent(path)) {
1017:                            // if invalidate type = node, then the node needs to be optional
1018:                            if (contentDefinition.getSchemaType(path)
1019:                                    .getMinOccurs() > 0) {
1020:                                // element is not optional
1021:                                throw new CmsXmlException(
1022:                                        Messages
1023:                                                .get()
1024:                                                .container(
1025:                                                        Messages.ERR_XMLCONTENT_CHECK_NOT_OPTIONAL_1,
1026:                                                        path));
1027:                            }
1028:                            // no need to further check
1029:                            break;
1030:                        } else if (!CmsXmlUtils.isDeepXpath(path)) {
1031:                            // if invalidate type = parent, then the node needs to be nested
1032:                            // document root can not be invalidated
1033:                            throw new CmsXmlException(
1034:                                    Messages
1035:                                            .get()
1036:                                            .container(
1037:                                                    Messages.ERR_XMLCONTENT_CHECK_NOT_EMPTY_DOC_0));
1038:                        }
1039:                        path = CmsXmlUtils.removeLastXpathElement(path);
1040:                    }
1041:                }
1042:            }
1043:
1044:            /**
1045:             * Adds a configuration value for an element widget.<p>
1046:             * 
1047:             * @param contentDefinition the XML content definition this XML content handler belongs to
1048:             * @param elementName the element name to map
1049:             * @param configurationValue the configuration value to use
1050:             * 
1051:             * @throws CmsXmlException in case an unknown element name is used
1052:             */
1053:            protected void addConfiguration(
1054:                    CmsXmlContentDefinition contentDefinition,
1055:                    String elementName, String configurationValue)
1056:                    throws CmsXmlException {
1057:
1058:                if (contentDefinition.getSchemaType(elementName) == null) {
1059:                    throw new CmsXmlException(Messages.get().container(
1060:                            Messages.ERR_XMLCONTENT_CONFIG_ELEM_UNKNOWN_1,
1061:                            elementName));
1062:                }
1063:
1064:                m_configurationValues.put(elementName, configurationValue);
1065:            }
1066:
1067:            /**
1068:             * Adds a default value for an element.<p>
1069:             * 
1070:             * @param contentDefinition the XML content definition this XML content handler belongs to
1071:             * @param elementName the element name to map
1072:             * @param defaultValue the default value to use
1073:             * 
1074:             * @throws CmsXmlException in case an unknown element name is used
1075:             */
1076:            protected void addDefault(
1077:                    CmsXmlContentDefinition contentDefinition,
1078:                    String elementName, String defaultValue)
1079:                    throws CmsXmlException {
1080:
1081:                if (contentDefinition.getSchemaType(elementName) == null) {
1082:                    throw new CmsXmlException(
1083:                            org.opencms.xml.types.Messages
1084:                                    .get()
1085:                                    .container(
1086:                                            Messages.ERR_XMLCONTENT_INVALID_ELEM_DEFAULT_1,
1087:                                            elementName));
1088:                }
1089:                // store mappings as xpath to allow better control about what is mapped
1090:                String xpath = CmsXmlUtils.createXpath(elementName, 1);
1091:                m_defaultValues.put(xpath, defaultValue);
1092:            }
1093:
1094:            /**
1095:             * Adds all needed default check rules recursively for the given schema type.<p> 
1096:             * 
1097:             * @param rootContentDefinition the root content definition
1098:             * @param schemaType the schema type to check
1099:             * @param elementPath the current element path
1100:             * 
1101:             * @throws CmsXmlException if something goes wrong
1102:             */
1103:            protected void addDefaultCheckRules(
1104:                    CmsXmlContentDefinition rootContentDefinition,
1105:                    I_CmsXmlSchemaType schemaType, String elementPath)
1106:                    throws CmsXmlException {
1107:
1108:                if ((schemaType != null) && schemaType.isSimpleType()) {
1109:                    if ((schemaType.getMinOccurs() == 0)
1110:                            && (CmsXmlVfsFileValue.TYPE_NAME.equals(schemaType
1111:                                    .getTypeName()) || CmsXmlVarLinkValue.TYPE_NAME
1112:                                    .equals(schemaType.getTypeName()))
1113:                            && !m_relations.containsKey(elementPath)
1114:                            && !m_relations.containsKey(RELATION_TYPE_PREFIX
1115:                                    + elementPath)) {
1116:                        // add default check rule for the element
1117:                        addCheckRule(rootContentDefinition, elementPath, null,
1118:                                null);
1119:                    }
1120:                } else {
1121:                    // recursion required
1122:                    CmsXmlContentDefinition nestedContentDefinition = rootContentDefinition;
1123:                    if (schemaType != null) {
1124:                        CmsXmlNestedContentDefinition nestedDefinition = (CmsXmlNestedContentDefinition) schemaType;
1125:                        nestedContentDefinition = nestedDefinition
1126:                                .getNestedContentDefinition();
1127:                    }
1128:                    Iterator itElems = nestedContentDefinition.getSchemaTypes()
1129:                            .iterator();
1130:                    while (itElems.hasNext()) {
1131:                        String element = (String) itElems.next();
1132:                        String path = (schemaType != null) ? CmsXmlUtils
1133:                                .concatXpath(elementPath, element) : element;
1134:                        addDefaultCheckRules(rootContentDefinition,
1135:                                nestedContentDefinition.getSchemaType(element),
1136:                                path);
1137:                    }
1138:                }
1139:            }
1140:
1141:            /**
1142:             * Adds an element mapping.<p>
1143:             * 
1144:             * @param contentDefinition the XML content definition this XML content handler belongs to
1145:             * @param elementName the element name to map
1146:             * @param mapping the mapping to use
1147:             * 
1148:             * @throws CmsXmlException in case an unknown element name is used
1149:             */
1150:            protected void addMapping(
1151:                    CmsXmlContentDefinition contentDefinition,
1152:                    String elementName, String mapping) throws CmsXmlException {
1153:
1154:                if (contentDefinition.getSchemaType(elementName) == null) {
1155:                    throw new CmsXmlException(Messages.get().container(
1156:                            Messages.ERR_XMLCONTENT_INVALID_ELEM_MAPPING_1,
1157:                            elementName));
1158:                }
1159:
1160:                // store mappings as xpath to allow better control about what is mapped
1161:                String xpath = CmsXmlUtils.createXpath(elementName, 1);
1162:                // since 7.0.2 multiple mappings are possible, so the mappings are stored in an array
1163:                String[] values = (String[]) m_elementMappings.get(xpath);
1164:                if (values == null) {
1165:                    values = new String[] { mapping };
1166:                } else {
1167:                    String[] newValues = new String[values.length + 1];
1168:                    System.arraycopy(values, 0, newValues, 0, values.length);
1169:                    newValues[values.length] = mapping;
1170:                    values = newValues;
1171:                }
1172:                m_elementMappings.put(xpath, values);
1173:            }
1174:
1175:            /**
1176:             * Adds a search setting for an element.<p>
1177:             * 
1178:             * @param contentDefinition the XML content definition this XML content handler belongs to
1179:             * @param elementName the element name to map
1180:             * @param value the search setting value to store
1181:             * 
1182:             * @throws CmsXmlException in case an unknown element name is used
1183:             */
1184:            protected void addSearchSetting(
1185:                    CmsXmlContentDefinition contentDefinition,
1186:                    String elementName, Boolean value) throws CmsXmlException {
1187:
1188:                if (contentDefinition.getSchemaType(elementName) == null) {
1189:                    throw new CmsXmlException(
1190:                            org.opencms.xml.types.Messages
1191:                                    .get()
1192:                                    .container(
1193:                                            Messages.ERR_XMLCONTENT_INVALID_ELEM_SEARCHSETTINGS_1,
1194:                                            elementName));
1195:                }
1196:                // store the search exclusion as defined
1197:                m_searchSettings.put(elementName, value);
1198:            }
1199:
1200:            /**
1201:             * Adds a validation rule for a specified element.<p> 
1202:             * 
1203:             * @param contentDefinition the XML content definition this XML content handler belongs to
1204:             * @param elementName the element name to add the rule to 
1205:             * @param regex the validation rule regular expression
1206:             * @param message the message in case validation fails (may be null)
1207:             * @param isWarning if true, this rule is used for warnings, otherwise it's an error
1208:             * 
1209:             * @throws CmsXmlException in case an unknown element name is used
1210:             */
1211:            protected void addValidationRule(
1212:                    CmsXmlContentDefinition contentDefinition,
1213:                    String elementName, String regex, String message,
1214:                    boolean isWarning) throws CmsXmlException {
1215:
1216:                if (contentDefinition.getSchemaType(elementName) == null) {
1217:                    throw new CmsXmlException(Messages.get().container(
1218:                            Messages.ERR_XMLCONTENT_INVALID_ELEM_VALIDATION_1,
1219:                            elementName));
1220:                }
1221:
1222:                if (isWarning) {
1223:                    m_validationWarningRules.put(elementName, regex);
1224:                    if (message != null) {
1225:                        m_validationWarningMessages.put(elementName, message);
1226:                    }
1227:                } else {
1228:                    m_validationErrorRules.put(elementName, regex);
1229:                    if (message != null) {
1230:                        m_validationErrorMessages.put(elementName, message);
1231:                    }
1232:                }
1233:            }
1234:
1235:            /**
1236:             * Adds a GUI widget for a specified element.<p> 
1237:             * 
1238:             * @param contentDefinition the XML content definition this XML content handler belongs to
1239:             * @param elementName the element name to map
1240:             * @param widgetClassOrAlias the widget to use as GUI for the element (registered alias or class name)
1241:             * 
1242:             * @throws CmsXmlException in case an unknown element name is used
1243:             */
1244:            protected void addWidget(CmsXmlContentDefinition contentDefinition,
1245:                    String elementName, String widgetClassOrAlias)
1246:                    throws CmsXmlException {
1247:
1248:                if (contentDefinition.getSchemaType(elementName) == null) {
1249:                    throw new CmsXmlException(
1250:                            Messages
1251:                                    .get()
1252:                                    .container(
1253:                                            Messages.ERR_XMLCONTENT_INVALID_ELEM_LAYOUTWIDGET_1,
1254:                                            elementName));
1255:                }
1256:
1257:                // get the base widget from the XML content type manager
1258:                I_CmsWidget widget = OpenCms.getXmlContentTypeManager()
1259:                        .getWidget(widgetClassOrAlias);
1260:
1261:                if (widget == null) {
1262:                    // no registered widget class found
1263:                    if (CmsStringUtil.isValidJavaClassName(widgetClassOrAlias)) {
1264:                        // java class name given, try to create new instance of the class and cast to widget
1265:                        try {
1266:                            Class specialWidgetClass = Class
1267:                                    .forName(widgetClassOrAlias);
1268:                            widget = (I_CmsWidget) specialWidgetClass
1269:                                    .newInstance();
1270:                        } catch (Exception e) {
1271:                            throw new CmsXmlException(
1272:                                    Messages
1273:                                            .get()
1274:                                            .container(
1275:                                                    Messages.ERR_XMLCONTENT_INVALID_CUSTOM_CLASS_3,
1276:                                                    widgetClassOrAlias,
1277:                                                    elementName,
1278:                                                    contentDefinition
1279:                                                            .getSchemaLocation()),
1280:                                    e);
1281:                        }
1282:                    }
1283:                    if (widget == null) {
1284:                        // no valid widget found
1285:                        throw new CmsXmlException(Messages.get().container(
1286:                                Messages.ERR_XMLCONTENT_INVALID_WIDGET_3,
1287:                                widgetClassOrAlias, elementName,
1288:                                contentDefinition.getSchemaLocation()));
1289:                    }
1290:                }
1291:                m_elementWidgets.put(elementName, widget);
1292:            }
1293:
1294:            /**
1295:             * Returns the validation message to be displayed if a certain rule was violated.<p> 
1296:             * 
1297:             * @param cms the current users OpenCms context
1298:             * @param value the value to validate
1299:             * @param regex the rule that was violated
1300:             * @param valueStr the string value of the given value
1301:             * @param matchResult if false, the rule was negated
1302:             * @param isWarning if true, this validation indicate a warning, otherwise an error
1303:             * 
1304:             * @return the validation message to be displayed 
1305:             */
1306:            protected String getValidationMessage(CmsObject cms,
1307:                    I_CmsXmlContentValue value, String regex, String valueStr,
1308:                    boolean matchResult, boolean isWarning) {
1309:
1310:                String message = null;
1311:                if (isWarning) {
1312:                    message = (String) m_validationWarningMessages.get(value
1313:                            .getName());
1314:                } else {
1315:                    message = (String) m_validationErrorMessages.get(value
1316:                            .getName());
1317:                }
1318:
1319:                if (message == null) {
1320:                    if (isWarning) {
1321:                        message = MESSAGE_VALIDATION_DEFAULT_WARNING;
1322:                    } else {
1323:                        message = MESSAGE_VALIDATION_DEFAULT_ERROR;
1324:                    }
1325:                }
1326:
1327:                // create additional macro values
1328:                Map additionalValues = new HashMap();
1329:                additionalValues.put(CmsMacroResolver.KEY_VALIDATION_VALUE,
1330:                        valueStr);
1331:                additionalValues.put(CmsMacroResolver.KEY_VALIDATION_REGEX,
1332:                        ((!matchResult) ? "!" : "") + regex);
1333:                additionalValues.put(CmsMacroResolver.KEY_VALIDATION_PATH,
1334:                        value.getPath());
1335:
1336:                CmsMacroResolver resolver = CmsMacroResolver
1337:                        .newInstance()
1338:                        .setCmsObject(cms)
1339:                        .setMessages(
1340:                                getMessages(cms.getRequestContext().getLocale()))
1341:                        .setAdditionalMacros(additionalValues);
1342:
1343:                return resolver.resolveMacros(message);
1344:            }
1345:
1346:            /**
1347:             * Called when this content handler is initialized.<p> 
1348:             */
1349:            protected void init() {
1350:
1351:                m_elementMappings = new HashMap();
1352:                m_elementWidgets = new HashMap();
1353:                m_validationErrorRules = new HashMap();
1354:                m_validationErrorMessages = new HashMap();
1355:                m_validationWarningRules = new HashMap();
1356:                m_validationWarningMessages = new HashMap();
1357:                m_defaultValues = new HashMap();
1358:                m_configurationValues = new HashMap();
1359:                m_searchSettings = new HashMap();
1360:                m_relations = new HashMap();
1361:                m_previewLocation = null;
1362:                m_modelFolder = null;
1363:            }
1364:
1365:            /**
1366:             * Initializes the default values for this content handler.<p>
1367:             * 
1368:             * Using the default values from the appinfo node, it's possible to have more 
1369:             * sophisticated logic for generating the defaults then just using the XML schema "default"
1370:             * attribute.<p> 
1371:             * 
1372:             * @param root the "defaults" element from the appinfo node of the XML content definition
1373:             * @param contentDefinition the content definition the default values belong to
1374:             * @throws CmsXmlException if something goes wrong
1375:             */
1376:            protected void initDefaultValues(Element root,
1377:                    CmsXmlContentDefinition contentDefinition)
1378:                    throws CmsXmlException {
1379:
1380:                Iterator i = root.elementIterator(APPINFO_DEFAULT);
1381:                while (i.hasNext()) {
1382:                    // iterate all "default" elements in the "defaults" node
1383:                    Element element = (Element) i.next();
1384:                    String elementName = element
1385:                            .attributeValue(APPINFO_ATTR_ELEMENT);
1386:                    String defaultValue = element
1387:                            .attributeValue(APPINFO_ATTR_VALUE);
1388:                    if ((elementName != null) && (defaultValue != null)) {
1389:                        // add a default value mapping for the element
1390:                        addDefault(contentDefinition, elementName, defaultValue);
1391:                    }
1392:                }
1393:            }
1394:
1395:            /**
1396:             * Initializes the layout for this content handler.<p>
1397:             * 
1398:             * Unless otherwise instructed, the editor uses one specific GUI widget for each 
1399:             * XML value schema type. For example, for a {@link org.opencms.xml.types.CmsXmlStringValue} 
1400:             * the default widget is the {@link org.opencms.widgets.CmsInputWidget}.
1401:             * However, certain values can also use more then one widget, for example you may 
1402:             * also use a {@link org.opencms.widgets.CmsCheckboxWidget} for a String value,
1403:             * and as a result the Strings possible values would be eithe <code>"false"</code> or <code>"true"</code>,
1404:             * but nevertheless be a String.<p>
1405:             *
1406:             * The widget to use can further be controlled using the <code>widget</code> attribute.
1407:             * You can specify either a valid widget alias such as <code>StringWidget</code>, 
1408:             * or the name of a Java class that implements <code>{@link I_CmsWidget}</code>.<p>
1409:             * 
1410:             * Configuration options to the widget can be passed using the <code>configuration</code>
1411:             * attribute. You can specify any String as configuration. This String is then passed
1412:             * to the widget during initialization. It's up to the individual widget implementation 
1413:             * to interpret this configuration String.<p>
1414:             * 
1415:             * @param root the "layouts" element from the appinfo node of the XML content definition
1416:             * @param contentDefinition the content definition the layout belongs to
1417:             * 
1418:             * @throws CmsXmlException if something goes wrong
1419:             */
1420:            protected void initLayouts(Element root,
1421:                    CmsXmlContentDefinition contentDefinition)
1422:                    throws CmsXmlException {
1423:
1424:                Iterator i = root.elementIterator(APPINFO_LAYOUT);
1425:                while (i.hasNext()) {
1426:                    // iterate all "layout" elements in the "layouts" node
1427:                    Element element = (Element) i.next();
1428:                    String elementName = element
1429:                            .attributeValue(APPINFO_ATTR_ELEMENT);
1430:                    String widgetClassOrAlias = element
1431:                            .attributeValue(APPINFO_ATTR_WIDGET);
1432:                    String configuration = element
1433:                            .attributeValue(APPINFO_ATTR_CONFIGURATION);
1434:                    if ((elementName != null) && (widgetClassOrAlias != null)) {
1435:                        // add a widget mapping for the element
1436:                        addWidget(contentDefinition, elementName,
1437:                                widgetClassOrAlias);
1438:                        if (configuration != null) {
1439:                            addConfiguration(contentDefinition, elementName,
1440:                                    configuration);
1441:                        }
1442:                    }
1443:                }
1444:            }
1445:
1446:            /**
1447:             * Initializes the element mappings for this content handler.<p>
1448:             * 
1449:             * Element mappings allow storing values from the XML content in other locations.
1450:             * For example, if you have an element called "Title", it's likely a good idea to 
1451:             * store the value of this element also in the "Title" property of a XML content resource.<p>
1452:             * 
1453:             * @param root the "mappings" element from the appinfo node of the XML content definition
1454:             * @param contentDefinition the content definition the mappings belong to
1455:             * @throws CmsXmlException if something goes wrong
1456:             */
1457:            protected void initMappings(Element root,
1458:                    CmsXmlContentDefinition contentDefinition)
1459:                    throws CmsXmlException {
1460:
1461:                Iterator i = root.elementIterator(APPINFO_MAPPING);
1462:                while (i.hasNext()) {
1463:                    // iterate all "mapping" elements in the "mappings" node
1464:                    Element element = (Element) i.next();
1465:                    // this is a mapping node
1466:                    String elementName = element
1467:                            .attributeValue(APPINFO_ATTR_ELEMENT);
1468:                    String maptoName = element
1469:                            .attributeValue(APPINFO_ATTR_MAPTO);
1470:                    if ((elementName != null) && (maptoName != null)) {
1471:                        // add the element mapping 
1472:                        addMapping(contentDefinition, elementName, maptoName);
1473:                    }
1474:                }
1475:            }
1476:
1477:            /**
1478:             * Initializes the folder containing the model file(s) for this content handler.<p>
1479:             * 
1480:             * @param root the "modelfolder" element from the appinfo node of the XML content definition
1481:             * @param contentDefinition the content definition the model folder belongs to
1482:             * @throws CmsXmlException if something goes wrong
1483:             */
1484:            protected void initModelFolder(Element root,
1485:                    CmsXmlContentDefinition contentDefinition)
1486:                    throws CmsXmlException {
1487:
1488:                String master = root.attributeValue(APPINFO_ATTR_URI);
1489:                if (master == null) {
1490:                    throw new CmsXmlException(Messages.get().container(
1491:                            Messages.ERR_XMLCONTENT_MISSING_MODELFOLDER_URI_2,
1492:                            root.getName(),
1493:                            contentDefinition.getSchemaLocation()));
1494:                }
1495:                m_modelFolder = master;
1496:            }
1497:
1498:            /**
1499:             * Initializes the preview location for this content handler.<p>
1500:             * 
1501:             * @param root the "preview" element from the appinfo node of the XML content definition
1502:             * @param contentDefinition the content definition the validation rules belong to
1503:             * @throws CmsXmlException if something goes wrong
1504:             */
1505:            protected void initPreview(Element root,
1506:                    CmsXmlContentDefinition contentDefinition)
1507:                    throws CmsXmlException {
1508:
1509:                String preview = root.attributeValue(APPINFO_ATTR_URI);
1510:                if (preview == null) {
1511:                    throw new CmsXmlException(Messages.get().container(
1512:                            Messages.ERR_XMLCONTENT_MISSING_PREVIEW_URI_2,
1513:                            root.getName(),
1514:                            contentDefinition.getSchemaLocation()));
1515:                }
1516:                m_previewLocation = preview;
1517:            }
1518:
1519:            /**
1520:             * Initializes the relation configuration for this content handler.<p>
1521:             * 
1522:             * OpenCms performs link checks for all OPTIONAL links defined in XML content values of type 
1523:             * OpenCmsVfsFile. However, for most projects in the real world a more fine-grained control 
1524:             * over the link check process is required. For these cases, individual relation behavior can 
1525:             * be defined for the appinfo node.<p>
1526:             * 
1527:             * Additional here can be defined an optional type for the relations, for instance.<p>
1528:             * 
1529:             * @param root the "relations" element from the appinfo node of the XML content definition
1530:             * @param contentDefinition the content definition the check rules belong to
1531:             * 
1532:             * @throws CmsXmlException if something goes wrong
1533:             */
1534:            protected void initRelations(Element root,
1535:                    CmsXmlContentDefinition contentDefinition)
1536:                    throws CmsXmlException {
1537:
1538:                Iterator i = root.elementIterator(APPINFO_RELATION);
1539:                while (i.hasNext()) {
1540:                    // iterate all "checkrule" elements in the "checkrule" node
1541:                    Element element = (Element) i.next();
1542:                    String elementName = element
1543:                            .attributeValue(APPINFO_ATTR_ELEMENT);
1544:                    String invalidate = element
1545:                            .attributeValue(APPINFO_ATTR_INVALIDATE);
1546:                    if (invalidate != null) {
1547:                        invalidate = invalidate.toUpperCase();
1548:                    }
1549:                    String type = element.attributeValue(APPINFO_ATTR_TYPE);
1550:                    if (type != null) {
1551:                        type = type.toLowerCase();
1552:                    }
1553:                    if (elementName != null) {
1554:                        // add a check rule for the element
1555:                        addCheckRule(contentDefinition, elementName,
1556:                                invalidate, type);
1557:                    }
1558:                }
1559:            }
1560:
1561:            /**
1562:             * Initializes the resource bundle to use for localized messages in this content handler.<p>
1563:             * 
1564:             * @param root the "resourcebundle" element from the appinfo node of the XML content definition
1565:             * @param contentDefinition the content definition the validation rules belong to
1566:             * 
1567:             * @throws CmsXmlException if something goes wrong
1568:             */
1569:            protected void initResourceBundle(Element root,
1570:                    CmsXmlContentDefinition contentDefinition)
1571:                    throws CmsXmlException {
1572:
1573:                String name = root.attributeValue(APPINFO_ATTR_NAME);
1574:                if (name == null) {
1575:                    throw new CmsXmlException(
1576:                            Messages
1577:                                    .get()
1578:                                    .container(
1579:                                            Messages.ERR_XMLCONTENT_MISSING_RESOURCE_BUNDLE_NAME_2,
1580:                                            root.getName(),
1581:                                            contentDefinition
1582:                                                    .getSchemaLocation()));
1583:                }
1584:                m_messageBundleName = name;
1585:            }
1586:
1587:            /**
1588:             * Initializes the search exclusions values for this content handler.<p>
1589:             * 
1590:             * For the full text search, the value of all elements in one locale of the XML content are combined
1591:             * to one big text, which is referred to as the "content" in the context of the full text search.
1592:             * With this option, it is possible to hide certain elements from this "content" that does not make sense 
1593:             * to include in the full text search.<p>   
1594:             * 
1595:             * @param root the "searchsettings" element from the appinfo node of the XML content definition
1596:             * @param contentDefinition the content definition the default values belong to
1597:             * 
1598:             * @throws CmsXmlException if something goes wrong
1599:             */
1600:            protected void initSearchSettings(Element root,
1601:                    CmsXmlContentDefinition contentDefinition)
1602:                    throws CmsXmlException {
1603:
1604:                Iterator i = root.elementIterator(APPINFO_SEARCHSETTING);
1605:                while (i.hasNext()) {
1606:                    // iterate all "searchsetting" elements in the "searchsettings" node
1607:                    Element element = (Element) i.next();
1608:                    String elementName = element
1609:                            .attributeValue(APPINFO_ATTR_ELEMENT);
1610:                    String searchContent = element
1611:                            .attributeValue(APPINFO_ATTR_SEARCHCONTENT);
1612:                    boolean include = CmsStringUtil.isEmpty(searchContent)
1613:                            || Boolean.valueOf(searchContent).booleanValue();
1614:                    if (elementName != null) {
1615:                        // add search exclusion for the element
1616:                        // this may also be "false" in case a default of "true" is to be overwritten
1617:                        addSearchSetting(contentDefinition, elementName,
1618:                                Boolean.valueOf(include));
1619:                    }
1620:                }
1621:            }
1622:
1623:            /**
1624:             * Initializes the validation rules this content handler.<p>
1625:             * 
1626:             * OpenCms always performs XML schema validation for all XML contents. However,
1627:             * for most projects in the real world a more fine-grained control over the validation process is
1628:             * required. For these cases, individual validation rules can be defined for the appinfo node.<p>
1629:             * 
1630:             * @param root the "validationrules" element from the appinfo node of the XML content definition
1631:             * @param contentDefinition the content definition the validation rules belong to
1632:             * 
1633:             * @throws CmsXmlException if something goes wrong
1634:             */
1635:            protected void initValidationRules(Element root,
1636:                    CmsXmlContentDefinition contentDefinition)
1637:                    throws CmsXmlException {
1638:
1639:                List elements = new ArrayList(root.elements(APPINFO_RULE));
1640:                elements.addAll(root.elements(APPINFO_VALIDATIONRULE));
1641:                Iterator i = elements.iterator();
1642:                while (i.hasNext()) {
1643:                    // iterate all "rule" or "validationrule" elements in the "validationrules" node
1644:                    Element element = (Element) i.next();
1645:                    String elementName = element
1646:                            .attributeValue(APPINFO_ATTR_ELEMENT);
1647:                    String regex = element.attributeValue(APPINFO_ATTR_REGEX);
1648:                    String type = element.attributeValue(APPINFO_ATTR_TYPE);
1649:                    if (type != null) {
1650:                        type = type.toLowerCase();
1651:                    }
1652:                    String message = element
1653:                            .attributeValue(APPINFO_ATTR_MESSAGE);
1654:                    if ((elementName != null) && (regex != null)) {
1655:                        // add a validation rule for the element
1656:                        addValidationRule(contentDefinition, elementName,
1657:                                regex, message, APPINFO_ATTR_TYPE_WARNING
1658:                                        .equals(type));
1659:                    }
1660:                }
1661:            }
1662:
1663:            /**
1664:             * Returns the is-invalidate-parent flag for the given xpath.<p>
1665:             * 
1666:             * @param xpath the path to get the check rule for
1667:             * 
1668:             * @return the configured is-invalidate-parent flag for the given xpath
1669:             */
1670:            protected boolean isInvalidateParent(String xpath) {
1671:
1672:                if (!CmsXmlUtils.isDeepXpath(xpath)) {
1673:                    return false;
1674:                }
1675:                Boolean isInvalidateParent = null;
1676:                // look up the default from the configured mappings
1677:                isInvalidateParent = (Boolean) m_relations.get(xpath);
1678:                if (isInvalidateParent == null) {
1679:                    // no value found, try default xpath
1680:                    String path = CmsXmlUtils.removeXpath(xpath);
1681:                    // look up the default value again without indexes
1682:                    isInvalidateParent = (Boolean) m_relations.get(path);
1683:                }
1684:                if (isInvalidateParent == null) {
1685:                    return false;
1686:                }
1687:                return isInvalidateParent.booleanValue();
1688:            }
1689:
1690:            /**
1691:             * Returns the localized resource string for a given message key according to the configured resource bundle
1692:             * of this content handler.<p>
1693:             * 
1694:             * If the key was not found in the configured bundle, or no bundle is configured for this 
1695:             * content handler, the return value is
1696:             * <code>"??? " + keyName + " ???"</code>.<p>
1697:             * 
1698:             * @param keyName the key for the desired string 
1699:             * @param locale the locale to get the key from
1700:             * 
1701:             * @return the resource string for the given key 
1702:             * 
1703:             * @see CmsMessages#formatUnknownKey(String)
1704:             * @see CmsMessages#isUnknownKey(String)
1705:             */
1706:            protected String key(String keyName, Locale locale) {
1707:
1708:                CmsMessages messages = getMessages(locale);
1709:                if (messages != null) {
1710:                    return messages.key(keyName);
1711:                }
1712:                return CmsMessages.formatUnknownKey(keyName);
1713:            }
1714:
1715:            /**
1716:             * Removes property values on resources for non-existing, optional elements.<p>
1717:             * 
1718:             * @param cms the current users OpenCms context
1719:             * @param content the XML content to remove the property values for
1720:             * 
1721:             * @throws CmsException in case of read/write errors accessing the OpenCms VFS
1722:             */
1723:            protected void removeEmptyMappings(CmsObject cms,
1724:                    CmsXmlContent content) throws CmsException {
1725:
1726:                List siblings = null;
1727:                CmsObject rootCms = null;
1728:
1729:                Iterator mappings = m_elementMappings.entrySet().iterator();
1730:                while (mappings.hasNext()) {
1731:                    Map.Entry e = (Map.Entry) mappings.next();
1732:                    String path = String.valueOf(e.getKey());
1733:                    String[] values = (String[]) e.getValue();
1734:                    if (values == null) {
1735:                        // nothing to do if we have no mappings at all
1736:                        continue;
1737:                    }
1738:                    if ((siblings == null) || (rootCms == null)) {
1739:                        // create OpenCms user context initialized with "/" as site root to read all siblings
1740:                        rootCms = OpenCms.initCmsObject(cms);
1741:                        rootCms.getRequestContext().setSiteRoot("/");
1742:                        siblings = rootCms.readSiblings(content.getFile()
1743:                                .getRootPath(),
1744:                                CmsResourceFilter.IGNORE_EXPIRATION);
1745:                    }
1746:                    for (int v = values.length - 1; v >= 0; v--) {
1747:                        String mapping = values[v];
1748:                        if (mapping.startsWith(MAPTO_PROPERTY_LIST)
1749:                                || mapping.startsWith(MAPTO_PROPERTY)) {
1750:
1751:                            for (int i = 0; i < siblings.size(); i++) {
1752:
1753:                                // get siblings filename and locale
1754:                                String filename = ((CmsResource) siblings
1755:                                        .get(i)).getRootPath();
1756:                                Locale locale = OpenCms.getLocaleManager()
1757:                                        .getDefaultLocale(rootCms, filename);
1758:
1759:                                if (!content.hasLocale(locale)) {
1760:                                    // only remove property if the locale fits
1761:                                    continue;
1762:                                }
1763:                                if (content.hasValue(path, locale)) {
1764:                                    // value is available, property must be kept
1765:                                    continue;
1766:                                }
1767:
1768:                                String property;
1769:                                if (mapping.startsWith(MAPTO_PROPERTY_LIST)) {
1770:                                    // this is a property list mapping
1771:                                    property = mapping
1772:                                            .substring(MAPTO_PROPERTY_LIST
1773:                                                    .length());
1774:                                } else {
1775:                                    // this is a property mapping
1776:                                    property = mapping.substring(MAPTO_PROPERTY
1777:                                            .length());
1778:                                }
1779:                                // delete the property value for the not existing node
1780:                                rootCms
1781:                                        .writePropertyObject(
1782:                                                filename,
1783:                                                new CmsProperty(
1784:                                                        property,
1785:                                                        CmsProperty.DELETE_VALUE,
1786:                                                        null));
1787:                            }
1788:                        }
1789:                    }
1790:                }
1791:            }
1792:
1793:            /**
1794:             * Validates if the given <code>appinfo</code> element node from the XML content definition schema
1795:             * is valid according the the capabilities of this content handler.<p> 
1796:             * 
1797:             * @param appinfoElement the <code>appinfo</code> element node to validate
1798:             *  
1799:             * @throws CmsXmlException in case the element validation fails
1800:             */
1801:            protected void validateAppinfoElement(Element appinfoElement)
1802:                    throws CmsXmlException {
1803:
1804:                // create a document to validate
1805:                Document doc = DocumentHelper.createDocument();
1806:                Element root = doc.addElement(APPINFO_APPINFO);
1807:                // attach the default appinfo schema
1808:                root.add(I_CmsXmlSchemaType.XSI_NAMESPACE);
1809:                root
1810:                        .addAttribute(
1811:                                I_CmsXmlSchemaType.XSI_NAMESPACE_ATTRIBUTE_NO_SCHEMA_LOCATION,
1812:                                APPINFO_SCHEMA_SYSTEM_ID);
1813:                // append the content from the appinfo node in the content definition 
1814:                root.appendContent(appinfoElement);
1815:                // now validate the document with the default appinfo schema
1816:                CmsXmlUtils.validateXmlStructure(doc,
1817:                        CmsEncoder.ENCODING_UTF_8, new CmsXmlEntityResolver(
1818:                                null));
1819:            }
1820:
1821:            /**
1822:             * Validates the given rules against the given value.<p> 
1823:             * 
1824:             * @param cms the current users OpenCms context
1825:             * @param value the value to validate
1826:             * @param errorHandler the error handler to use in case errors or warnings are detected
1827:             * 
1828:             * @return if a broken link has been found
1829:             */
1830:            protected boolean validateLink(CmsObject cms,
1831:                    I_CmsXmlContentValue value,
1832:                    CmsXmlContentErrorHandler errorHandler) {
1833:
1834:                // if there is a value of type file reference
1835:                if ((value == null)
1836:                        || (!(value instanceof  CmsXmlVfsFileValue) && !(value instanceof  CmsXmlVarLinkValue))) {
1837:                    return false;
1838:                }
1839:                // if the value has a link (this will automatically fix, for instance, the path of moved resources)
1840:                CmsLink link = null;
1841:                if (value instanceof  CmsXmlVfsFileValue) {
1842:                    link = ((CmsXmlVfsFileValue) value).getLink(cms);
1843:                } else if (value instanceof  CmsXmlVarLinkValue) {
1844:                    link = ((CmsXmlVarLinkValue) value).getLink(cms);
1845:                }
1846:                if ((link == null) || !link.isInternal()) {
1847:                    return false;
1848:                }
1849:                try {
1850:                    // validate the link for error
1851:                    CmsResource res = cms.readResource(link.getStructureId(),
1852:                            CmsResourceFilter.IGNORE_EXPIRATION);
1853:
1854:                    // check the time range 
1855:                    if (res != null) {
1856:                        long time = System.currentTimeMillis();
1857:                        if (!res.isReleased(time)) {
1858:                            if (errorHandler != null) {
1859:                                // generate warning message
1860:                                errorHandler
1861:                                        .addWarning(
1862:                                                value,
1863:                                                Messages
1864:                                                        .get()
1865:                                                        .getBundle(
1866:                                                                value
1867:                                                                        .getLocale())
1868:                                                        .key(
1869:                                                                Messages.GUI_XMLCONTENT_CHECK_WARNING_NOT_RELEASED_0));
1870:                            }
1871:                            return true;
1872:                        } else if (res.isExpired(time)) {
1873:                            if (errorHandler != null) {
1874:                                // generate warning message
1875:                                errorHandler
1876:                                        .addWarning(
1877:                                                value,
1878:                                                Messages
1879:                                                        .get()
1880:                                                        .getBundle(
1881:                                                                value
1882:                                                                        .getLocale())
1883:                                                        .key(
1884:                                                                Messages.GUI_XMLCONTENT_CHECK_WARNING_EXPIRED_0));
1885:                            }
1886:                            return true;
1887:                        }
1888:                    }
1889:                } catch (CmsException e) {
1890:                    if (errorHandler != null) {
1891:                        // generate error message
1892:                        errorHandler.addError(value, Messages.get().getBundle(
1893:                                value.getLocale()).key(
1894:                                Messages.GUI_XMLCONTENT_CHECK_ERROR_0));
1895:                    }
1896:                    return true;
1897:                }
1898:                return false;
1899:            }
1900:
1901:            /**
1902:             * Validates the given rules against the given value.<p> 
1903:             * 
1904:             * @param cms the current users OpenCms context
1905:             * @param value the value to validate
1906:             * @param errorHandler the error handler to use in case errors or warnings are detected
1907:             * @param rules the rules to validate the value against
1908:             * @param isWarning if true, this validation should be stored as a warning, otherwise as an error
1909:             * 
1910:             * @return the updated error handler
1911:             */
1912:            protected CmsXmlContentErrorHandler validateValue(CmsObject cms,
1913:                    I_CmsXmlContentValue value,
1914:                    CmsXmlContentErrorHandler errorHandler, Map rules,
1915:                    boolean isWarning) {
1916:
1917:                if (validateLink(cms, value, errorHandler)) {
1918:                    return errorHandler;
1919:                }
1920:                try {
1921:                    if (value.getContentDefinition().getContentHandler()
1922:                            .getWidget(value) instanceof  CmsDisplayWidget) {
1923:                        // display widgets should not be validated
1924:                        return errorHandler;
1925:                    }
1926:                } catch (CmsXmlException e) {
1927:                    errorHandler.addError(value, e.getMessage());
1928:                    return errorHandler;
1929:                }
1930:
1931:                String valueStr;
1932:                try {
1933:                    valueStr = value.getStringValue(cms);
1934:                } catch (Exception e) {
1935:                    // if the value can not be accessed it's useless to continue
1936:                    errorHandler.addError(value, e.getMessage());
1937:                    return errorHandler;
1938:                }
1939:
1940:                String regex = (String) rules.get(value.getName());
1941:                if (regex == null) {
1942:                    // no customized rule, check default XML schema validation rules
1943:                    return validateValue(cms, value, valueStr, errorHandler,
1944:                            isWarning);
1945:                }
1946:
1947:                boolean matchResult = true;
1948:                if (regex.charAt(0) == '!') {
1949:                    // negate the pattern
1950:                    matchResult = false;
1951:                    regex = regex.substring(1);
1952:                }
1953:
1954:                String matchValue = valueStr;
1955:                if (matchValue == null) {
1956:                    // set match value to empty String to avoid exceptions in pattern matcher
1957:                    matchValue = "";
1958:                }
1959:
1960:                // use the custom validation pattern
1961:                if (matchResult != Pattern.matches(regex, matchValue)) {
1962:                    // generate the message
1963:                    String message = getValidationMessage(cms, value, regex,
1964:                            valueStr, matchResult, isWarning);
1965:                    if (isWarning) {
1966:                        errorHandler.addWarning(value, message);
1967:                    } else {
1968:                        errorHandler.addError(value, message);
1969:                        // if an error was found, the default XML schema validation is not applied
1970:                        return errorHandler;
1971:                    }
1972:                }
1973:
1974:                // no error found, check default XML schema validation rules
1975:                return validateValue(cms, value, valueStr, errorHandler,
1976:                        isWarning);
1977:            }
1978:
1979:            /**
1980:             * Checks the default XML schema validation rules.<p>
1981:             * 
1982:             * These rules should only be tested if this is not a test for warnings.<p>
1983:             * 
1984:             * @param cms the current users OpenCms context
1985:             * @param value the value to validate
1986:             * @param valueStr the string value of the given value
1987:             * @param errorHandler the error handler to use in case errors or warnings are detected
1988:             * @param isWarning if true, this validation should be stored as a warning, otherwise as an error
1989:             * 
1990:             * @return the updated error handler
1991:             */
1992:            protected CmsXmlContentErrorHandler validateValue(CmsObject cms,
1993:                    I_CmsXmlContentValue value, String valueStr,
1994:                    CmsXmlContentErrorHandler errorHandler, boolean isWarning) {
1995:
1996:                if (isWarning) {
1997:                    // default schema validation only applies to errors
1998:                    return errorHandler;
1999:                }
2000:
2001:                if (!value.validateValue(valueStr)) {
2002:                    // value is not valid, add an error to the handler
2003:                    String message = getValidationMessage(cms, value, value
2004:                            .getTypeName(), valueStr, true, false);
2005:                    errorHandler.addError(value, message);
2006:                }
2007:
2008:                return errorHandler;
2009:            }
2010:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.