001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH (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, 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; 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(Messages.get().container( 344 Messages.ERR_INVALID_COLLECTOR_NAME_1, 345 className)); 346 } catch (IllegalAccessException e) { 347 throw new CmsConfigurationException(Messages.get().container( 348 Messages.ERR_INVALID_COLLECTOR_NAME_1, 349 className)); 350 } catch (ClassCastException e) { 351 throw new CmsConfigurationException(Messages.get().container( 352 Messages.ERR_INVALID_COLLECTOR_NAME_1, 353 className)); 354 } 355 356 // set the configured order for the collector 357 int ord = 0; 358 try { 359 ord = Integer.valueOf(order).intValue(); 360 } catch (NumberFormatException e) { 361 LOG.error(Messages.get().getBundle().key(Messages.LOG_COLLECTOR_BAD_ORDER_NUMBER_1, className), e); 362 } 363 collector.setOrder(ord); 364 365 if (CmsLog.INIT.isInfoEnabled()) { 366 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_COLLECTOR_CLASS_2, className, order)); 367 } 368 369 // extend or init the current list of configured collectors 370 if (m_collectors != null) { 371 m_collectors = new ArrayList<I_CmsResourceCollector>(m_collectors); 372 m_collectorNameMappings = new HashMap<String, I_CmsResourceCollector>(m_collectorNameMappings); 373 } else { 374 m_collectors = new ArrayList<I_CmsResourceCollector>(); 375 m_collectorNameMappings = new HashMap<String, I_CmsResourceCollector>(); 376 } 377 378 if (!m_collectors.contains(collector)) { 379 // this is a collector not currently configured 380 m_collectors.add(collector); 381 382 Iterator<String> i = collector.getCollectorNames().iterator(); 383 while (i.hasNext()) { 384 String name = i.next(); 385 if (m_collectorNameMappings.containsKey(name)) { 386 // this name is already configured, check the order of the collector 387 I_CmsResourceCollector otherCollector = m_collectorNameMappings.get(name); 388 if (collector.getOrder() > otherCollector.getOrder()) { 389 // new collector has a greater order than the old collector in the Map 390 m_collectorNameMappings.put(name, collector); 391 if (CmsLog.INIT.isInfoEnabled()) { 392 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_COLLECTOR_REPLACED_1, name)); 393 } 394 } else { 395 if (CmsLog.INIT.isInfoEnabled()) { 396 CmsLog.INIT.info(Messages.get().getBundle().key( 397 Messages.INIT_DUPLICATE_COLLECTOR_SKIPPED_1, 398 name)); 399 } 400 } 401 } else { 402 m_collectorNameMappings.put(name, collector); 403 if (CmsLog.INIT.isInfoEnabled()) { 404 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_COLLECTOR_1, name)); 405 } 406 } 407 } 408 } 409 410 // ensure list is unmodifiable to avoid potential misuse or accidental changes 411 Collections.sort(m_collectors); 412 m_collectors = Collections.unmodifiableList(m_collectors); 413 m_collectorNameMappings = Collections.unmodifiableMap(m_collectorNameMappings); 414 415 // return the created collector instance 416 return collector; 417 } 418 419 /** 420 * Adds a new HTML converter class to internal list of loaded converter classes.<p> 421 * 422 * @param name the name of the option that should trigger the HTML converter class 423 * @param className the name of the class to add 424 * 425 * @return the created HTML converter instance 426 * 427 * @throws CmsConfigurationException in case the HTML converter could not be properly initialized 428 */ 429 public I_CmsHtmlConverter addHtmlConverter(String name, String className) throws CmsConfigurationException { 430 431 // check if new conversion option can still be added 432 if (m_frozen) { 433 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 434 } 435 436 Class<?> classClazz; 437 // init class for content converter 438 try { 439 classClazz = Class.forName(className); 440 } catch (ClassNotFoundException e) { 441 LOG.error(Messages.get().getBundle().key(Messages.LOG_HTML_CONVERTER_CLASS_NOT_FOUND_1, className), e); 442 return null; 443 } 444 445 I_CmsHtmlConverter converter; 446 try { 447 converter = (I_CmsHtmlConverter)classClazz.newInstance(); 448 } catch (InstantiationException e) { 449 throw new CmsConfigurationException(Messages.get().container( 450 Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, 451 className)); 452 } catch (IllegalAccessException e) { 453 throw new CmsConfigurationException(Messages.get().container( 454 Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, 455 className)); 456 } catch (ClassCastException e) { 457 throw new CmsConfigurationException(Messages.get().container( 458 Messages.ERR_INVALID_HTMLCONVERTER_NAME_1, 459 className)); 460 } 461 462 if (CmsLog.INIT.isInfoEnabled()) { 463 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_ADD_HTML_CONVERTER_CLASS_2, className, name)); 464 } 465 466 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(name, className)); 467 return converter; 468 } 469 470 /** 471 * Adds a new loader to the internal list of loaded loaders.<p> 472 * 473 * @param loader the loader to add 474 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 475 */ 476 public void addLoader(I_CmsResourceLoader loader) throws CmsConfigurationException { 477 478 // check if new loaders can still be added 479 if (m_frozen) { 480 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 481 } 482 483 // add the loader to the internal list of loaders 484 int pos = loader.getLoaderId(); 485 if (pos >= m_loaders.length) { 486 I_CmsResourceLoader[] buffer = new I_CmsResourceLoader[pos * 2]; 487 System.arraycopy(m_loaders, 0, buffer, 0, m_loaders.length); 488 m_loaders = buffer; 489 } 490 m_loaders[pos] = loader; 491 m_loaderList.add(loader); 492 if (CmsLog.INIT.isInfoEnabled()) { 493 CmsLog.INIT.info(Messages.get().getBundle().key( 494 Messages.INIT_ADD_LOADER_2, 495 loader.getClass().getName(), 496 new Integer(pos))); 497 } 498 } 499 500 /** 501 * Adds a new MIME type from the XML configuration to the internal list of MIME types.<p> 502 * 503 * @param extension the MIME type extension 504 * @param type the MIME type description 505 * 506 * @return the created MIME type instance 507 * 508 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 509 */ 510 public CmsMimeType addMimeType(String extension, String type) throws CmsConfigurationException { 511 512 // check if new mime types can still be added 513 if (m_frozen) { 514 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 515 } 516 517 CmsMimeType mimeType = new CmsMimeType(extension, type); 518 m_configuredMimeTypes.add(mimeType); 519 return mimeType; 520 } 521 522 /** 523 * Adds a new relation type from the XML configuration to the list of user defined relation types.<p> 524 * 525 * @param name the name of the relation type 526 * @param type the type of the relation type, weak or strong 527 * 528 * @return the new created relation type instance 529 * 530 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 531 */ 532 public CmsRelationType addRelationType(String name, String type) throws CmsConfigurationException { 533 534 // check if new relation types can still be added 535 if (m_frozen) { 536 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 537 } 538 539 CmsRelationType relationType = new CmsRelationType(m_configuredRelationTypes.size(), name, type); 540 m_configuredRelationTypes.add(relationType); 541 return relationType; 542 } 543 544 /** 545 * Adds a new resource type from the XML configuration to the internal list of loaded resource types.<p> 546 * 547 * Resource types can also be added from a module.<p> 548 * 549 * @param resourceType the resource type to add 550 * @throws CmsConfigurationException in case the resource manager configuration is already initialized 551 */ 552 public void addResourceType(I_CmsResourceType resourceType) throws CmsConfigurationException { 553 554 // check if new resource types can still be added 555 if (m_frozen) { 556 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 557 } 558 559 I_CmsResourceType conflictingType = null; 560 if (resourceType.getTypeId() == CmsResourceTypeUnknownFile.RESOURCE_TYPE_ID) { 561 // default unknown file resource type 562 if (m_restypeUnknownFile != null) { 563 // error: already set 564 conflictingType = m_restypeUnknownFile; 565 } else { 566 m_restypeUnknownFile = resourceType; 567 return; 568 } 569 } else if (resourceType.getTypeId() == CmsResourceTypeUnknownFolder.RESOURCE_TYPE_ID) { 570 // default unknown folder resource type 571 if (m_restypeUnknownFolder != null) { 572 // error: already set 573 conflictingType = m_restypeUnknownFolder; 574 } else { 575 m_restypeUnknownFolder = resourceType; 576 return; 577 } 578 } else { 579 // normal resource types 580 int conflictIndex = m_resourceTypesFromXml.indexOf(resourceType); 581 if (conflictIndex >= 0) { 582 conflictingType = m_resourceTypesFromXml.get(conflictIndex); 583 } 584 } 585 if (conflictingType != null) { 586 // configuration problem: the resource type (or at least the id or the name) is already configured 587 throw new CmsConfigurationException(Messages.get().container( 588 Messages.ERR_CONFLICTING_RESOURCE_TYPES_4, 589 new Object[] { 590 resourceType.getTypeName(), 591 new Integer(resourceType.getTypeId()), 592 conflictingType.getTypeName(), 593 new Integer(conflictingType.getTypeId())})); 594 } 595 596 m_resourceTypesFromXml.add(resourceType); 597 } 598 599 /** 600 * Gets the map of forbidden contexts for resource types.<p> 601 * 602 * @param cms the current CMS context 603 * @return the map from resource types to the forbidden contexts 604 */ 605 public Map<String, CmsDefaultSet<String>> getAllowedContextMap(CmsObject cms) { 606 607 Map<String, CmsDefaultSet<String>> result = new HashMap<String, CmsDefaultSet<String>>(); 608 for (I_CmsResourceType resType : getResourceTypes()) { 609 if (resType instanceof CmsResourceTypeXmlContent) { 610 String schema = null; 611 try { 612 schema = ((CmsResourceTypeXmlContent)resType).getSchema(); 613 if (schema != null) { 614 CmsXmlContentDefinition contentDefinition = CmsXmlContentDefinition.unmarshal(cms, schema); 615 616 CmsDefaultSet<String> allowedContexts = contentDefinition.getContentHandler().getAllowedTemplates(); 617 result.put(resType.getTypeName(), allowedContexts); 618 } else { 619 LOG.info("No schema for XML type " 620 + resType.getTypeName() 621 + " / " 622 + resType.getClass().getName()); 623 } 624 } catch (Exception e) { 625 LOG.error("Error in getAllowedContextMap, schema=" 626 + schema 627 + ", type=" 628 + resType.getTypeName() 629 + ", " 630 + e.getLocalizedMessage(), e); 631 } 632 } 633 } 634 return result; 635 } 636 637 /** 638 * Returns the configured content collector with the given name, or <code>null</code> if 639 * no collector with this name is configured.<p> 640 * 641 * @param collectorName the name of the collector to get 642 * @return the configured content collector with the given name 643 */ 644 public I_CmsResourceCollector getContentCollector(String collectorName) { 645 646 return m_collectorNameMappings.get(collectorName); 647 } 648 649 /** 650 * Returns the default resource type for the given resource name, using the 651 * configured resource type file extensions.<p> 652 * 653 * In case the given name does not map to a configured resource type, 654 * {@link CmsResourceTypePlain} is returned.<p> 655 * 656 * This is only required (and should <i>not</i> be used otherwise) when 657 * creating a new resource automatically during file upload or synchronization. 658 * Only in this case, the file type for the new resource is determined using this method. 659 * Otherwise the resource type is <i>always</i> stored as part of the resource, 660 * and is <i>not</i> related to the file name.<p> 661 * 662 * @param resourcename the resource name to look up the resource type for 663 * 664 * @return the default resource type for the given resource name 665 * 666 * @throws CmsException if something goes wrong 667 */ 668 public I_CmsResourceType getDefaultTypeForName(String resourcename) throws CmsException { 669 670 String typeName = null; 671 String suffix = null; 672 if (CmsStringUtil.isNotEmpty(resourcename)) { 673 int pos = resourcename.lastIndexOf('.'); 674 if (pos >= 0) { 675 suffix = resourcename.substring(pos); 676 if (CmsStringUtil.isNotEmpty(suffix)) { 677 suffix = suffix.toLowerCase(); 678 typeName = m_configuration.m_extensionMappings.get(suffix); 679 680 } 681 } 682 } 683 684 if (typeName == null) { 685 // use default type "plain" 686 typeName = CmsResourceTypePlain.getStaticTypeName(); 687 } 688 689 if (CmsLog.INIT.isDebugEnabled()) { 690 CmsLog.INIT.debug(Messages.get().getBundle().key(Messages.INIT_GET_RESTYPE_2, typeName, suffix)); 691 } 692 // look up and return the resource type 693 return getResourceType(typeName); 694 } 695 696 /** 697 * Returns the file extensions (suffixes) mappings to resource types.<p> 698 * 699 * @return a Map with all known file extensions as keys and their resource types as values. 700 */ 701 public Map<String, String> getExtensionMapping() { 702 703 return m_configuration.m_extensionMappings; 704 } 705 706 /** 707 * Returns the file translator.<p> 708 * 709 * @return the file translator 710 */ 711 public CmsResourceTranslator getFileTranslator() { 712 713 return m_fileTranslator; 714 } 715 716 /** 717 * Returns the folder translator.<p> 718 * 719 * @return the folder translator 720 */ 721 public CmsResourceTranslator getFolderTranslator() { 722 723 return m_folderTranslator; 724 } 725 726 /** 727 * Returns the matching HTML converter class name for the specified option name.<p> 728 * 729 * @param name the name of the option that should trigger the HTML converter class 730 * 731 * @return the matching HTML converter class name for the specified option name or <code>null</code> if no match is found 732 */ 733 public String getHtmlConverter(String name) { 734 735 return m_htmlConverters.get(name); 736 } 737 738 /** 739 * Returns an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects.<p> 740 * 741 * @return an unmodifiable List of the configured {@link CmsHtmlConverterOption} objects 742 */ 743 public List<CmsHtmlConverterOption> getHtmlConverters() { 744 745 return m_configuredHtmlConverters; 746 } 747 748 /** 749 * Returns the loader class instance for a given resource.<p> 750 * 751 * @param resource the resource 752 * @return the appropriate loader class instance 753 * @throws CmsLoaderException if something goes wrong 754 */ 755 public I_CmsResourceLoader getLoader(CmsResource resource) throws CmsLoaderException { 756 757 return getLoader(getResourceType(resource.getTypeId()).getLoaderId()); 758 } 759 760 /** 761 * Returns the loader class instance for the given loader id.<p> 762 * 763 * @param id the id of the loader to return 764 * @return the loader class instance for the given loader id 765 */ 766 public I_CmsResourceLoader getLoader(int id) { 767 768 return m_loaders[id]; 769 } 770 771 /** 772 * Returns the (unmodifiable array) list with all initialized resource loaders.<p> 773 * 774 * @return the (unmodifiable array) list with all initialized resource loaders 775 */ 776 public List<I_CmsResourceLoader> getLoaders() { 777 778 return m_loaderList; 779 } 780 781 /** 782 * Returns the MIME type for a specified file name.<p> 783 * 784 * If an encoding parameter that is not <code>null</code> is provided, 785 * the returned MIME type is extended with a <code>; charset={encoding}</code> setting.<p> 786 * 787 * If no MIME type for the given filename can be determined, the 788 * default <code>{@link #MIMETYPE_HTML}</code> is used.<p> 789 * 790 * @param filename the file name to check the MIME type for 791 * @param encoding the default encoding (charset) in case of MIME types is of type "text" 792 * 793 * @return the MIME type for a specified file 794 */ 795 public String getMimeType(String filename, String encoding) { 796 797 return getMimeType(filename, encoding, MIMETYPE_HTML); 798 } 799 800 /** 801 * Returns the MIME type for a specified file name.<p> 802 * 803 * If an encoding parameter that is not <code>null</code> is provided, 804 * the returned MIME type is extended with a <code>; charset={encoding}</code> setting.<p> 805 * 806 * If no MIME type for the given filename can be determined, the 807 * provided default is used.<p> 808 * 809 * @param filename the file name to check the MIME type for 810 * @param encoding the default encoding (charset) in case of MIME types is of type "text" 811 * @param defaultMimeType the default MIME type to use if no matching type for the filename is found 812 * 813 * @return the MIME type for a specified file 814 */ 815 public String getMimeType(String filename, String encoding, String defaultMimeType) { 816 817 String mimeType = null; 818 int lastDot = filename.lastIndexOf('.'); 819 // check the MIME type for the file extension 820 if ((lastDot > 0) && (lastDot < (filename.length() - 1))) { 821 mimeType = m_mimeTypes.get(filename.substring(lastDot).toLowerCase(Locale.ENGLISH)); 822 } 823 if (mimeType == null) { 824 mimeType = defaultMimeType; 825 if (mimeType == null) { 826 // no default MIME type was provided 827 return null; 828 } 829 } 830 StringBuffer result = new StringBuffer(mimeType); 831 if ((encoding != null) && mimeType.startsWith("text") && (mimeType.indexOf("charset") == -1)) { 832 result.append("; charset="); 833 result.append(encoding); 834 } 835 return result.toString(); 836 } 837 838 /** 839 * Returns an unmodifiable List of the configured {@link CmsMimeType} objects.<p> 840 * 841 * @return an unmodifiable List of the configured {@link CmsMimeType} objects 842 */ 843 public List<CmsMimeType> getMimeTypes() { 844 845 return m_configuredMimeTypes; 846 } 847 848 /** 849 * Returns the name generator for XML content file names.<p> 850 * 851 * @return the name generator for XML content file names. 852 */ 853 public I_CmsFileNameGenerator getNameGenerator() { 854 855 if (m_nameGenerator == null) { 856 m_nameGenerator = new CmsDefaultFileNameGenerator(); 857 } 858 return m_nameGenerator; 859 } 860 861 /** 862 * Returns an (unmodifiable) list of class names of all currently registered content collectors 863 * ({@link I_CmsResourceCollector} objects).<p> 864 * 865 * @return an (unmodifiable) list of class names of all currently registered content collectors 866 * ({@link I_CmsResourceCollector} objects) 867 */ 868 public List<I_CmsResourceCollector> getRegisteredContentCollectors() { 869 870 return m_collectors; 871 } 872 873 /** 874 * Returns an unmodifiable List of the configured {@link CmsRelationType} objects.<p> 875 * 876 * @return an unmodifiable List of the configured {@link CmsRelationType} objects 877 */ 878 public List<CmsRelationType> getRelationTypes() { 879 880 return m_configuredRelationTypes; 881 } 882 883 /** 884 * Convenience method to get the initialized resource type instance for the given resource, 885 * with a fall back to special "unknown" resource types in case the resource type is not configured.<p> 886 * 887 * @param resource the resource to get the type for 888 * 889 * @return the initialized resource type instance for the given resource 890 */ 891 public I_CmsResourceType getResourceType(CmsResource resource) { 892 893 I_CmsResourceType result = m_configuration.getResourceTypeById(resource.getTypeId()); 894 if (result == null) { 895 // this resource type is unknown, return the default files instead 896 if (resource.isFolder()) { 897 // resource is a folder 898 if (m_restypeUnknownFolder != null) { 899 result = m_restypeUnknownFolder; 900 } else { 901 result = m_configuration.getResourceTypeByName(CmsResourceTypeFolder.getStaticTypeName()); 902 } 903 } else { 904 // resource is a file 905 if (m_restypeUnknownFile != null) { 906 result = m_restypeUnknownFile; 907 } else { 908 result = m_configuration.getResourceTypeByName(CmsResourceTypeBinary.getStaticTypeName()); 909 } 910 } 911 } 912 return result; 913 } 914 915 /** 916 * Returns the initialized resource type instance for the given id.<p> 917 * 918 * @param typeId the id of the resource type to get 919 * 920 * @return the initialized resource type instance for the given id 921 * 922 * @throws CmsLoaderException if no resource type is available for the given id 923 */ 924 public I_CmsResourceType getResourceType(int typeId) throws CmsLoaderException { 925 926 I_CmsResourceType result = m_configuration.getResourceTypeById(typeId); 927 if (result == null) { 928 throw new CmsLoaderException(Messages.get().container( 929 Messages.ERR_UNKNOWN_RESTYPE_ID_REQ_1, 930 new Integer(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) throws CmsException { 1023 1024 String templateProp = cms.readPropertyObject(resource, templateProperty, true).getValue(); 1025 CmsTemplateContext templateContext = null; 1026 String templateName = null; 1027 if (templateProp == null) { 1028 1029 // use default template, if template is not set 1030 templateProp = DEFAULT_TEMPLATE; 1031 NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp); 1032 if (namedTemplate == null) { 1033 // no template property defined, this is a must for facade loaders 1034 throw new CmsLoaderException(Messages.get().container( 1035 Messages.ERR_NONDEF_PROP_2, 1036 templateProperty, 1037 cms.getSitePath(resource))); 1038 } 1039 templateName = namedTemplate.getName(); 1040 } else { 1041 if ((request != null) && CmsTemplateContextManager.hasPropertyPrefix(templateProp)) { 1042 templateContext = OpenCms.getTemplateContextManager().getTemplateContext( 1043 templateProp, 1044 cms, 1045 request, 1046 resource); 1047 if (templateContext != null) { 1048 templateProp = templateContext.getTemplatePath(); 1049 } 1050 } 1051 NamedTemplate namedTemplate = readTemplateWithName(cms, templateProp); 1052 if (namedTemplate == null) { 1053 namedTemplate = readTemplateWithName(cms, DEFAULT_TEMPLATE); 1054 if (namedTemplate != null) { 1055 templateProp = DEFAULT_TEMPLATE; 1056 templateName = namedTemplate.getName(); 1057 } 1058 } else { 1059 templateName = namedTemplate.getName(); 1060 } 1061 } 1062 CmsResource template = cms.readFile(templateProp, CmsResourceFilter.IGNORE_EXPIRATION); 1063 CmsTemplateLoaderFacade result = new CmsTemplateLoaderFacade(getLoader(template), resource, template); 1064 result.setTemplateContext(templateContext); 1065 result.setTemplateName(templateName); 1066 return result; 1067 1068 } 1069 1070 /** 1071 * Returns the XSD translator.<p> 1072 * 1073 * @return the XSD translator 1074 */ 1075 public CmsResourceTranslator getXsdTranslator() { 1076 1077 return m_xsdTranslator; 1078 } 1079 1080 /** 1081 * Checks if an initialized resource type instance equal to the given resource type is available.<p> 1082 * 1083 * @param type the resource type to check 1084 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1085 * 1086 * @see #getResourceType(String) 1087 * @see #getResourceType(int) 1088 */ 1089 public boolean hasResourceType(I_CmsResourceType type) { 1090 1091 return hasResourceType(type.getTypeId()); 1092 } 1093 1094 /** 1095 * Checks if an initialized resource type instance for the given resource type is is available.<p> 1096 * 1097 * @param typeId the id of the resource type to check 1098 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1099 * 1100 * @see #getResourceType(int) 1101 */ 1102 public boolean hasResourceType(int typeId) { 1103 1104 return m_configuration.getResourceTypeById(typeId) != null; 1105 } 1106 1107 /** 1108 * Checks if an initialized resource type instance for the given resource type name is available.<p> 1109 * 1110 * @param typeName the name of the resource type to check 1111 * @return <code>true</code> if such a resource type has been configured, <code>false</code> otherwise 1112 * 1113 * @see #getResourceType(String) 1114 */ 1115 public boolean hasResourceType(String typeName) { 1116 1117 return m_configuration.getResourceTypeByName(typeName) != null; 1118 } 1119 1120 /** 1121 * @see org.opencms.configuration.I_CmsConfigurationParameterHandler#initConfiguration() 1122 * 1123 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1124 */ 1125 public void initConfiguration() throws CmsConfigurationException { 1126 1127 if (CmsLog.INIT.isInfoEnabled()) { 1128 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0)); 1129 } 1130 1131 m_resourceTypesFromXml = Collections.unmodifiableList(m_resourceTypesFromXml); 1132 m_loaderList = Collections.unmodifiableList(m_loaderList); 1133 Collections.sort(m_configuredMimeTypes); 1134 m_configuredMimeTypes = Collections.unmodifiableList(m_configuredMimeTypes); 1135 m_configuredRelationTypes = Collections.unmodifiableList(m_configuredRelationTypes); 1136 1137 // initialize the HTML converters 1138 initHtmlConverters(); 1139 m_configuredHtmlConverters = Collections.unmodifiableList(m_configuredHtmlConverters); 1140 1141 // initialize the resource types 1142 initResourceTypes(); 1143 // initialize the MIME types 1144 initMimeTypes(); 1145 } 1146 1147 /** 1148 * Initializes all additional resource types stored in the modules.<p> 1149 * 1150 * @param cms an initialized OpenCms user context with "module manager" role permissions 1151 * 1152 * @throws CmsRoleViolationException in case the provided OpenCms user context did not have "module manager" role permissions 1153 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1154 */ 1155 public synchronized void initialize(CmsObject cms) throws CmsRoleViolationException, CmsConfigurationException { 1156 1157 if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_1_CORE_OBJECT) { 1158 // some simple test cases don't require this check 1159 OpenCms.getRoleManager().checkRole(cms, CmsRole.DATABASE_MANAGER); 1160 } 1161 1162 // initialize the resource types 1163 initResourceTypes(); 1164 1165 // call initialize method on all resource types 1166 Iterator<I_CmsResourceType> i = m_configuration.m_resourceTypeList.iterator(); 1167 while (i.hasNext()) { 1168 I_CmsResourceType type = i.next(); 1169 type.initialize(cms); 1170 } 1171 1172 if (CmsLog.INIT.isInfoEnabled()) { 1173 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_LOADER_CONFIG_FINISHED_0)); 1174 } 1175 } 1176 1177 /** 1178 * Loads the requested resource and writes the contents to the response stream.<p> 1179 * 1180 * @param req the current HTTP request 1181 * @param res the current HTTP response 1182 * @param cms the current OpenCms user context 1183 * @param resource the requested resource 1184 * @throws ServletException if something goes wrong 1185 * @throws IOException if something goes wrong 1186 * @throws CmsException if something goes wrong 1187 */ 1188 public void loadResource(CmsObject cms, CmsResource resource, HttpServletRequest req, HttpServletResponse res) 1189 throws ServletException, IOException, CmsException { 1190 1191 res.setContentType(getMimeType(resource.getName(), cms.getRequestContext().getEncoding())); 1192 I_CmsResourceLoader loader = getLoader(resource); 1193 loader.load(cms, resource, req, res); 1194 } 1195 1196 /** 1197 * Checks if there is a resource type with a given name whose id matches the given id.<p> 1198 * 1199 * This will return 'false' if no resource type with the given name is registered.<p> 1200 * 1201 * @param name a resource type name 1202 * @param id a resource type id 1203 * 1204 * @return true if a matching resource type with the given name and id was found 1205 */ 1206 public boolean matchResourceType(String name, int id) { 1207 1208 if (hasResourceType(name)) { 1209 try { 1210 return getResourceType(name).getTypeId() == id; 1211 } catch (Exception e) { 1212 // should never happen because we already checked with hasResourceType, still have to 1213 // catch it so the compiler is happy 1214 LOG.error(e.getLocalizedMessage(), e); 1215 return false; 1216 } 1217 } else { 1218 return false; 1219 } 1220 } 1221 1222 /** 1223 * Configures the URL name generator for XML contents.<p> 1224 * 1225 * @param nameGenerator the configured name generator class 1226 * 1227 * @throws CmsConfigurationException if something goes wrong 1228 */ 1229 public void setNameGenerator(I_CmsFileNameGenerator nameGenerator) throws CmsConfigurationException { 1230 1231 if (m_frozen) { 1232 throw new CmsConfigurationException(Messages.get().container(Messages.ERR_NO_CONFIG_AFTER_STARTUP_0)); 1233 } 1234 m_nameGenerator = nameGenerator; 1235 } 1236 1237 /** 1238 * Sets the folder, the file and the XSD translator.<p> 1239 * 1240 * @param folderTranslator the folder translator to set 1241 * @param fileTranslator the file translator to set 1242 * @param xsdTranslator the XSD translator to set 1243 */ 1244 public void setTranslators( 1245 CmsResourceTranslator folderTranslator, 1246 CmsResourceTranslator fileTranslator, 1247 CmsResourceTranslator xsdTranslator) { 1248 1249 m_folderTranslator = folderTranslator; 1250 m_fileTranslator = fileTranslator; 1251 m_xsdTranslator = xsdTranslator; 1252 } 1253 1254 /** 1255 * Shuts down this resource manage instance.<p> 1256 * 1257 * @throws Exception in case of errors during shutdown 1258 */ 1259 public synchronized void shutDown() throws Exception { 1260 1261 Iterator<I_CmsResourceLoader> it = m_loaderList.iterator(); 1262 while (it.hasNext()) { 1263 // destroy all resource loaders 1264 I_CmsResourceLoader loader = it.next(); 1265 loader.destroy(); 1266 } 1267 1268 m_loaderList = null; 1269 m_loaders = null; 1270 m_collectorNameMappings = null; 1271 m_mimeTypes = null; 1272 m_configuredMimeTypes = null; 1273 m_configuredRelationTypes = null; 1274 m_configuredHtmlConverters = null; 1275 m_htmlConverters = null; 1276 1277 if (CmsLog.INIT.isInfoEnabled()) { 1278 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_SHUTDOWN_1, this.getClass().getName())); 1279 } 1280 } 1281 1282 /** 1283 * Gets the template name for a template resource, using a cache for efficiency.<p> 1284 * 1285 * @param cms the current CMS context 1286 * @param resource the template resource 1287 * @return the template name 1288 * 1289 * @throws CmsException if something goes wrong 1290 */ 1291 private String getTemplateName(CmsObject cms, CmsResource resource) throws CmsException { 1292 1293 String templateName = (String)(m_templateNameCache.getCachedObject(cms, resource.getRootPath())); 1294 if (templateName == null) { 1295 CmsProperty nameProperty = cms.readPropertyObject( 1296 resource, 1297 CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS, 1298 false); 1299 String nameFromProperty = ""; 1300 if (!nameProperty.isNullProperty()) { 1301 nameFromProperty = nameProperty.getValue(); 1302 } 1303 m_templateNameCache.putCachedObject(cms, resource.getRootPath(), nameFromProperty); 1304 return nameFromProperty; 1305 } else { 1306 return templateName; 1307 } 1308 } 1309 1310 /** 1311 * Initialize the HTML converters.<p> 1312 * 1313 * HTML converters are configured in the OpenCms <code>opencms-vfs.xml</code> configuration file.<p> 1314 * 1315 * For legacy reasons, the default JTidy HTML converter has to be loaded if no explicit HTML converters 1316 * are configured in the configuration file.<p> 1317 */ 1318 private void initHtmlConverters() { 1319 1320 // check if any HTML converter configuration were found 1321 if (m_configuredHtmlConverters.size() == 0) { 1322 // no converters configured, add default JTidy converter configuration 1323 String classJTidy = CmsHtmlConverterJTidy.class.getName(); 1324 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_ENABLED, classJTidy, true)); 1325 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_XHTML, classJTidy, true)); 1326 m_configuredHtmlConverters.add(new CmsHtmlConverterOption(CmsHtmlConverter.PARAM_WORD, classJTidy, true)); 1327 m_configuredHtmlConverters.add(new CmsHtmlConverterOption( 1328 CmsHtmlConverter.PARAM_REPLACE_PARAGRAPHS, 1329 classJTidy, 1330 true)); 1331 } 1332 1333 // initialize lookup map of configured HTML converters 1334 m_htmlConverters = new HashMap<String, String>(m_configuredHtmlConverters.size()); 1335 for (Iterator<CmsHtmlConverterOption> i = m_configuredHtmlConverters.iterator(); i.hasNext();) { 1336 CmsHtmlConverterOption converterOption = i.next(); 1337 m_htmlConverters.put(converterOption.getName(), converterOption.getClassName()); 1338 } 1339 } 1340 1341 /** 1342 * Initialize the MIME types.<p> 1343 * 1344 * MIME types are configured in the OpenCms <code>opencms-vfs.xml</code> configuration file.<p> 1345 * 1346 * For legacy reasons, the MIME types are also read from a file <code>"mimetypes.properties"</code> 1347 * that must be located in the default <code>"classes"</code> folder of the web application.<p> 1348 */ 1349 private void initMimeTypes() { 1350 1351 // legacy MIME type initialization: try to read properties file 1352 Properties mimeTypes = new Properties(); 1353 try { 1354 // first try: read MIME types from default package 1355 mimeTypes.load(getClass().getClassLoader().getResourceAsStream("mimetypes.properties")); 1356 } catch (Throwable t) { 1357 try { 1358 // second try: read MIME types from loader package (legacy reasons, there are no types by default) 1359 mimeTypes.load(getClass().getClassLoader().getResourceAsStream( 1360 "org/opencms/loader/mimetypes.properties")); 1361 } catch (Throwable t2) { 1362 if (LOG.isInfoEnabled()) { 1363 LOG.info(Messages.get().getBundle().key( 1364 Messages.LOG_READ_MIMETYPES_FAILED_2, 1365 "mimetypes.properties", 1366 "org/opencms/loader/mimetypes.properties")); 1367 } 1368 } 1369 } 1370 1371 // initialize the Map with all available MIME types 1372 List<CmsMimeType> combinedMimeTypes = new ArrayList<CmsMimeType>(mimeTypes.size() 1373 + m_configuredMimeTypes.size()); 1374 // first add all MIME types from the configuration 1375 combinedMimeTypes.addAll(m_configuredMimeTypes); 1376 // now add the MIME types from the properties 1377 Iterator<Map.Entry<Object, Object>> i = mimeTypes.entrySet().iterator(); 1378 while (i.hasNext()) { 1379 Map.Entry<Object, Object> entry = i.next(); 1380 CmsMimeType mimeType = new CmsMimeType(entry.getKey().toString(), entry.getValue().toString(), false); 1381 if (!combinedMimeTypes.contains(mimeType)) { 1382 // make sure no MIME types from the XML configuration are overwritten 1383 combinedMimeTypes.add(mimeType); 1384 } 1385 } 1386 1387 // create a lookup Map for the MIME types 1388 m_mimeTypes = new HashMap<String, String>(mimeTypes.size()); 1389 Iterator<CmsMimeType> j = combinedMimeTypes.iterator(); 1390 while (j.hasNext()) { 1391 CmsMimeType mimeType = j.next(); 1392 m_mimeTypes.put(mimeType.getExtension(), mimeType.getType()); 1393 } 1394 1395 if (CmsLog.INIT.isInfoEnabled()) { 1396 CmsLog.INIT.info(Messages.get().getBundle().key( 1397 Messages.INIT_NUM_MIMETYPES_1, 1398 new Integer(m_mimeTypes.size()))); 1399 } 1400 } 1401 1402 /** 1403 * Adds a new resource type to the internal list of loaded resource types and initializes 1404 * options for the resource type.<p> 1405 * 1406 * @param resourceType the resource type to add 1407 * @param configuration the resource configuration 1408 */ 1409 private synchronized void initResourceType( 1410 I_CmsResourceType resourceType, 1411 CmsResourceManagerConfiguration configuration) { 1412 1413 // add the loader to the internal list of loaders 1414 configuration.addResourceType(resourceType); 1415 if (CmsLog.INIT.isInfoEnabled()) { 1416 CmsLog.INIT.info(Messages.get().getBundle().key( 1417 Messages.INIT_ADD_RESTYPE_3, 1418 resourceType.getTypeName(), 1419 new Integer(resourceType.getTypeId()), 1420 resourceType.getClass().getName())); 1421 } 1422 1423 // add the mappings 1424 List<String> mappings = resourceType.getConfiguredMappings(); 1425 Iterator<String> i = mappings.iterator(); 1426 while (i.hasNext()) { 1427 String mapping = i.next(); 1428 // only add this mapping if a mapping with this file extension does not 1429 // exist already 1430 if (!configuration.m_extensionMappings.containsKey(mapping)) { 1431 configuration.m_extensionMappings.put(mapping, resourceType.getTypeName()); 1432 if (CmsLog.INIT.isInfoEnabled()) { 1433 CmsLog.INIT.info(Messages.get().getBundle().key( 1434 Messages.INIT_MAP_RESTYPE_2, 1435 mapping, 1436 resourceType.getTypeName())); 1437 } 1438 } 1439 } 1440 } 1441 1442 /** 1443 * Initializes member variables required for storing the resource types.<p> 1444 * 1445 * @throws CmsConfigurationException in case of duplicate resource types in the configuration 1446 */ 1447 private synchronized void initResourceTypes() throws CmsConfigurationException { 1448 1449 if (CmsLog.INIT.isInfoEnabled()) { 1450 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_STARTING_LOADER_CONFIG_0)); 1451 } 1452 1453 CmsResourceManagerConfiguration newConfiguration = new CmsResourceManagerConfiguration(); 1454 1455 if (CmsLog.INIT.isInfoEnabled()) { 1456 CmsLog.INIT.info(Messages.get().getBundle().key( 1457 Messages.INIT_ADD_RESTYPE_FROM_FILE_2, 1458 new Integer(m_resourceTypesFromXml.size()), 1459 CmsVfsConfiguration.DEFAULT_XML_FILE_NAME)); 1460 } 1461 1462 // build a new resource type list from the resource types of the XML configuration 1463 Iterator<I_CmsResourceType> i; 1464 i = m_resourceTypesFromXml.iterator(); 1465 while (i.hasNext()) { 1466 I_CmsResourceType resourceType = i.next(); 1467 initResourceType(resourceType, newConfiguration); 1468 } 1469 1470 // add all resource types declared in the modules 1471 CmsModuleManager moduleManager = OpenCms.getModuleManager(); 1472 if (moduleManager != null) { 1473 Iterator<String> modules = moduleManager.getModuleNames().iterator(); 1474 while (modules.hasNext()) { 1475 CmsModule module = moduleManager.getModule(modules.next()); 1476 if ((module != null) && (module.getResourceTypes().size() > 0)) { 1477 // module contains resource types 1478 if (CmsLog.INIT.isInfoEnabled()) { 1479 CmsLog.INIT.info(Messages.get().getBundle().key( 1480 Messages.INIT_ADD_NUM_RESTYPES_FROM_MOD_2, 1481 new Integer(module.getResourceTypes().size()), 1482 module.getName())); 1483 } 1484 1485 Iterator<I_CmsResourceType> j = module.getResourceTypes().iterator(); 1486 while (j.hasNext()) { 1487 I_CmsResourceType resourceType = j.next(); 1488 I_CmsResourceType conflictingType = null; 1489 if (resourceType.getTypeId() == CmsResourceTypeUnknownFile.RESOURCE_TYPE_ID) { 1490 // default unknown file resource type 1491 if (m_restypeUnknownFile != null) { 1492 // error: already set 1493 conflictingType = m_restypeUnknownFile; 1494 } else { 1495 m_restypeUnknownFile = resourceType; 1496 continue; 1497 } 1498 } else if (resourceType.getTypeId() == CmsResourceTypeUnknownFolder.RESOURCE_TYPE_ID) { 1499 // default unknown folder resource type 1500 if (m_restypeUnknownFolder != null) { 1501 // error: already set 1502 conflictingType = m_restypeUnknownFolder; 1503 } else { 1504 m_restypeUnknownFile = resourceType; 1505 continue; 1506 } 1507 } else { 1508 // normal resource types 1509 conflictingType = newConfiguration.getResourceTypeById(resourceType.getTypeId()); 1510 } 1511 if (conflictingType != null) { 1512 throw new CmsConfigurationException(Messages.get().container( 1513 Messages.ERR_CONFLICTING_MODULE_RESOURCE_TYPES_5, 1514 new Object[] { 1515 resourceType.getTypeName(), 1516 new Integer(resourceType.getTypeId()), 1517 module.getName(), 1518 conflictingType.getTypeName(), 1519 new Integer(conflictingType.getTypeId())})); 1520 } 1521 initResourceType(resourceType, newConfiguration); 1522 } 1523 } 1524 } 1525 } 1526 1527 // freeze the current configuration 1528 newConfiguration.freeze(m_restypeUnknownFile, m_restypeUnknownFile); 1529 m_configuration = newConfiguration; 1530 m_frozen = true; 1531 1532 if (CmsLog.INIT.isInfoEnabled()) { 1533 CmsLog.INIT.info(Messages.get().getBundle().key(Messages.INIT_RESOURCE_TYPE_INITIALIZED_0)); 1534 } 1535 } 1536 1537 /** 1538 * Reads a template resource together with its name.<p> 1539 * 1540 * @param cms the current CMS context 1541 * @param path the template path 1542 * 1543 * @return the template together with its name, or null if the template couldn't be read 1544 */ 1545 private NamedTemplate readTemplateWithName(CmsObject cms, String path) { 1546 1547 try { 1548 CmsResource resource = cms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION); 1549 String name = getTemplateName(cms, resource); 1550 return new NamedTemplate(resource, name); 1551 } catch (Exception e) { 1552 return null; 1553 } 1554 } 1555 1556}