View Javadoc

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 }