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.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 /** Constant for the index content relation, telling the content of a linked resource should be merged into 112 * the content of the linking XML. 113 */ 114 public static final CmsRelationType INDEX_CONTENT = new CmsRelationType( 115 13, 116 "INDEX_CONTENT", 117 true, 118 true, 119 CopyBehavior.copy); 120 121 /** Constant for the all types of links in a jsp file using the <code>link.strong</code> macro. */ 122 public static final CmsRelationType JSP_STRONG = new CmsRelationType( 123 5, 124 PREFIX_JSP + VALUE_STRONG, 125 true, 126 true, 127 CopyBehavior.copy); 128 129 /** Constant for the all types of links in a jsp file using the <code>link.weak</code> macro. */ 130 public static final CmsRelationType JSP_WEAK = new CmsRelationType( 131 6, 132 PREFIX_JSP + VALUE_WEAK, 133 false, 134 true, 135 CopyBehavior.copy); 136 137 /** Constant for the organizational units resource associations. */ 138 public static final CmsRelationType OU_RESOURCE = new CmsRelationType(8, "OU", false, false, CopyBehavior.copy); 139 140 /** Constant for the <code>OpenCmsVfsFile</code> values in xml content that were defined as 'strong' links. */ 141 public static final CmsRelationType XML_STRONG = new CmsRelationType( 142 3, 143 PREFIX_XML + VALUE_STRONG, 144 true, 145 true, 146 CopyBehavior.copy); 147 148 /** Constant for the <code>OpenCmsVfsFile</code> values in xml content that were defined as 'weak' links. */ 149 public static final CmsRelationType XML_WEAK = new CmsRelationType( 150 4, 151 PREFIX_XML + VALUE_WEAK, 152 false, 153 true, 154 CopyBehavior.copy); 155 156 /** Constant for the type of relations between resources which are locale variants. */ 157 public static final CmsRelationType LOCALE_VARIANT = new CmsRelationType( 158 11, 159 "LOCALE_VARIANT", 160 false, 161 false, 162 CopyBehavior.ignore); 163 164 /** Constant for the type of relations between a detail content and its detail-only container pages. */ 165 public static final CmsRelationType DETAIL_ONLY = new CmsRelationType( 166 12, 167 "DETAIL_ONLY", 168 true, 169 false, 170 CopyBehavior.ignore); 171 172 /** Constant for the weak links from xmlcontent to the used xsd. */ 173 public static final CmsRelationType XSD = new CmsRelationType(10, "XSD", true, true, CopyBehavior.copy); 174 175 /** Serial version UID required for safe serialization. */ 176 private static final long serialVersionUID = -4060567973007877250L; 177 178 /** Constant indicating the starting mode for user defined relation types. */ 179 private static final int USER_DEFINED_MODE_LIMIT = 100; 180 181 /** Array constant for all available system relation types. */ 182 private static final CmsRelationType[] VALUE_ARRAY = { 183 HYPERLINK, 184 EMBEDDED_IMAGE, 185 XML_STRONG, 186 XML_WEAK, 187 JSP_STRONG, 188 JSP_WEAK, 189 EMBEDDED_OBJECT, 190 OU_RESOURCE, 191 CATEGORY, 192 XSD, 193 LOCALE_VARIANT, 194 DETAIL_ONLY, 195 INDEX_CONTENT}; 196 197 /** The copy behavior. */ 198 private CopyBehavior m_copyBehavior = CopyBehavior.copy; 199 200 /** Flag to indicate if the relations of this type are parsed from the content or not. */ 201 private final boolean m_defInContent; 202 203 /** Internal representation. */ 204 private final int m_id; 205 206 /** Some name for this relation type, ie. for <link> tag representation. */ 207 private final String m_name; 208 209 /** Flag to indicate if the relations of this type are strong or weak. */ 210 private final boolean m_strong; 211 212 /** 213 * Public constructor for user defined relation types.<p> 214 * 215 * @param id the id of the relation type 216 * @param name the name of the relation 217 * @param type the type of relation type, strong or weak 218 */ 219 public CmsRelationType(int id, String name, String type) { 220 221 m_name = name.toUpperCase(); 222 if (OpenCms.getRunLevel() > OpenCms.RUNLEVEL_2_INITIALIZING) { 223 // allow relation type definitions only during startup 224 throw new CmsInitException(Messages.get().container(Messages.ERR_RELATION_TYPE_INIT_1, m_name)); 225 } 226 m_strong = type.toUpperCase().equals(VALUE_STRONG); 227 m_defInContent = false; 228 m_id = USER_DEFINED_MODE_LIMIT + id; 229 } 230 231 /** 232 * Private constructor for system relation types.<p> 233 * 234 * @param id the internal representation 235 * @param name the name of the relation 236 * @param strong if the relation is strong or weak 237 * @param defInContent <code>true</code> if the link is defined in the content 238 * @param copyBehavior the copy behavior of the content 239 */ 240 private CmsRelationType(int id, String name, boolean strong, boolean defInContent, CopyBehavior copyBehavior) { 241 242 m_id = id; 243 m_name = name; 244 m_strong = strong; 245 m_defInContent = defInContent; 246 m_copyBehavior = copyBehavior; 247 } 248 249 /** 250 * Returns all relation types in the given list that define relations in the content.<p> 251 * 252 * @param relationTypes the collection of relation types to filter 253 * 254 * @return a list of {@link CmsRelationType} objects 255 */ 256 public static List<CmsRelationType> filterDefinedInContent(Collection<CmsRelationType> relationTypes) { 257 258 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 259 Iterator<CmsRelationType> it = result.iterator(); 260 while (it.hasNext()) { 261 CmsRelationType type = it.next(); 262 if (!type.isDefinedInContent()) { 263 it.remove(); 264 } 265 } 266 return result; 267 } 268 269 /** 270 * Returns all internal defined relation types in the given list.<p> 271 * 272 * @param relationTypes the collection of relation types to filter 273 * 274 * @return a list of {@link CmsRelationType} objects 275 */ 276 public static List<CmsRelationType> filterInternal(Collection<CmsRelationType> relationTypes) { 277 278 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 279 Iterator<CmsRelationType> it = result.iterator(); 280 while (it.hasNext()) { 281 CmsRelationType type = it.next(); 282 if (!type.isInternal()) { 283 it.remove(); 284 } 285 } 286 return result; 287 } 288 289 /** 290 * Returns all relation types in the given list that are not defined in the content.<p> 291 * 292 * @param relationTypes the collection of relation types to filter 293 * 294 * @return a list of {@link CmsRelationType} objects 295 */ 296 public static List<CmsRelationType> filterNotDefinedInContent(Collection<CmsRelationType> relationTypes) { 297 298 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 299 Iterator<CmsRelationType> it = result.iterator(); 300 while (it.hasNext()) { 301 CmsRelationType type = it.next(); 302 if (type.isDefinedInContent()) { 303 it.remove(); 304 } 305 } 306 return result; 307 } 308 309 /** 310 * Returns all strong relation types in the given list.<p> 311 * 312 * @param relationTypes the collection of relation types to filter 313 * 314 * @return a list of {@link CmsRelationType} objects 315 */ 316 public static List<CmsRelationType> filterStrong(Collection<CmsRelationType> relationTypes) { 317 318 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 319 Iterator<CmsRelationType> it = result.iterator(); 320 while (it.hasNext()) { 321 CmsRelationType type = it.next(); 322 if (!type.isStrong()) { 323 it.remove(); 324 } 325 } 326 return result; 327 } 328 329 /** 330 * Returns all user defined relation types in the given list.<p> 331 * 332 * @param relationTypes the collection of relation types to filter 333 * 334 * @return a list of {@link CmsRelationType} objects 335 */ 336 public static List<CmsRelationType> filterUserDefined(Collection<CmsRelationType> relationTypes) { 337 338 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 339 Iterator<CmsRelationType> it = result.iterator(); 340 while (it.hasNext()) { 341 CmsRelationType type = it.next(); 342 if (type.isInternal()) { 343 it.remove(); 344 } 345 } 346 return result; 347 } 348 349 /** 350 * Returns all weak relation types in the given list.<p> 351 * 352 * @param relationTypes the collection of relation types to filter 353 * 354 * @return a list of {@link CmsRelationType} objects 355 */ 356 public static List<CmsRelationType> filterWeak(Collection<CmsRelationType> relationTypes) { 357 358 List<CmsRelationType> result = new ArrayList<CmsRelationType>(relationTypes); 359 Iterator<CmsRelationType> it = result.iterator(); 360 while (it.hasNext()) { 361 CmsRelationType type = it.next(); 362 if (type.isStrong()) { 363 it.remove(); 364 } 365 } 366 return result; 367 } 368 369 /** 370 * Returns all relation types.<p> 371 * 372 * @return a list of {@link CmsRelationType} objects 373 */ 374 public static List<CmsRelationType> getAll() { 375 376 List<CmsRelationType> all = new ArrayList<CmsRelationType>(Arrays.asList(VALUE_ARRAY)); 377 all.addAll(OpenCms.getResourceManager().getRelationTypes()); 378 return Collections.unmodifiableList(all); 379 } 380 381 /** 382 * Returns all relation types for relations defined in the content.<p> 383 * 384 * @return a list of {@link CmsRelationType} objects 385 */ 386 public static List<CmsRelationType> getAllDefinedInContent() { 387 388 return filterDefinedInContent(getAll()); 389 } 390 391 /** 392 * Returns all internally defined relation types.<p> 393 * 394 * @return a list of {@link CmsRelationType} objects 395 */ 396 public static List<CmsRelationType> getAllInternal() { 397 398 return Collections.unmodifiableList(Arrays.asList(VALUE_ARRAY)); 399 } 400 401 /** 402 * Returns all relation types for relations that are not defined in the content.<p> 403 * 404 * @return a list of {@link CmsRelationType} objects 405 */ 406 public static List<CmsRelationType> getAllNotDefinedInContent() { 407 408 return filterNotDefinedInContent(getAll()); 409 } 410 411 /** 412 * Returns all strong relation types.<p> 413 * 414 * @return a list of {@link CmsRelationType} objects 415 */ 416 public static List<CmsRelationType> getAllStrong() { 417 418 return filterStrong(getAll()); 419 } 420 421 /** 422 * Returns all user defined relation types.<p> 423 * 424 * @return a list of {@link CmsRelationType} objects 425 */ 426 public static List<CmsRelationType> getAllUserDefined() { 427 428 return OpenCms.getResourceManager().getRelationTypes(); 429 } 430 431 /** 432 * Returns all weak relation types.<p> 433 * 434 * @return a list of {@link CmsRelationType} objects 435 */ 436 public static List<CmsRelationType> getAllWeak() { 437 438 return filterWeak(getAll()); 439 } 440 441 /** 442 * Parses an <code>int</code> into a relation type.<p> 443 * 444 * @param id the internal representation number to parse 445 * 446 * @return the enumeration element 447 * 448 * @throws CmsIllegalArgumentException if the given value could not be matched against a 449 * <code>{@link CmsRelationType}</code> object. 450 */ 451 public static CmsRelationType valueOf(int id) throws CmsIllegalArgumentException { 452 453 if ((id > 0) && (id <= VALUE_ARRAY.length)) { 454 return VALUE_ARRAY[id - 1]; 455 } 456 id -= USER_DEFINED_MODE_LIMIT; 457 if ((id >= 0) && (id < getAllUserDefined().size())) { 458 return getAllUserDefined().get(id); 459 } 460 throw new CmsIllegalArgumentException( 461 org.opencms.db.Messages.get().container( 462 org.opencms.db.Messages.ERR_MODE_ENUM_PARSE_2, 463 Integer.valueOf(id), 464 CmsRelationType.class.getName())); 465 } 466 467 /** 468 * Parses an <code>String</code> into a relation type.<p> 469 * 470 * @param name the relation type name 471 * 472 * @return the enumeration element 473 * 474 * @throws CmsIllegalArgumentException if the given value could not be matched against a 475 * <code>{@link CmsRelationType}</code> object 476 * 477 * @see #valueOfXml(String) 478 * @see #valueOfJsp(String) 479 */ 480 public static CmsRelationType valueOf(String name) throws CmsIllegalArgumentException { 481 482 CmsRelationType result = valueOfInternal(name); 483 if (result == null) { 484 // no type found 485 throw new CmsIllegalArgumentException( 486 org.opencms.db.Messages.get().container( 487 org.opencms.db.Messages.ERR_MODE_ENUM_PARSE_2, 488 name, 489 CmsRelationType.class.getName())); 490 } 491 return result; 492 } 493 494 /** 495 * Parses the given value into a valid enumeration element for a JSP relation type.<p> 496 * 497 * This should be used to extend Strings like "weak" or "strong" to full relation type descriptors 498 * for JSP pages like "JSP_WEAK" or "JSP_STRONG".<p> 499 * 500 * @param name the name to get the JSP type for 501 * 502 * @return the JSP enumeration element 503 * 504 * @see #valueOf(String) 505 */ 506 public static CmsRelationType valueOfJsp(String name) { 507 508 CmsRelationType result = valueOfInternal(name); 509 if (result == null) { 510 result = valueOf(PREFIX_JSP + name); 511 } 512 return result; 513 } 514 515 /** 516 * Parses the given value into a valid enumeration element for a XML relation type.<p> 517 * 518 * This should be used to extend Strings like "weak" or "strong" to full relation type descriptors 519 * for XML documents like "XML_WEAK" or "XML_STRONG".<p> 520 * 521 * @param name the name to get the XML type for 522 * 523 * @return the XML enumeration element 524 * 525 * @see #valueOf(String) 526 */ 527 public static CmsRelationType valueOfXml(String name) { 528 529 CmsRelationType result = valueOfInternal(name); 530 if (result == null) { 531 result = valueOf(PREFIX_XML + name); 532 } 533 return result; 534 } 535 536 /** 537 * Internal parse method.<p> 538 * 539 * @param name the type to parse 540 * 541 * @return the enumeration element, or <code>null</code> if no matching element is found 542 */ 543 private static CmsRelationType valueOfInternal(String name) { 544 545 if (name != null) { 546 String valueUp = name.toUpperCase(); 547 for (int i = 0; i < VALUE_ARRAY.length; i++) { 548 if (valueUp.equals(VALUE_ARRAY[i].m_name)) { 549 return VALUE_ARRAY[i]; 550 } 551 } 552 // deprecated types 553 if (valueUp.equals("REFERENCE") || valueUp.equals("XML_REFERENCE")) { 554 return XML_WEAK; 555 } else if (valueUp.equals("ATTACHMENT") || valueUp.equals("XML_ATTACHMENT")) { 556 return XML_STRONG; 557 } 558 // user defined 559 for (int i = 0; i < getAllUserDefined().size(); i++) { 560 CmsRelationType type = getAllUserDefined().get(i); 561 if (valueUp.equals(type.m_name)) { 562 return type; 563 } 564 } 565 } 566 return null; 567 } 568 569 /** 570 * @see java.lang.Object#equals(java.lang.Object) 571 */ 572 @Override 573 public boolean equals(Object obj) { 574 575 if (this == obj) { 576 return true; 577 } 578 if (obj instanceof CmsRelationType) { 579 return (m_id == ((CmsRelationType)obj).m_id); 580 } 581 return false; 582 } 583 584 /** 585 * Gets the 'copy behavior' of the relation type, which is how relations of a resource should be handled when copying that resource.<p> 586 * 587 * @return the copy behavior of the relation type 588 */ 589 public CopyBehavior getCopyBehavior() { 590 591 return m_copyBehavior; 592 } 593 594 /** 595 * Returns the internal representation of this type.<p> 596 * 597 * @return the internal representation of this type 598 */ 599 public int getId() { 600 601 return m_id; 602 } 603 604 /** 605 * Returns a localized name for the given relation type.<p> 606 * 607 * @param messages the message bundle to use to resolve the name 608 * 609 * @return a localized name 610 */ 611 public String getLocalizedName(CmsMessages messages) { 612 613 String nameKey = "GUI_RELATION_TYPE_" + getName() + "_0"; 614 return messages.key(nameKey); 615 } 616 617 /** 618 * Returns a localized name for the given relation type.<p> 619 * 620 * @param locale the locale 621 * 622 * @return a localized name 623 */ 624 public String getLocalizedName(Locale locale) { 625 626 return getLocalizedName(Messages.get().getBundle(locale)); 627 } 628 629 /** 630 * Returns the type name.<p> 631 * 632 * @return the type name 633 * 634 * @see CmsRelationType#valueOf(String) 635 */ 636 public String getName() { 637 638 return m_name; 639 } 640 641 /** 642 * Returns the type name for xml output.<p> 643 * 644 * The short type name of XML or JSP types is only <code>"WEAK"</code> or <code>"STRONG"</code>. 645 * For other types the short name is equal to the name.<p> 646 * 647 * In case you need the full type name, use {@link #getName()}.<p> 648 * 649 * @return the short type name 650 * 651 * @see #getName() 652 * @see CmsRelationType#valueOfJsp(String) 653 * @see CmsRelationType#valueOfXml(String) 654 */ 655 public String getNameForXml() { 656 657 String result; 658 switch (getId()) { 659 case 3: // xml strong 660 result = VALUE_STRONG; 661 break; 662 case 4: // xml weak 663 result = VALUE_WEAK; 664 break; 665 case 5: // jsp strong 666 result = VALUE_STRONG; 667 break; 668 case 6: // jsp weak 669 result = VALUE_WEAK; 670 break; 671 default: 672 result = getName(); 673 } 674 return result; 675 } 676 677 /** 678 * Returns the string strong or weak.<p> 679 * 680 * @return the string strong or weak 681 * 682 * @see #isStrong() 683 */ 684 public String getType() { 685 686 return isStrong() ? VALUE_STRONG : VALUE_WEAK; 687 } 688 689 /** 690 * @see java.lang.Object#hashCode() 691 */ 692 @Override 693 public int hashCode() { 694 695 return m_id; 696 } 697 698 /** 699 * Checks if this relation type is defined in the content of a resource or not.<p> 700 * 701 * @return <code>true</code> if this relation type is defined in the content of a resource 702 */ 703 public boolean isDefinedInContent() { 704 705 return m_defInContent; 706 } 707 708 /** 709 * Checks if this is an internal relation type.<p> 710 * 711 * @return <code>true</code> if this is an internal relation type 712 */ 713 public boolean isInternal() { 714 715 return (getId() < USER_DEFINED_MODE_LIMIT); 716 } 717 718 /** 719 * Checks if the relation type is strong or weak.<p> 720 * 721 * @return <code>true</code> if the relation type is strong 722 */ 723 public boolean isStrong() { 724 725 return m_strong; 726 } 727 728 /** 729 * @see java.lang.Object#toString() 730 */ 731 @Override 732 public String toString() { 733 734 return m_name; 735 } 736}