001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.loader; 029 030import org.opencms.cache.CmsVfsMemoryObjectCache; 031import org.opencms.configuration.CmsConfigurationException; 032import org.opencms.configuration.CmsVfsConfiguration; 033import org.opencms.file.CmsObject; 034import org.opencms.file.CmsProperty; 035import org.opencms.file.CmsPropertyDefinition; 036import org.opencms.file.CmsResource; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.file.collectors.I_CmsResourceCollector; 039import org.opencms.file.types.CmsResourceTypeBinary; 040import org.opencms.file.types.CmsResourceTypeFolder; 041import org.opencms.file.types.CmsResourceTypePlain; 042import org.opencms.file.types.CmsResourceTypeUnknownFile; 043import org.opencms.file.types.CmsResourceTypeUnknownFolder; 044import org.opencms.file.types.CmsResourceTypeXmlContent; 045import org.opencms.file.types.I_CmsResourceType; 046import org.opencms.main.CmsException; 047import org.opencms.main.CmsLog; 048import org.opencms.main.OpenCms; 049import org.opencms.module.CmsModule; 050import org.opencms.module.CmsModuleManager; 051import org.opencms.relations.CmsRelationType; 052import org.opencms.security.CmsRole; 053import org.opencms.security.CmsRoleViolationException; 054import org.opencms.util.CmsDefaultSet; 055import org.opencms.util.CmsHtmlConverter; 056import org.opencms.util.CmsHtmlConverterJTidy; 057import org.opencms.util.CmsHtmlConverterOption; 058import org.opencms.util.CmsResourceTranslator; 059import org.opencms.util.CmsStringUtil; 060import org.opencms.util.I_CmsHtmlConverter; 061import org.opencms.workplace.CmsWorkplace; 062import org.opencms.xml.CmsXmlContentDefinition; 063 064import java.io.IOException; 065import java.util.ArrayList; 066import java.util.Collections; 067import java.util.HashMap; 068import java.util.Iterator; 069import java.util.List; 070import java.util.Locale; 071import java.util.Map; 072import java.util.Properties; 073 074import javax.servlet.ServletException; 075import javax.servlet.http.HttpServletRequest; 076import javax.servlet.http.HttpServletResponse; 077 078import org.apache.commons.logging.Log; 079 080/** 081 * Collects all available resource loaders, resource types and resource collectors at startup and provides 082 * methods to access them during OpenCms runtime.<p> 083 * 084 * @since 6.0.0 085 */ 086public class CmsResourceManager { 087 088 /** 089 * Bean containing a template resource and the name of the template.<p> 090 */ 091 public static class NamedTemplate { 092 093 /** The template name. */ 094 private String m_name; 095 096 /** The template resource. */ 097 private CmsResource m_resource; 098 099 /** 100 * Creates a new instance.<p> 101 * 102 * @param resource the template resource 103 * @param name the template name 104 */ 105 public NamedTemplate(CmsResource resource, String name) { 106 107 m_resource = resource; 108 m_name = name; 109 } 110 111 /** 112 * Gets the template name.<p> 113 * 114 * @return the template name 115 */ 116 public String getName() { 117 118 return m_name; 119 } 120 121 /** 122 * Gets the template resource.<p> 123 * 124 * @return the template resource 125 */ 126 public CmsResource getResource() { 127 128 return m_resource; 129 } 130 } 131 132 /** 133 * Contains the part of the resource manager configuration that can be changed 134 * during runtime by the import / deletion of a module.<p> 135 * 136 * A module can add resource types and extension mappings to resource types.<p> 137 */ 138 static final class CmsResourceManagerConfiguration { 139 140 /** The mappings of file extensions to resource types. */ 141 protected Map<String, String> m_extensionMappings; 142 143 /** A list that contains all initialized resource types. */ 144 protected List<I_CmsResourceType> m_resourceTypeList; 145 146 /** A list that contains all initialized resource types, plus configured types for "unknown" resources. */ 147 protected List<I_CmsResourceType> m_resourceTypeListWithUnknown; 148 149 /** A map that contains all initialized resource types mapped to their type id. */ 150 private Map<Integer, I_CmsResourceType> m_resourceTypeIdMap; 151 152 /** A map that contains all initialized resource types mapped to their type name. */ 153 private Map<String, I_CmsResourceType> m_resourceTypeNameMap; 154 155 /** 156 * Creates a new resource manager data storage.<p> 157 */ 158 protected CmsResourceManagerConfiguration() { 159 160 m_resourceTypeIdMap = new HashMap<Integer, I_CmsResourceType>(128); 161 m_resourceTypeNameMap = new HashMap<String, I_CmsResourceType>(128); 162 m_extensionMappings = new HashMap<String, String>(128); 163 m_resourceTypeList = new ArrayList<I_CmsResourceType>(32); 164 } 165 166 /** 167 * Adds a resource type to the list of configured resource types.<p> 168 * 169 * @param type the resource type to add 170 */ 171 protected void addResourceType(I_CmsResourceType type) { 172 173 m_resourceTypeIdMap.put(Integer.valueOf(type.getTypeId()), type); 174 m_resourceTypeNameMap.put(type.getTypeName(), type); 175 m_resourceTypeList.add(type); 176 } 177 178 /** 179 * Freezes the current configuration by making all data structures unmodifiable 180 * that can be accessed form outside this class.<p> 181 * 182 * @param restypeUnknownFolder the configured default resource type for unknown folders 183 * @param restypeUnknownFile the configured default resource type for unknown files 184 */ 185 protected void freeze(I_CmsResourceType restypeUnknownFolder, I_CmsResourceType restypeUnknownFile) { 186 187 // generate the resource type list with unknown resource types 188 m_resourceTypeListWithUnknown = new ArrayList<I_CmsResourceType>(m_resourceTypeList.size() + 2); 189 if (restypeUnknownFolder != null) { 190 m_resourceTypeListWithUnknown.add(restypeUnknownFolder); 191 } 192 if (restypeUnknownFile != null) { 193 m_resourceTypeListWithUnknown.add(restypeUnknownFile); 194 } 195 m_resourceTypeListWithUnknown.addAll(m_resourceTypeList); 196 197 // freeze the current configuration 198 m_resourceTypeListWithUnknown = Collections.unmodifiableList(m_resourceTypeListWithUnknown); 199 m_resourceTypeList = Collections.unmodifiableList(m_resourceTypeList); 200 m_extensionMappings = Collections.unmodifiableMap(m_extensionMappings); 201 } 202 203 /** 204 * Returns the configured resource type with the matching type id, or <code>null</code> 205 * if a resource type with that id is not configured.<p> 206 * 207 * @param typeId the type id to get the resource type for 208 * 209 * @return the configured resource type with the matching type id, or <code>null</code> 210 */ 211 protected I_CmsResourceType getResourceTypeById(int typeId) { 212 213 return m_resourceTypeIdMap.get(Integer.valueOf(typeId)); 214 } 215 216 /** 217 * Returns the configured resource type with the matching type name, or <code>null</code> 218 * if a resource type with that name is not configured.<p> 219 * 220 * @param typeName the type name to get the resource type for 221 * 222 * @return the configured resource type with the matching type name, or <code>null</code> 223 */ 224 protected I_CmsResourceType getResourceTypeByName(String typeName) { 225 226 return m_resourceTypeNameMap.get(typeName); 227 } 228 } 229 230 /** The path to the default template. */ 231 public static final String DEFAULT_TEMPLATE = CmsWorkplace.VFS_PATH_COMMONS + "template/default.jsp"; 232 233 /** The MIME type <code>"text/html"</code>. */ 234 public static final String MIMETYPE_HTML = "text/html"; 235 236 /** The MIME type <code>"text/plain"</code>. */ 237 public static final String MIMETYPE_TEXT = "text/plain"; 238 239 /** The log object for this class. */ 240 private static final Log LOG = CmsLog.getLog(CmsResourceManager.class); 241 242 /** The map for all configured collector names, mapped to their collector class. */ 243 private Map<String, I_CmsResourceCollector> m_collectorNameMappings; 244 245 /** The list of all currently configured content collector instances. */ 246 private List<I_CmsResourceCollector> m_collectors; 247 248 /** The current resource manager configuration. */ 249 private CmsResourceManagerConfiguration m_configuration; 250 251 /** The list of all configured HTML converters. */ 252 private List<CmsHtmlConverterOption> m_configuredHtmlConverters; 253 254 /** The list of all configured MIME types. */ 255 private List<CmsMimeType> m_configuredMimeTypes; 256 257 /** The list of all configured relation types. */ 258 private List<CmsRelationType> m_configuredRelationTypes; 259 260 /** Filename translator, used only for the creation of new files. */ 261 private CmsResourceTranslator m_fileTranslator; 262 263 /** Folder translator, used to translate all accesses to resources. */ 264 private CmsResourceTranslator m_folderTranslator; 265 266 /** Indicates if the configuration is finalized (frozen). */ 267 private boolean m_frozen; 268 269 /** The OpenCms map of configured HTML converters. */ 270 private Map<String, String> m_htmlConverters; 271 272 /** A list that contains all initialized resource loaders. */ 273 private List<I_CmsResourceLoader> m_loaderList; 274 275 /** All initialized resource loaders, mapped to their id. */ 276 private I_CmsResourceLoader[] m_loaders; 277 278 /** The OpenCms map of configured MIME types. */ 279 private Map<String, String> m_mimeTypes; 280 281 /** The URL name generator for XML contents. */ 282 private I_CmsFileNameGenerator m_nameGenerator = new CmsDefaultFileNameGenerator(); 283 284 /** A list that contains all resource types added from the XML configuration. */ 285 private List<I_CmsResourceType> m_resourceTypesFromXml; 286 287 /** The configured default type for files when the resource type is missing. */ 288 private I_CmsResourceType m_restypeUnknownFile; 289 290 /** The configured default type for folders when the resource type is missing. */ 291 private I_CmsResourceType m_restypeUnknownFolder; 292 293 /** Cache for template names. */ 294 private CmsVfsMemoryObjectCache m_templateNameCache = new CmsVfsMemoryObjectCache(); 295 296 /** XSD translator, used to translate all accesses to XML schemas from Strings. */ 297 private CmsResourceTranslator m_xsdTranslator; 298 299 /** 300 * Creates a new instance for the resource manager, 301 * will be called by the VFS configuration manager.<p> 302 */ 303 public CmsResourceManager() { 304 305 if (CmsLog.INIT.isInfoEnabled()) { 306 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_STARTING_LOADER_CONFIG_0)); 307 } 308 309 m_resourceTypesFromXml = new ArrayList<I_CmsResourceType>(); 310 m_loaders = new I_CmsResourceLoader[16]; 311 m_loaderList = new ArrayList<I_CmsResourceLoader>(); 312 m_configuredMimeTypes = new ArrayList<CmsMimeType>(); 313 m_configuredRelationTypes = new ArrayList<CmsRelationType>(); 314 m_configuredHtmlConverters = new ArrayList<CmsHtmlConverterOption>(); 315 } 316 317 /** 318 * Adds a given content collector class to the type manager.<p> 319 * 320 * @param className the name of the class to add 321 * @param order the order number for this collector 322 * 323 * @return the created content collector instance 324 * 325 * @throws CmsConfigurationException in case the collector could not be properly initialized 326 */ 327 public synchronized I_CmsResourceCollector addContentCollector(String className, String order) 328 throws CmsConfigurationException { 329 330 Class<?> classClazz; 331 // init class for content collector 332 try { 333 classClazz = Class.forName(className); 334 } catch (ClassNotFoundException e) { 335 LOG.error(Messages.get().getBundle().key(Messages.LOG_CONTENT_COLLECTOR_CLASS_NOT_FOUND_1, className), e); 336 return null; 337 } 338 339 I_CmsResourceCollector collector; 340 try { 341 collector = (I_CmsResourceCollector)classClazz.newInstance(); 342 } catch (InstantiationException e) { 343 throw new CmsConfigurationException( 344 Messages.get().container(Messages.ERR_INVALID_COLLECTOR_NAME_1, className)); 345 } catch (IllegalAccessException e) { 346 throw new CmsConfigurationException( 347 Messages.get().container(Messages.ERR_INVALID_COLLECTOR_NAME_1, className)); 348 } catch (ClassCastException e) { 349 throw new CmsConfigurationException( 350 Messages.get().container(Messages.ERR_INVALID_COLLECTOR_NAME_1, className)); 351 } 352 353 // set the configured order for the collector 354 int ord = 0; 355 try { 356 ord = Integer.valueOf(order).intValue(); 357 } catch (NumberFormatException e) { 358 LOG.error(Messages.get().getBundle().key(Messages.LOG_COLLECTOR_BAD_ORDER_NUMBER_1, className), e); 359 } 360 collector.setOrder(ord); 361 362 if (CmsLog.INIT.isInfoEnabled()) { 363 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_COLLECTOR_CLASS_2, className, order)); 364 } 365 366 // extend or init the current list of configured collectors 367 if (m_collectors != null) { 368 m_collectors = new ArrayList<I_CmsResourceCollector>(m_collectors); 369 m_collectorNameMappings = new HashMap<String, I_CmsResourceCollector>(m_collectorNameMappings); 370 } else { 371 m_collectors = new ArrayList<I_CmsResourceCollector>(); 372 m_collectorNameMappings = new HashMap<String, I_CmsResourceCollector>(); 373 } 374 375 if (!m_collectors.contains(collector)) { 376 // this is a collector not currently configured 377 m_collectors.add(collector); 378 379 Iterator<String> i = collector.getCollectorNames().iterator(); 380 while (i.hasNext()) { 381 String name = i.next(); 382 if (m_collectorNameMappings.containsKey(name)) { 383 // this name is already configured, check the order of the collector 384 I_CmsResourceCollector otherCollector = m_collectorNameMappings.get(name); 385 if (collector.getOrder() > otherCollector.getOrder()) { 386 // new collector has a greater order than the old collector in the Map 387 m_collectorNameMappings.put(name, collector); 388 if (CmsLog.INIT.isInfoEnabled()) { 389 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_COLLECTOR_REPLACED_1, name)); 390 } 391 } else { 392 if (CmsLog.INIT.isInfoEnabled()) { 393 CmsLog.INIT.info( 394 Messages.get().getBundle().key(Messages.INIT_DUPLICATE_COLLECTOR_SKIPPED_1, name)); 395 } 396 } 397 } else { 398 m_collectorNameMappings.put(name, collector); 399 if (CmsLog.INIT.isInfoEnabled()) { 400 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_COLLECTOR_1, name)); 401 } 402 } 403 } 404 } 405 406 // ensure list is unmodifiable to avoid potential misuse or accidental changes 407 Collections.sort(m_collectors); 408 m_collectors = Collections.unmodifiableList(m_collectors); 409 m_collectorNameMappings = Collections.unmodifiableMap(m_collectorNameMappings); 410 411 // return the created collector instance 412 return collector; 413 } 414 415 /** 416 * Adds a new HTML converter class to internal list of loaded converter classes.<p> 417 * 418 * @param name the name of the option that should trigger the HTML converter class 419 * @param className the name of the class to add 420 * 421 * @return the created HTML converter instance 422 * 423 * @throws CmsConfigurationException in case the HTML converter could not be properly initialized 424 */ 425 public I_CmsHtmlConverter addHtmlConverter(String name, String className) throws CmsConfigurationException { 426 427 // check if new conversion option can still be added 428 if (m_frozen) { 429 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 430 } 431 432 Class<?> classClazz; 433 // init class for content converter 434 try { 435 classClazz = Class.forName(className); 436 } catch (ClassNotFoundException e) { 437 LOG.error(Messages.get().getBundle().key(Messages.LOG_HTML_CONVERTER_CLASS_NOT_FOUND_1, className), e); 438 return null; 439 } 440 441 I_CmsHtmlConverter converter; 442 try { 443 converter = (I_CmsHtmlConverter)classClazz.newInstance(); 444 } catch (InstantiationException e) { 445 throw new CmsConfigurationException( 446 Messages.get().container(Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, className)); 447 } catch (IllegalAccessException e) { 448 throw new CmsConfigurationException( 449 Messages.get().container(Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, className)); 450 } catch (ClassCastException e) { 451 throw new CmsConfigurationException( 452 Messages.get().container(Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, className)); 453 } 454 455 if (CmsLog.INIT.isInfoEnabled()) { 456 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_HTML_CONVERTER_CLASS_2, className, name)); 457 } 458 459 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(name, className)); 460 return converter; 461 } 462 463 /** 464 * Adds a new loader to the internal list of loaded loaders.<p> 465 * 466 * @param loader the loader to add 467 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 468 */ 469 public void addLoader(I_CmsResourceLoader loader) throws CmsConfigurationException { 470 471 // check if new loaders can still be added 472 if (m_frozen) { 473 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 474 } 475 476 // add the loader to the internal list of loaders 477 int pos = loader.getLoaderId(); 478 if (pos >= m_loaders.length) { 479 I_CmsResourceLoader[] buffer = new I_CmsResourceLoader[pos * 2]; 480 System.arraycopy(m_loaders, 0, buffer, 0, m_loaders.length); 481 m_loaders = buffer; 482 } 483 m_loaders[pos] = loader; 484 m_loaderList.add(loader); 485 if (CmsLog.INIT.isInfoEnabled()) { 486 CmsLog.INIT.info( 487 Messages.get().getBundle().key( 488 Messages.INIT_ADD_LOADER_2, 489 loader.getClass().getName(), 490 Integer.valueOf(pos))); 491 } 492 } 493 494 /** 495 * Adds a new MIME type from the XML configuration to the internal list of MIME types.<p> 496 * 497 * @param extension the MIME type extension 498 * @param type the MIME type description 499 * 500 * @return the created MIME type instance 501 * 502 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 503 */ 504 public CmsMimeType addMimeType(String extension, String type) throws CmsConfigurationException { 505 506 // check if new mime types can still be added 507 if (m_frozen) { 508 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 509 } 510 511 CmsMimeType mimeType = new CmsMimeType(extension, type); 512 m_configuredMimeTypes.add(mimeType); 513 return mimeType; 514 } 515 516 /** 517 * Adds a new relation type from the XML configuration to the list of user defined relation types.<p> 518 * 519 * @param name the name of the relation type 520 * @param type the type of the relation type, weak or strong 521 * 522 * @return the new created relation type instance 523 * 524 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 525 */ 526 public CmsRelationType addRelationType(String name, String type) throws CmsConfigurationException { 527 528 // check if new relation types can still be added 529 if (m_frozen) { 530 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 531 } 532 533 CmsRelationType relationType = new CmsRelationType(m_configuredRelationTypes.size(), name, type); 534 m_configuredRelationTypes.add(relationType); 535 return relationType; 536 } 537 538 /** 539 * Adds a new resource type from the XML configuration to the internal list of loaded resource types.<p> 540 * 541 * Resource types can also be added from a module.<p> 542 * 543 * @param resourceType the resource type to add 544 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 545 */ 546 public void addResourceType(I_CmsResourceType resourceType) throws CmsConfigurationException { 547 548 // check if new resource types can still be added 549 if (m_frozen) { 550 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 551 } 552 553 I_CmsResourceType conflictingType = null; 554 if (resourceType.getTypeId() == CmsResourceTypeUnknownFile.RESOURCE_TYPE_ID) { 555 // default unknown file resource type 556 if (m_restypeUnknownFile != null) { 557 // error: already set 558 conflictingType = m_restypeUnknownFile; 559 } else { 560 m_restypeUnknownFile = resourceType; 561 return; 562 } 563 } else if (resourceType.getTypeId() == CmsResourceTypeUnknownFolder.RESOURCE_TYPE_ID) { 564 // default unknown folder resource type 565 if (m_restypeUnknownFolder != null) { 566 // error: already set 567 conflictingType = m_restypeUnknownFolder; 568 } else { 569 m_restypeUnknownFolder = resourceType; 570 return; 571 } 572 } else { 573 // normal resource types 574 int conflictIndex = m_resourceTypesFromXml.indexOf(resourceType); 575 if (conflictIndex >= 0) { 576 conflictingType = m_resourceTypesFromXml.get(conflictIndex); 577 } 578 } 579 if (conflictingType != null) { 580 // configuration problem: the resource type (or at least the id or the name) is already configured 581 throw new CmsConfigurationException( 582 Messages.get().container( 583 Messages.ERR_CONFLICTING_RESOURCE_TYPES_4, 584 new Object[] { 585 resourceType.getTypeName(), 586 Integer.valueOf(resourceType.getTypeId()), 587 conflictingType.getTypeName(), 588 Integer.valueOf(conflictingType.getTypeId())})); 589 } 590 591 m_resourceTypesFromXml.add(resourceType); 592 } 593 594 /** 595 * Gets the map of forbidden contexts for resource types.<p> 596 * 597 * @param cms the current CMS context 598 * @return the map from resource types to the forbidden contexts 599 */ 600 public Map<String, CmsDefaultSet<String>> getAllowedContextMap(CmsObject cms) { 601 602 Map<String, CmsDefaultSet<String>> result = new HashMap<String, CmsDefaultSet<String>>(); 603 for (I_CmsResourceType resType : getResourceTypes()) { 604 if (resType instanceof CmsResourceTypeXmlContent) { 605 String ignoreMissingSchema = resType.getConfiguration().getString( 606 I_CmsResourceType.PARAM_IGNORE_MISSING_SCHEMA, 607 "false"); 608 String schema = null; 609 try { 610 schema = ((CmsResourceTypeXmlContent)resType).getSchema(); 611 if (schema != null) { 612 CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema); 613 614 CmsDefaultSet<String> allowedContexts = contentDefinition.getContentHandler().getAllowedTemplates(); 615 result.put(resType.getTypeName(), allowedContexts); 616 } else { 617 LOG.info( 618 "No schema for XML type " + resType.getTypeName() + " / " + resType.getClass().getName()); 619 } 620 } catch (Exception e) { 621 if (Boolean.parseBoolean(ignoreMissingSchema)) { 622 continue; 623 } 624 LOG.error( 625 "Error in getAllowedContextMap, schema=" 626 + schema 627 + ", type=" 628 + resType.getTypeName() 629 + ", " 630 + e.getLocalizedMessage(), 631 e); 632 633 } 634 } 635 } 636 return result; 637 } 638 639 /** 640 * Returns the configured content collector with the given name, or <code>null</code> if 641 * no collector with this name is configured.<p> 642 * 643 * @param collectorName the name of the collector to get 644 * @return the configured content collector with the given name 645 */ 646 public I_CmsResourceCollector getContentCollector(String collectorName) { 647 648 return m_collectorNameMappings.get(collectorName); 649 } 650 651 /** 652 * Returns the default resource type for the given resource name, using the 653 * configured resource type file extensions.<p> 654 * 655 * In case the given name does not map to a configured resource type, 656 * {@link CmsResourceTypePlain} is returned.<p> 657 * 658 * This is only required (and should <i>not</i> be used otherwise) when 659 * creating a new resource automatically during file upload or synchronization. 660 * Only in this case, the file type for the new resource is determined using this method. 661 * Otherwise the resource type is <i>always</i> stored as part of the resource, 662 * and is <i>not</i> related to the file name.<p> 663 * 664 * @param resourcename the resource name to look up the resource type for 665 * 666 * @return the default resource type for the given resource name 667 * 668 * @throws CmsException if something goes wrong 669 */ 670 public I_CmsResourceType getDefaultTypeForName(String resourcename) throws CmsException { 671 672 String typeName = null; 673 String suffix = null; 674 if (CmsStringUtil.isNotEmpty(resourcename)) { 675 int pos = resourcename.lastIndexOf('.'); 676 if (pos >= 0) { 677 suffix = resourcename.substring(pos); 678 if (CmsStringUtil.isNotEmpty(suffix)) { 679 suffix = suffix.toLowerCase(); 680 typeName = m_configuration.m_extensionMappings.get(suffix); 681 682 } 683 } 684 } 685 686 if (typeName == null) { 687 // use default type "plain" 688 typeName = CmsResourceTypePlain.getStaticTypeName(); 689 } 690 691 if (CmsLog.INIT.isDebugEnabled()) { 692 CmsLog.INIT.debug(Messages.get().getBundle().key(Messages.INIT_GET_RESTYPE_2, typeName, suffix)); 693 } 694 // look up and return the resource type 695 return getResourceType(typeName); 696 } 697 698 /** 699 * Returns the file extensions (suffixes) mappings to resource types.<p> 700 * 701 * @return a Map with all known file extensions as keys and their resource types as values. 702 */ 703 public Map<String, String> getExtensionMapping() { 704 705 return m_configuration.m_extensionMappings; 706 } 707 708 /** 709 * Returns the file translator.<p> 710 * 711 * @return the file translator 712 */ 713 public CmsResourceTranslator getFileTranslator() { 714 715 return m_fileTranslator; 716 } 717 718 /** 719 * Returns the folder translator.<p> 720 * 721 * @return the folder translator 722 */ 723 public CmsResourceTranslator getFolderTranslator() { 724 725 return m_folderTranslator; 726 } 727 728 /** 729 * Returns the matching HTML converter class name for the specified option name.<p> 730 * 731 * @param name the name of the option that should trigger the HTML converter class 732 * 733 * @return the matching HTML converter class name for the specified option name or <code>null</code> if no match is found 734 */ 735 public String getHtmlConverter(String name) { 736 737 return m_htmlConverters.get(name); 738 } 739 740 /** 741 * Returns an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects.<p> 742 * 743 * @return an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects 744 */ 745 public List<CmsHtmlConverterOption> getHtmlConverters() { 746 747 return m_configuredHtmlConverters; 748 } 749 750 /** 751 * Returns the loader class instance for a given resource.<p> 752 * 753 * @param resource the resource 754 * @return the appropriate loader class instance 755 * @throws CmsLoaderException if something goes wrong 756 */ 757 public I_CmsResourceLoader getLoader(CmsResource resource) throws CmsLoaderException { 758 759 return getLoader(getResourceType(resource.getTypeId()).getLoaderId()); 760 } 761 762 /** 763 * Returns the loader class instance for the given loader id.<p> 764 * 765 * @param id the id of the loader to return 766 * @return the loader class instance for the given loader id 767 */ 768 public I_CmsResourceLoader getLoader(int id) { 769 770 return m_loaders[id]; 771 } 772 773 /** 774 * Returns the (unmodifiable array) list with all initialized resource loaders.<p> 775 * 776 * @return the (unmodifiable array) list with all initialized resource loaders 777 */ 778 public List<I_CmsResourceLoader> getLoaders() { 779 780 return m_loaderList; 781 } 782 783 /** 784 * Returns the MIME type for a specified file name.<p> 785 * 786 * If an encoding parameter that is not <code>null</code> is provided, 787 * the returned MIME type is extended with a <code>; charset={encoding}</code> setting.<p> 788 * 789 * If no MIME type for the given filename can be determined, the 790 * default <code>{@link #MIMETYPE_HTML}</code> is used.<p> 791 * 792 * @param filename the file name to check the MIME type for 793 * @param encoding the default encoding (charset) in case of MIME types is of type "text" 794 * 795 * @return the MIME type for a specified file 796 */ 797 public String getMimeType(String filename, String encoding) { 798 799 return getMimeType(filename, encoding, MIMETYPE_HTML); 800 } 801 802 /** 803 * Returns the MIME type for a specified file name.<p> 804 * 805 * If an encoding parameter that is not <code>null</code> is provided, 806 * the returned MIME type is extended with a <code>; charset={encoding}</code> setting.<p> 807 * 808 * If no MIME type for the given filename can be determined, the 809 * provided default is used.<p> 810 * 811 * @param filename the file name to check the MIME type for 812 * @param encoding the default encoding (charset) in case of MIME types is of type "text" 813 * @param defaultMimeType the default MIME type to use if no matching type for the filename is found 814 * 815 * @return the MIME type for a specified file 816 */ 817 public String getMimeType(String filename, String encoding, String defaultMimeType) { 818 819 String mimeType = null; 820 int lastDot = filename.lastIndexOf('.'); 821 // check the MIME type for the file extension 822 if ((lastDot > 0) && (lastDot < (filename.length() - 1))) { 823 mimeType = m_mimeTypes.get(filename.substring(lastDot).toLowerCase(Locale.ENGLISH)); 824 } 825 if (mimeType == null) { 826 mimeType = defaultMimeType; 827 if (mimeType == null) { 828 // no default MIME type was provided 829 return null; 830 } 831 } 832 StringBuffer result = new StringBuffer(mimeType); 833 if ((encoding != null) 834 && (mimeType.startsWith("text") || mimeType.endsWith("javascript")) 835 && (mimeType.indexOf("charset") == -1)) { 836 result.append("; charset="); 837 result.append(encoding); 838 } 839 return result.toString(); 840 } 841 842 /** 843 * Returns an unmodifiable List of the configured {@link CmsMimeType} objects.<p> 844 * 845 * @return an unmodifiable List of the configured {@link CmsMimeType} objects 846 */ 847 public List<CmsMimeType> getMimeTypes() { 848 849 return m_configuredMimeTypes; 850 } 851 852 /** 853 * Returns the name generator for XML content file names.<p> 854 * 855 * @return the name generator for XML content file names. 856 */ 857 public I_CmsFileNameGenerator getNameGenerator() { 858 859 return m_nameGenerator; 860 } 861 862 /** 863 * Returns an (unmodifiable) list of class names of all currently registered content collectors 864 * ({@link I_CmsResourceCollector} objects).<p> 865 * 866 * @return an (unmodifiable) list of class names of all currently registered content collectors 867 * ({@link I_CmsResourceCollector} objects) 868 */ 869 public List<I_CmsResourceCollector> getRegisteredContentCollectors() { 870 871 return m_collectors; 872 } 873 874 /** 875 * Returns an unmodifiable List of the configured {@link CmsRelationType} objects.<p> 876 * 877 * @return an unmodifiable List of the configured {@link CmsRelationType} objects 878 */ 879 public List<CmsRelationType> getRelationTypes() { 880 881 return m_configuredRelationTypes; 882 } 883 884 /** 885 * Convenience method to get the initialized resource type instance for the given resource, 886 * with a fall back to special "unknown" resource types in case the resource type is not configured.<p> 887 * 888 * @param resource the resource to get the type for 889 * 890 * @return the initialized resource type instance for the given resource 891 */ 892 public I_CmsResourceType getResourceType(CmsResource resource) { 893 894 I_CmsResourceType result = m_configuration.getResourceTypeById(resource.getTypeId()); 895 if (result == null) { 896 // this resource type is unknown, return the default files instead 897 if (resource.isFolder()) { 898 // resource is a folder 899 if (m_restypeUnknownFolder != null) { 900 result = m_restypeUnknownFolder; 901 } else { 902 result = m_configuration.getResourceTypeByName(CmsResourceTypeFolder.getStaticTypeName()); 903 } 904 } else { 905 // resource is a file 906 if (m_restypeUnknownFile != null) { 907 result = m_restypeUnknownFile; 908 } else { 909 result = m_configuration.getResourceTypeByName(CmsResourceTypeBinary.getStaticTypeName()); 910 } 911 } 912 } 913 return result; 914 } 915 916 /** 917 * Returns the initialized resource type instance for the given id.<p> 918 * 919 * @param typeId the id of the resource type to get 920 * 921 * @return the initialized resource type instance for the given id 922 * 923 * @throws CmsLoaderException if no resource type is available for the given id 924 */ 925 public I_CmsResourceType getResourceType(int typeId) throws CmsLoaderException { 926 927 I_CmsResourceType result = m_configuration.getResourceTypeById(typeId); 928 if (result == null) { 929 throw new CmsLoaderException( 930 Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_ID_REQ_1, Integer.valueOf(typeId))); 931 } 932 return result; 933 } 934 935 /** 936 * Returns the initialized resource type instance for the given resource type name.<p> 937 * 938 * @param typeName the name of the resource type to get 939 * 940 * @return the initialized resource type instance for the given name 941 * 942 * @throws CmsLoaderException if no resource type is available for the given name 943 */ 944 public I_CmsResourceType getResourceType(String typeName) throws CmsLoaderException { 945 946 I_CmsResourceType result = m_configuration.getResourceTypeByName(typeName); 947 if (result != null) { 948 return result; 949 } 950 throw new CmsLoaderException(Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_NAME_REQ_1, typeName)); 951 } 952 953 /** 954 * Returns the (unmodifiable) list with all initialized resource types.<p> 955 * 956 * @return the (unmodifiable) list with all initialized resource types 957 */ 958 public List<I_CmsResourceType> getResourceTypes() { 959 960 return m_configuration.m_resourceTypeList; 961 } 962 963 /** 964 * Returns the (unmodifiable) list with all initialized resource types including unknown types.<p> 965 * 966 * @return the (unmodifiable) list with all initialized resource types including unknown types 967 */ 968 public List<I_CmsResourceType> getResourceTypesWithUnknown() { 969 970 return m_configuration.m_resourceTypeListWithUnknown; 971 } 972 973 /** 974 * The configured default type for files when the resource type is missing.<p> 975 * 976 * @return the configured default type for files 977 */ 978 public I_CmsResourceType getResTypeUnknownFile() { 979 980 return m_restypeUnknownFile; 981 } 982 983 /** 984 * The configured default type for folders when the resource type is missing.<p> 985 * 986 * @return The configured default type for folders 987 */ 988 public I_CmsResourceType getResTypeUnknownFolder() { 989 990 return m_restypeUnknownFolder; 991 } 992 993 /** 994 * Returns a template loader facade for the given file.<p> 995 * @param cms the current OpenCms user context 996 * @param resource the requested file 997 * @param templateProperty the property to read for the template 998 * 999 * @return a resource loader facade for the given file 1000 * @throws CmsException if something goes wrong 1001 */ 1002 public CmsTemplateLoaderFacade getTemplateLoaderFacade(CmsObject cms, CmsResource resource, String templateProperty) 1003 throws CmsException { 1004 1005 return getTemplateLoaderFacade(cms, null, resource, templateProperty); 1006 } 1007 1008 /** 1009 * Returns a template loader facade for the given file.<p> 1010 * @param cms the current OpenCms user context 1011 * @param request the current request 1012 * @param resource the requested file 1013 * @param templateProperty the property to read for the template 1014 * 1015 * @return a resource loader facade for the given file 1016 * @throws CmsException if something goes wrong 1017 */ 1018 public CmsTemplateLoaderFacade getTemplateLoaderFacade( 1019 CmsObject cms, 1020 HttpServletRequest request, 1021 CmsResource resource, 1022 String templateProperty) 1023 throws CmsException { 1024 1025 String templateProp = cms.readPropertyObject(resource, templateProperty, true).getValue(); 1026 CmsTemplateContext templateContext = null; 1027 String templateName = null; 1028 if (templateProp == null) { 1029 1030 // use default template, if template is not set 1031 templateProp = DEFAULT_TEMPLATE; 1032 NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp); 1033 if (namedTemplate == null) { 1034 // no template property defined, this is a must for facade loaders 1035 throw new CmsLoaderException( 1036 Messages.get().container(Messages.ERR_NONDEF_PROP_2, templateProperty, cms.getSitePath(resource))); 1037 } 1038 templateName = namedTemplate.getName(); 1039 } else { 1040 if (CmsTemplateContextManager.hasPropertyPrefix(templateProp)) { 1041 templateContext = OpenCms.getTemplateContextManager().getTemplateContext( 1042 templateProp, 1043 cms, 1044 request, 1045 resource); 1046 if (templateContext != null) { 1047 templateProp = templateContext.getTemplatePath(); 1048 } 1049 } 1050 NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp); 1051 if (namedTemplate == null) { 1052 namedTemplate = readTemplateWithName(cms, DEFAULT_TEMPLATE); 1053 if (namedTemplate != null) { 1054 templateProp = DEFAULT_TEMPLATE; 1055 templateName = namedTemplate.getName(); 1056 } 1057 } else { 1058 templateName = namedTemplate.getName(); 1059 } 1060 } 1061 CmsResource template = cms.readFile(templateProp, CmsResourceFilter.IGNORE_EXPIRATION); 1062 CmsTemplateLoaderFacade result = new CmsTemplateLoaderFacade(getLoader(template), resource, template); 1063 result.setTemplateContext(templateContext); 1064 result.setTemplateName(templateName); 1065 return result; 1066 1067 } 1068 1069 /** 1070 * Returns the XSD translator.<p> 1071 * 1072 * @return the XSD translator 1073 */ 1074 public CmsResourceTranslator getXsdTranslator() { 1075 1076 return m_xsdTranslator; 1077 } 1078 1079 /** 1080 * Checks if an initialized resource type instance equal to the given resource type is available.<p> 1081 * 1082 * @param type the resource type to check 1083 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1084 * 1085 * @see #getResourceType(String) 1086 * @see #getResourceType(int) 1087 */ 1088 public boolean hasResourceType(I_CmsResourceType type) { 1089 1090 return hasResourceType(type.getTypeName()); 1091 } 1092 1093 /** 1094 * Checks if an initialized resource type instance for the given resource type is is available.<p> 1095 * 1096 * @param typeId the id of the resource type to check 1097 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1098 * 1099 * @see #getResourceType(int) 1100 * 1101 * @deprecated 1102 * Use {@link #hasResourceType(I_CmsResourceType)} or {@link #hasResourceType(I_CmsResourceType)} instead. 1103 * Resource types should always be referenced either by its type class (preferred) or by type name. 1104 * Use of int based resource type references will be discontinued in a future OpenCms release. 1105 */ 1106 @Deprecated 1107 public boolean hasResourceType(int typeId) { 1108 1109 return m_configuration.getResourceTypeById(typeId) != null; 1110 } 1111 1112 /** 1113 * Checks if an initialized resource type instance for the given resource type name is available.<p> 1114 * 1115 * @param typeName the name of the resource type to check 1116 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1117 * 1118 * @see #getResourceType(String) 1119 */ 1120 public boolean hasResourceType(String typeName) { 1121 1122 return m_configuration.getResourceTypeByName(typeName) != null; 1123 } 1124 1125 /** 1126 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 1127 * 1128 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1129 */ 1130 public void initConfiguration() throws CmsConfigurationException { 1131 1132 if (CmsLog.INIT.isInfoEnabled()) { 1133 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0)); 1134 } 1135 1136 m_resourceTypesFromXml = Collections.unmodifiableList(m_resourceTypesFromXml); 1137 m_loaderList = Collections.unmodifiableList(m_loaderList); 1138 Collections.sort(m_configuredMimeTypes); 1139 m_configuredMimeTypes = Collections.unmodifiableList(m_configuredMimeTypes); 1140 m_configuredRelationTypes = Collections.unmodifiableList(m_configuredRelationTypes); 1141 1142 // initialize the HTML converters 1143 initHtmlConverters(); 1144 m_configuredHtmlConverters = Collections.unmodifiableList(m_configuredHtmlConverters); 1145 1146 // initialize the resource types 1147 initResourceTypes(); 1148 // initialize the MIME types 1149 initMimeTypes(); 1150 } 1151 1152 /** 1153 * Initializes all additional resource types stored in the modules.<p> 1154 * 1155 * @param cms an initialized OpenCms user context with "module manager" role permissions 1156 * 1157 * @throws CmsRoleViolationException in case the provided OpenCms user context did not have "module manager" role permissions 1158 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1159 */ 1160 public synchronized void initialize(CmsObject cms) throws CmsRoleViolationException, CmsConfigurationException { 1161 1162 if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_1_CORE_OBJECT) { 1163 // some simple test cases don't require this check 1164 OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER); 1165 } 1166 1167 // initialize the resource types 1168 initResourceTypes(); 1169 1170 // call initialize method on all resource types 1171 Iterator<I_CmsResourceType> i = m_configuration.m_resourceTypeList.iterator(); 1172 while (i.hasNext()) { 1173 I_CmsResourceType type = i.next(); 1174 type.initialize(cms); 1175 } 1176 1177 // This only sets the CmsObject the first time it's called 1178 m_nameGenerator.setAdminCms(cms); 1179 1180 if (CmsLog.INIT.isInfoEnabled()) { 1181 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0)); 1182 } 1183 } 1184 1185 /** 1186 * Loads the requested resource and writes the contents to the response stream.<p> 1187 * 1188 * @param req the current HTTP request 1189 * @param res the current HTTP response 1190 * @param cms the current OpenCms user context 1191 * @param resource the requested resource 1192 * @throws ServletException if something goes wrong 1193 * @throws IOException if something goes wrong 1194 * @throws CmsException if something goes wrong 1195 */ 1196 public void loadResource(CmsObject cms, CmsResource resource, HttpServletRequest req, HttpServletResponse res) 1197 throws ServletException, IOException, CmsException { 1198 1199 res.setContentType(getMimeType(resource.getName(), cms.getRequestContext().getEncoding())); 1200 I_CmsResourceLoader loader = getLoader(resource); 1201 loader.load(cms, resource, req, res); 1202 } 1203 1204 /** 1205 * Checks if there is a resource type with a given name whose id matches the given id.<p> 1206 * 1207 * This will return 'false' if no resource type with the given name is registered.<p> 1208 * 1209 * @param name a resource type name 1210 * @param id a resource type id 1211 * 1212 * @return true if a matching resource type with the given name and id was found 1213 */ 1214 public boolean matchResourceType(String name, int id) { 1215 1216 if (hasResourceType(name)) { 1217 try { 1218 return getResourceType(name).getTypeId() == id; 1219 } catch (Exception e) { 1220 // should never happen because we already checked with hasResourceType, still have to 1221 // catch it so the compiler is happy 1222 LOG.error(e.getLocalizedMessage(), e); 1223 return false; 1224 } 1225 } else { 1226 return false; 1227 } 1228 } 1229 1230 /** 1231 * Configures the URL name generator for XML contents.<p> 1232 * 1233 * @param nameGenerator the configured name generator class 1234 * 1235 * @throws CmsConfigurationException if something goes wrong 1236 */ 1237 public void setNameGenerator(I_CmsFileNameGenerator nameGenerator) throws CmsConfigurationException { 1238 1239 if (m_frozen) { 1240 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 1241 } 1242 m_nameGenerator = nameGenerator; 1243 1244 if (CmsLog.INIT.isInfoEnabled()) { 1245 CmsLog.INIT.info( 1246 Messages.get().getBundle().key(Messages.INIT_SET_NAME_GENERATOR_1, nameGenerator.getClass().getName())); 1247 } 1248 } 1249 1250 /** 1251 * Sets the folder, the file and the XSD translator.<p> 1252 * 1253 * @param folderTranslator the folder translator to set 1254 * @param fileTranslator the file translator to set 1255 * @param xsdTranslator the XSD translator to set 1256 */ 1257 public void setTranslators( 1258 CmsResourceTranslator folderTranslator, 1259 CmsResourceTranslator fileTranslator, 1260 CmsResourceTranslator xsdTranslator) { 1261 1262 m_folderTranslator = folderTranslator; 1263 m_fileTranslator = fileTranslator; 1264 m_xsdTranslator = xsdTranslator; 1265 } 1266 1267 /** 1268 * Shuts down this resource manage instance.<p> 1269 * 1270 * @throws Exception in case of errors during shutdown 1271 */ 1272 public synchronized void shutDown() throws Exception { 1273 1274 Iterator<I_CmsResourceLoader> it = m_loaderList.iterator(); 1275 while (it.hasNext()) { 1276 // destroy all resource loaders 1277 I_CmsResourceLoader loader = it.next(); 1278 loader.destroy(); 1279 } 1280 1281 m_loaderList = null; 1282 m_loaders = null; 1283 m_collectorNameMappings = null; 1284 m_mimeTypes = null; 1285 m_configuredMimeTypes = null; 1286 m_configuredRelationTypes = null; 1287 m_configuredHtmlConverters = null; 1288 m_htmlConverters = null; 1289 1290 if (CmsLog.INIT.isInfoEnabled()) { 1291 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_1, this.getClass().getName())); 1292 } 1293 } 1294 1295 /** 1296 * Gets the template name for a template resource, using a cache for efficiency.<p> 1297 * 1298 * @param cms the current CMS context 1299 * @param resource the template resource 1300 * @return the template name 1301 * 1302 * @throws CmsException if something goes wrong 1303 */ 1304 private String getTemplateName(CmsObject cms, CmsResource resource) throws CmsException { 1305 1306 String templateName = (String)(m_templateNameCache.getCachedObject(cms, resource.getRootPath())); 1307 if (templateName == null) { 1308 CmsProperty nameProperty = cms.readPropertyObject( 1309 resource, 1310 CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS, 1311 false); 1312 String nameFromProperty = ""; 1313 if (!nameProperty.isNullProperty()) { 1314 nameFromProperty = nameProperty.getValue(); 1315 } 1316 m_templateNameCache.putCachedObject(cms, resource.getRootPath(), nameFromProperty); 1317 return nameFromProperty; 1318 } else { 1319 return templateName; 1320 } 1321 } 1322 1323 /** 1324 * Initialize the HTML converters.<p> 1325 * 1326 * HTML converters are configured in the OpenCms <code>opencms-vfs.xml</code> configuration file.<p> 1327 * 1328 * For legacy reasons, the default JTidy HTML converter has to be loaded if no explicit HTML converters 1329 * are configured in the configuration file.<p> 1330 */ 1331 private void initHtmlConverters() { 1332 1333 // check if any HTML converter configuration were found 1334 if (m_configuredHtmlConverters.size() == 0) { 1335 // no converters configured, add default JTidy converter configuration 1336 String classJTidy = CmsHtmlConverterJTidy.class.getName(); 1337 m_configuredHtmlConverters.add( 1338 new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_ENABLED, classJTidy, true)); 1339 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_XHTML, classJTidy, true)); 1340 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_WORD, classJTidy, true)); 1341 m_configuredHtmlConverters.add( 1342 new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_REPLACE_PARAGRAPHS, classJTidy, true)); 1343 } 1344 1345 // initialize lookup map of configured HTML converters 1346 m_htmlConverters = new HashMap<String, String>(m_configuredHtmlConverters.size()); 1347 for (Iterator<CmsHtmlConverterOption> i = m_configuredHtmlConverters.iterator(); i.hasNext();) { 1348 CmsHtmlConverterOption converterOption = i.next(); 1349 m_htmlConverters.put(converterOption.getName(), converterOption.getClassName()); 1350 } 1351 } 1352 1353 /** 1354 * Initialize the MIME types.<p> 1355 * 1356 * MIME types are configured in the OpenCms <code>opencms-vfs.xml</code> configuration file.<p> 1357 * 1358 * For legacy reasons, the MIME types are also read from a file <code>"mimetypes.properties"</code> 1359 * that must be located in the default <code>"classes"</code> folder of the web application.<p> 1360 */ 1361 private void initMimeTypes() { 1362 1363 // legacy MIME type initialization: try to read properties file 1364 Properties mimeTypes = new Properties(); 1365 try { 1366 // first try: read MIME types from default package 1367 mimeTypes.load(getClass().getClassLoader().getResourceAsStream("mimetypes.properties")); 1368 } catch (Throwable t) { 1369 try { 1370 // second try: read MIME types from loader package (legacy reasons, there are no types by default) 1371 mimeTypes.load( 1372 getClass().getClassLoader().getResourceAsStream("org/opencms/loader/mimetypes.properties")); 1373 } catch (Throwable t2) { 1374 if (LOG.isInfoEnabled()) { 1375 LOG.info( 1376 Messages.get().getBundle().key( 1377 Messages.LOG_READ_MIMETYPES_FAILED_2, 1378 "mimetypes.properties", 1379 "org/opencms/loader/mimetypes.properties")); 1380 } 1381 } 1382 } 1383 1384 // initialize the Map with all available MIME types 1385 List<CmsMimeType> combinedMimeTypes = new ArrayList<CmsMimeType>( 1386 mimeTypes.size() + m_configuredMimeTypes.size()); 1387 // first add all MIME types from the configuration 1388 combinedMimeTypes.addAll(m_configuredMimeTypes); 1389 // now add the MIME types from the properties 1390 Iterator<Map.Entry<Object, Object>> i = mimeTypes.entrySet().iterator(); 1391 while (i.hasNext()) { 1392 Map.Entry<Object, Object> entry = i.next(); 1393 CmsMimeType mimeType = new CmsMimeType(entry.getKey().toString(), entry.getValue().toString(), false); 1394 if (!combinedMimeTypes.contains(mimeType)) { 1395 // make sure no MIME types from the XML configuration are overwritten 1396 combinedMimeTypes.add(mimeType); 1397 } 1398 } 1399 1400 // create a lookup Map for the MIME types 1401 m_mimeTypes = new HashMap<String, String>(mimeTypes.size()); 1402 Iterator<CmsMimeType> j = combinedMimeTypes.iterator(); 1403 while (j.hasNext()) { 1404 CmsMimeType mimeType = j.next(); 1405 m_mimeTypes.put(mimeType.getExtension(), mimeType.getType()); 1406 } 1407 1408 if (CmsLog.INIT.isInfoEnabled()) { 1409 CmsLog.INIT.info( 1410 Messages.get().getBundle().key(Messages.INIT_NUM_MIMETYPES_1, Integer.valueOf(m_mimeTypes.size()))); 1411 } 1412 } 1413 1414 /** 1415 * Adds a new resource type to the internal list of loaded resource types and initializes 1416 * options for the resource type.<p> 1417 * 1418 * @param resourceType the resource type to add 1419 * @param configuration the resource configuration 1420 */ 1421 private synchronized void initResourceType( 1422 I_CmsResourceType resourceType, 1423 CmsResourceManagerConfiguration configuration) { 1424 1425 // add the loader to the internal list of loaders 1426 configuration.addResourceType(resourceType); 1427 if (CmsLog.INIT.isInfoEnabled()) { 1428 CmsLog.INIT.info( 1429 Messages.get().getBundle().key( 1430 Messages.INIT_ADD_RESTYPE_3, 1431 resourceType.getTypeName(), 1432 Integer.valueOf(resourceType.getTypeId()), 1433 resourceType.getClass().getName())); 1434 } 1435 1436 // add the mappings 1437 List<String> mappings = resourceType.getConfiguredMappings(); 1438 Iterator<String> i = mappings.iterator(); 1439 while (i.hasNext()) { 1440 String mapping = i.next(); 1441 // only add this mapping if a mapping with this file extension does not 1442 // exist already 1443 if (!configuration.m_extensionMappings.containsKey(mapping)) { 1444 configuration.m_extensionMappings.put(mapping, resourceType.getTypeName()); 1445 if (CmsLog.INIT.isInfoEnabled()) { 1446 CmsLog.INIT.info( 1447 Messages.get().getBundle().key( 1448 Messages.INIT_MAP_RESTYPE_2, 1449 mapping, 1450 resourceType.getTypeName())); 1451 } 1452 } 1453 } 1454 } 1455 1456 /** 1457 * Initializes member variables required for storing the resource types.<p> 1458 * 1459 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1460 */ 1461 private synchronized void initResourceTypes() throws CmsConfigurationException { 1462 1463 if (CmsLog.INIT.isInfoEnabled()) { 1464 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_STARTING_LOADER_CONFIG_0)); 1465 } 1466 1467 CmsResourceManagerConfiguration newConfiguration = new CmsResourceManagerConfiguration(); 1468 1469 if (CmsLog.INIT.isInfoEnabled()) { 1470 CmsLog.INIT.info( 1471 Messages.get().getBundle().key( 1472 Messages.INIT_ADD_RESTYPE_FROM_FILE_2, 1473 Integer.valueOf(m_resourceTypesFromXml.size()), 1474 CmsVfsConfiguration.DEFAULT_XML_FILE_NAME)); 1475 } 1476 1477 // build a new resource type list from the resource types of the XML configuration 1478 Iterator<I_CmsResourceType> i; 1479 i = m_resourceTypesFromXml.iterator(); 1480 while (i.hasNext()) { 1481 I_CmsResourceType resourceType = i.next(); 1482 initResourceType(resourceType, newConfiguration); 1483 } 1484 1485 // add all resource types declared in the modules 1486 CmsModuleManager moduleManager = OpenCms.getModuleManager(); 1487 if (moduleManager != null) { 1488 Iterator<String> modules = moduleManager.getModuleNames().iterator(); 1489 while (modules.hasNext()) { 1490 CmsModule module = moduleManager.getModule(modules.next()); 1491 if ((module != null) && (module.getResourceTypes().size() > 0)) { 1492 // module contains resource types 1493 if (CmsLog.INIT.isInfoEnabled()) { 1494 CmsLog.INIT.info( 1495 Messages.get().getBundle().key( 1496 Messages.INIT_ADD_NUM_RESTYPES_FROM_MOD_2, 1497 Integer.valueOf(module.getResourceTypes().size()), 1498 module.getName())); 1499 } 1500 1501 Iterator<I_CmsResourceType> j = module.getResourceTypes().iterator(); 1502 while (j.hasNext()) { 1503 I_CmsResourceType resourceType = j.next(); 1504 I_CmsResourceType conflictingType = null; 1505 if (resourceType.getTypeId() == CmsResourceTypeUnknownFile.RESOURCE_TYPE_ID) { 1506 // default unknown file resource type 1507 if (m_restypeUnknownFile != null) { 1508 // error: already set 1509 conflictingType = m_restypeUnknownFile; 1510 } else { 1511 m_restypeUnknownFile = resourceType; 1512 continue; 1513 } 1514 } else if (resourceType.getTypeId() == CmsResourceTypeUnknownFolder.RESOURCE_TYPE_ID) { 1515 // default unknown folder resource type 1516 if (m_restypeUnknownFolder != null) { 1517 // error: already set 1518 conflictingType = m_restypeUnknownFolder; 1519 } else { 1520 m_restypeUnknownFile = resourceType; 1521 continue; 1522 } 1523 } else { 1524 // normal resource types 1525 conflictingType = newConfiguration.getResourceTypeById(resourceType.getTypeId()); 1526 } 1527 if (conflictingType != null) { 1528 throw new CmsConfigurationException( 1529 Messages.get().container( 1530 Messages.ERR_CONFLICTING_MODULE_RESOURCE_TYPES_5, 1531 new Object[] { 1532 resourceType.getTypeName(), 1533 Integer.valueOf(resourceType.getTypeId()), 1534 module.getName(), 1535 conflictingType.getTypeName(), 1536 Integer.valueOf(conflictingType.getTypeId())})); 1537 } 1538 initResourceType(resourceType, newConfiguration); 1539 } 1540 } 1541 } 1542 } 1543 1544 // freeze the current configuration 1545 newConfiguration.freeze(m_restypeUnknownFile, m_restypeUnknownFile); 1546 m_configuration = newConfiguration; 1547 m_frozen = true; 1548 1549 if (CmsLog.INIT.isInfoEnabled()) { 1550 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_RESOURCE_TYPE_INITIALIZED_0)); 1551 } 1552 } 1553 1554 /** 1555 * Reads a template resource together with its name.<p> 1556 * 1557 * @param cms the current CMS context 1558 * @param path the template path 1559 * 1560 * @return the template together with its name, or null if the template couldn't be read 1561 */ 1562 private NamedTemplate readTemplateWithName(CmsObject cms, String path) { 1563 1564 try { 1565 CmsResource resource = cms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION); 1566 String name = getTemplateName(cms, resource); 1567 return new NamedTemplate(resource, name); 1568 } catch (Exception e) { 1569 return null; 1570 } 1571 } 1572 1573}