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.properties.admin.resources.representation.html.share;
17  
18  import static de.smartics.resteasy.hypermedia.relations.Relations.HOME;
19  import static de.smartics.resteasy.hypermedia.relations.Relations.SELF;
20  import static de.smartics.resteasy.hypermedia.relations.Relations.UP;
21  
22  import java.io.IOException;
23  import java.io.OutputStream;
24  import java.net.URI;
25  import java.security.Principal;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import javax.ws.rs.core.UriBuilder;
30  
31  import org.apache.commons.lang.StringUtils;
32  
33  import de.smartics.html5.jatl.Html;
34  import de.smartics.html5.jatl.HtmlFactory;
35  import de.smartics.html5.jatl.HtmlResourceContext;
36  import de.smartics.properties.admin.resources.controller.ApiResource;
37  import de.smartics.properties.admin.resources.representation.share.AbstractRepresentationRenderer;
38  import de.smartics.resteasy.hypermedia.renderer.LinkDescriptor;
39  import de.smartics.resteasy.hypermedia.resources.Resources;
40  
41  /**
42   * Base implementation for HTML documents.
43   *
44   * @param <T> the type of the resource the renderer is rendering representations
45   *          for.
46   */
47  public abstract class AbstractHtmlRepresentationRenderer<T> extends
48      AbstractRepresentationRenderer<T>
49  {
50    // ********************************* Fields *********************************
51  
52    // --- constants ------------------------------------------------------------
53  
54    // --- members --------------------------------------------------------------
55  
56    /**
57     * The context information to render the representation.
58     */
59    protected final HtmlResourceContext htmlContext;
60  
61    /**
62     * The factory to access output properties.
63     */
64    protected final HtmlFactory factory;
65  
66    /**
67     * The HTML instance to create HTML documents.
68     */
69    protected final Html html;
70  
71    /**
72     * Helper to localize application specific resources.
73     */
74    protected final HtmlPathHelper pathHelper;
75  
76    // ****************************** Initializer *******************************
77  
78    // ****************************** Constructors ******************************
79  
80    /**
81     * Default constructor using a stream.
82     *
83     * @param htmlContext the context information to render the representation.
84     * @param entityStream the stream to write to.
85     */
86    protected AbstractHtmlRepresentationRenderer(
87        final HtmlResourceContext htmlContext, final OutputStream entityStream)
88    {
89      super(htmlContext.getContext(), htmlContext.getFactory().getCharset()
90          .displayName(), entityStream, "getAsHtml");
91  
92      this.htmlContext = htmlContext;
93      this.factory = htmlContext.getFactory();
94      this.html = factory.create(entityStream);
95      this.pathHelper = new HtmlPathHelper(htmlContext.getContext().getUriInfo());
96    }
97  
98    // ****************************** Inner Classes *****************************
99  
100   // ********************************* Methods ********************************
101 
102   // --- init -----------------------------------------------------------------
103 
104   // --- get&set --------------------------------------------------------------
105 
106   // --- business -------------------------------------------------------------
107 
108   @Override
109   protected final void httpBody()
110   {
111     html.declaration();
112     html.html();
113 
114     htmlHead();
115     htmlBody();
116 
117     html.end();
118   }
119 
120   private void htmlHead()
121   {
122     html.head();
123     html.title().text(getTitle()).end();
124     html.meta().attr("charset", factory.getCharset().toString()).end();
125 
126     final String bootstrapCssUrl = pathHelper.bootstrap("css/bootstrap.css");
127     html.link().rel("stylesheet").type("text/css").href(bootstrapCssUrl)
128         .media("screen").end();
129 
130     final String cssUrl = pathHelper.css("properties.css");
131     html.link().rel("stylesheet").type("text/css").href(cssUrl).media("screen")
132         .end();
133 
134     renderApplicationStateHtmlHead();
135 
136     html.end();
137   }
138 
139   private void renderApplicationStateHtmlHead()
140   {
141     final Resources discovery = htmlContext.getContext().getDiscovery();
142     for (final LinkDescriptor link : discovery.links())
143     {
144       final String rel = link.getRel();
145       final String href = link.getHref();
146 
147       html.link().rel(rel);
148 
149       final String type = link.getType();
150       if (StringUtils.isNotBlank(type))
151       {
152         html.type(type);
153       }
154       html.href(href);
155 
156       html.end();
157     }
158   }
159 
160   /**
161    * Returns the title to the page.
162    *
163    * @return the title to the page.
164    */
165   protected abstract String getTitle();
166 
167   /**
168    * Renders the subtitle within the page body.
169    *
170    * @param subTitle the optional sub title to render.
171    */
172   protected void renderPageTitle(final String subTitle)
173   {
174     html.div().classAttr("page-header");
175 
176     html.h1().text(getTitle());
177     if (StringUtils.isNotBlank(subTitle))
178     {
179       html.text(" ").small().text(subTitle).end();
180     }
181     html.end();
182 
183     html.end();
184   }
185 
186   private void htmlBody()
187   {
188     html.body();
189     html.script().src(pathHelper.jquery("jquery.js")).end();
190     html.script().src(pathHelper.bootstrap("js/bootstrap.js")).end();
191 
192     html.div().id("wrap");
193     controls();
194     breadcrumbs();
195     html.div().classAttr("container");
196     bodyContents();
197     html.end();
198     html.end();
199 
200     footer();
201     html.end();
202   }
203 
204   private void controls()
205   {
206     html.div().classAttr("pull-right");
207     html.div().classAttr("btn-group");
208 
209     renderLogout();
210 
211     html.end();
212     html.end();
213   }
214 
215   private void renderLogout()
216   {
217     final UriBuilder builder =
218         htmlContext.getContext().getUriInfo().getBaseUriBuilder();
219     final URI uri = builder.path(ApiResource.class, "logout").build();
220     final String logoutUrl = uri.toString();
221     html.form().classAttr("form-inline").method("POST").action(logoutUrl);
222 
223     html.button().type("submit").id("logout")
224         .classAttr("btn btn-mini btn-default");
225     final String user = calcUser();
226     html.text("logout " + user).end();
227 
228     html.end();
229   }
230 
231   private String calcUser()
232   {
233     final Principal principal =
234         htmlContext.getContext().getRequest().getUserPrincipal();
235     if (principal != null)
236     {
237       return principal.getName();
238     }
239     else
240     {
241       return "";
242     }
243   }
244 
245   /**
246    * Returns the breadcrumbs.
247    *
248    * @return the list of breadcrumb links.
249    */
250   protected abstract List<LinkDescriptor> breadcrumbLinks();
251 
252   private void breadcrumbs()
253   {
254     final List<LinkDescriptor> breadcrumbs = breadcrumbLinks();
255     if (breadcrumbs.isEmpty())
256     {
257       return;
258     }
259 
260     final int size = breadcrumbs.size();
261     if (size == 0)
262     {
263       return;
264     }
265 
266     html.start("nav").ul().classAttr("breadcrumb");
267     final List<String> ups = new ArrayList<String>();
268     for (int i = 0; i < size - 1; i++)
269     {
270       final LinkDescriptor link = breadcrumbs.get(i);
271       if (i > 0)
272       {
273         ups.add(UP);
274       }
275       else
276       {
277         link.addRels(HOME);
278       }
279       link.addRels(ups);
280       render(link);
281     }
282     final LinkDescriptor link = breadcrumbs.get(size - 1);
283     if (size == 1)
284     {
285       link.addRels(HOME);
286     }
287     link.addRels(SELF);
288     render(link, true);
289 
290     html.end().end();
291   }
292 
293   private void render(final LinkDescriptor link)
294   {
295     render(link, false);
296   }
297 
298   private void render(final LinkDescriptor link, final boolean last)
299   {
300     final String label = link.getShortLabel();
301     if (StringUtils.isNotBlank(label))
302     {
303       html.li().shortLink(link);
304       if (!last)
305       {
306         html.span().classAttr("divider").text("/").end();
307       }
308 
309       html.end();
310     }
311   }
312 
313   /**
314    * The contents to write to the HTML body.
315    */
316   protected abstract void bodyContents();
317 
318   private void footer()
319   {
320     html.div().id("footer");
321     html.div().classAttr("container");
322     html.p().classAttr("muted credit");
323     html.text("powered by ");
324     html.a().href("http://www.smartics.eu/smartics-properties")
325         .text("smartics-properties").end();
326     html.end();
327     html.end();
328   }
329 
330   @Override
331   protected final void close()
332   {
333     html.done();
334     try
335     {
336       html.getWriter().flush();
337     }
338     catch (final IOException e)
339     {
340       // Ignore
341     }
342   }
343 
344   // --- object basics --------------------------------------------------------
345 
346 }