001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.juneau.marshall.html;
018
019import static org.apache.juneau.commons.utils.Shorts.*;
020
021import org.apache.juneau.commons.bean.*;
022import org.apache.juneau.commons.inject.*;
023import org.apache.juneau.commons.reflect.*;
024import org.apache.juneau.marshall.*;
025
026/**
027 * Metadata on bean properties specific to the HTML serializers and parsers pulled from the {@link Html @Html}
028 * annotation on the bean property.
029 *
030 * <h5 class='section'>See Also:</h5><ul>
031 *    <li class='link'><a class="doclink" href="https://juneau.apache.org/docs/topics/HtmlSupport">HTML</a>
032
033 * </ul>
034 */
035@SuppressWarnings({
036   "rawtypes" // Raw types necessary for HtmlRender class parameter
037})
038public class HtmlBeanPropertyMeta extends ExtendedBeanPropertyMeta {
039
040   static class Builder {
041      boolean noTables;
042      boolean noTableHeaders;
043      HtmlFormat format = HtmlFormat.HTML;
044      BeanInstantiator.Builder<HtmlRender> render = BeanInstantiator.of(HtmlRender.class);
045      String link;
046      String anchorText;
047      String style;
048
049      void findHtmlInfo(Html html) {
050         if (html == null)
051            return;
052         format = html.format();
053         if (html.noTables())
054            noTables = html.noTables();
055         if (html.noTableHeaders())
056            noTableHeaders = html.noTableHeaders();
057         if (html.render() != HtmlRender.class)
058            render.type(html.render());
059         if (! html.link().isEmpty())
060            link = html.link();
061         if (! html.anchorText().isEmpty())
062            anchorText = html.anchorText();
063         if (! html.style().isEmpty())
064            style = html.style();
065      }
066   }
067
068   /**
069    * Default instance.
070    */
071   public static final HtmlBeanPropertyMeta DEFAULT = new HtmlBeanPropertyMeta();
072   private final boolean noTables;
073   private final boolean noTableHeaders;
074   private final HtmlFormat format;
075   private final HtmlRender render;
076
077   private final String link;
078   private final String anchorText;
079   private final String style;
080
081   /**
082    * Constructor.
083    *
084    * @param bpm The metadata of the bean property of this additional metadata.
085    *    <br>Must not be <jk>null</jk>.
086    * @param ap The annotation provider.
087    *    <br>Must not be <jk>null</jk>.
088    * @param mp HTML metadata provider (for finding information about other artifacts).
089    */
090   public HtmlBeanPropertyMeta(BeanPropertyMeta bpm, AnnotationProvider ap, HtmlMetaProvider mp) {
091      super(bpm);
092
093      var b = new Builder();
094      if (nn(bpm.getInnerField()))
095         ap.find(Html.class, bpm.getInnerField()).forEach(x -> b.findHtmlInfo(x.inner()));
096      if (nn(bpm.getGetter()))
097         ap.find(Html.class, bpm.getGetter()).forEach(x -> b.findHtmlInfo(x.inner()));
098      if (nn(bpm.getSetter()))
099         ap.find(Html.class, bpm.getSetter()).forEach(x -> b.findHtmlInfo(x.inner()));
100
101      format = b.format;
102      noTables = b.noTables;
103      noTableHeaders = b.noTableHeaders;
104      render = b.render.fallback(() -> null).run();
105      link = b.link;
106      anchorText = b.anchorText;
107      style = b.style;
108   }
109
110   private HtmlBeanPropertyMeta() {
111      super(null);
112      this.format = HtmlFormat.HTML;
113      this.noTables = false;
114      this.noTableHeaders = false;
115      this.render = null;
116      this.link = null;
117      this.anchorText = null;
118      this.style = null;
119   }
120
121   /**
122    * Specifies the anchor text for this property.
123    *
124    * <p>
125    * This value is specified via the {@link Html#anchorText() @Html(anchorText)} annotation.
126    *
127    * @return The link string, or <jk>null</jk> if not specified.
128    */
129   public String getAnchorText() { return anchorText; }
130
131   /**
132    * Adds a hyperlink to this value in HTML.
133    *
134    * <p>
135    * This value is specified via the {@link Html#link() @Html(link)} annotation.
136    *
137    * @return The link string, or <jk>null</jk> if not specified.
138    */
139   public String getLink() { return link; }
140
141   /**
142    * Returns the render class for rendering the style and contents of this property value in HTML.
143    *
144    * <p>
145    * This value is specified via the {@link Html#render() @Html(render)} annotation.
146    *
147    * @return The render class, or <jk>null</jk> if not specified.
148    */
149   public HtmlRender getRender() { return render; }
150
151   /**
152    * Returns the CSS style string for this property.
153    *
154    * <p>
155    * This value is specified via the {@link Html#style() @Html(style)} annotation.
156    *
157    * @return The CSS style string, or <jk>null</jk> if not specified.
158    */
159   public String getStyle() { return style; }
160
161   /**
162    * Returns whether this bean property should not include table headers when serialized as an HTML table.
163    *
164    * @return
165    *    <jk>true</jk> if the the {@link Html @Html} annotation is specified, and {@link Html#noTableHeaders() @Html(noTableHeaders)} is
166    *    <jk>true</jk>.
167    */
168   public boolean isNoTableHeaders() { return noTableHeaders; }
169
170   /**
171    * Returns the format of this bean property
172    *
173    * @return The value of the {@link Html#format()} annotation.
174    */
175   protected HtmlFormat getFormat() { return format; }
176
177   /**
178    * Returns <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#HTML}.
179    *
180    * @return <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#HTML}.
181    */
182   protected boolean isHtml() { return format == HtmlFormat.HTML; }
183
184   /**
185    * Returns <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#HTML_CDC}.
186    *
187    * @return <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#HTML_CDC}.
188    */
189   protected boolean isHtmlCdc() { return format == HtmlFormat.HTML_CDC; }
190
191   /**
192    * Returns <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#HTML_SDC}.
193    *
194    * @return <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#HTML_SDC}.
195    */
196   protected boolean isHtmlSdc() { return format == HtmlFormat.HTML_SDC; }
197
198   /**
199    * Returns whether this bean property should not be serialized as an HTML table.
200    *
201    * @return
202    *    <jk>true</jk> if the the {@link Html @Html} annotation is specified, and {@link Html#noTables() @Html(noTables)} is
203    *    <jk>true</jk>.
204    */
205   protected boolean isNoTables() { return noTables; }
206
207   /**
208    * Returns <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#PLAIN_TEXT}.
209    *
210    * @return <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#PLAIN_TEXT}.
211    */
212   protected boolean isPlainText() { return format == HtmlFormat.PLAIN_TEXT; }
213
214   /**
215    * Returns <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#XML}.
216    *
217    * @return <jk>true</jk> if {@link #getFormat()} returns {@link HtmlFormat#XML}.
218    */
219   protected boolean isXml() { return format == HtmlFormat.XML; }
220}