1 /* 2 * Copyright 2013 smartics, Kronseder & Reiner GmbH 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package de.smartics.resteasy.hypermedia.renderer; 17 18 import java.net.URI; 19 import java.util.ArrayList; 20 import java.util.Arrays; 21 import java.util.List; 22 import java.util.Map; 23 24 import javax.ws.rs.core.Link; 25 import javax.ws.rs.core.UriBuilder; 26 27 import org.apache.commons.lang3.StringUtils; 28 29 import de.smartics.util.lang.Arg; 30 31 /** 32 * Provides information on a single link. 33 */ 34 public abstract class LinkDescriptor extends Link 35 { 36 // ********************************* Fields ********************************* 37 38 // --- constants ------------------------------------------------------------ 39 40 // --- members -------------------------------------------------------------- 41 42 /** 43 * The additional link metadata about the link. 44 */ 45 protected final LinkMetadata metadata; 46 47 /** 48 * The path parameters to apply to the template link. 49 */ 50 protected final Map<String, String> params; 51 52 /** 53 * The list of tokens that specify the relationship between the document 54 * containing the hyperlink and the destination indicated by the hyperlink. 55 * 56 * @see <a href="http://dev.w3.org/html5/markup/a.html#a.attrs.rel">rel</a> 57 */ 58 protected final List<String> rels; 59 60 // ****************************** Initializer ******************************* 61 62 // ****************************** Constructors ****************************** 63 64 /** 65 * Default constructor. 66 * 67 * @param metadata the additional link metadata about the link. 68 * @param params the value for params. 69 * @param rels the relations of this link. 70 */ 71 protected LinkDescriptor(final LinkMetadata metadata, 72 final Map<String, String> params, final List<String> rels) 73 { 74 this.metadata = metadata; 75 this.params = params; 76 this.rels = rels; 77 } 78 79 // ****************************** Inner Classes ***************************** 80 81 // ********************************* Methods ******************************** 82 83 // --- init ----------------------------------------------------------------- 84 85 /** 86 * Splits the whitespace separated relation link attribute into its parts. 87 * 88 * @param rel the whitespace separated relation link attribute. 89 * @return the individual parts. 90 */ 91 protected static final List<String> splitRel(final String rel) 92 { 93 if (StringUtils.isBlank(rel)) 94 { 95 return new ArrayList<String>(); 96 } 97 98 final List<String> rels = Arrays.asList(rel.split("\\s+")); 99 return rels; 100 } 101 102 // --- get&set -------------------------------------------------------------- 103 104 @Override 105 public URI getUri() 106 { 107 final UriBuilder builder = getUriBuilder(); 108 109 if (builder == null) 110 { 111 return null; 112 } 113 114 final URI uri; 115 if (!params.isEmpty()) 116 { 117 uri = builder.build(params); 118 } 119 else 120 { 121 uri = builder.build(); 122 } 123 return uri; 124 } 125 126 @Override 127 public UriBuilder getUriBuilder() 128 { 129 final String href = getHref(); 130 131 if (href == null) 132 { 133 return null; 134 } 135 136 return UriBuilder.fromPath(href); 137 } 138 139 /** 140 * Returns the URI to the resource the link points to. 141 * 142 * @return the URI to the resource the link points to. 143 */ 144 public abstract String getHref(); 145 146 /** 147 * Sets the URI to the resource the link points to. 148 * 149 * @param href the URI to the resource the link points to. 150 */ 151 public abstract void setHref(String href); 152 153 /** 154 * Returns the content that describes the language of the resource pointed to 155 * by the link. When used together with the rel="alternate", it implies a 156 * translated version of the entry. Link elements MAY have an hreflang 157 * attribute, whose value MUST be a language tag [RFC3066]. 158 * 159 * @return the content that describes the language of the resource pointed to 160 * by the link. 161 */ 162 public abstract String getHrefLang(); 163 164 /** 165 * Sets the content that describes the language of the resource pointed to by 166 * the link. When used together with the rel="alternate", it implies a 167 * translated version of the entry. Link elements MAY have an hreflang 168 * attribute, whose value MUST be a language tag [RFC3066]. 169 * 170 * @param hrefLang the content that describes the language of the resource 171 * pointed to by the link. 172 */ 173 public abstract void setHrefLang(String hrefLang); 174 175 /** 176 * Returns the media type of the resource the link points to. 177 * 178 * @return the media type of the resource the link points to. 179 */ 180 @Override 181 public abstract String getType(); 182 183 /** 184 * Sets the media type of the resource the link points to. 185 * 186 * @param type the media type of the resource the link points to. 187 */ 188 public abstract void setType(String type); 189 190 /** 191 * Returns the advisory length of the linked content in octets; it is a hint 192 * about the content length of the representation returned when the IRI in the 193 * href attribute is mapped to a URI and dereferenced. Note that the length 194 * attribute does not override the actual content length of the representation 195 * as reported by the underlying protocol. Link elements MAY have a length 196 * attribute. 197 * 198 * @return the advisory length of the linked content in octets. 199 */ 200 public abstract String getLength(); 201 202 /** 203 * Sets the advisory length of the linked content in octets; it is a hint 204 * about the content length of the representation returned when the IRI in the 205 * href attribute is mapped to a URI and dereferenced. Note that the length 206 * attribute does not override the actual content length of the representation 207 * as reported by the underlying protocol. Link elements MAY have a length 208 * attribute. 209 * 210 * @param length the advisory length of the linked content in octets. 211 */ 212 public abstract void setLength(String length); 213 214 /** 215 * Returns the relations of this link. 216 * 217 * @return the relations of this link. 218 */ 219 @Override 220 public List<String> getRels() 221 { 222 return rels; 223 } 224 225 /** 226 * Adds the list of relations. 227 * 228 * @param rels the relations to add. 229 * @throws NullPointerException if {@code rels} is <code>null</code>. 230 */ 231 public void addRels(final String... rels) throws NullPointerException 232 { 233 for (final String rel : rels) 234 { 235 this.rels.add(rel); 236 } 237 } 238 239 /** 240 * Adds the list of relations. 241 * 242 * @param rels the relations to add. 243 * @throws NullPointerException if {@code rels} is <code>null</code>. 244 */ 245 public void addRels(final List<String> rels) throws NullPointerException 246 { 247 for (final String rel : rels) 248 { 249 this.rels.add(rel); 250 } 251 } 252 253 /** 254 * Returns the relation attribute of the link. The relations are separated by 255 * whitespaces. 256 * 257 * @return the whitespace separated relations of the link. 258 */ 259 @Override 260 public String getRel() 261 { 262 final StringBuilder buffer = new StringBuilder(128); 263 for (final String rel : this.rels) 264 { 265 buffer.append(rel).append(' '); 266 } 267 return StringUtils.removeEnd(buffer.toString(), " "); 268 } 269 270 /** 271 * Returns the path parameters to apply to the template link. 272 * 273 * @return the path parameters. 274 */ 275 @Override 276 public Map<String, String> getParams() 277 { 278 return params; 279 } 280 281 /** 282 * Adds the given parameter to the map of parameters. 283 * 284 * @param name the name of the parameter to add. 285 * @param value the value to the parameter to add. 286 * @throws NullPointerException if {@code name} or {@code value} is 287 * <code>null</code>. 288 * @throws IllegalArgumentException if {@code name} is blank}. 289 */ 290 public void putParam(final String name, final String value) 291 throws NullPointerException, IllegalArgumentException 292 { 293 params.put(Arg.checkNotBlank("name", name), 294 Arg.checkNotBlank("value", value)); 295 } 296 297 /** 298 * Returns the key label or list of key labels with which to associate the 299 * element; each key label represents a keyboard shortcut which UAs can use to 300 * activate the element or give focus to the element. 301 * <p> 302 * An ordered set of unique space-separated tokens, each of which must be 303 * exactly one Unicode code point in length. 304 * </p> 305 * 306 * @return the key label or list of key labels with which to associate the 307 * element. 308 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 309 * attributes</a> 310 */ 311 public final String getAccessKey() 312 { 313 return metadata.getAccessKey(); 314 } 315 316 /** 317 * Sets the key label or list of key labels with which to associate the 318 * element; each key label represents a keyboard shortcut which UAs can use to 319 * activate the element or give focus to the element. 320 * <p> 321 * An ordered set of unique space-separated tokens, each of which must be 322 * exactly one Unicode code point in length. 323 * </p> 324 * 325 * @param accessKey the key label or list of key labels with which to 326 * associate the element. 327 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 328 * attributes</a> 329 */ 330 public final void setAccessKey(final String accessKey) 331 { 332 metadata.setAccessKey(accessKey); 333 } 334 335 /** 336 * Returns the tab index. 337 * <p> 338 * Specifies whether the element represents an element that is is focusable 339 * (that is, an element which is part of the sequence of focusable elements in 340 * the document), and the relative order of the element in the sequence of 341 * focusable elements in the document. 342 * </p> 343 * 344 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 345 * attributes</a> 346 * @return the tab index. 347 */ 348 public final Integer getTabIndex() 349 { 350 return metadata.getTabIndex(); 351 } 352 353 /** 354 * Sets the tab index. 355 * <p> 356 * Specifies whether the element represents an element that is is focusable 357 * (that is, an element which is part of the sequence of focusable elements in 358 * the document), and the relative order of the element in the sequence of 359 * focusable elements in the document. 360 * </p> 361 * 362 * @param tabIndex the tab index. 363 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 364 * attributes</a> 365 */ 366 public final void setTabIndex(final Integer tabIndex) 367 { 368 metadata.setTabIndex(tabIndex); 369 } 370 371 /** 372 * Sets the advisory information associated with the element. 373 * 374 * @param title the advisory information associated with the element. 375 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 376 * attributes</a> 377 */ 378 public final void setTitle(final String title) 379 { 380 metadata.setTitle(title); 381 } 382 383 /** 384 * Returns the element’s text directionality. 385 * 386 * @return the element’s text directionality. 387 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 388 * attributes</a> 389 */ 390 public final String getDir() 391 { 392 return metadata.getDir(); 393 } 394 395 /** 396 * Sets the element’s text directionality. 397 * 398 * @param dir the element’s text directionality. 399 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 400 * attributes</a> 401 */ 402 public final void setDir(final String dir) 403 { 404 metadata.setDir(dir); 405 } 406 407 /** 408 * Returns the hidden flag to specify that the element represents an element 409 * that is not yet, or is no longer, relevant. 410 * 411 * @return the hidden flag to specify that the element represents an element 412 * that is not yet, or is no longer, relevant. 413 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 414 * attributes</a> 415 */ 416 public final Boolean isHidden() 417 { 418 return metadata.isHidden(); 419 } 420 421 /** 422 * Sets the hidden flag to specify that the element represents an element that 423 * is not yet, or is no longer, relevant. 424 * 425 * @param hidden the hidden flag to specify that the element represents an 426 * element that is not yet, or is no longer, relevant. 427 * @see <a href="http://dev.w3.org/html5/markup/global-attributes.html">global 428 * attributes</a> 429 */ 430 public void setHidden(final Boolean hidden) 431 { 432 metadata.setHidden(hidden); 433 } 434 435 /** 436 * Returns the standard label to be rendered as the visible part of the link. 437 * 438 * @return the standard label to be rendered as the visible part of the link. 439 */ 440 public String getLabel() 441 { 442 return metadata.getLabel(); 443 } 444 445 /** 446 * Sets the standard label to be rendered as the visible part of the link. 447 * 448 * @param label the standard label to be rendered as the visible part of the 449 * link. 450 */ 451 public final void setLabel(final String label) 452 { 453 metadata.setLabel(label); 454 } 455 456 /** 457 * Returns the short version of the label to be rendered in confined space. 458 * 459 * @return the short version of the label to be rendered in confined space. 460 */ 461 public final String getShortLabel() 462 { 463 return metadata.getShortLabel(); 464 } 465 466 /** 467 * Sets the short version of the label to be rendered in confined space. 468 * 469 * @param shortLabel the short version of the label to be rendered in confined 470 * space. 471 */ 472 public final void setShortLabel(final String shortLabel) 473 { 474 metadata.setShortLabel(shortLabel); 475 } 476 477 /** 478 * Returns the detailed help information on the link. 479 * 480 * @return the detailed help information on the link. 481 */ 482 public final String getHelp() 483 { 484 return metadata.getHelp(); 485 } 486 487 /** 488 * Sets the detailed help information on the link. 489 * 490 * @param help the detailed help information on the link. 491 */ 492 public final void setHelp(final String help) 493 { 494 metadata.setHelp(help); 495 } 496 497 /** 498 * Returns the CSS class information to the link. 499 * 500 * @return the CSS class information to the link. 501 */ 502 public final String getCssClass() 503 { 504 return metadata.getCssClass(); 505 } 506 507 /** 508 * Sets the CSS class information to the link. 509 * 510 * @param cssClass the CSS class information to the link. 511 */ 512 public final void setCssClass(final String cssClass) 513 { 514 metadata.setCssClass(cssClass); 515 } 516 517 /** 518 * Returns the identifier of the link. 519 * 520 * @return the identifier of the link. 521 */ 522 public String getId() 523 { 524 return metadata.getId(); 525 } 526 527 /** 528 * Sets the identifier of the link. 529 * 530 * @param id the identifier of the link. 531 */ 532 public void setId(final String id) 533 { 534 metadata.setId(id); 535 } 536 537 /** 538 * Returns the advisory information associated with the element. 539 * 540 * @return the advisory information associated with the element. 541 */ 542 @Override 543 public String getTitle() 544 { 545 return metadata.getTitle(); 546 } 547 548 /** 549 * Returns the name or keyword giving a browsing context for UAs to use when 550 * following the hyperlink. 551 * 552 * @return the name or keyword giving a browsing context for UAs to use when 553 * following the hyperlink. 554 */ 555 public String getTarget() 556 { 557 return metadata.getTarget(); 558 } 559 560 /** 561 * Sets the name or keyword giving a browsing context for UAs to use when 562 * following the hyperlink. 563 * 564 * @param target the name or keyword giving a browsing context for UAs to use 565 * when following the hyperlink. 566 */ 567 public void setTarget(final String target) 568 { 569 metadata.setTarget(target); 570 } 571 572 /** 573 * Returns the media for which the destination of the hyperlink was designed. 574 * <p> 575 * Values are according to <a 576 * href="http://www.w3.org/TR/2009/CR-css3-mediaqueries-20090915/">Media 577 * Queries</a>. 578 * </p> 579 * 580 * @return the media for which the destination of the hyperlink was designed. 581 */ 582 public String getMedia() 583 { 584 return metadata.getMedia(); 585 } 586 587 /** 588 * Sets the media for which the destination of the hyperlink was designed. 589 * <p> 590 * Values are according to <a 591 * href="http://www.w3.org/TR/2009/CR-css3-mediaqueries-20090915/">Media 592 * Queries</a>. 593 * </p> 594 * 595 * @param media the media for which the destination of the hyperlink was 596 * designed. 597 */ 598 public void setMedia(final String media) 599 { 600 metadata.setMedia(media); 601 } 602 603 /** 604 * Returns the identifier of a menu with which to associate the element as a 605 * context menu. 606 * 607 * @return the identifier of a menu with which to associate the element as a 608 * context menu. 609 */ 610 public String getContextMenu() 611 { 612 return metadata.getContextMenu(); 613 } 614 615 /** 616 * Sets the identifier of a menu with which to associate the element as a 617 * context menu. 618 * 619 * @param contextMenu the identifier of a menu with which to associate the 620 * element as a context menu. 621 */ 622 public void setContextMenu(final String contextMenu) 623 { 624 metadata.setContextMenu(contextMenu); 625 } 626 627 // --- business ------------------------------------------------------------- 628 629 // --- object basics -------------------------------------------------------- 630 631 @Override 632 public String toString() 633 { 634 final StringBuilder buffer = new StringBuilder(64); 635 636 buffer.append('<').append(getHref()).append('>'); 637 append(buffer, "title", getTitle()); 638 append(buffer, "rel", getRel()); 639 append(buffer, "type", getType()); 640 append(buffer, "hreflang", getHrefLang()); 641 append(buffer, "length", getLength()); 642 643 return buffer.toString(); 644 } 645 646 private void append(final StringBuilder buffer, final String name, 647 final String value) 648 { 649 if (StringUtils.isNotBlank(value)) 650 { 651 buffer.append("; ").append(name).append("=\"").append(value).append('"'); 652 } 653 } 654 }