001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.xml.types; 029 030import org.opencms.file.CmsObject; 031import org.opencms.main.CmsIllegalArgumentException; 032import org.opencms.main.CmsRuntimeException; 033import org.opencms.main.OpenCms; 034import org.opencms.relations.CmsLink; 035import org.opencms.relations.CmsLinkUpdateUtil; 036import org.opencms.relations.CmsRelationType; 037import org.opencms.util.CmsRequestUtil; 038import org.opencms.util.CmsStringUtil; 039import org.opencms.util.CmsUUID; 040import org.opencms.xml.I_CmsXmlDocument; 041import org.opencms.xml.page.CmsXmlPage; 042 043import java.util.Locale; 044 045import org.dom4j.Attribute; 046import org.dom4j.Element; 047 048/** 049 * Describes the XML content type "OpenCmsVfsFile".<p> 050 * 051 * This type allows links to internal VFS resources only.<p> 052 * 053 * @since 7.0.0 054 */ 055public class CmsXmlVfsFileValue extends A_CmsXmlContentValue { 056 057 /** Value to mark that no link is defined, "none". */ 058 public static final String NO_LINK = "none"; 059 060 /** The name of this type as used in the XML schema. */ 061 public static final String TYPE_NAME = "OpenCmsVfsFile"; 062 063 /** The vfs link type constant. */ 064 public static final String TYPE_VFS_LINK = "vfsLink"; 065 066 /** The schema definition String is located in a text for easier editing. */ 067 private static String m_schemaDefinition; 068 069 /** The String value of the element node. */ 070 private String m_stringValue; 071 072 /** 073 * Creates a new, empty schema type descriptor of type "OpenCmsVfsFile".<p> 074 */ 075 public CmsXmlVfsFileValue() { 076 077 // empty constructor is required for class registration 078 } 079 080 /** 081 * Creates a new XML content value of type "OpenCmsVfsFile".<p> 082 * 083 * @param document the XML content instance this value belongs to 084 * @param element the XML element that contains this value 085 * @param locale the locale this value is created for 086 * @param type the type instance to create the value for 087 */ 088 public CmsXmlVfsFileValue(I_CmsXmlDocument document, Element element, Locale locale, I_CmsXmlSchemaType type) { 089 090 super(document, element, locale, type); 091 } 092 093 /** 094 * Creates a new schema type descriptor for the type "OpenCmsVfsFile".<p> 095 * 096 * @param name the name of the XML node containing the value according to the XML schema 097 * @param minOccurs minimum number of occurrences of this type according to the XML schema 098 * @param maxOccurs maximum number of occurrences of this type according to the XML schema 099 */ 100 public CmsXmlVfsFileValue(String name, String minOccurs, String maxOccurs) { 101 102 super(name, minOccurs, maxOccurs); 103 } 104 105 /** 106 * Fills the given element with a {@link CmsXmlVfsFileValue} for the given data.<p> 107 * 108 * @param element the element to fill 109 * @param id the id to use 110 * @param rootPath the path to use 111 * @param type the relation type to use 112 */ 113 public static void fillEntry(Element element, CmsUUID id, String rootPath, CmsRelationType type) { 114 115 CmsLink link = new CmsLink(CmsXmlVfsFileValue.TYPE_VFS_LINK, type, id, rootPath, true); 116 // get xml node 117 Element linkElement = element.element(CmsXmlPage.NODE_LINK); 118 if (linkElement == null) { 119 // create xml node if needed 120 linkElement = element.addElement(CmsXmlPage.NODE_LINK); 121 } 122 // update xml node 123 CmsLinkUpdateUtil.updateXmlForVfsFile(link, linkElement); 124 } 125 126 /** 127 * @see org.opencms.xml.types.A_CmsXmlContentValue#createValue(I_CmsXmlDocument, org.dom4j.Element, Locale) 128 */ 129 public I_CmsXmlContentValue createValue(I_CmsXmlDocument document, Element element, Locale locale) { 130 131 return new CmsXmlVfsFileValue(document, element, locale, this); 132 } 133 134 /** 135 * @see org.opencms.xml.types.I_CmsXmlSchemaType#generateXml(org.opencms.file.CmsObject, org.opencms.xml.I_CmsXmlDocument, org.dom4j.Element, java.util.Locale) 136 */ 137 @Override 138 public Element generateXml(CmsObject cms, I_CmsXmlDocument document, Element root, Locale locale) { 139 140 Element element = root.addElement(getName()); 141 142 // get the default value from the content handler 143 String defaultValue = document.getHandler().getDefault(cms, this, locale); 144 if (defaultValue != null) { 145 I_CmsXmlContentValue value = createValue(document, element, locale); 146 value.setStringValue(cms, defaultValue); 147 } 148 return element; 149 } 150 151 /** 152 * Returns the link object represented by this XML content value.<p> 153 * 154 * @param cms the cms context, can be <code>null</code> but in this case no link check is performed 155 * 156 * @return the link object represented by this XML content value (will return null for an empty link) 157 */ 158 public CmsLink getLink(CmsObject cms) { 159 160 Element linkElement = m_element.element(CmsXmlPage.NODE_LINK); 161 if (linkElement == null) { 162 String textValue = m_element.getText(); 163 if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(textValue)) { 164 if (CmsUUID.isValidUUID(textValue)) { 165 setIdValue(cms, new CmsUUID(textValue)); 166 } else { 167 setStringValue(cms, textValue); 168 } 169 } 170 linkElement = m_element.element(CmsXmlPage.NODE_LINK); 171 if (linkElement == null) { 172 return null; 173 } 174 } 175 CmsLinkUpdateUtil.updateType(linkElement, getRelationType(getPath())); 176 CmsLink link = new CmsLink(linkElement); 177 link.checkConsistency(cms); 178 if (CmsStringUtil.isEmptyOrWhitespaceOnly(link.getTarget())) { 179 return null; 180 } 181 return link; 182 } 183 184 /** 185 * @see org.opencms.xml.types.I_CmsXmlContentValue#getPlainText(org.opencms.file.CmsObject) 186 */ 187 @Override 188 public String getPlainText(CmsObject cms) { 189 190 return getStringValue(cms); 191 } 192 193 /** 194 * @see org.opencms.xml.types.I_CmsXmlSchemaType#getSchemaDefinition() 195 */ 196 public String getSchemaDefinition() { 197 198 // the schema definition is located in a separate file for easier editing 199 if (m_schemaDefinition == null) { 200 m_schemaDefinition = readSchemaDefinition("org/opencms/xml/types/XmlVfsFileValue.xsd"); 201 } 202 return m_schemaDefinition; 203 } 204 205 /** 206 * @see org.opencms.xml.types.I_CmsXmlContentValue#getStringValue(CmsObject) 207 */ 208 public String getStringValue(CmsObject cms) throws CmsRuntimeException { 209 210 if (m_stringValue == null) { 211 m_stringValue = createStringValue(cms); 212 } 213 return m_stringValue; 214 } 215 216 /** 217 * @see org.opencms.xml.types.A_CmsXmlContentValue#getTypeName() 218 */ 219 public String getTypeName() { 220 221 return TYPE_NAME; 222 } 223 224 /** 225 * @see org.opencms.xml.types.A_CmsXmlContentValue#isSearchable() 226 */ 227 @Override 228 public boolean isSearchable() { 229 230 // there is no point in searching link values 231 return false; 232 } 233 234 /** 235 * @see org.opencms.xml.types.A_CmsXmlContentValue#newInstance(java.lang.String, java.lang.String, java.lang.String) 236 */ 237 public I_CmsXmlSchemaType newInstance(String name, String minOccurs, String maxOccurs) { 238 239 return new CmsXmlVfsFileValue(name, minOccurs, maxOccurs); 240 } 241 242 /** 243 * Sets the value as a structure id.<p> 244 * 245 * @param cms the current CMS context 246 * @param id the structure id which should be stored in the file value 247 */ 248 public void setIdValue(CmsObject cms, CmsUUID id) { 249 250 CmsRelationType type = getRelationType(getPath()); 251 CmsLink link = new CmsLink(TYPE_VFS_LINK, type, id, "@", true); 252 // link management check 253 link.checkConsistency(cms); 254 // update xml node 255 CmsLinkUpdateUtil.updateXmlForVfsFile(link, m_element.addElement(CmsXmlPage.NODE_LINK)); 256 257 } 258 259 /** 260 * @see org.opencms.xml.types.A_CmsXmlContentValue#setStringValue(org.opencms.file.CmsObject, java.lang.String) 261 */ 262 public void setStringValue(CmsObject cms, String value) throws CmsIllegalArgumentException { 263 264 m_element.clearContent(); 265 // ensure the String value is re-calculated next time it's needed 266 m_stringValue = null; 267 if (CmsStringUtil.isEmptyOrWhitespaceOnly(value)) { 268 // no valid value given 269 return; 270 } 271 if (CmsUUID.isValidUUID(value)) { 272 setIdValue(cms, new CmsUUID(value)); 273 return; 274 } 275 String path = value; 276 if (cms != null) { 277 String siteRoot = OpenCms.getSiteManager().getSiteRoot(value); 278 String oldSite = cms.getRequestContext().getSiteRoot(); 279 try { 280 if (siteRoot != null) { 281 // only switch the site if needed 282 cms.getRequestContext().setSiteRoot(siteRoot); 283 // remove the site root, because the link manager call will append it anyway 284 path = cms.getRequestContext().removeSiteRoot(value); 285 if (CmsStringUtil.isEmptyOrWhitespaceOnly(path)) { 286 path = "/"; 287 } 288 } 289 // remove parameters, if not the link manager call might fail 290 String query = ""; 291 int pos = path.indexOf(CmsRequestUtil.URL_DELIMITER); 292 int anchorPos = path.indexOf('#'); 293 if ((pos == -1) || ((anchorPos > -1) && (pos > anchorPos))) { 294 pos = anchorPos; 295 } 296 if (pos > -1) { 297 query = path.substring(pos); 298 path = path.substring(0, pos); 299 } 300 // get the root path 301 path = OpenCms.getLinkManager().getRootPath(cms, path); 302 if (path == null) { 303 path = value; 304 } else { 305 // append parameters again 306 path += query; 307 } 308 } finally { 309 if (siteRoot != null) { 310 cms.getRequestContext().setSiteRoot(oldSite); 311 } 312 } 313 } 314 if (CmsStringUtil.isEmptyOrWhitespaceOnly(path)) { 315 return; 316 } 317 CmsRelationType type = getRelationType(getPath()); 318 CmsLink link = new CmsLink(TYPE_VFS_LINK, type, path, true); 319 // link management check 320 link.checkConsistency(cms); 321 // update xml node 322 CmsLinkUpdateUtil.updateXmlForVfsFile(link, m_element.addElement(CmsXmlPage.NODE_LINK)); 323 } 324 325 /** 326 * Creates the String value for this vfs file value element.<p> 327 * 328 * @param cms the cms context 329 * 330 * @return the String value for this vfs file value element 331 */ 332 private String createStringValue(CmsObject cms) { 333 334 Attribute enabled = m_element.attribute(CmsXmlPage.ATTRIBUTE_ENABLED); 335 336 String content = ""; 337 if ((enabled == null) || Boolean.valueOf(enabled.getText()).booleanValue()) { 338 CmsLink link = getLink(cms); 339 if (link != null) { 340 content = link.getUri(); 341 if (cms != null) { 342 content = cms.getRequestContext().removeSiteRoot(link.getUri()); 343 } 344 } 345 } 346 return content; 347 } 348}