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.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 schema = null; 606 try { 607 schema = ((CmsResourceTypeXmlContent)resType).getSchema(); 608 if (schema != null) { 609 CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema); 610 611 CmsDefaultSet<String> allowedContexts = contentDefinition.getContentHandler().getAllowedTemplates(); 612 result.put(resType.getTypeName(), allowedContexts); 613 } else { 614 LOG.info( 615 "No schema for XML type " + resType.getTypeName() + " / " + resType.getClass().getName()); 616 } 617 } catch (Exception e) { 618 LOG.error( 619 "Error in getAllowedContextMap, schema=" 620 + schema 621 + ", type=" 622 + resType.getTypeName() 623 + ", " 624 + e.getLocalizedMessage(), 625 e); 626 } 627 } 628 } 629 return result; 630 } 631 632 /** 633 * Returns the configured content collector with the given name, or <code>null</code> if 634 * no collector with this name is configured.<p> 635 * 636 * @param collectorName the name of the collector to get 637 * @return the configured content collector with the given name 638 */ 639 public I_CmsResourceCollector getContentCollector(String collectorName) { 640 641 return m_collectorNameMappings.get(collectorName); 642 } 643 644 /** 645 * Returns the default resource type for the given resource name, using the 646 * configured resource type file extensions.<p> 647 * 648 * In case the given name does not map to a configured resource type, 649 * {@link CmsResourceTypePlain} is returned.<p> 650 * 651 * This is only required (and should <i>not</i> be used otherwise) when 652 * creating a new resource automatically during file upload or synchronization. 653 * Only in this case, the file type for the new resource is determined using this method. 654 * Otherwise the resource type is <i>always</i> stored as part of the resource, 655 * and is <i>not</i> related to the file name.<p> 656 * 657 * @param resourcename the resource name to look up the resource type for 658 * 659 * @return the default resource type for the given resource name 660 * 661 * @throws CmsException if something goes wrong 662 */ 663 public I_CmsResourceType getDefaultTypeForName(String resourcename) throws CmsException { 664 665 String typeName = null; 666 String suffix = null; 667 if (CmsStringUtil.isNotEmpty(resourcename)) { 668 int pos = resourcename.lastIndexOf('.'); 669 if (pos >= 0) { 670 suffix = resourcename.substring(pos); 671 if (CmsStringUtil.isNotEmpty(suffix)) { 672 suffix = suffix.toLowerCase(); 673 typeName = m_configuration.m_extensionMappings.get(suffix); 674 675 } 676 } 677 } 678 679 if (typeName == null) { 680 // use default type "plain" 681 typeName = CmsResourceTypePlain.getStaticTypeName(); 682 } 683 684 if (CmsLog.INIT.isDebugEnabled()) { 685 CmsLog.INIT.debug(Messages.get().getBundle().key(Messages.INIT_GET_RESTYPE_2, typeName, suffix)); 686 } 687 // look up and return the resource type 688 return getResourceType(typeName); 689 } 690 691 /** 692 * Returns the file extensions (suffixes) mappings to resource types.<p> 693 * 694 * @return a Map with all known file extensions as keys and their resource types as values. 695 */ 696 public Map<String, String> getExtensionMapping() { 697 698 return m_configuration.m_extensionMappings; 699 } 700 701 /** 702 * Returns the file translator.<p> 703 * 704 * @return the file translator 705 */ 706 public CmsResourceTranslator getFileTranslator() { 707 708 return m_fileTranslator; 709 } 710 711 /** 712 * Returns the folder translator.<p> 713 * 714 * @return the folder translator 715 */ 716 public CmsResourceTranslator getFolderTranslator() { 717 718 return m_folderTranslator; 719 } 720 721 /** 722 * Returns the matching HTML converter class name for the specified option name.<p> 723 * 724 * @param name the name of the option that should trigger the HTML converter class 725 * 726 * @return the matching HTML converter class name for the specified option name or <code>null</code> if no match is found 727 */ 728 public String getHtmlConverter(String name) { 729 730 return m_htmlConverters.get(name); 731 } 732 733 /** 734 * Returns an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects.<p> 735 * 736 * @return an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects 737 */ 738 public List<CmsHtmlConverterOption> getHtmlConverters() { 739 740 return m_configuredHtmlConverters; 741 } 742 743 /** 744 * Returns the loader class instance for a given resource.<p> 745 * 746 * @param resource the resource 747 * @return the appropriate loader class instance 748 * @throws CmsLoaderException if something goes wrong 749 */ 750 public I_CmsResourceLoader getLoader(CmsResource resource) throws CmsLoaderException { 751 752 return getLoader(getResourceType(resource.getTypeId()).getLoaderId()); 753 } 754 755 /** 756 * Returns the loader class instance for the given loader id.<p> 757 * 758 * @param id the id of the loader to return 759 * @return the loader class instance for the given loader id 760 */ 761 public I_CmsResourceLoader getLoader(int id) { 762 763 return m_loaders[id]; 764 } 765 766 /** 767 * Returns the (unmodifiable array) list with all initialized resource loaders.<p> 768 * 769 * @return the (unmodifiable array) list with all initialized resource loaders 770 */ 771 public List<I_CmsResourceLoader> getLoaders() { 772 773 return m_loaderList; 774 } 775 776 /** 777 * Returns the MIME type for a specified file name.<p> 778 * 779 * If an encoding parameter that is not <code>null</code> is provided, 780 * the returned MIME type is extended with a <code>; charset={encoding}</code> setting.<p> 781 * 782 * If no MIME type for the given filename can be determined, the 783 * default <code>{@link #MIMETYPE_HTML}</code> is used.<p> 784 * 785 * @param filename the file name to check the MIME type for 786 * @param encoding the default encoding (charset) in case of MIME types is of type "text" 787 * 788 * @return the MIME type for a specified file 789 */ 790 public String getMimeType(String filename, String encoding) { 791 792 return getMimeType(filename, encoding, MIMETYPE_HTML); 793 } 794 795 /** 796 * Returns the MIME type for a specified file name.<p> 797 * 798 * If an encoding parameter that is not <code>null</code> is provided, 799 * the returned MIME type is extended with a <code>; charset={encoding}</code> setting.<p> 800 * 801 * If no MIME type for the given filename can be determined, the 802 * provided default is used.<p> 803 * 804 * @param filename the file name to check the MIME type for 805 * @param encoding the default encoding (charset) in case of MIME types is of type "text" 806 * @param defaultMimeType the default MIME type to use if no matching type for the filename is found 807 * 808 * @return the MIME type for a specified file 809 */ 810 public String getMimeType(String filename, String encoding, String defaultMimeType) { 811 812 String mimeType = null; 813 int lastDot = filename.lastIndexOf('.'); 814 // check the MIME type for the file extension 815 if ((lastDot > 0) && (lastDot < (filename.length() - 1))) { 816 mimeType = m_mimeTypes.get(filename.substring(lastDot).toLowerCase(Locale.ENGLISH)); 817 } 818 if (mimeType == null) { 819 mimeType = defaultMimeType; 820 if (mimeType == null) { 821 // no default MIME type was provided 822 return null; 823 } 824 } 825 StringBuffer result = new StringBuffer(mimeType); 826 if ((encoding != null) 827 && (mimeType.startsWith("text") || mimeType.endsWith("javascript")) 828 && (mimeType.indexOf("charset") == -1)) { 829 result.append("; charset="); 830 result.append(encoding); 831 } 832 return result.toString(); 833 } 834 835 /** 836 * Returns an unmodifiable List of the configured {@link CmsMimeType} objects.<p> 837 * 838 * @return an unmodifiable List of the configured {@link CmsMimeType} objects 839 */ 840 public List<CmsMimeType> getMimeTypes() { 841 842 return m_configuredMimeTypes; 843 } 844 845 /** 846 * Returns the name generator for XML content file names.<p> 847 * 848 * @return the name generator for XML content file names. 849 */ 850 public I_CmsFileNameGenerator getNameGenerator() { 851 852 return m_nameGenerator; 853 } 854 855 /** 856 * Returns an (unmodifiable) list of class names of all currently registered content collectors 857 * ({@link I_CmsResourceCollector} objects).<p> 858 * 859 * @return an (unmodifiable) list of class names of all currently registered content collectors 860 * ({@link I_CmsResourceCollector} objects) 861 */ 862 public List<I_CmsResourceCollector> getRegisteredContentCollectors() { 863 864 return m_collectors; 865 } 866 867 /** 868 * Returns an unmodifiable List of the configured {@link CmsRelationType} objects.<p> 869 * 870 * @return an unmodifiable List of the configured {@link CmsRelationType} objects 871 */ 872 public List<CmsRelationType> getRelationTypes() { 873 874 return m_configuredRelationTypes; 875 } 876 877 /** 878 * Convenience method to get the initialized resource type instance for the given resource, 879 * with a fall back to special "unknown" resource types in case the resource type is not configured.<p> 880 * 881 * @param resource the resource to get the type for 882 * 883 * @return the initialized resource type instance for the given resource 884 */ 885 public I_CmsResourceType getResourceType(CmsResource resource) { 886 887 I_CmsResourceType result = m_configuration.getResourceTypeById(resource.getTypeId()); 888 if (result == null) { 889 // this resource type is unknown, return the default files instead 890 if (resource.isFolder()) { 891 // resource is a folder 892 if (m_restypeUnknownFolder != null) { 893 result = m_restypeUnknownFolder; 894 } else { 895 result = m_configuration.getResourceTypeByName(CmsResourceTypeFolder.getStaticTypeName()); 896 } 897 } else { 898 // resource is a file 899 if (m_restypeUnknownFile != null) { 900 result = m_restypeUnknownFile; 901 } else { 902 result = m_configuration.getResourceTypeByName(CmsResourceTypeBinary.getStaticTypeName()); 903 } 904 } 905 } 906 return result; 907 } 908 909 /** 910 * Returns the initialized resource type instance for the given id.<p> 911 * 912 * @param typeId the id of the resource type to get 913 * 914 * @return the initialized resource type instance for the given id 915 * 916 * @throws CmsLoaderException if no resource type is available for the given id 917 */ 918 public I_CmsResourceType getResourceType(int typeId) throws CmsLoaderException { 919 920 I_CmsResourceType result = m_configuration.getResourceTypeById(typeId); 921 if (result == null) { 922 throw new CmsLoaderException( 923 Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_ID_REQ_1, Integer.valueOf(typeId))); 924 } 925 return result; 926 } 927 928 /** 929 * Returns the initialized resource type instance for the given resource type name.<p> 930 * 931 * @param typeName the name of the resource type to get 932 * 933 * @return the initialized resource type instance for the given name 934 * 935 * @throws CmsLoaderException if no resource type is available for the given name 936 */ 937 public I_CmsResourceType getResourceType(String typeName) throws CmsLoaderException { 938 939 I_CmsResourceType result = m_configuration.getResourceTypeByName(typeName); 940 if (result != null) { 941 return result; 942 } 943 throw new CmsLoaderException(Messages.get().container(Messages.ERR_UNKNOWN_RESTYPE_NAME_REQ_1, typeName)); 944 } 945 946 /** 947 * Returns the (unmodifiable) list with all initialized resource types.<p> 948 * 949 * @return the (unmodifiable) list with all initialized resource types 950 */ 951 public List<I_CmsResourceType> getResourceTypes() { 952 953 return m_configuration.m_resourceTypeList; 954 } 955 956 /** 957 * Returns the (unmodifiable) list with all initialized resource types including unknown types.<p> 958 * 959 * @return the (unmodifiable) list with all initialized resource types including unknown types 960 */ 961 public List<I_CmsResourceType> getResourceTypesWithUnknown() { 962 963 return m_configuration.m_resourceTypeListWithUnknown; 964 } 965 966 /** 967 * The configured default type for files when the resource type is missing.<p> 968 * 969 * @return the configured default type for files 970 */ 971 public I_CmsResourceType getResTypeUnknownFile() { 972 973 return m_restypeUnknownFile; 974 } 975 976 /** 977 * The configured default type for folders when the resource type is missing.<p> 978 * 979 * @return The configured default type for folders 980 */ 981 public I_CmsResourceType getResTypeUnknownFolder() { 982 983 return m_restypeUnknownFolder; 984 } 985 986 /** 987 * Returns a template loader facade for the given file.<p> 988 * @param cms the current OpenCms user context 989 * @param resource the requested file 990 * @param templateProperty the property to read for the template 991 * 992 * @return a resource loader facade for the given file 993 * @throws CmsException if something goes wrong 994 */ 995 public CmsTemplateLoaderFacade getTemplateLoaderFacade(CmsObject cms, CmsResource resource, String templateProperty) 996 throws CmsException { 997 998 return getTemplateLoaderFacade(cms, null, resource, templateProperty); 999 } 1000 1001 /** 1002 * Returns a template loader facade for the given file.<p> 1003 * @param cms the current OpenCms user context 1004 * @param request the current request 1005 * @param resource the requested file 1006 * @param templateProperty the property to read for the template 1007 * 1008 * @return a resource loader facade for the given file 1009 * @throws CmsException if something goes wrong 1010 */ 1011 public CmsTemplateLoaderFacade getTemplateLoaderFacade( 1012 CmsObject cms, 1013 HttpServletRequest request, 1014 CmsResource resource, 1015 String templateProperty) 1016 throws CmsException { 1017 1018 String templateProp = cms.readPropertyObject(resource, templateProperty, true).getValue(); 1019 CmsTemplateContext templateContext = null; 1020 String templateName = null; 1021 if (templateProp == null) { 1022 1023 // use default template, if template is not set 1024 templateProp = DEFAULT_TEMPLATE; 1025 NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp); 1026 if (namedTemplate == null) { 1027 // no template property defined, this is a must for facade loaders 1028 throw new CmsLoaderException( 1029 Messages.get().container(Messages.ERR_NONDEF_PROP_2, templateProperty, cms.getSitePath(resource))); 1030 } 1031 templateName = namedTemplate.getName(); 1032 } else { 1033 if (CmsTemplateContextManager.hasPropertyPrefix(templateProp)) { 1034 templateContext = OpenCms.getTemplateContextManager().getTemplateContext( 1035 templateProp, 1036 cms, 1037 request, 1038 resource); 1039 if (templateContext != null) { 1040 templateProp = templateContext.getTemplatePath(); 1041 } 1042 } 1043 NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp); 1044 if (namedTemplate == null) { 1045 namedTemplate = readTemplateWithName(cms, DEFAULT_TEMPLATE); 1046 if (namedTemplate != null) { 1047 templateProp = DEFAULT_TEMPLATE; 1048 templateName = namedTemplate.getName(); 1049 } 1050 } else { 1051 templateName = namedTemplate.getName(); 1052 } 1053 } 1054 CmsResource template = cms.readFile(templateProp, CmsResourceFilter.IGNORE_EXPIRATION); 1055 CmsTemplateLoaderFacade result = new CmsTemplateLoaderFacade(getLoader(template), resource, template); 1056 result.setTemplateContext(templateContext); 1057 result.setTemplateName(templateName); 1058 return result; 1059 1060 } 1061 1062 /** 1063 * Returns the XSD translator.<p> 1064 * 1065 * @return the XSD translator 1066 */ 1067 public CmsResourceTranslator getXsdTranslator() { 1068 1069 return m_xsdTranslator; 1070 } 1071 1072 /** 1073 * Checks if an initialized resource type instance equal to the given resource type is available.<p> 1074 * 1075 * @param type the resource type to check 1076 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1077 * 1078 * @see #getResourceType(String) 1079 * @see #getResourceType(int) 1080 */ 1081 public boolean hasResourceType(I_CmsResourceType type) { 1082 1083 return hasResourceType(type.getTypeName()); 1084 } 1085 1086 /** 1087 * Checks if an initialized resource type instance for the given resource type is is available.<p> 1088 * 1089 * @param typeId the id of the resource type to check 1090 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1091 * 1092 * @see #getResourceType(int) 1093 * 1094 * @deprecated 1095 * Use {@link #hasResourceType(I_CmsResourceType)} or {@link #hasResourceType(I_CmsResourceType)} instead. 1096 * Resource types should always be referenced either by its type class (preferred) or by type name. 1097 * Use of int based resource type references will be discontinued in a future OpenCms release. 1098 */ 1099 @Deprecated 1100 public boolean hasResourceType(int typeId) { 1101 1102 return m_configuration.getResourceTypeById(typeId) != null; 1103 } 1104 1105 /** 1106 * Checks if an initialized resource type instance for the given resource type name is available.<p> 1107 * 1108 * @param typeName the name of the resource type to check 1109 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1110 * 1111 * @see #getResourceType(String) 1112 */ 1113 public boolean hasResourceType(String typeName) { 1114 1115 return m_configuration.getResourceTypeByName(typeName) != null; 1116 } 1117 1118 /** 1119 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 1120 * 1121 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1122 */ 1123 public void initConfiguration() throws CmsConfigurationException { 1124 1125 if (CmsLog.INIT.isInfoEnabled()) { 1126 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0)); 1127 } 1128 1129 m_resourceTypesFromXml = Collections.unmodifiableList(m_resourceTypesFromXml); 1130 m_loaderList = Collections.unmodifiableList(m_loaderList); 1131 Collections.sort(m_configuredMimeTypes); 1132 m_configuredMimeTypes = Collections.unmodifiableList(m_configuredMimeTypes); 1133 m_configuredRelationTypes = Collections.unmodifiableList(m_configuredRelationTypes); 1134 1135 // initialize the HTML converters 1136 initHtmlConverters(); 1137 m_configuredHtmlConverters = Collections.unmodifiableList(m_configuredHtmlConverters); 1138 1139 // initialize the resource types 1140 initResourceTypes(); 1141 // initialize the MIME types 1142 initMimeTypes(); 1143 } 1144 1145 /** 1146 * Initializes all additional resource types stored in the modules.<p> 1147 * 1148 * @param cms an initialized OpenCms user context with "module manager" role permissions 1149 * 1150 * @throws CmsRoleViolationException in case the provided OpenCms user context did not have "module manager" role permissions 1151 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1152 */ 1153 public synchronized void initialize(CmsObject cms) throws CmsRoleViolationException, CmsConfigurationException { 1154 1155 if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_1_CORE_OBJECT) { 1156 // some simple test cases don't require this check 1157 OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER); 1158 } 1159 1160 // initialize the resource types 1161 initResourceTypes(); 1162 1163 // call initialize method on all resource types 1164 Iterator<I_CmsResourceType> i = m_configuration.m_resourceTypeList.iterator(); 1165 while (i.hasNext()) { 1166 I_CmsResourceType type = i.next(); 1167 type.initialize(cms); 1168 } 1169 1170 // This only sets the CmsObject the first time it's called 1171 m_nameGenerator.setAdminCms(cms); 1172 1173 if (CmsLog.INIT.isInfoEnabled()) { 1174 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0)); 1175 } 1176 } 1177 1178 /** 1179 * Loads the requested resource and writes the contents to the response stream.<p> 1180 * 1181 * @param req the current HTTP request 1182 * @param res the current HTTP response 1183 * @param cms the current OpenCms user context 1184 * @param resource the requested resource 1185 * @throws ServletException if something goes wrong 1186 * @throws IOException if something goes wrong 1187 * @throws CmsException if something goes wrong 1188 */ 1189 public void loadResource(CmsObject cms, CmsResource resource, HttpServletRequest req, HttpServletResponse res) 1190 throws ServletException, IOException, CmsException { 1191 1192 res.setContentType(getMimeType(resource.getName(), cms.getRequestContext().getEncoding())); 1193 I_CmsResourceLoader loader = getLoader(resource); 1194 loader.load(cms, resource, req, res); 1195 } 1196 1197 /** 1198 * Checks if there is a resource type with a given name whose id matches the given id.<p> 1199 * 1200 * This will return 'false' if no resource type with the given name is registered.<p> 1201 * 1202 * @param name a resource type name 1203 * @param id a resource type id 1204 * 1205 * @return true if a matching resource type with the given name and id was found 1206 */ 1207 public boolean matchResourceType(String name, int id) { 1208 1209 if (hasResourceType(name)) { 1210 try { 1211 return getResourceType(name).getTypeId() == id; 1212 } catch (Exception e) { 1213 // should never happen because we already checked with hasResourceType, still have to 1214 // catch it so the compiler is happy 1215 LOG.error(e.getLocalizedMessage(), e); 1216 return false; 1217 } 1218 } else { 1219 return false; 1220 } 1221 } 1222 1223 /** 1224 * Configures the URL name generator for XML contents.<p> 1225 * 1226 * @param nameGenerator the configured name generator class 1227 * 1228 * @throws CmsConfigurationException if something goes wrong 1229 */ 1230 public void setNameGenerator(I_CmsFileNameGenerator nameGenerator) throws CmsConfigurationException { 1231 1232 if (m_frozen) { 1233 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 1234 } 1235 m_nameGenerator = nameGenerator; 1236 1237 if (CmsLog.INIT.isInfoEnabled()) { 1238 CmsLog.INIT.info( 1239 Messages.get().getBundle().key(Messages.INIT_SET_NAME_GENERATOR_1, nameGenerator.getClass().getName())); 1240 } 1241 } 1242 1243 /** 1244 * Sets the folder, the file and the XSD translator.<p> 1245 * 1246 * @param folderTranslator the folder translator to set 1247 * @param fileTranslator the file translator to set 1248 * @param xsdTranslator the XSD translator to set 1249 */ 1250 public void setTranslators( 1251 CmsResourceTranslator folderTranslator, 1252 CmsResourceTranslator fileTranslator, 1253 CmsResourceTranslator xsdTranslator) { 1254 1255 m_folderTranslator = folderTranslator; 1256 m_fileTranslator = fileTranslator; 1257 m_xsdTranslator = xsdTranslator; 1258 } 1259 1260 /** 1261 * Shuts down this resource manage instance.<p> 1262 * 1263 * @throws Exception in case of errors during shutdown 1264 */ 1265 public synchronized void shutDown() throws Exception { 1266 1267 Iterator<I_CmsResourceLoader> it = m_loaderList.iterator(); 1268 while (it.hasNext()) { 1269 // destroy all resource loaders 1270 I_CmsResourceLoader loader = it.next(); 1271 loader.destroy(); 1272 } 1273 1274 m_loaderList = null; 1275 m_loaders = null; 1276 m_collectorNameMappings = null; 1277 m_mimeTypes = null; 1278 m_configuredMimeTypes = null; 1279 m_configuredRelationTypes = null; 1280 m_configuredHtmlConverters = null; 1281 m_htmlConverters = null; 1282 1283 if (CmsLog.INIT.isInfoEnabled()) { 1284 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_1, this.getClass().getName())); 1285 } 1286 } 1287 1288 /** 1289 * Gets the template name for a template resource, using a cache for efficiency.<p> 1290 * 1291 * @param cms the current CMS context 1292 * @param resource the template resource 1293 * @return the template name 1294 * 1295 * @throws CmsException if something goes wrong 1296 */ 1297 private String getTemplateName(CmsObject cms, CmsResource resource) throws CmsException { 1298 1299 String templateName = (String)(m_templateNameCache.getCachedObject(cms, resource.getRootPath())); 1300 if (templateName == null) { 1301 CmsProperty nameProperty = cms.readPropertyObject( 1302 resource, 1303 CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS, 1304 false); 1305 String nameFromProperty = ""; 1306 if (!nameProperty.isNullProperty()) { 1307 nameFromProperty = nameProperty.getValue(); 1308 } 1309 m_templateNameCache.putCachedObject(cms, resource.getRootPath(), nameFromProperty); 1310 return nameFromProperty; 1311 } else { 1312 return templateName; 1313 } 1314 } 1315 1316 /** 1317 * Initialize the HTML converters.<p> 1318 * 1319 * HTML converters are configured in the OpenCms <code>opencms-vfs.xml</code> configuration file.<p> 1320 * 1321 * For legacy reasons, the default JTidy HTML converter has to be loaded if no explicit HTML converters 1322 * are configured in the configuration file.<p> 1323 */ 1324 private void initHtmlConverters() { 1325 1326 // check if any HTML converter configuration were found 1327 if (m_configuredHtmlConverters.size() == 0) { 1328 // no converters configured, add default JTidy converter configuration 1329 String classJTidy = CmsHtmlConverterJTidy.class.getName(); 1330 m_configuredHtmlConverters.add( 1331 new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_ENABLED, classJTidy, true)); 1332 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_XHTML, classJTidy, true)); 1333 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_WORD, classJTidy, true)); 1334 m_configuredHtmlConverters.add( 1335 new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_REPLACE_PARAGRAPHS, classJTidy, true)); 1336 } 1337 1338 // initialize lookup map of configured HTML converters 1339 m_htmlConverters = new HashMap<String, String>(m_configuredHtmlConverters.size()); 1340 for (Iterator<CmsHtmlConverterOption> i = m_configuredHtmlConverters.iterator(); i.hasNext();) { 1341 CmsHtmlConverterOption converterOption = i.next(); 1342 m_htmlConverters.put(converterOption.getName(), converterOption.getClassName()); 1343 } 1344 } 1345 1346 /** 1347 * Initialize the MIME types.<p> 1348 * 1349 * MIME types are configured in the OpenCms <code>opencms-vfs.xml</code> configuration file.<p> 1350 * 1351 * For legacy reasons, the MIME types are also read from a file <code>"mimetypes.properties"</code> 1352 * that must be located in the default <code>"classes"</code> folder of the web application.<p> 1353 */ 1354 private void initMimeTypes() { 1355 1356 // legacy MIME type initialization: try to read properties file 1357 Properties mimeTypes = new Properties(); 1358 try { 1359 // first try: read MIME types from default package 1360 mimeTypes.load(getClass().getClassLoader().getResourceAsStream("mimetypes.properties")); 1361 } catch (Throwable t) { 1362 try { 1363 // second try: read MIME types from loader package (legacy reasons, there are no types by default) 1364 mimeTypes.load( 1365 getClass().getClassLoader().getResourceAsStream("org/opencms/loader/mimetypes.properties")); 1366 } catch (Throwable t2) { 1367 if (LOG.isInfoEnabled()) { 1368 LOG.info( 1369 Messages.get().getBundle().key( 1370 Messages.LOG_READ_MIMETYPES_FAILED_2, 1371 "mimetypes.properties", 1372 "org/opencms/loader/mimetypes.properties")); 1373 } 1374 } 1375 } 1376 1377 // initialize the Map with all available MIME types 1378 List<CmsMimeType> combinedMimeTypes = new ArrayList<CmsMimeType>( 1379 mimeTypes.size() + m_configuredMimeTypes.size()); 1380 // first add all MIME types from the configuration 1381 combinedMimeTypes.addAll(m_configuredMimeTypes); 1382 // now add the MIME types from the properties 1383 Iterator<Map.Entry<Object, Object>> i = mimeTypes.entrySet().iterator(); 1384 while (i.hasNext()) { 1385 Map.Entry<Object, Object> entry = i.next(); 1386 CmsMimeType mimeType = new CmsMimeType(entry.getKey().toString(), entry.getValue().toString(), false); 1387 if (!combinedMimeTypes.contains(mimeType)) { 1388 // make sure no MIME types from the XML configuration are overwritten 1389 combinedMimeTypes.add(mimeType); 1390 } 1391 } 1392 1393 // create a lookup Map for the MIME types 1394 m_mimeTypes = new HashMap<String, String>(mimeTypes.size()); 1395 Iterator<CmsMimeType> j = combinedMimeTypes.iterator(); 1396 while (j.hasNext()) { 1397 CmsMimeType mimeType = j.next(); 1398 m_mimeTypes.put(mimeType.getExtension(), mimeType.getType()); 1399 } 1400 1401 if (CmsLog.INIT.isInfoEnabled()) { 1402 CmsLog.INIT.info( 1403 Messages.get().getBundle().key(Messages.INIT_NUM_MIMETYPES_1, Integer.valueOf(m_mimeTypes.size()))); 1404 } 1405 } 1406 1407 /** 1408 * Adds a new resource type to the internal list of loaded resource types and initializes 1409 * options for the resource type.<p> 1410 * 1411 * @param resourceType the resource type to add 1412 * @param configuration the resource configuration 1413 */ 1414 private synchronized void initResourceType( 1415 I_CmsResourceType resourceType, 1416 CmsResourceManagerConfiguration configuration) { 1417 1418 // add the loader to the internal list of loaders 1419 configuration.addResourceType(resourceType); 1420 if (CmsLog.INIT.isInfoEnabled()) { 1421 CmsLog.INIT.info( 1422 Messages.get().getBundle().key( 1423 Messages.INIT_ADD_RESTYPE_3, 1424 resourceType.getTypeName(), 1425 Integer.valueOf(resourceType.getTypeId()), 1426 resourceType.getClass().getName())); 1427 } 1428 1429 // add the mappings 1430 List<String> mappings = resourceType.getConfiguredMappings(); 1431 Iterator<String> i = mappings.iterator(); 1432 while (i.hasNext()) { 1433 String mapping = i.next(); 1434 // only add this mapping if a mapping with this file extension does not 1435 // exist already 1436 if (!configuration.m_extensionMappings.containsKey(mapping)) { 1437 configuration.m_extensionMappings.put(mapping, resourceType.getTypeName()); 1438 if (CmsLog.INIT.isInfoEnabled()) { 1439 CmsLog.INIT.info( 1440 Messages.get().getBundle().key( 1441 Messages.INIT_MAP_RESTYPE_2, 1442 mapping, 1443 resourceType.getTypeName())); 1444 } 1445 } 1446 } 1447 } 1448 1449 /** 1450 * Initializes member variables required for storing the resource types.<p> 1451 * 1452 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1453 */ 1454 private synchronized void initResourceTypes() throws CmsConfigurationException { 1455 1456 if (CmsLog.INIT.isInfoEnabled()) { 1457 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_STARTING_LOADER_CONFIG_0)); 1458 } 1459 1460 CmsResourceManagerConfiguration newConfiguration = new CmsResourceManagerConfiguration(); 1461 1462 if (CmsLog.INIT.isInfoEnabled()) { 1463 CmsLog.INIT.info( 1464 Messages.get().getBundle().key( 1465 Messages.INIT_ADD_RESTYPE_FROM_FILE_2, 1466 Integer.valueOf(m_resourceTypesFromXml.size()), 1467 CmsVfsConfiguration.DEFAULT_XML_FILE_NAME)); 1468 } 1469 1470 // build a new resource type list from the resource types of the XML configuration 1471 Iterator<I_CmsResourceType> i; 1472 i = m_resourceTypesFromXml.iterator(); 1473 while (i.hasNext()) { 1474 I_CmsResourceType resourceType = i.next(); 1475 initResourceType(resourceType, newConfiguration); 1476 } 1477 1478 // add all resource types declared in the modules 1479 CmsModuleManager moduleManager = OpenCms.getModuleManager(); 1480 if (moduleManager != null) { 1481 Iterator<String> modules = moduleManager.getModuleNames().iterator(); 1482 while (modules.hasNext()) { 1483 CmsModule module = moduleManager.getModule(modules.next()); 1484 if ((module != null) && (module.getResourceTypes().size() > 0)) { 1485 // module contains resource types 1486 if (CmsLog.INIT.isInfoEnabled()) { 1487 CmsLog.INIT.info( 1488 Messages.get().getBundle().key( 1489 Messages.INIT_ADD_NUM_RESTYPES_FROM_MOD_2, 1490 Integer.valueOf(module.getResourceTypes().size()), 1491 module.getName())); 1492 } 1493 1494 Iterator<I_CmsResourceType> j = module.getResourceTypes().iterator(); 1495 while (j.hasNext()) { 1496 I_CmsResourceType resourceType = j.next(); 1497 I_CmsResourceType conflictingType = null; 1498 if (resourceType.getTypeId() == CmsResourceTypeUnknownFile.RESOURCE_TYPE_ID) { 1499 // default unknown file resource type 1500 if (m_restypeUnknownFile != null) { 1501 // error: already set 1502 conflictingType = m_restypeUnknownFile; 1503 } else { 1504 m_restypeUnknownFile = resourceType; 1505 continue; 1506 } 1507 } else if (resourceType.getTypeId() == CmsResourceTypeUnknownFolder.RESOURCE_TYPE_ID) { 1508 // default unknown folder resource type 1509 if (m_restypeUnknownFolder != null) { 1510 // error: already set 1511 conflictingType = m_restypeUnknownFolder; 1512 } else { 1513 m_restypeUnknownFile = resourceType; 1514 continue; 1515 } 1516 } else { 1517 // normal resource types 1518 conflictingType = newConfiguration.getResourceTypeById(resourceType.getTypeId()); 1519 } 1520 if (conflictingType != null) { 1521 throw new CmsConfigurationException( 1522 Messages.get().container( 1523 Messages.ERR_CONFLICTING_MODULE_RESOURCE_TYPES_5, 1524 new Object[] { 1525 resourceType.getTypeName(), 1526 Integer.valueOf(resourceType.getTypeId()), 1527 module.getName(), 1528 conflictingType.getTypeName(), 1529 Integer.valueOf(conflictingType.getTypeId())})); 1530 } 1531 initResourceType(resourceType, newConfiguration); 1532 } 1533 } 1534 } 1535 } 1536 1537 // freeze the current configuration 1538 newConfiguration.freeze(m_restypeUnknownFile, m_restypeUnknownFile); 1539 m_configuration = newConfiguration; 1540 m_frozen = true; 1541 1542 if (CmsLog.INIT.isInfoEnabled()) { 1543 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_RESOURCE_TYPE_INITIALIZED_0)); 1544 } 1545 } 1546 1547 /** 1548 * Reads a template resource together with its name.<p> 1549 * 1550 * @param cms the current CMS context 1551 * @param path the template path 1552 * 1553 * @return the template together with its name, or null if the template couldn't be read 1554 */ 1555 private NamedTemplate readTemplateWithName(CmsObject cms, String path) { 1556 1557 try { 1558 CmsResource resource = cms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION); 1559 String name = getTemplateName(cms, resource); 1560 return new NamedTemplate(resource, name); 1561 } catch (Exception e) { 1562 return null; 1563 } 1564 } 1565 1566}