001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: http://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: http://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.file.wrapper; 029 030import org.opencms.file.CmsFile; 031import org.opencms.file.CmsObject; 032import org.opencms.file.CmsProperty; 033import org.opencms.file.CmsRequestContext; 034import org.opencms.file.CmsResource; 035import org.opencms.file.CmsResource.CmsResourceCopyMode; 036import org.opencms.file.CmsResource.CmsResourceDeleteMode; 037import org.opencms.file.CmsResourceFilter; 038import org.opencms.file.CmsUser; 039import org.opencms.file.I_CmsResource; 040import org.opencms.file.types.CmsResourceTypeJsp; 041import org.opencms.file.types.CmsResourceTypePlain; 042import org.opencms.file.types.CmsResourceTypeXmlContent; 043import org.opencms.file.types.CmsResourceTypeXmlPage; 044import org.opencms.file.types.I_CmsResourceType; 045import org.opencms.i18n.CmsEncoder; 046import org.opencms.i18n.CmsLocaleManager; 047import org.opencms.loader.CmsLoaderException; 048import org.opencms.lock.CmsLock; 049import org.opencms.main.CmsException; 050import org.opencms.main.CmsIllegalArgumentException; 051import org.opencms.main.CmsLog; 052import org.opencms.main.OpenCms; 053import org.opencms.util.CmsUUID; 054 055import java.util.ArrayList; 056import java.util.Collections; 057import java.util.Iterator; 058import java.util.List; 059 060import org.apache.commons.logging.Log; 061 062/** 063 * This class contains a subset of the methods of {@link CmsObject} and uses the 064 * configured resource wrappers ({@link I_CmsResourceWrapper}) to change the view 065 * to the existing resources in the VFS.<p> 066 * 067 * Almost every method in this class iterates through the configured list of 068 * {@link I_CmsResourceWrapper} and calls the same method there. The first resource 069 * wrapper in the list which feels responsible for that action handles it and the 070 * iteration ends. So the resource wrappers should check in every method if it is 071 * responsible or not. Be careful if there are more than one resource wrapper for 072 * the same resource in the VFS, because the first in the list wins. If the iteration is 073 * finished and no resource wrapper felt responsible the default action is to call the 074 * method in the {@link CmsObject}.<p> 075 * 076 * It is possible to create an unchanged access to the resource in the VFS by creating 077 * a new instance of the CmsObjectWrapper with an empty list of resource wrappers.<p> 078 * 079 * @since 6.2.4 080 */ 081public class CmsObjectWrapper { 082 083 /** The name of the attribute in the {@link CmsRequestContext} where the current CmsObjectWrapper can be found. */ 084 public static final String ATTRIBUTE_NAME = "org.opencms.file.wrapper.CmsObjectWrapper"; 085 086 /** The log object for this class. */ 087 private static final Log LOG = CmsLog.getLog(CmsObjectWrapper.class); 088 089 /** Flag to contro whether byte order marks should be added to plaintext files. */ 090 private boolean m_addByteOrderMark = true; 091 092 /** The initialized CmsObject. */ 093 private CmsObject m_cms; 094 095 /** The list with the configured wrappers (entries of type {@link I_CmsResourceWrapper}). */ 096 private List<I_CmsResourceWrapper> m_wrappers; 097 098 /** 099 * Constructor with the CmsObject to wrap and the resource wrappers to use.<p> 100 * 101 * @param cms the initialized CmsObject 102 * @param wrappers the configured wrappers to use (entries of type {@link I_CmsResourceWrapper}) 103 */ 104 public CmsObjectWrapper(CmsObject cms, List<I_CmsResourceWrapper> wrappers) { 105 106 m_cms = cms; 107 m_wrappers = wrappers; 108 } 109 110 /** 111 * Copies a resource.<p> 112 * 113 * Iterates through all configured resource wrappers till the first returns <code>true</code>.<p> 114 * 115 * @see I_CmsResourceWrapper#copyResource(CmsObject, String, String, CmsResource.CmsResourceCopyMode) 116 * @see CmsObject#copyResource(String, String, CmsResource.CmsResourceCopyMode) 117 * 118 * @param source the name of the resource to copy (full path) 119 * @param destination the name of the copy destination (full path) 120 * @param siblingMode indicates how to handle siblings during copy 121 * 122 * @throws CmsException if something goes wrong 123 * @throws CmsIllegalArgumentException if the <code>destination</code> argument is null or of length 0 124 */ 125 public void copyResource(String source, String destination, CmsResourceCopyMode siblingMode) 126 throws CmsException, CmsIllegalArgumentException { 127 128 boolean exec = false; 129 130 // iterate through all wrappers and call "copyResource" till one does not return null 131 List<I_CmsResourceWrapper> wrappers = getWrappers(); 132 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 133 while (iter.hasNext()) { 134 I_CmsResourceWrapper wrapper = iter.next(); 135 exec = wrapper.copyResource(m_cms, source, destination, siblingMode); 136 if (exec) { 137 break; 138 } 139 } 140 141 // delegate the call to the CmsObject 142 if (!exec) { 143 m_cms.copyResource(source, destination, siblingMode); 144 } 145 146 } 147 148 /** 149 * Creates a new resource of the given resource type with empty content and no properties.<p> 150 * 151 * @see #createResource(String, int, byte[], List) 152 * 153 * @param resourcename the name of the resource to create (full path) 154 * @param type the type of the resource to create 155 * 156 * @return the created resource 157 * 158 * @throws CmsException if something goes wrong 159 * @throws CmsIllegalArgumentException if the given <code>resourcename</code> is null or of length 0 160 */ 161 public CmsResource createResource(String resourcename, int type) throws CmsException, CmsIllegalArgumentException { 162 163 return createResource(resourcename, type, new byte[0], new ArrayList<CmsProperty>(0)); 164 } 165 166 /** 167 * Creates a new resource of the given resource type with the provided content and properties.<p> 168 * 169 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 170 * 171 * @see I_CmsResourceWrapper#createResource(CmsObject, String, int, byte[], List) 172 * @see CmsObject#createResource(String, int, byte[], List) 173 * 174 * @param resourcename the name of the resource to create (full path) 175 * @param type the type of the resource to create 176 * @param content the contents for the new resource 177 * @param properties the properties for the new resource 178 * 179 * @return the created resource 180 * 181 * @throws CmsException if something goes wrong 182 * @throws CmsIllegalArgumentException if the <code>resourcename</code> argument is null or of length 0 183 */ 184 public CmsResource createResource(String resourcename, int type, byte[] content, List<CmsProperty> properties) 185 throws CmsException, CmsIllegalArgumentException { 186 187 CmsResource res = null; 188 189 // iterate through all wrappers and call "createResource" till one does not return null 190 List<I_CmsResourceWrapper> wrappers = getWrappers(); 191 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 192 while (iter.hasNext()) { 193 I_CmsResourceWrapper wrapper = iter.next(); 194 res = wrapper.createResource(m_cms, resourcename, type, content, properties); 195 if (res != null) { 196 break; 197 } 198 } 199 200 // delegate the call to the CmsObject 201 if (res == null) { 202 res = m_cms.createResource(resourcename, type, content, properties); 203 } 204 205 return res; 206 } 207 208 /** 209 * Deletes a resource given its name.<p> 210 * 211 * Iterates through all configured resource wrappers till the first returns <code>true</code>.<p> 212 * 213 * @see I_CmsResourceWrapper#deleteResource(CmsObject, String, CmsResource.CmsResourceDeleteMode) 214 * @see CmsObject#deleteResource(String, CmsResource.CmsResourceDeleteMode) 215 * 216 * @param resourcename the name of the resource to delete (full path) 217 * @param siblingMode indicates how to handle siblings of the deleted resource 218 * 219 * @throws CmsException if something goes wrong 220 */ 221 public void deleteResource(String resourcename, CmsResourceDeleteMode siblingMode) throws CmsException { 222 223 boolean exec = false; 224 225 // iterate through all wrappers and call "deleteResource" till one does not return false 226 List<I_CmsResourceWrapper> wrappers = getWrappers(); 227 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 228 while (iter.hasNext()) { 229 I_CmsResourceWrapper wrapper = iter.next(); 230 exec = wrapper.deleteResource(m_cms, resourcename, siblingMode); 231 if (exec) { 232 break; 233 } 234 } 235 236 // delegate the call to the CmsObject 237 if (!exec) { 238 m_cms.deleteResource(resourcename, siblingMode); 239 } 240 } 241 242 /** 243 * Checks the availability of a resource in the VFS, 244 * using the {@link CmsResourceFilter#DEFAULT} filter.<p> 245 * 246 * Here it will be first checked if the resource exists in the VFS by calling 247 * {@link org.opencms.file.CmsObject#existsResource(String)}. Only if it doesn't exist 248 * in the VFS the method {@link I_CmsResourceWrapper#readResource(CmsObject, String, CmsResourceFilter)} 249 * in the configured resource wrappers are called till the first does not throw an exception or returns 250 * <code>null</code>.<p> 251 * 252 * @param resourcename the name of the resource to check (full path) 253 * 254 * @return <code>true</code> if the resource is available 255 */ 256 public boolean existsResource(String resourcename) { 257 258 // first try to find the resource 259 boolean ret = m_cms.existsResource(resourcename); 260 261 // if not exists, ask the resource type wrappers 262 if (!ret) { 263 264 List<I_CmsResourceWrapper> wrappers = getWrappers(); 265 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 266 while (iter.hasNext()) { 267 I_CmsResourceWrapper wrapper = iter.next(); 268 try { 269 CmsResource res = wrapper.readResource(m_cms, resourcename, CmsResourceFilter.DEFAULT); 270 if (res != null) { 271 ret = true; 272 break; 273 } 274 } catch (CmsException ex) { 275 // noop 276 } 277 } 278 279 } 280 281 return ret; 282 } 283 284 /** 285 * Returns the lock state for a specified resource.<p> 286 * 287 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 288 * 289 * @see I_CmsResourceWrapper#getLock(CmsObject, CmsResource) 290 * @see CmsObject#getLock(CmsResource) 291 * 292 * @param resource the resource to return the lock state for 293 * 294 * @return the lock state for the specified resource 295 * 296 * @throws CmsException if something goes wrong 297 */ 298 public CmsLock getLock(CmsResource resource) throws CmsException { 299 300 CmsLock lock = null; 301 302 // iterate through all wrappers and call "getLock" till one does not return null 303 List<I_CmsResourceWrapper> wrappers = getWrappers(); 304 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 305 while (iter.hasNext()) { 306 I_CmsResourceWrapper wrapper = iter.next(); 307 lock = wrapper.getLock(m_cms, resource); 308 if (lock != null) { 309 break; 310 } 311 } 312 313 // delegate the call to the CmsObject 314 if (lock == null) { 315 lock = m_cms.getLock(resource); 316 } 317 318 return lock; 319 } 320 321 /** 322 * Delegate method for {@link CmsObject#getRequestContext()}.<p> 323 * 324 * @see CmsObject#getRequestContext() 325 326 * @return the current users request context 327 */ 328 public CmsRequestContext getRequestContext() { 329 330 return m_cms.getRequestContext(); 331 } 332 333 /** 334 * Returns all child resources of a resource, that is the resources 335 * contained in a folder.<p> 336 * 337 * First fetch all child resources from VFS by calling {@link CmsObject#getResourcesInFolder(String, CmsResourceFilter)}. 338 * After that all resource wrapper are called {@link I_CmsResourceWrapper#addResourcesToFolder(CmsObject, String, CmsResourceFilter)} 339 * to have the chance to add additional resources to those already existing. In that list every resource is given to 340 * the appropriate resource wrapper ({@link I_CmsResourceWrapper#wrapResource(CmsObject, CmsResource)}) to have the 341 * possibility to change the existing resources. The matching resource wrapper for a resource is found by a call to 342 * {@link I_CmsResourceWrapper#isWrappedResource(CmsObject, CmsResource)}.<p> 343 * 344 * @see I_CmsResourceWrapper#addResourcesToFolder(CmsObject, String, CmsResourceFilter) 345 * @see CmsObject#getResourcesInFolder(String, CmsResourceFilter) 346 * 347 * @param resourcename the full path of the resource to return the child resources for 348 * @param filter the resource filter to use 349 * 350 * @return a list of all child <code>{@link CmsResource}</code>s 351 * 352 * @throws CmsException if something goes wrong 353 */ 354 public List<CmsResource> getResourcesInFolder(String resourcename, CmsResourceFilter filter) throws CmsException { 355 356 List<CmsResource> list = new ArrayList<CmsResource>(); 357 358 // read children existing in the VFS 359 try { 360 list.addAll(m_cms.getResourcesInFolder(resourcename, filter)); 361 } catch (CmsException ex) { 362 //noop 363 } 364 365 // iterate through all wrappers and call "addResourcesToFolder" and add the results to the list 366 List<I_CmsResourceWrapper> wrappers = getWrappers(); 367 Iterator<I_CmsResourceWrapper> iter1 = wrappers.iterator(); 368 while (iter1.hasNext()) { 369 I_CmsResourceWrapper wrapper = iter1.next(); 370 List<CmsResource> added = wrapper.addResourcesToFolder(m_cms, resourcename, filter); 371 if (added != null) { 372 list.addAll(added); 373 } 374 } 375 376 // create a new list to add all resources 377 ArrayList<CmsResource> wrapped = new ArrayList<CmsResource>(); 378 379 // eventually wrap the found resources 380 Iterator<CmsResource> iter2 = list.iterator(); 381 while (iter2.hasNext()) { 382 CmsResource res = iter2.next(); 383 384 // correct the length of the content if an UTF-8 marker would be added later 385 if (needUtf8Marker(res) && !startsWithUtf8Marker(res)) { 386 CmsWrappedResource wrap = new CmsWrappedResource(res); 387 wrap.setLength(res.getLength() + CmsResourceWrapperUtils.UTF8_MARKER.length); 388 389 res = wrap.getResource(); 390 } 391 392 // get resource type wrapper for the resource 393 I_CmsResourceWrapper resWrapper = getResourceTypeWrapper(res); 394 395 if (resWrapper != null) { 396 397 // adds the wrapped resources 398 wrapped.add(resWrapper.wrapResource(m_cms, res)); 399 } else { 400 401 // add the resource unwrapped 402 wrapped.add(res); 403 } 404 } 405 406 // sort the wrapped list correctly 407 Collections.sort(wrapped, I_CmsResource.COMPARE_ROOT_PATH_IGNORE_CASE_FOLDERS_FIRST); 408 409 return wrapped; 410 } 411 412 /** 413 * Delegate method for {@link CmsObject#getSitePath(CmsResource)}.<p> 414 * 415 * @see CmsObject#getSitePath(org.opencms.file.CmsResource) 416 * 417 * @param resource the resource to get the adjusted site root path for 418 * 419 * @return the absolute resource path adjusted for the current site 420 */ 421 public String getSitePath(CmsResource resource) { 422 423 return m_cms.getSitePath(resource); 424 } 425 426 /** 427 * Returns the configured resource wrappers used by this instance.<p> 428 * 429 * Entries in list are from type {@link I_CmsResourceWrapper}.<p> 430 * 431 * @return the configured resource wrappers for this instance 432 */ 433 public List<I_CmsResourceWrapper> getWrappers() { 434 435 return m_wrappers; 436 } 437 438 /** 439 * Locks a resource.<p> 440 * 441 * Iterates through all configured resource wrappers till the first returns <code>true</code>.<p> 442 * 443 * @see CmsObject#lockResource(String) 444 * 445 * @param resourcename the name of the resource to lock (full path) 446 * 447 * @throws CmsException if something goes wrong 448 */ 449 public void lockResource(String resourcename) throws CmsException { 450 451 boolean exec = false; 452 453 // iterate through all wrappers and call "lockResource" till one does not return false 454 List<I_CmsResourceWrapper> wrappers = getWrappers(); 455 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 456 while (iter.hasNext()) { 457 I_CmsResourceWrapper wrapper = iter.next(); 458 exec = wrapper.lockResource(m_cms, resourcename, false); 459 if (exec) { 460 break; 461 } 462 } 463 464 // delegate the call to the CmsObject 465 if (!exec) { 466 m_cms.lockResource(resourcename); 467 } 468 } 469 470 /** 471 * Locks a resource temporarily.<p> 472 * 473 * @param resourceName the name of the resource to lock 474 * 475 * @throws CmsException if something goes wrong 476 */ 477 public void lockResourceTemporary(String resourceName) throws CmsException { 478 479 boolean exec = false; 480 // iterate through all wrappers and call "lockResource" till one does not return false 481 List<I_CmsResourceWrapper> wrappers = getWrappers(); 482 for (I_CmsResourceWrapper wrapper : wrappers) { 483 exec = wrapper.lockResource(m_cms, resourceName, true); 484 if (exec) { 485 break; 486 } 487 } 488 489 // delegate the call to the CmsObject 490 if (!exec) { 491 m_cms.lockResourceTemporary(resourceName); 492 } 493 } 494 495 /** 496 * Moves a resource to the given destination.<p> 497 * 498 * Iterates through all configured resource wrappers till the first returns <code>true</code>.<p> 499 * 500 * @see I_CmsResourceWrapper#moveResource(CmsObject, String, String) 501 * @see CmsObject#moveResource(String, String) 502 * 503 * @param source the name of the resource to move (full path) 504 * @param destination the destination resource name (full path) 505 * 506 * @throws CmsException if something goes wrong 507 */ 508 public void moveResource(String source, String destination) throws CmsException { 509 510 boolean exec = false; 511 512 // iterate through all wrappers and call "moveResource" till one does not return false 513 List<I_CmsResourceWrapper> wrappers = getWrappers(); 514 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 515 while (iter.hasNext()) { 516 I_CmsResourceWrapper wrapper = iter.next(); 517 exec = wrapper.moveResource(m_cms, source, destination); 518 if (exec) { 519 break; 520 } 521 } 522 523 // delegate the call to the CmsObject 524 if (!exec) { 525 m_cms.moveResource(source, destination); 526 } 527 } 528 529 /** 530 * Reads a file resource (including it's binary content) from the VFS, 531 * using the specified resource filter.<p> 532 * 533 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 534 * 535 * If the resource contains textual content and the encoding is UTF-8, then the byte order mask 536 * for UTF-8 is added at the start of the content to make sure that a client using this content 537 * displays it correctly.<p> 538 * 539 * @see I_CmsResourceWrapper#readFile(CmsObject, String, CmsResourceFilter) 540 * @see CmsObject#readFile(String, CmsResourceFilter) 541 * 542 * @param resourcename the name of the resource to read (full path) 543 * @param filter the resource filter to use while reading 544 * 545 * @return the file resource that was read 546 * 547 * @throws CmsException if the file resource could not be read for any reason 548 */ 549 public CmsFile readFile(String resourcename, CmsResourceFilter filter) throws CmsException { 550 551 CmsFile res = null; 552 553 // iterate through all wrappers and call "readFile" till one does not return null 554 List<I_CmsResourceWrapper> wrappers = getWrappers(); 555 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 556 while (iter.hasNext()) { 557 I_CmsResourceWrapper wrapper = iter.next(); 558 res = wrapper.readFile(m_cms, resourcename, filter); 559 if (res != null) { 560 break; 561 } 562 } 563 564 // delegate the call to the CmsObject 565 if (res == null) { 566 res = m_cms.readFile(resourcename, filter); 567 } 568 569 // for text based resources which are encoded in UTF-8 add the UTF marker at the start 570 // of the content 571 if (needUtf8Marker(res)) { 572 573 if (LOG.isDebugEnabled()) { 574 LOG.debug(Messages.get().getBundle().key(Messages.LOG_ADD_UTF8_MARKER_1, res.getRootPath())); 575 } 576 577 res.setContents(CmsResourceWrapperUtils.addUtf8Marker(res.getContents())); 578 } 579 580 return res; 581 } 582 583 /** 584 * Delegate method for {@link CmsObject#readPropertyObject(CmsResource, String, boolean)}.<p> 585 * 586 * @see CmsObject#readPropertyObject(CmsResource, String, boolean) 587 * 588 * @param resource the resource where the property is attached to 589 * @param property the property name 590 * @param search if true, the property is searched on all parent folders of the resource, 591 * if it's not found attached directly to the resource 592 * 593 * @return the required property, or <code>{@link CmsProperty#getNullProperty()}</code> if the property was not found 594 * 595 * @throws CmsException if something goes wrong 596 */ 597 public CmsProperty readPropertyObject(CmsResource resource, String property, boolean search) throws CmsException { 598 599 return m_cms.readPropertyObject(resource, property, search); 600 } 601 602 /** 603 * Delegate method for {@link CmsObject#readResource(CmsUUID, CmsResourceFilter)}.<p> 604 * 605 * @see CmsObject#readResource(CmsUUID, CmsResourceFilter) 606 * 607 * @param structureID the ID of the structure to read 608 * @param filter the resource filter to use while reading 609 * 610 * @return the resource that was read 611 * 612 * @throws CmsException if the resource could not be read for any reason 613 */ 614 public CmsResource readResource(CmsUUID structureID, CmsResourceFilter filter) throws CmsException { 615 616 return m_cms.readResource(structureID, filter); 617 } 618 619 /** 620 * Reads a resource from the VFS, 621 * using the <code>{@link CmsResourceFilter#DEFAULT}</code> filter.<p> 622 * 623 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 624 * 625 * @see I_CmsResourceWrapper#readResource(CmsObject, String, CmsResourceFilter) 626 * @see CmsObject#readResource(String, CmsResourceFilter) 627 * 628 * @param resourcename The name of the resource to read (full path) 629 * @param filter the resource filter to use while reading 630 * 631 * @return the resource that was read 632 * 633 * @throws CmsException if the resource could not be read for any reason 634 */ 635 public CmsResource readResource(String resourcename, CmsResourceFilter filter) throws CmsException { 636 637 CmsResource res = null; 638 639 // iterate through all wrappers and call "readResource" till one does not return null 640 List<I_CmsResourceWrapper> wrappers = getWrappers(); 641 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 642 while (iter.hasNext()) { 643 I_CmsResourceWrapper wrapper = iter.next(); 644 res = wrapper.readResource(m_cms, resourcename, filter); 645 if (res != null) { 646 break; 647 } 648 } 649 650 // delegate the call to the CmsObject 651 if (res == null) { 652 res = m_cms.readResource(resourcename, filter); 653 } 654 655 // correct the length of the content if an UTF-8 marker would be added later 656 if (needUtf8Marker(res) && !startsWithUtf8Marker(res)) { 657 CmsWrappedResource wrap = new CmsWrappedResource(res); 658 wrap.setLength(res.getLength() + CmsResourceWrapperUtils.UTF8_MARKER.length); 659 660 return wrap.getResource(); 661 } 662 663 return res; 664 } 665 666 /** 667 * Delegate method for {@link CmsObject#readUser(CmsUUID)}.<p> 668 * 669 * @see CmsObject#readUser(CmsUUID) 670 * 671 * @param userId the id of the user to be read 672 * 673 * @return the user with the given id 674 * 675 * @throws CmsException if something goes wrong 676 */ 677 public CmsUser readUser(CmsUUID userId) throws CmsException { 678 679 return m_cms.readUser(userId); 680 } 681 682 /** 683 * Returns a link to an existing resource in the VFS.<p> 684 * 685 * Because it is possible through the <code>CmsObjectWrapper</code> to create "virtual" resources, 686 * which can not be found in the VFS, it is necessary to change the links in pages 687 * as well, so that they point to resources which really exists in the VFS.<p> 688 * 689 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 690 * 691 * @see #rewriteLink(String) 692 * @see I_CmsResourceWrapper#restoreLink(CmsObject, String) 693 * 694 * @param path the path to the resource 695 * 696 * @return the path for the resource which exists in the VFS 697 */ 698 public String restoreLink(String path) { 699 700 if ((path != null) && (path.startsWith("#"))) { 701 return path; 702 } 703 704 String ret = null; 705 706 // iterate through all wrappers and call "restoreLink" till one does not return null 707 List<I_CmsResourceWrapper> wrappers = getWrappers(); 708 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 709 while (iter.hasNext()) { 710 I_CmsResourceWrapper wrapper = iter.next(); 711 ret = wrapper.restoreLink(m_cms, m_cms.getRequestContext().removeSiteRoot(path)); 712 if (ret != null) { 713 return ret; 714 } 715 } 716 717 return path; 718 } 719 720 /** 721 * Returns a link to a resource after it was wrapped by the CmsObjectWrapper.<p> 722 * 723 * Because it is possible to change the names of resources inside the VFS by this 724 * <code>CmsObjectWrapper</code>, it is necessary to change the links used in pages 725 * as well, so that they point to the changed name of the resource.<p> 726 * 727 * For example: <code>/sites/default/index.html</code> becomes to 728 * <code>/sites/default/index.html.jsp</code>, because it is a jsp page, the links 729 * in pages where corrected so that they point to the new name (with extension "jsp").<p> 730 * 731 * Used for the link processing in the class {@link org.opencms.relations.CmsLink}.<p> 732 * 733 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 734 * 735 * @see #restoreLink(String) 736 * @see I_CmsResourceWrapper#rewriteLink(CmsObject, CmsResource) 737 * 738 * @param path the full path where to find the resource 739 * 740 * @return the rewritten link for the resource 741 */ 742 public String rewriteLink(String path) { 743 744 CmsResource res = null; 745 746 try { 747 res = readResource(m_cms.getRequestContext().removeSiteRoot(path), CmsResourceFilter.ALL); 748 if (res != null) { 749 String ret = null; 750 751 // iterate through all wrappers and call "rewriteLink" till one does not return null 752 List<I_CmsResourceWrapper> wrappers = getWrappers(); 753 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 754 while (iter.hasNext()) { 755 I_CmsResourceWrapper wrapper = iter.next(); 756 ret = wrapper.rewriteLink(m_cms, res); 757 if (ret != null) { 758 return ret; 759 } 760 } 761 } 762 } catch (CmsException ex) { 763 // noop 764 } 765 766 return path; 767 } 768 769 /** 770 * Enables or disables the automatic adding of byte order marks to plaintext files.<p> 771 * 772 * @param addByteOrderMark true if byte order marks should be added to plaintext files automatically 773 */ 774 public void setAddByteOrderMark(boolean addByteOrderMark) { 775 776 m_addByteOrderMark = addByteOrderMark; 777 } 778 779 /** 780 * Unlocks a resource.<p> 781 * 782 * Iterates through all configured resource wrappers till the first returns <code>true</code>.<p> 783 * 784 * @see I_CmsResourceWrapper#unlockResource(CmsObject, String) 785 * @see CmsObject#unlockResource(String) 786 * 787 * @param resourcename the name of the resource to unlock (full path) 788 * 789 * @throws CmsException if something goes wrong 790 */ 791 public void unlockResource(String resourcename) throws CmsException { 792 793 boolean exec = false; 794 795 // iterate through all wrappers and call "lockResource" till one does not return false 796 List<I_CmsResourceWrapper> wrappers = getWrappers(); 797 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 798 while (iter.hasNext()) { 799 I_CmsResourceWrapper wrapper = iter.next(); 800 exec = wrapper.unlockResource(m_cms, resourcename); 801 if (exec) { 802 break; 803 } 804 } 805 806 // delegate the call to the CmsObject 807 if (!exec) { 808 m_cms.unlockResource(resourcename); 809 } 810 } 811 812 /** 813 * Writes a resource to the OpenCms VFS, including it's content.<p> 814 * 815 * Iterates through all configured resource wrappers till the first returns not <code>null</code>.<p> 816 * 817 * @see I_CmsResourceWrapper#writeFile(CmsObject, CmsFile) 818 * @see CmsObject#writeFile(CmsFile) 819 * 820 * @param resource the resource to write 821 * 822 * @return the written resource (may have been modified) 823 * 824 * @throws CmsException if something goes wrong 825 */ 826 public CmsFile writeFile(CmsFile resource) throws CmsException { 827 828 CmsFile res = null; 829 830 // remove the added UTF-8 marker 831 if (needUtf8Marker(resource)) { 832 resource.setContents(CmsResourceWrapperUtils.removeUtf8Marker(resource.getContents())); 833 } 834 835 String resourcename = m_cms.getSitePath(resource); 836 if (!m_cms.existsResource(resourcename)) { 837 838 // iterate through all wrappers and call "writeFile" till one does not return null 839 List<I_CmsResourceWrapper> wrappers = getWrappers(); 840 Iterator<I_CmsResourceWrapper> iter = wrappers.iterator(); 841 while (iter.hasNext()) { 842 I_CmsResourceWrapper wrapper = iter.next(); 843 res = wrapper.writeFile(m_cms, resource); 844 if (res != null) { 845 break; 846 } 847 } 848 849 // delegate the call to the CmsObject 850 if (res == null) { 851 res = m_cms.writeFile(resource); 852 } 853 } else { 854 res = m_cms.writeFile(resource); 855 } 856 857 return res; 858 } 859 860 /** 861 * Try to find a resource type wrapper for the resource.<p> 862 * 863 * Takes all configured resource type wrappers and ask if one of them is responsible 864 * for that resource. The first in the list which feels responsible is returned. 865 * If no wrapper could be found null will be returned.<p> 866 * 867 * @see I_CmsResourceWrapper#isWrappedResource(CmsObject, CmsResource) 868 * 869 * @param res the resource to find a resource type wrapper for 870 * 871 * @return the found resource type wrapper for the resource or null if not found 872 */ 873 private I_CmsResourceWrapper getResourceTypeWrapper(CmsResource res) { 874 875 Iterator<I_CmsResourceWrapper> iter = getWrappers().iterator(); 876 while (iter.hasNext()) { 877 I_CmsResourceWrapper wrapper = iter.next(); 878 879 if (wrapper.isWrappedResource(m_cms, res)) { 880 return wrapper; 881 } 882 } 883 884 return null; 885 } 886 887 /** 888 * Checks if the resource type needs an UTF-8 marker.<p> 889 * 890 * If the encoding of the resource is "UTF-8" and the resource 891 * type is one of the following:<br/> 892 * <ul> 893 * <li>{@link CmsResourceTypeJsp}</li> 894 * <li>{@link CmsResourceTypePlain}</li> 895 * <li>{@link CmsResourceTypeXmlContent}</li> 896 * <li>{@link CmsResourceTypeXmlPage}</li> 897 * </ul> 898 * 899 * it needs an UTF-8 marker.<p> 900 * 901 * @param res the resource to check if the content needs a UTF-8 marker 902 * 903 * @return <code>true</code> if the resource needs an UTF-8 maker otherwise <code>false</code> 904 */ 905 private boolean needUtf8Marker(CmsResource res) { 906 907 if (!m_addByteOrderMark) { 908 return false; 909 } 910 // if the encoding of the resource is not UTF-8 return false 911 String encoding = CmsLocaleManager.getResourceEncoding(m_cms, res); 912 boolean result = false; 913 if (CmsEncoder.ENCODING_UTF_8.equals(encoding)) { 914 try { 915 I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(res.getTypeId()); 916 if (resType instanceof CmsResourceTypeJsp) { 917 result = true; 918 } else if (resType instanceof CmsResourceTypePlain) { 919 result = true; 920 } else if (resType instanceof CmsResourceTypeXmlContent) { 921 result = true; 922 } else if (resType instanceof CmsResourceTypeXmlPage) { 923 result = true; 924 } 925 } catch (CmsLoaderException e) { 926 LOG.debug(e); 927 } 928 } 929 return result; 930 } 931 932 /** 933 * Checks if the file content already contains the UTF8 marker.<p> 934 * 935 * @param res the resource to check 936 * 937 * @return <code>true</code> if the file content already contains the UTF8 marker 938 */ 939 private boolean startsWithUtf8Marker(CmsResource res) { 940 941 boolean result = false; 942 try { 943 if (res.isFile()) { 944 CmsFile file = m_cms.readFile(res); 945 if ((file.getContents().length >= 3) 946 && (file.getContents()[0] == CmsResourceWrapperUtils.UTF8_MARKER[0]) 947 && (file.getContents()[1] == CmsResourceWrapperUtils.UTF8_MARKER[1]) 948 && (file.getContents()[2] == CmsResourceWrapperUtils.UTF8_MARKER[2])) { 949 result = true; 950 } 951 } 952 } catch (CmsException e) { 953 LOG.debug(e); 954 } 955 return result; 956 } 957}