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.file.types; 029 030import org.opencms.ade.containerpage.shared.CmsContainerElement; 031import org.opencms.configuration.CmsConfigurationException; 032import org.opencms.db.CmsSecurityManager; 033import org.opencms.file.CmsFile; 034import org.opencms.file.CmsObject; 035import org.opencms.file.CmsProperty; 036import org.opencms.file.CmsPropertyDefinition; 037import org.opencms.file.CmsRequestContext; 038import org.opencms.file.CmsResource; 039import org.opencms.file.CmsResourceFilter; 040import org.opencms.loader.CmsLoaderException; 041import org.opencms.loader.CmsXmlContainerPageLoader; 042import org.opencms.main.CmsException; 043import org.opencms.main.CmsLog; 044import org.opencms.main.OpenCms; 045import org.opencms.relations.CmsLink; 046import org.opencms.relations.I_CmsLinkParseable; 047import org.opencms.security.CmsPermissionSet; 048import org.opencms.xml.CmsXmlContentDefinition; 049import org.opencms.xml.containerpage.CmsXmlContainerPage; 050import org.opencms.xml.containerpage.CmsXmlContainerPageFactory; 051import org.opencms.xml.types.CmsXmlVfsFileValue; 052import org.opencms.xml.types.I_CmsXmlContentValue; 053 054import java.util.ArrayList; 055import java.util.Collections; 056import java.util.HashSet; 057import java.util.Iterator; 058import java.util.List; 059import java.util.Locale; 060import java.util.Set; 061 062import org.apache.commons.logging.Log; 063 064/** 065 * Resource type descriptor for the type "containerpage".<p> 066 * 067 * It is just a xml content with a fixed schema.<p> 068 * 069 * @since 7.6 070 */ 071public class CmsResourceTypeXmlContainerPage extends CmsResourceTypeXmlContent { 072 073 /** The configuration resource type name. */ 074 public static final String CONFIGURATION_TYPE_NAME = "sitemap_config"; 075 076 /** The group container resource type name. */ 077 public static final String GROUP_CONTAINER_TYPE_NAME = "groupcontainer"; 078 079 /** The inherit configuration resource type name. */ 080 public static final String INHERIT_CONTAINER_CONFIG_TYPE_NAME = "inheritance_config"; 081 082 /** The resource type name for inherited container references. */ 083 public static final String INHERIT_CONTAINER_TYPE_NAME = "inheritance_group"; 084 085 /** The model group resource type name. */ 086 public static final String MODEL_GROUP_TYPE_NAME = "modelgroup"; 087 088 /** The name of this resource type. */ 089 public static final String RESOURCE_TYPE_NAME = "containerpage"; 090 091 /** A variable containing the actual configured type id of container pages. */ 092 private static int containerPageTypeId; 093 094 /** The log object for this class. */ 095 private static final Log LOG = CmsLog.getLog(CmsResourceTypeXmlContainerPage.class); 096 097 /** Fixed schema for container pages. */ 098 private static final String SCHEMA = "/system/modules/org.opencms.ade.containerpage/schemas/container_page.xsd"; 099 100 /** The serial version id. */ 101 private static final long serialVersionUID = -6211941269510267155L; 102 103 /** 104 * Default constructor that sets the fixed schema for container pages.<p> 105 */ 106 public CmsResourceTypeXmlContainerPage() { 107 108 super(); 109 m_typeName = RESOURCE_TYPE_NAME; 110 addConfigurationParameter(CONFIGURATION_SCHEMA, SCHEMA); 111 } 112 113 /** 114 * Returns the container-page type id.<p> 115 * 116 * @return the container-page type id 117 * 118 * @throws CmsLoaderException if the type is not configured 119 */ 120 @SuppressWarnings("deprecation") 121 public static int getContainerPageTypeId() throws CmsLoaderException { 122 123 if (containerPageTypeId == 0) { 124 I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(getStaticTypeName()); 125 if (resType != null) { 126 containerPageTypeId = resType.getTypeId(); 127 } 128 } 129 return containerPageTypeId; 130 } 131 132 /** 133 * Returns the container-page type id, but returns -1 instead of throwing an exception when an error happens.<p> 134 * 135 * @return the container-page type id 136 */ 137 public static int getContainerPageTypeIdSafely() { 138 139 try { 140 return getContainerPageTypeId(); 141 } catch (CmsLoaderException e) { 142 if (LOG.isDebugEnabled()) { 143 LOG.debug(e.getLocalizedMessage(), e); 144 } 145 return -1; 146 } 147 } 148 149 /** 150 * Returns the static type name of this (default) resource type.<p> 151 * 152 * @return the static type name of this (default) resource type 153 */ 154 public static String getStaticTypeName() { 155 156 return RESOURCE_TYPE_NAME; 157 } 158 159 /** 160 * Returns <code>true</code> in case the given resource is a container page.<p> 161 * 162 * Internally this checks if the type id for the given resource is 163 * identical type id of the container page.<p> 164 * 165 * @param resource the resource to check 166 * 167 * @return <code>true</code> in case the given resource is a container page 168 */ 169 public static boolean isContainerPage(CmsResource resource) { 170 171 boolean result = false; 172 if (resource != null) { 173 result = (resource.getTypeId() == getContainerPageTypeIdSafely()) 174 || (OpenCms.getResourceManager().getResourceType(resource) instanceof CmsResourceTypeXmlContainerPage); 175 } 176 177 return result; 178 179 } 180 181 /** 182 * Checks whether the given resource is a model reuse group.<p> 183 * 184 * @param cms the cms context 185 * @param resource the resource 186 * 187 * @return <code>true</code> in case the resource is a model reuse group 188 */ 189 public static boolean isModelCopyGroup(CmsObject cms, CmsResource resource) { 190 191 boolean result = false; 192 if (isModelGroup(resource)) { 193 try { 194 CmsProperty tempElementsProp = cms.readPropertyObject( 195 resource, 196 CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS, 197 false); 198 if (!tempElementsProp.isNullProperty() 199 && CmsContainerElement.USE_AS_COPY_MODEL.equals(tempElementsProp.getValue())) { 200 result = true; 201 } 202 } catch (CmsException e) { 203 LOG.warn(e.getMessage(), e); 204 } 205 206 } 207 return result; 208 } 209 210 /** 211 * Checks whether the given resource is a model group.<p> 212 * 213 * @param resource the resource 214 * 215 * @return <code>true</code> in case the resource is a model group 216 */ 217 public static boolean isModelGroup(CmsResource resource) { 218 219 return OpenCms.getResourceManager().getResourceType(resource).getTypeName().equals(MODEL_GROUP_TYPE_NAME); 220 } 221 222 /** 223 * @see org.opencms.file.types.CmsResourceTypeXmlContent#createResource(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, java.lang.String, byte[], java.util.List) 224 */ 225 @Override 226 public CmsResource createResource( 227 CmsObject cms, 228 CmsSecurityManager securityManager, 229 String resourcename, 230 byte[] content, 231 List<CmsProperty> properties) 232 throws CmsException { 233 234 boolean hasModelUri = false; 235 CmsXmlContainerPage newContent = null; 236 if ((getSchema() != null) && ((content == null) || (content.length == 0))) { 237 // unmarshal the content definition for the new resource 238 CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, getSchema()); 239 240 // read the default locale for the new resource 241 Locale locale = OpenCms.getLocaleManager().getDefaultLocales( 242 cms, 243 CmsResource.getParentFolder(resourcename)).get(0); 244 245 String modelUri = (String)cms.getRequestContext().getAttribute(CmsRequestContext.ATTRIBUTE_MODEL); 246 247 // must set URI of OpenCms user context to parent folder of created resource, 248 // in order to allow reading of properties for default values 249 CmsObject newCms = OpenCms.initCmsObject(cms); 250 newCms.getRequestContext().setUri(CmsResource.getParentFolder(resourcename)); 251 if (modelUri != null) { 252 // create the new content from the model file 253 newContent = CmsXmlContainerPageFactory.createDocument(newCms, locale, modelUri); 254 hasModelUri = true; 255 } else { 256 // create the new content from the content definition 257 newContent = CmsXmlContainerPageFactory.createDocument( 258 newCms, 259 locale, 260 OpenCms.getSystemInfo().getDefaultEncoding(), 261 contentDefinition); 262 } 263 // get the bytes from the created content 264 content = newContent.marshal(); 265 } 266 267 // now create the resource using the super class 268 CmsResource resource = super.createResource(cms, securityManager, resourcename, content, properties); 269 270 // a model file was used, call the content handler for post-processing 271 if (hasModelUri) { 272 newContent = CmsXmlContainerPageFactory.unmarshal(cms, resource); 273 resource = newContent.getHandler().prepareForWrite(cms, newContent, newContent.getFile()); 274 } 275 276 return resource; 277 } 278 279 /** 280 * @see org.opencms.file.types.CmsResourceTypeXmlContent#getLoaderId() 281 */ 282 @Override 283 public int getLoaderId() { 284 285 return CmsXmlContainerPageLoader.CONTAINER_PAGE_RESOURCE_LOADER_ID; 286 } 287 288 /** 289 * @see org.opencms.file.types.A_CmsResourceType#initConfiguration(java.lang.String, java.lang.String, String) 290 */ 291 @Override 292 public void initConfiguration(String name, String id, String className) throws CmsConfigurationException { 293 294 if (!RESOURCE_TYPE_NAME.equals(name) && !MODEL_GROUP_TYPE_NAME.equals(name)) { 295 // default resource type MUST have default name 296 throw new CmsConfigurationException( 297 Messages.get().container( 298 Messages.ERR_INVALID_RESTYPE_CONFIG_NAME_3, 299 this.getClass().getName(), 300 RESOURCE_TYPE_NAME, 301 name)); 302 } 303 super.initConfiguration(name, id, className); 304 } 305 306 /** 307 * @see org.opencms.relations.I_CmsLinkParseable#parseLinks(org.opencms.file.CmsObject, org.opencms.file.CmsFile) 308 */ 309 @Override 310 public List<CmsLink> parseLinks(CmsObject cms, CmsFile file) { 311 312 if (file.getLength() == 0) { 313 return Collections.emptyList(); 314 } 315 CmsXmlContainerPage xmlContent; 316 long requestTime = cms.getRequestContext().getRequestTime(); 317 try { 318 // prevent the check rules to remove the broken links 319 cms.getRequestContext().setRequestTime(CmsResource.DATE_RELEASED_EXPIRED_IGNORE); 320 xmlContent = CmsXmlContainerPageFactory.unmarshal(cms, file); 321 } catch (CmsException e) { 322 if (LOG.isErrorEnabled()) { 323 LOG.error( 324 org.opencms.db.Messages.get().getBundle().key( 325 org.opencms.db.Messages.ERR_READ_RESOURCE_1, 326 cms.getSitePath(file)), 327 e); 328 } 329 return Collections.emptyList(); 330 } finally { 331 cms.getRequestContext().setRequestTime(requestTime); 332 } 333 334 Set<CmsLink> links = new HashSet<CmsLink>(); 335 336 // add XSD link 337 CmsLink xsdLink = getXsdLink(cms, xmlContent); 338 if (xsdLink != null) { 339 links.add(xsdLink); 340 } 341 342 // iterate over all languages 343 List<Locale> locales = xmlContent.getLocales(); 344 Iterator<Locale> i = locales.iterator(); 345 while (i.hasNext()) { 346 Locale locale = i.next(); 347 List<I_CmsXmlContentValue> values = xmlContent.getValues(locale); 348 349 // iterate over all body elements per language 350 Iterator<I_CmsXmlContentValue> j = values.iterator(); 351 while (j.hasNext()) { 352 I_CmsXmlContentValue value = j.next(); 353 if (!(value instanceof CmsXmlVfsFileValue)) { 354 // filter only relations relevant fields 355 // container pages do not have XmlHtml nor VarFiles 356 continue; 357 } 358 CmsXmlVfsFileValue refValue = (CmsXmlVfsFileValue)value; 359 CmsLink link = refValue.getLink(cms); 360 if (link != null) { 361 links.add(link); 362 } 363 } 364 } 365 return new ArrayList<CmsLink>(links); 366 } 367 368 /** 369 * @see org.opencms.file.types.CmsResourceTypeXmlContent#writeFile(org.opencms.file.CmsObject, org.opencms.db.CmsSecurityManager, org.opencms.file.CmsFile) 370 */ 371 @Override 372 public CmsFile writeFile(CmsObject cms, CmsSecurityManager securityManager, CmsFile resource) throws CmsException { 373 374 // check if the user has write access and if resource is locked 375 // done here so that all the XML operations are not performed if permissions not granted 376 securityManager.checkPermissions( 377 cms.getRequestContext(), 378 resource, 379 CmsPermissionSet.ACCESS_WRITE, 380 true, 381 CmsResourceFilter.ALL); 382 // read the XML content, use the encoding set in the property 383 CmsXmlContainerPage xmlContent = CmsXmlContainerPageFactory.unmarshal(cms, resource, false, true); 384 // call the content handler for post-processing 385 resource = xmlContent.getHandler().prepareForWrite(cms, xmlContent, resource); 386 387 // now write the file 388 CmsFile file = securityManager.writeFile(cms.getRequestContext(), resource); 389 I_CmsResourceType type = getResourceType(file); 390 // update the relations after writing!! 391 List<CmsLink> links = null; 392 if (type instanceof I_CmsLinkParseable) { // this check is needed because of type change 393 // if the new type is link parseable 394 links = ((I_CmsLinkParseable)type).parseLinks(cms, file); 395 } 396 // this has to be always executed, even if not link parseable to remove old links 397 securityManager.updateRelationsForResource(cms.getRequestContext(), file, links); 398 return file; 399 } 400}