001/* 002 * This library is part of OpenCms - 003 * the Open Source Content Management System 004 * 005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com) 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * For further information about Alkacon Software GmbH & Co. KG, please see the 018 * company website: https://www.alkacon.com 019 * 020 * For further information about OpenCms, please see the 021 * project website: https://www.opencms.org 022 * 023 * You should have received a copy of the GNU Lesser General Public 024 * License along with this library; if not, write to the Free Software 025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 026 */ 027 028package org.opencms.relations; 029 030import org.opencms.i18n.CmsMessages; 031import org.opencms.main.CmsIllegalArgumentException; 032import org.opencms.main.CmsInitException; 033import org.opencms.main.OpenCms; 034 035import java.io.Serializable; 036import java.util.ArrayList; 037import java.util.Arrays; 038import java.util.Collection; 039import java.util.Collections; 040import java.util.Iterator; 041import java.util.List; 042import java.util.Locale; 043 044/** 045 * Wrapper class for 046 * the different types of relations.<p> 047 * 048 * The possibles values are:<br> 049 * <ul> 050 * <li>{@link #HYPERLINK}</li> 051 * <li>{@link #EMBEDDED_IMAGE}</li> 052 * <li>{@link #EMBEDDED_OBJECT}</li> 053 * <li>{@link #XML_STRONG}</li> 054 * <li>{@link #XML_WEAK}</li> 055 * <li>{@link #JSP_STRONG}</li> 056 * <li>{@link #JSP_WEAK}</li> 057 * <li>{@link #OU_RESOURCE}</li> 058 * <li>{@link #CATEGORY}</li> 059 * <li>{@link #XSD}</li> 060 * </ul> 061 * <p> 062 * 063 * User defined relation types are also available.<p> 064 * 065 * @since 6.3.0 066 */ 067public final class CmsRelationType implements Serializable { 068 069 /** 070 * Enum representing how relations should be handled while copying resources.<p> 071 */ 072 public enum CopyBehavior { 073 /** Copy the relation when copying a resource. */ 074 copy, 075 076 /** Ignore the relation when copying a resource. */ 077 ignore; 078 } 079 080 // the following strings must not be public because they confuse the interface 081 // this means we can't sort this class members according to standard 082 /** String prefix for 'JSP relations. */ 083 private static final String PREFIX_JSP = "JSP_"; 084 085 /** String prefix for XML relations. */ 086 private static final String PREFIX_XML = "XML_"; 087 088 /** String constant for "STRONG" relations. */ 089 private static final String VALUE_STRONG = "STRONG"; 090 091 /** String constant for "WEAK" relations. */ 092 private static final String VALUE_WEAK = "WEAK"; 093 094 /** Constant for the category of an <code>OpenCmsVfsFile</code>. */ 095 public static final CmsRelationType CATEGORY = new CmsRelationType(9, "CATEGORY", false, false, CopyBehavior.copy); 096 097 /** Constant for the <code><img src=''></code> tag in a html page/element. */ 098 public static final CmsRelationType EMBEDDED_IMAGE = new CmsRelationType(2, "IMG", true, true, CopyBehavior.copy); 099 100 /** Constant for the <code><embed src=''></code> tag in a html page/element. */ 101 public static final CmsRelationType EMBEDDED_OBJECT = new CmsRelationType( 102 7, 103 "OBJECT", 104 true, 105 true, 106 CopyBehavior.copy); 107 108 /** Constant for the <code><a href=''></code> tag in a html page/element. */ 109 public static final CmsRelationType HYPERLINK = new CmsRelationType(1, "A", false, true, CopyBehavior.copy); 110 111 /** 112 * Constant for the index content relation, telling that a change of a linked resource should trigger re-indexing 113 * of the content of the linking XML. 114 */ 115 public static final CmsRelationType INDEX_CONTENT = new CmsRelationType( 116 13, 117 "INDEX_CONTENT", 118 true, 119 true, 120 CopyBehavior.copy); 121 122 /** Constant for the all types of links in a jsp file using the <code>link.strong</code> macro. */ 123 public static final CmsRelationType JSP_STRONG = new CmsRelationType( 124 5, 125 PREFIX_JSP + VALUE_STRONG, 126 true, 127 true, 128 CopyBehavior.copy); 129 130 /** Constant for the all types of links in a jsp file using the <code>link.weak</code> macro. */ 131 public static final CmsRelationType JSP_WEAK = new CmsRelationType( 132 6, 133 PREFIX_JSP + VALUE_WEAK, 134 false, 135 true, 136 CopyBehavior.copy); 137 138 /** Constant for the organizational units resource associations. */ 139 public static final CmsRelationType OU_RESOURCE = new CmsRelationType(8, "OU", false, false, CopyBehavior.copy); 140 141 /** Constant for the <code>OpenCmsVfsFile</code> values in xml content that were defined as 'strong' links. */ 142 public static final CmsRelationType XML_STRONG = new CmsRelationType( 143 3, 144 PREFIX_XML + VALUE_STRONG, 145 true, 146 true, 147 CopyBehavior.copy); 148 149 /** Constant for the <code>OpenCmsVfsFile</code> values in xml content that were defined as 'weak' links. */ 150 public static final CmsRelationType XML_WEAK = new CmsRelationType( 151 4, 152 PREFIX_XML + VALUE_WEAK, 153 false, 154 true, 155 CopyBehavior.copy); 156 157 /** Constant for the type of relations between resources which are locale variants. */ 158 public static final CmsRelationType LOCALE_VARIANT = new CmsRelationType( 159 11, 160 "LOCALE_VARIANT", 161 false, 162 false, 163 CopyBehavior.ignore); 164 165 /** Constant for the type of relations between a detail content and its detail-only container pages. */ 166 public static final CmsRelationType DETAIL_ONLY = new CmsRelationType( 167 12, 168 "DETAIL_ONLY", 169 true, 170 false, 171 CopyBehavior.ignore); 172 173 /** Constant for the weak links from xmlcontent to the used xsd. */ 174 public static final CmsRelationType XSD = new CmsRelationType(10, "XSD", true, true, CopyBehavior.copy); 175 176 /** Serial version UID required for safe serialization. */ 177 private static final long serialVersionUID = -4060567973007877250L; 178 179 /** Constant indicating the starting mode for user defined relation types. */ 180 private static final int USER_DEFINED_MODE_LIMIT = 100; 181 182 /** Array constant for all available system relation types. */ 183 private static final CmsRelationType[] VALUE_ARRAY = { 184 HYPERLINK, 185 EMBEDDED_IMAGE, 186 XML_STRONG, 187 XML_WEAK, 188 JSP_STRONG, 189 JSP_WEAK, 190 EMBEDDED_OBJECT, 191 OU_RESOURCE, 192 CATEGORY, 193 XSD, 194 LOCALE_VARIANT, 195 DETAIL_ONLY, 196 INDEX_CONTENT}; 197 198 /** The copy behavior. */ 199 private CopyBehavior m_copyBehavior = CopyBehavior.copy; 200 201 /** Flag to indicate if the relations of this type are parsed from the content or not. */ 202 private final boolean m_defInContent; 203 204 /** Internal representation. */ 205 private final int m_id; 206 207 /** Some name for this relation type, ie. for <link> tag representation. */ 208 private final String m_name; 209 210 /** Flag to indicate if the relations of this type are strong or weak. */ 211 private final boolean m_strong; 212 213 /** 214 * Public constructor for user defined relation types.<p> 215 * 216 * @param id the id of the relation type 217 * @param name the name of the relation 218 * @param type the type of relation type, strong or weak 219 */ 220 public CmsRelationType(int id, String name, String type) { 221 222 m_name = name.toUpperCase(); 223 if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) { 224 // allow relation type definitions only during startup 225 throw new CmsInitException(Messages.get().container(Messages.ERR_RELATION_TYPE_INIT_1, m_name)); 226 } 227 m_strong = type.toUpperCase().equals(VALUE_STRONG); 228 m_defInContent = false; 229 m_id = USER_DEFINED_MODE_LIMIT + id; 230 } 231 232 /** 233 * Private constructor for system relation types.<p> 234 * 235 * @param id the internal representation 236 * @param name the name of the relation 237 * @param strong if the relation is strong or weak 238 * @param defInContent <code>true</code> if the link is defined in the content 239 * @param copyBehavior the copy behavior of the content 240 */ 241 private CmsRelationType(int id, String name, boolean strong, boolean defInContent, CopyBehavior copyBehavior) { 242 243 m_id = id; 244 m_name = name; 245 m_strong = strong; 246 m_defInContent = defInContent; 247 m_copyBehavior = copyBehavior; 248 } 249 250 /** 251 * Returns all relation types in the given list that define relations in the content.<p> 252 * 253 * @param relationTypes the collection of relation types to filter 254 * 255 * @return a list of {@link CmsRelationType} objects 256 */ 257 public static List<CmsRelationType> filterDefinedInContent(Collection<CmsRelationType> relationTypes) { 258 259 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 260 Iterator<CmsRelationType> it = result.iterator(); 261 while (it.hasNext()) { 262 CmsRelationType type = it.next(); 263 if (!type.isDefinedInContent()) { 264 it.remove(); 265 } 266 } 267 return result; 268 } 269 270 /** 271 * Returns all internal defined relation types in the given list.<p> 272 * 273 * @param relationTypes the collection of relation types to filter 274 * 275 * @return a list of {@link CmsRelationType} objects 276 */ 277 public static List<CmsRelationType> filterInternal(Collection<CmsRelationType> relationTypes) { 278 279 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 280 Iterator<CmsRelationType> it = result.iterator(); 281 while (it.hasNext()) { 282 CmsRelationType type = it.next(); 283 if (!type.isInternal()) { 284 it.remove(); 285 } 286 } 287 return result; 288 } 289 290 /** 291 * Returns all relation types in the given list that are not defined in the content.<p> 292 * 293 * @param relationTypes the collection of relation types to filter 294 * 295 * @return a list of {@link CmsRelationType} objects 296 */ 297 public static List<CmsRelationType> filterNotDefinedInContent(Collection<CmsRelationType> relationTypes) { 298 299 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 300 Iterator<CmsRelationType> it = result.iterator(); 301 while (it.hasNext()) { 302 CmsRelationType type = it.next(); 303 if (type.isDefinedInContent()) { 304 it.remove(); 305 } 306 } 307 return result; 308 } 309 310 /** 311 * Returns all strong relation types in the given list.<p> 312 * 313 * @param relationTypes the collection of relation types to filter 314 * 315 * @return a list of {@link CmsRelationType} objects 316 */ 317 public static List<CmsRelationType> filterStrong(Collection<CmsRelationType> relationTypes) { 318 319 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 320 Iterator<CmsRelationType> it = result.iterator(); 321 while (it.hasNext()) { 322 CmsRelationType type = it.next(); 323 if (!type.isStrong()) { 324 it.remove(); 325 } 326 } 327 return result; 328 } 329 330 /** 331 * Returns all user defined relation types in the given list.<p> 332 * 333 * @param relationTypes the collection of relation types to filter 334 * 335 * @return a list of {@link CmsRelationType} objects 336 */ 337 public static List<CmsRelationType> filterUserDefined(Collection<CmsRelationType> relationTypes) { 338 339 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 340 Iterator<CmsRelationType> it = result.iterator(); 341 while (it.hasNext()) { 342 CmsRelationType type = it.next(); 343 if (type.isInternal()) { 344 it.remove(); 345 } 346 } 347 return result; 348 } 349 350 /** 351 * Returns all weak relation types in the given list.<p> 352 * 353 * @param relationTypes the collection of relation types to filter 354 * 355 * @return a list of {@link CmsRelationType} objects 356 */ 357 public static List<CmsRelationType> filterWeak(Collection<CmsRelationType> relationTypes) { 358 359 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 360 Iterator<CmsRelationType> it = result.iterator(); 361 while (it.hasNext()) { 362 CmsRelationType type = it.next(); 363 if (type.isStrong()) { 364 it.remove(); 365 } 366 } 367 return result; 368 } 369 370 /** 371 * Returns all relation types.<p> 372 * 373 * @return a list of {@link CmsRelationType} objects 374 */ 375 public static List<CmsRelationType> getAll() { 376 377 List<CmsRelationType> all = new ArrayList<CmsRelationType>(Arrays.asList(VALUE_ARRAY)); 378 all.addAll(OpenCms.getResourceManager().getRelationTypes()); 379 return Collections.unmodifiableList(all); 380 } 381 382 /** 383 * Returns all relation types for relations defined in the content.<p> 384 * 385 * @return a list of {@link CmsRelationType} objects 386 */ 387 public static List<CmsRelationType> getAllDefinedInContent() { 388 389 return filterDefinedInContent(getAll()); 390 } 391 392 /** 393 * Returns all internally defined relation types.<p> 394 * 395 * @return a list of {@link CmsRelationType} objects 396 */ 397 public static List<CmsRelationType> getAllInternal() { 398 399 return Collections.unmodifiableList(Arrays.asList(VALUE_ARRAY)); 400 } 401 402 /** 403 * Returns all relation types for relations that are not defined in the content.<p> 404 * 405 * @return a list of {@link CmsRelationType} objects 406 */ 407 public static List<CmsRelationType> getAllNotDefinedInContent() { 408 409 return filterNotDefinedInContent(getAll()); 410 } 411 412 /** 413 * Returns all strong relation types.<p> 414 * 415 * @return a list of {@link CmsRelationType} objects 416 */ 417 public static List<CmsRelationType> getAllStrong() { 418 419 return filterStrong(getAll()); 420 } 421 422 /** 423 * Returns all user defined relation types.<p> 424 * 425 * @return a list of {@link CmsRelationType} objects 426 */ 427 public static List<CmsRelationType> getAllUserDefined() { 428 429 return OpenCms.getResourceManager().getRelationTypes(); 430 } 431 432 /** 433 * Returns all weak relation types.<p> 434 * 435 * @return a list of {@link CmsRelationType} objects 436 */ 437 public static List<CmsRelationType> getAllWeak() { 438 439 return filterWeak(getAll()); 440 } 441 442 /** 443 * Parses an <code>int</code> into a relation type.<p> 444 * 445 * @param id the internal representation number to parse 446 * 447 * @return the enumeration element 448 * 449 * @throws CmsIllegalArgumentException if the given value could not be matched against a 450 * <code>{@link CmsRelationType}</code> object. 451 */ 452 public static CmsRelationType valueOf(int id) throws CmsIllegalArgumentException { 453 454 if ((id > 0) && (id <= VALUE_ARRAY.length)) { 455 return VALUE_ARRAY[id - 1]; 456 } 457 id -= USER_DEFINED_MODE_LIMIT; 458 if ((id >= 0) && (id < getAllUserDefined().size())) { 459 return getAllUserDefined().get(id); 460 } 461 throw new CmsIllegalArgumentException( 462 org.opencms.db.Messages.get().container( 463 org.opencms.db.Messages.ERR_MODE_ENUM_PARSE_2, 464 Integer.valueOf(id), 465 CmsRelationType.class.getName())); 466 } 467 468 /** 469 * Parses an <code>String</code> into a relation type.<p> 470 * 471 * @param name the relation type name 472 * 473 * @return the enumeration element 474 * 475 * @throws CmsIllegalArgumentException if the given value could not be matched against a 476 * <code>{@link CmsRelationType}</code> object 477 * 478 * @see #valueOfXml(String) 479 * @see #valueOfJsp(String) 480 */ 481 public static CmsRelationType valueOf(String name) throws CmsIllegalArgumentException { 482 483 CmsRelationType result = valueOfInternal(name); 484 if (result == null) { 485 // no type found 486 throw new CmsIllegalArgumentException( 487 org.opencms.db.Messages.get().container( 488 org.opencms.db.Messages.ERR_MODE_ENUM_PARSE_2, 489 name, 490 CmsRelationType.class.getName())); 491 } 492 return result; 493 } 494 495 /** 496 * Parses the given value into a valid enumeration element for a JSP relation type.<p> 497 * 498 * This should be used to extend Strings like "weak" or "strong" to full relation type descriptors 499 * for JSP pages like "JSP_WEAK" or "JSP_STRONG".<p> 500 * 501 * @param name the name to get the JSP type for 502 * 503 * @return the JSP enumeration element 504 * 505 * @see #valueOf(String) 506 */ 507 public static CmsRelationType valueOfJsp(String name) { 508 509 CmsRelationType result = valueOfInternal(name); 510 if (result == null) { 511 result = valueOf(PREFIX_JSP + name); 512 } 513 return result; 514 } 515 516 /** 517 * Parses the given value into a valid enumeration element for a XML relation type.<p> 518 * 519 * This should be used to extend Strings like "weak" or "strong" to full relation type descriptors 520 * for XML documents like "XML_WEAK" or "XML_STRONG".<p> 521 * 522 * @param name the name to get the XML type for 523 * 524 * @return the XML enumeration element 525 * 526 * @see #valueOf(String) 527 */ 528 public static CmsRelationType valueOfXml(String name) { 529 530 CmsRelationType result = valueOfInternal(name); 531 if (result == null) { 532 result = valueOf(PREFIX_XML + name); 533 } 534 return result; 535 } 536 537 /** 538 * Internal parse method.<p> 539 * 540 * @param name the type to parse 541 * 542 * @return the enumeration element, or <code>null</code> if no matching element is found 543 */ 544 private static CmsRelationType valueOfInternal(String name) { 545 546 if (name != null) { 547 String valueUp = name.toUpperCase(); 548 for (int i = 0; i < VALUE_ARRAY.length; i++) { 549 if (valueUp.equals(VALUE_ARRAY[i].m_name)) { 550 return VALUE_ARRAY[i]; 551 } 552 } 553 // deprecated types 554 if (valueUp.equals("REFERENCE") || valueUp.equals("XML_REFERENCE")) { 555 return XML_WEAK; 556 } else if (valueUp.equals("ATTACHMENT") || valueUp.equals("XML_ATTACHMENT")) { 557 return XML_STRONG; 558 } 559 // user defined 560 for (int i = 0; i < getAllUserDefined().size(); i++) { 561 CmsRelationType type = getAllUserDefined().get(i); 562 if (valueUp.equals(type.m_name)) { 563 return type; 564 } 565 } 566 } 567 return null; 568 } 569 570 /** 571 * @see java.lang.Object#equals(java.lang.Object) 572 */ 573 @Override 574 public boolean equals(Object obj) { 575 576 if (this == obj) { 577 return true; 578 } 579 if (obj instanceof CmsRelationType) { 580 return (m_id == ((CmsRelationType)obj).m_id); 581 } 582 return false; 583 } 584 585 /** 586 * Gets the 'copy behavior' of the relation type, which is how relations of a resource should be handled when copying that resource.<p> 587 * 588 * @return the copy behavior of the relation type 589 */ 590 public CopyBehavior getCopyBehavior() { 591 592 return m_copyBehavior; 593 } 594 595 /** 596 * Returns the internal representation of this type.<p> 597 * 598 * @return the internal representation of this type 599 */ 600 public int getId() { 601 602 return m_id; 603 } 604 605 /** 606 * Returns a localized name for the given relation type.<p> 607 * 608 * @param messages the message bundle to use to resolve the name 609 * 610 * @return a localized name 611 */ 612 public String getLocalizedName(CmsMessages messages) { 613 614 String nameKey = "GUI_RELATION_TYPE_" + getName() + "_0"; 615 return messages.key(nameKey); 616 } 617 618 /** 619 * Returns a localized name for the given relation type.<p> 620 * 621 * @param locale the locale 622 * 623 * @return a localized name 624 */ 625 public String getLocalizedName(Locale locale) { 626 627 return getLocalizedName(Messages.get().getBundle(locale)); 628 } 629 630 /** 631 * Returns the type name.<p> 632 * 633 * @return the type name 634 * 635 * @see CmsRelationType#valueOf(String) 636 */ 637 public String getName() { 638 639 return m_name; 640 } 641 642 /** 643 * Returns the type name for xml output.<p> 644 * 645 * The short type name of XML or JSP types is only <code>"WEAK"</code> or <code>"STRONG"</code>. 646 * For other types the short name is equal to the name.<p> 647 * 648 * In case you need the full type name, use {@link #getName()}.<p> 649 * 650 * @return the short type name 651 * 652 * @see #getName() 653 * @see CmsRelationType#valueOfJsp(String) 654 * @see CmsRelationType#valueOfXml(String) 655 */ 656 public String getNameForXml() { 657 658 String result; 659 switch (getId()) { 660 case 3: // xml strong 661 result = VALUE_STRONG; 662 break; 663 case 4: // xml weak 664 result = VALUE_WEAK; 665 break; 666 case 5: // jsp strong 667 result = VALUE_STRONG; 668 break; 669 case 6: // jsp weak 670 result = VALUE_WEAK; 671 break; 672 default: 673 result = getName(); 674 } 675 return result; 676 } 677 678 /** 679 * Returns the string strong or weak.<p> 680 * 681 * @return the string strong or weak 682 * 683 * @see #isStrong() 684 */ 685 public String getType() { 686 687 return isStrong() ? VALUE_STRONG : VALUE_WEAK; 688 } 689 690 /** 691 * @see java.lang.Object#hashCode() 692 */ 693 @Override 694 public int hashCode() { 695 696 return m_id; 697 } 698 699 /** 700 * Checks if this relation type is defined in the content of a resource or not.<p> 701 * 702 * @return <code>true</code> if this relation type is defined in the content of a resource 703 */ 704 public boolean isDefinedInContent() { 705 706 return m_defInContent; 707 } 708 709 /** 710 * Checks if this is an internal relation type.<p> 711 * 712 * @return <code>true</code> if this is an internal relation type 713 */ 714 public boolean isInternal() { 715 716 return (getId() < USER_DEFINED_MODE_LIMIT); 717 } 718 719 /** 720 * Checks if the relation type is strong or weak.<p> 721 * 722 * @return <code>true</code> if the relation type is strong 723 */ 724 public boolean isStrong() { 725 726 return m_strong; 727 } 728 729 /** 730 * @see java.lang.Object#toString() 731 */ 732 @Override 733 public String toString() { 734 735 return m_name; 736 } 737}