001/* 002 * File : $Source$ 003 * Date : $Date$ 004 * Version: $Revision$ 005 * 006 * This library is part of OpenCms - 007 * the Open Source Content Management System 008 * 009 * Copyright (C) 2002 - 2009 Alkacon Software (http://www.alkacon.com) 010 * 011 * This library is free software; you can redistribute it and/or 012 * modify it under the terms of the GNU Lesser General Public 013 * License as published by the Free Software Foundation; either 014 * version 2.1 of the License, or (at your option) any later version. 015 * 016 * This library is distributed in the hope that it will be useful, 017 * but WITHOUT ANY WARRANTY; without even the implied warranty of 018 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 019 * Lesser General Public License for more details. 020 * 021 * For further information about Alkacon Software, please see the 022 * company website: http://www.alkacon.com 023 * 024 * For further information about OpenCms, please see the 025 * project website: http://www.opencms.org 026 * 027 * You should have received a copy of the GNU Lesser General Public 028 * License along with this library; if not, write to the Free Software 029 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 030 */ 031 032package org.opencms.search.documents; 033 034import org.opencms.db.CmsPublishedResource; 035import org.opencms.db.CmsResourceState; 036import org.opencms.file.CmsObject; 037import org.opencms.file.CmsProperty; 038import org.opencms.file.CmsPropertyDefinition; 039import org.opencms.file.CmsResource; 040import org.opencms.file.CmsResourceFilter; 041import org.opencms.i18n.CmsLocaleManager; 042import org.opencms.json.JSONArray; 043import org.opencms.json.JSONException; 044import org.opencms.json.JSONObject; 045import org.opencms.main.CmsException; 046import org.opencms.main.CmsLog; 047import org.opencms.main.OpenCms; 048import org.opencms.util.CmsStringUtil; 049 050import java.util.ArrayList; 051import java.util.HashMap; 052import java.util.Iterator; 053import java.util.List; 054import java.util.Locale; 055import java.util.Map; 056import java.util.regex.Matcher; 057 058import org.apache.commons.logging.Log; 059 060/** 061 * Provides the dependency information about one search result document, 062 * used to generate the list of document search results.<p> 063 * 064 * @since 8.5.0 065 */ 066public final class CmsDocumentDependency { 067 068 /** 069 * Defines the possible dependency types.<p> 070 */ 071 public static enum DependencyType { 072 073 /** A attachment dependency. */ 074 attachment, 075 076 /** The main document dependency. */ 077 document, 078 079 /** A variant dependency. */ 080 variant 081 } 082 083 /** Prefix for context attributes. */ 084 private static final String ATTR_DOC_DEPENDENCY = "CmsDocumentDependency."; 085 086 /** Field name in JSON. */ 087 private static final String JSON_ATTACHMENTS = "attachments"; 088 089 /** Field name in JSON. */ 090 private static final String JSON_DATE_CREATED = "dateCreated"; 091 092 /** Field name in JSON. */ 093 private static final String JSON_DATE_MODIFIED = "dateModified"; 094 095 /** Field name in JSON. */ 096 private static final String JSON_LANGUAGES = "languages"; 097 098 /** Field name in JSON. */ 099 private static final String JSON_LOCALE = "locale"; 100 101 /** Field name in JSON. */ 102 private static final String JSON_MAIN = "main"; 103 104 /** Field name in JSON. */ 105 private static final String JSON_PATH = "path"; 106 107 /** Field name in JSON. */ 108 private static final String JSON_TITLE = "title"; 109 110 /** Field name in JSON. */ 111 private static final String JSON_UUID = "uuid"; 112 113 /** The log object for this class. */ 114 private static final Log LOG = CmsLog.getLog(CmsDocumentDependency.class); 115 116 /** The attachment number. */ 117 private Integer m_attachmentNumber; 118 119 /** The document attachments . */ 120 private List<CmsDocumentDependency> m_attachments = new ArrayList<CmsDocumentDependency>(); 121 122 /** The list of resources the main resource depends on, including the main resource itself. */ 123 private List<CmsDocumentDependency> m_dependencies = new ArrayList<CmsDocumentDependency>(); 124 125 /** The file name of the document without attachment or locale suffixes. */ 126 private String m_documentName; 127 128 /** The file suffix of the document. */ 129 private String m_documentSuffix; 130 131 /** The locale of this document container. */ 132 private Locale m_locale; 133 134 /** Signals whether this document exists with different locale file name extensions. */ 135 private boolean m_localeFileName; 136 137 /** The main document in case this document is an attachment. */ 138 private CmsDocumentDependency m_mainDocument; 139 140 /** The VFS resource for which the dependencies are calculated. */ 141 private CmsPublishedResource m_resource; 142 143 /** Stores the root path of this dependency. */ 144 private String m_rootPath; 145 146 /** The dependency type for this dependency. */ 147 private DependencyType m_type; 148 149 /** The language version dependencies. */ 150 private List<CmsDocumentDependency> m_variants = new ArrayList<CmsDocumentDependency>(); 151 152 /** 153 * Creates a new dependency container for the given VFS resource.<p> 154 * 155 * @param res the VFS resource for which the dependencies are calculated 156 */ 157 private CmsDocumentDependency(CmsPublishedResource res) { 158 159 this(res, res.getRootPath()); 160 } 161 162 /** 163 * Creates a new dependency container for the given VFS resource.<p> 164 * 165 * Additional constructor with extra root path, to be used only for test cases.<p> 166 * 167 * @param resource the VFS resource for which the dependencies are calculated 168 * @param rootPath the root path to use 169 */ 170 private CmsDocumentDependency(CmsPublishedResource resource, String rootPath) { 171 172 m_resource = resource; 173 m_rootPath = rootPath; 174 String docName = CmsResource.getName(rootPath); 175 176 // check if an attachment number is present 177 Matcher matcher = CmsStringUtil.PATTERN_NUMBER_SUFFIX.matcher(docName); 178 if (matcher.find()) { 179 docName = matcher.group(1); 180 try { 181 Integer partNumber = Integer.valueOf(Integer.parseInt(matcher.group(2))); 182 setAttachmentNumber(partNumber); 183 } catch (NumberFormatException e) { 184 // ignore, can happen if the second group of the matcher is larger than Integer.MAX_VALUE 185 } 186 } 187 188 Locale locale = null; 189 matcher = CmsStringUtil.PATTERN_LOCALE_SUFFIX.matcher(docName); 190 if (matcher.find()) { 191 docName = matcher.group(1); 192 String suffix = matcher.group(2); 193 String langString = suffix.substring(0, 2); 194 locale = suffix.length() == 5 ? new Locale(langString, suffix.substring(3, 5)) : new Locale(langString); 195 m_localeFileName = true; 196 } 197 if (locale == null) { 198 locale = CmsLocaleManager.getDefaultLocale(); 199 } 200 if ((locale == null) || !OpenCms.getLocaleManager().getAvailableLocales().contains(locale)) { 201 // check if the determined locale is available in the opencms-system.xml 202 // use the default locale as fall-back 203 // locale = CmsLocaleManager.getDefaultLocale(); 204 } 205 setLocale(locale); 206 207 // we must remove file suffixes like "plapla.doc", ".pdf" etc. because attachments can have different types 208 int index = rootPath.lastIndexOf('.'); 209 if (index != -1) { 210 // store the suffix for comparison to decide if this is a main document or a variation later 211 String suffix = rootPath.substring(index); 212 setDocumentSuffix(suffix); 213 if ((docName.lastIndexOf(suffix) == (docName.length() - suffix.length())) && docName.contains(suffix)) { 214 docName = docName.substring(0, docName.length() - suffix.length()); 215 } 216 } 217 setDocumentName(CmsResource.getFolderPath(rootPath) + docName); 218 } 219 220 /** 221 * Creates a new dependency container for the given VFS resource.<p> 222 * 223 * @param res the VFS resource for which the dependencies are calculated 224 */ 225 private CmsDocumentDependency(CmsResource res) { 226 227 this(new CmsPublishedResource(res, -1, CmsResourceState.STATE_CHANGED)); 228 } 229 230 /** 231 * Creates a dependency object from a String representation.<p> 232 * 233 * @param input the String representation 234 * @param rootPath the root path of the base document of which the dependencies are encoded 235 * 236 * @return the dependency object created from a String representation 237 */ 238 public static CmsDocumentDependency fromDependencyString(String input, String rootPath) { 239 240 CmsDocumentDependency result = new CmsDocumentDependency(null, rootPath); 241 if (input != null) { 242 243 try { 244 if (input.startsWith("{")) { 245 JSONObject jsonDoc = new JSONObject(input); 246 result.fromJSON(jsonDoc, rootPath); 247 248 // main document 249 if (jsonDoc.has(JSON_MAIN)) { 250 251 JSONObject jsonMain = jsonDoc.getJSONObject(JSON_MAIN); 252 253 CmsDocumentDependency main = new CmsDocumentDependency(null, jsonMain.getString(JSON_PATH)); 254 main.fromJSON(jsonMain, rootPath); 255 result.setMainDocument(main); 256 } 257 } else { 258 // special handling for news 259 String[] docs = CmsStringUtil.splitAsArray(input, '|'); 260 for (int i = 0; i < docs.length; i++) { 261 String doc = docs[i]; 262 263 String lang = doc.substring(0, 2); 264 Locale loc = new Locale(lang); 265 266 if (i == 0) { 267 result.setLocale(loc); 268 } else { 269 String rp = doc.substring(3); 270 CmsDocumentDependency dep = new CmsDocumentDependency(null, rp); 271 if (!loc.equals(result.getLocale())) { 272 dep.setLocale(new Locale(lang)); 273 result.addVariant(dep); 274 } 275 } 276 } 277 } 278 } catch (Exception ex) { 279 if (LOG.isErrorEnabled()) { 280 LOG.error(ex.getLocalizedMessage(), ex); 281 } 282 } 283 } 284 return result; 285 } 286 287 /** 288 * Returns the locale (language) of the given resource based on the resource root path.<p> 289 * 290 * @param rootPath the resource name to check for the locale information 291 * 292 * @return the locale of the given resource based on the resource root path 293 */ 294 public static Locale getLocale(String rootPath) { 295 296 return (new CmsDocumentDependency(null, rootPath)).getLocale(); 297 } 298 299 /** 300 * Loads or creates a dependency object for the given parameters.<p> 301 * 302 * @param cms the current OpenCms user context 303 * @param pubRes the published resource to get the dependency object for 304 * 305 * @return a dependency object for the given parameters 306 */ 307 public static CmsDocumentDependency load(CmsObject cms, CmsPublishedResource pubRes) { 308 309 CmsDocumentDependency result = readFromContext(cms, pubRes.getRootPath()); 310 if (result == null) { 311 result = new CmsDocumentDependency(pubRes); 312 result.readDependencies(cms); 313 } 314 return result; 315 } 316 317 /** 318 * Loads or creates a dependency object for the given parameters.<p> 319 * 320 * @param cms the current OpenCms user context 321 * @param res the VFS resource to get the dependency object for 322 * 323 * @return a dependency object for the given parameters 324 */ 325 public static CmsDocumentDependency load(CmsObject cms, CmsResource res) { 326 327 CmsDocumentDependency result = readFromContext(cms, res.getRootPath()); 328 if (result == null) { 329 result = new CmsDocumentDependency(res); 330 result.readDependencies(cms); 331 } 332 return result; 333 } 334 335 /** 336 * Loads or creates a dependency object for the given parameters.<p> 337 * 338 * @param cms the current OpenCms user context 339 * @param res the VFS resource to get the dependency object for 340 * @param resources the resource folder data to check for dependencies 341 * 342 * @return a dependency object for the given parameters 343 */ 344 public static CmsDocumentDependency load(CmsObject cms, CmsResource res, List<CmsResource> resources) { 345 346 CmsDocumentDependency result = readFromContext(cms, res.getRootPath()); 347 if (result == null) { 348 result = new CmsDocumentDependency(res); 349 result.readDependencies(cms, resources); 350 } 351 return result; 352 } 353 354 /** 355 * Creates a dependency object for the given root path, to be used only for test cases.<p> 356 * 357 * @param rootPath the root path to create the dependency object for 358 * 359 * @return a dependency object for the given parameters 360 */ 361 protected static CmsDocumentDependency loadForTest(String rootPath) { 362 363 return new CmsDocumentDependency(null, rootPath); 364 } 365 366 /** 367 * Removes the dependency object for a published resource from the OpenCms 368 * runtime context.<p> 369 * 370 * <b>Please note:</b> This must be used with caution since the information 371 * may be required to generate documents for several configured indexes. It 372 * must be ensured that this is called only when all indexes have been 373 * updated.<p> 374 * 375 * @param cms the current OpenCms user context 376 * @param pubRes the published resource info 377 * 378 * @see #storeInContext(CmsObject) 379 */ 380 protected static void removeFromContext(CmsObject cms, CmsPublishedResource pubRes) { 381 382 cms.getRequestContext().removeAttribute(getAttributeKey(pubRes.getRootPath())); 383 } 384 385 /** 386 * Generates a context attribute name for a root path. 387 * 388 * @param rootPath the root path 389 * 390 * @return the Attr_Doc_Deps + rootPapth 391 */ 392 private static String getAttributeKey(String rootPath) { 393 394 return ATTR_DOC_DEPENDENCY + rootPath; 395 } 396 397 /** 398 * Reads the dependency object for the given root path in the OpenCms runtime context.<p> 399 * 400 * @param cms the current OpenCms user context 401 * @param rootPath the root path to look up the dependency object for 402 * 403 * @return the deps 404 */ 405 private static CmsDocumentDependency readFromContext(CmsObject cms, String rootPath) { 406 407 return (CmsDocumentDependency)cms.getRequestContext().getAttribute(getAttributeKey(rootPath)); 408 } 409 410 /** 411 * Adds another document attachment dependency to this document.<p> 412 * 413 * @param dep the document attachment dependency to add 414 */ 415 public void addAttachment(CmsDocumentDependency dep) { 416 417 // don't add attachment if this is a language version of an already existing attachment 418 boolean exist = false; 419 for (CmsDocumentDependency att : m_attachments) { 420 if (att.getAttachmentNumber() == dep.getAttachmentNumber()) { 421 422 if (m_locale.equals(dep.getLocale())) { 423 // if dependency has same locale as main document it is added as attachment 424 // and gets the old attachment as a language-version with all previous language-versions 425 for (CmsDocumentDependency langAtt : att.getVariants()) { 426 dep.addVariant(langAtt); 427 } 428 dep.addVariant(att); 429 m_attachments.remove(att); 430 } else { 431 exist = true; 432 att.addVariant(dep); 433 } 434 break; 435 } 436 } 437 438 if (!exist) { 439 dep.setType(DependencyType.attachment); 440 m_attachments.add(dep); 441 } else { 442 dep.setType(DependencyType.variant); 443 } 444 addDependency(dep); 445 } 446 447 /** 448 * Adds another document dependency to this document.<p> 449 * 450 * @param dep the document dependency to add 451 */ 452 public void addDependency(CmsDocumentDependency dep) { 453 454 m_dependencies.add(dep); 455 } 456 457 /** 458 * Adds another language version document dependency to this document.<p> 459 * 460 * @param dep the language version document dependency to add 461 */ 462 public void addVariant(CmsDocumentDependency dep) { 463 464 // check if already exists 465 for (CmsDocumentDependency lang : m_variants) { 466 if (lang.getLocale().equals(dep.getLocale())) { 467 return; 468 } 469 } 470 dep.setType(DependencyType.variant); 471 m_variants.add(dep); 472 addDependency(dep); 473 } 474 475 /** 476 * @see java.lang.Object#equals(java.lang.Object) 477 */ 478 @Override 479 public boolean equals(Object obj) { 480 481 if (obj == this) { 482 return true; 483 } 484 if (obj instanceof CmsDocumentDependency) { 485 CmsDocumentDependency other = (CmsDocumentDependency)obj; 486 return m_resource.getRootPath().equals(other.getResource().getRootPath()) 487 && m_locale.equals(other.m_locale); 488 } 489 return false; 490 } 491 492 /** 493 * Read the information out of the given JSON object to fill 494 * the values of the document.<p> 495 * 496 * @param json the JSON object with the information about this document 497 * @param rootPath the current path the home division 498 */ 499 public void fromJSON(JSONObject json, String rootPath) { 500 501 try { 502 // language versions 503 if (json.has(JSON_LANGUAGES)) { 504 JSONArray jsonLanguages = json.getJSONArray(JSON_LANGUAGES); 505 for (int i = 0; i < jsonLanguages.length(); i++) { 506 JSONObject jsonLang = (JSONObject)jsonLanguages.get(i); 507 508 CmsDocumentDependency lang = new CmsDocumentDependency(null, jsonLang.getString(JSON_PATH)); 509 lang.fromJSON(jsonLang, rootPath); 510 addVariant(lang); 511 } 512 } 513 514 // attachments 515 if (json.has(JSON_ATTACHMENTS)) { 516 JSONArray jsonAttachments = json.getJSONArray(JSON_ATTACHMENTS); 517 for (int i = 0; i < jsonAttachments.length(); i++) { 518 try { 519 JSONObject jsonAttachment = (JSONObject)jsonAttachments.get(i); 520 521 CmsDocumentDependency att = new CmsDocumentDependency( 522 null, 523 jsonAttachment.getString(JSON_PATH)); 524 att.fromJSON(jsonAttachment, rootPath); 525 526 // language versions of attachment 527 if (jsonAttachment.has(JSON_LANGUAGES)) { 528 JSONArray jsonAttLanguages = jsonAttachment.getJSONArray(JSON_LANGUAGES); 529 for (int j = 0; j < jsonAttLanguages.length(); j++) { 530 JSONObject jsonAttLanguage = (JSONObject)jsonAttLanguages.get(j); 531 532 CmsDocumentDependency attLang = new CmsDocumentDependency( 533 null, 534 jsonAttLanguage.getString(JSON_PATH)); 535 attLang.fromJSON(jsonAttLanguage, rootPath); 536 att.addVariant(attLang); 537 } 538 } 539 addAttachment(att); 540 } catch (Exception e) { 541 LOG.error(e.getLocalizedMessage(), e); 542 } 543 } 544 } 545 } catch (Exception ex) { 546 if (LOG.isErrorEnabled()) { 547 LOG.error(ex.getLocalizedMessage(), ex); 548 } 549 } 550 } 551 552 /** 553 * Returns the attachment number.<p> 554 * 555 * @return the attachment number 556 */ 557 public int getAttachmentNumber() { 558 559 if (m_attachmentNumber != null) { 560 return m_attachmentNumber.intValue(); 561 } 562 return 0; 563 } 564 565 /** 566 * Returns the attachments.<p> 567 * 568 * @return the attachments 569 */ 570 public List<CmsDocumentDependency> getAttachments() { 571 572 return m_attachments; 573 } 574 575 /** 576 * Returns the list of resources the main resource depends on, including the main resource itself.<p> 577 * 578 * @return the list of resources the main resource depends on, including the main resource itself 579 */ 580 public List<CmsDocumentDependency> getDependencies() { 581 582 return m_dependencies; 583 } 584 585 /** 586 * Returns the file name of the document without attachment or locale suffixes.<p> 587 * 588 * @return the file name of the document without attachment or locale suffixes 589 */ 590 public String getDocumentName() { 591 592 return m_documentName; 593 } 594 595 /** 596 * Returns the suffix of the document.<p> 597 * 598 * @return the suffix of the document 599 */ 600 public String getDocumentSuffix() { 601 602 return m_documentSuffix; 603 } 604 605 /** 606 * Returns the locale of this document container.<p> 607 * 608 * @return the locale of this document container 609 */ 610 public Locale getLocale() { 611 612 return m_locale; 613 } 614 615 /** 616 * Returns the main document in case this document is an attachment.<p> 617 * 618 * @return the main document in case this document is an attachment 619 */ 620 public CmsDocumentDependency getMainDocument() { 621 622 return m_mainDocument; 623 } 624 625 /** 626 * Returns the VFS resource for which the dependencies are calculated.<p> 627 * 628 * @return the VFS resource for which the dependencies are calculated 629 */ 630 public CmsPublishedResource getResource() { 631 632 return m_resource; 633 } 634 635 /** 636 * Returns the root path of this dependency.<p> 637 * 638 * @return the root path 639 */ 640 public String getRootPath() { 641 642 if (m_resource != null) { 643 return m_resource.getRootPath(); 644 } else { 645 return m_rootPath; 646 } 647 } 648 649 /** 650 * Returns the type.<p> 651 * 652 * @return the type 653 */ 654 public DependencyType getType() { 655 656 return m_type; 657 } 658 659 /** 660 * Returns the variants.<p> 661 * 662 * @return the variants 663 */ 664 public List<CmsDocumentDependency> getVariants() { 665 666 return m_variants; 667 } 668 669 /** 670 * @see java.lang.Object#hashCode() 671 */ 672 @Override 673 public int hashCode() { 674 675 return getResource().hashCode(); 676 } 677 678 /** 679 * Returns the locale file name flag.<p> 680 * 681 * @return the locale file name flag 682 */ 683 public boolean hasLocaleFileName() { 684 685 return m_localeFileName; 686 } 687 688 /** 689 * Returns true if this document is an attachment, i.e. an attachment number is provided.<p> 690 * 691 * @return true if this document is an attachment, otherwise false 692 */ 693 public boolean isAttachment() { 694 695 return m_attachmentNumber != null; 696 } 697 698 /** 699 * Reads all dependencies that exist for this main resource in the OpenCms VFS.<p> 700 * 701 * To be used when incremental updating an index.<p> 702 * 703 * @param cms the current users OpenCms context 704 */ 705 public void readDependencies(CmsObject cms) { 706 707 try { 708 // read all resources in the parent folder of the published resource 709 List<CmsResource> folderContent = cms.getResourcesInFolder( 710 CmsResource.getParentFolder(cms.getRequestContext().removeSiteRoot(getResource().getRootPath())), 711 CmsResourceFilter.DEFAULT); 712 // now calculate the dependencies form the folder content that has been read 713 readDependencies(cms, folderContent); 714 } catch (CmsException e) { 715 LOG.warn("Unable to read dependencies for " + getResource().getRootPath(), e); 716 } 717 } 718 719 /** 720 * Reads all dependencies that exist for this main resource in provided list of resources.<p> 721 * 722 * @param cms the current users OpenCms context 723 * @param folderContent the contents of the folder to check the dependencies for 724 */ 725 public void readDependencies(CmsObject cms, List<CmsResource> folderContent) { 726 727 Map<Integer, CmsDocumentDependency> attachments = new HashMap<Integer, CmsDocumentDependency>(); 728 if (isAttachment()) { 729 attachments.put(Integer.valueOf(getAttachmentNumber()), this); 730 } 731 732 // iterate all resources in the folder to check if this is a language version 733 Iterator<CmsResource> i = folderContent.iterator(); 734 while (i.hasNext()) { 735 CmsResource r = i.next(); 736 // only add files and don't add the resource itself again 737 if (r.isFile() && !getResource().getRootPath().equals(r.getRootPath())) { 738 CmsPublishedResource pubRes = new CmsPublishedResource( 739 r, 740 getResource().getPublishTag(), 741 CmsResourceState.STATE_CHANGED); 742 CmsDocumentDependency dep = new CmsDocumentDependency(pubRes); 743 if (getDocumentName().equals(dep.getDocumentName())) { 744 if (isAttachment()) { 745 // this document is an attachment 746 if (dep.isAttachment()) { 747 if ((getAttachmentNumber() == dep.getAttachmentNumber()) && dep.hasLocaleFileName()) { 748 // the dependency must be a language version of this attachment document 749 addVariant(dep); 750 } 751 if (getAttachmentNumber() == dep.getAttachmentNumber()) { 752 dep.setMainDocument(dep); 753 } else { 754 Integer attNum = Integer.valueOf(dep.getAttachmentNumber()); 755 CmsDocumentDependency att = attachments.get(attNum); 756 if (att != null) { 757 att.addVariant(dep); 758 } else { 759 attachments.put(attNum, dep); 760 } 761 } 762 } else { 763 // this is the main document of the dependency 764 setMainDocument(dep); 765 } 766 } else { 767 // this document is a main document 768 if (dep.isAttachment()) { 769 // add this dependency as an attachment 770 addAttachment(dep); 771 } else if (CmsStringUtil.isEqual(getDocumentSuffix(), dep.getDocumentSuffix())) { 772 // if this is no attachment, and the file suffix is equal, 773 // this must be a language version of the main document 774 addVariant(dep); 775 } 776 // if the file suffix is NOT equal, this is a new main document 777 setMainDocument(this); 778 } 779 } 780 } 781 } 782 783 if (m_mainDocument != null) { 784 for (CmsDocumentDependency att : attachments.values()) { 785 m_mainDocument.addAttachment(att); 786 } 787 // add the main document as dependency for this attachment 788 addDependency(m_mainDocument); 789 for (CmsDocumentDependency var : getVariants()) { 790 String mainFileName = getMainDocument().getDocumentName(); 791 if (getMainDocument().getDocumentSuffix() != null) { 792 mainFileName += getMainDocument().getDocumentSuffix(); 793 } 794 if (mainFileName.equals(var.getResource().getRootPath())) { 795 setType(DependencyType.variant); 796 break; 797 } else { 798 setType(DependencyType.document); 799 break; 800 } 801 } 802 } 803 } 804 805 /** 806 * Sets the attachment number.<p> 807 * 808 * @param attachmentNumber the attachment number 809 */ 810 public void setAttachmentNumber(Integer attachmentNumber) { 811 812 m_attachmentNumber = attachmentNumber; 813 } 814 815 /** 816 * Sets the file name of the document without attachment or locale suffixes.<p> 817 * 818 * @param documentName the file name of the document without attachment or locale suffixes 819 */ 820 public void setDocumentName(String documentName) { 821 822 m_documentName = documentName; 823 } 824 825 /** 826 * Sets the suffix (.pdf, .doc etc.) of the document.<p> 827 * 828 * @param documentSuffix the suffix to set 829 */ 830 public void setDocumentSuffix(String documentSuffix) { 831 832 m_documentSuffix = documentSuffix; 833 } 834 835 /** 836 * Sets the locale of this document container.<p> 837 * 838 * @param locale the locale of this document container 839 */ 840 public void setLocale(Locale locale) { 841 842 m_locale = locale; 843 } 844 845 /** 846 * Sets the main document in case this document is an attachment.<p> 847 * 848 * @param mainDocument the main document to set 849 */ 850 public void setMainDocument(CmsDocumentDependency mainDocument) { 851 852 if (m_mainDocument == null) { 853 // we currently have no main document at all 854 m_mainDocument = mainDocument; 855 } else { 856 // check if we find a better match for the main document locale 857 if (mainDocument.getLocale().equals(getLocale())) { 858 // mainDocument.addVariant(m_mainDocument); 859 // main document locale is the "best" one 860 m_mainDocument = mainDocument; 861 } else { 862 // check if the new document is a "better" one 863 List<Locale> locales = OpenCms.getLocaleManager().getDefaultLocales(); 864 int pos1 = locales.indexOf(m_mainDocument.getLocale()); 865 if (pos1 > 0) { 866 int pos2 = locales.indexOf(mainDocument.getLocale()); 867 if (pos2 < pos1) { 868 mainDocument.addVariant(m_mainDocument); 869 // locale is closer to the default 870 m_mainDocument = mainDocument; 871 } 872 } else { 873 m_mainDocument.addVariant(mainDocument); 874 } 875 } 876 } 877 } 878 879 /** 880 * Sets the type for this dependency.<p> 881 * 882 * @param type the type to set 883 */ 884 public void setType(DependencyType type) { 885 886 m_type = type; 887 } 888 889 /** 890 * Stores this dependency object for a published resource in the OpenCms runtime context.<p> 891 * 892 * This done to optimize indexing speed. When the index update information is calculated, 893 * all dependencies for a resource must be calculated also. The same information is later needed when 894 * the Lucene document is created, for example in order to store the list of other available languages.<p> 895 * 896 * @param cms the current OpenCms user context 897 */ 898 public void storeInContext(CmsObject cms) { 899 900 cms.getRequestContext().setAttribute(getAttributeKey(getResource().getRootPath()), this); 901 } 902 903 /** 904 * Creates the String representation of this dependency object.<p> 905 * 906 * @param cms the current OpenCms user context 907 * 908 * @return the String representation of this dependency object 909 */ 910 public String toDependencyString(CmsObject cms) { 911 912 JSONObject jsonDoc = toJSON(cms, true); 913 914 try { 915 if ((!isAttachment()) && (m_attachments != null)) { 916 // iterate through all attachments 917 JSONArray jsonAttachments = new JSONArray(); 918 for (CmsDocumentDependency att : m_attachments) { 919 JSONObject jsonAttachment = att.toJSON(cms, true); 920 jsonAttachments.put(jsonAttachment); 921 } 922 jsonDoc.put(JSON_ATTACHMENTS, jsonAttachments); 923 } else if (isAttachment()) { 924 CmsDocumentDependency main = getMainDocument(); 925 if (main != null) { 926 JSONObject jsonMain = main.toJSON(cms, true); 927 // iterate through all attachments of the main document 928 List<CmsDocumentDependency> attachments = main.getAttachments(); 929 if (attachments != null) { 930 JSONArray jsonAttachments = new JSONArray(); 931 for (CmsDocumentDependency att : attachments) { 932 JSONObject jsonAttachment = att.toJSON(cms, true); 933 jsonAttachments.put(jsonAttachment); 934 } 935 jsonMain.put(JSON_ATTACHMENTS, jsonAttachments); 936 } 937 jsonDoc.put(JSON_MAIN, jsonMain); 938 } 939 } 940 return jsonDoc.toString(); 941 } catch (JSONException e) { 942 if (LOG.isErrorEnabled()) { 943 LOG.error(e.getLocalizedMessage(), e); 944 } 945 } 946 return null; 947 } 948 949 /** 950 * Returns a JSON object describing this dependency document.<p> 951 * 952 * @param cms the current cms object 953 * @param includeLang flag if language versions should be included 954 * 955 * @return a JSON object describing this dependency document 956 */ 957 public JSONObject toJSON(CmsObject cms, boolean includeLang) { 958 959 try { 960 CmsObject clone = OpenCms.initCmsObject(cms); 961 clone.getRequestContext().setSiteRoot(""); 962 JSONObject jsonAttachment = new JSONObject(); 963 CmsResource res = clone.readResource(m_rootPath, CmsResourceFilter.IGNORE_EXPIRATION); 964 Map<String, String> props = CmsProperty.toMap(clone.readPropertyObjects(res, false)); 965 // id and path 966 jsonAttachment.put(JSON_UUID, res.getStructureId()); 967 jsonAttachment.put(JSON_PATH, res.getRootPath()); 968 // title 969 jsonAttachment.put(JSON_TITLE, props.get(CmsPropertyDefinition.PROPERTY_TITLE)); 970 // date created 971 jsonAttachment.put(JSON_DATE_CREATED, res.getDateCreated()); 972 // date created 973 jsonAttachment.put(JSON_LOCALE, m_locale); 974 // date modified 975 jsonAttachment.put(JSON_DATE_MODIFIED, res.getDateLastModified()); 976 977 if (includeLang) { 978 // get all language versions of the document 979 List<CmsDocumentDependency> langs = getVariants(); 980 if (langs != null) { 981 JSONArray jsonLanguages = new JSONArray(); 982 for (CmsDocumentDependency lang : langs) { 983 984 JSONObject jsonLanguage = lang.toJSON(cms, false); 985 jsonLanguages.put(jsonLanguage); 986 } 987 jsonAttachment.put(JSON_LANGUAGES, jsonLanguages); 988 } 989 } 990 return jsonAttachment; 991 } catch (Exception ex) { 992 LOG.error(ex.getLocalizedMessage(), ex); 993 } 994 return null; 995 } 996 997 /** 998 * @see java.lang.Object#toString() 999 */ 1000 @Override 1001 public String toString() { 1002 1003 if (m_resource != null) { 1004 return m_resource.toString(); 1005 } else { 1006 return m_rootPath; 1007 } 1008 } 1009}