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;
17  
18  import static de.smartics.properties.admin.domain.model.AppRelations.PROPERTY;
19  
20  import java.io.OutputStream;
21  import java.net.URI;
22  import java.util.List;
23  
24  import org.apache.commons.lang.ObjectUtils;
25  import org.apache.commons.lang.StringUtils;
26  
27  import de.smartics.html5.jatl.HtmlResourceContext;
28  import de.smartics.properties.admin.domain.model.ConfigurationProperty;
29  import de.smartics.properties.admin.domain.model.Paths;
30  import de.smartics.properties.admin.domain.model.Roles;
31  import de.smartics.properties.admin.resources.controller.ApiResource;
32  import de.smartics.properties.admin.resources.controller.PropertyResource;
33  import de.smartics.properties.admin.resources.representation.html.share.AbstractHtmlRepresentationRenderer;
34  import de.smartics.properties.api.config.domain.DescribedProperty;
35  import de.smartics.properties.api.config.domain.ValidatedProperty;
36  import de.smartics.properties.api.config.domain.key.ConfigurationKey;
37  import de.smartics.properties.api.core.domain.PropertyCategories;
38  import de.smartics.properties.api.core.domain.PropertyConstraint;
39  import de.smartics.properties.api.core.domain.PropertyDescriptor;
40  import de.smartics.properties.spi.core.constraints.PropertyRangeConstraint;
41  import de.smartics.resteasy.hypermedia.renderer.LinkDescriptor;
42  import de.smartics.util.lang.StringFunction;
43  
44  /**
45   * Displays a single property in an HTML page.
46   */
47  public final class PropertyHtmlRepresentationRenderer extends
48      AbstractHtmlRepresentationRenderer<ConfigurationProperty>
49  {
50    // ********************************* Fields *********************************
51  
52    // --- constants ------------------------------------------------------------
53  
54    /**
55     * The class for HTML tables.
56     * <p>
57     * The value of this constant is {@value}.
58     * </p>
59     */
60    private static final String CSS_CLASS_TABLE =
61        "table table-striped table-bordered";
62  
63    // --- members --------------------------------------------------------------
64  
65    /**
66     * The domain object to render.
67     */
68    private final ConfigurationProperty domainObject;
69  
70    // ****************************** Initializer *******************************
71  
72    // ****************************** Constructors ******************************
73  
74    /**
75     * Default constructor.
76     *
77     * @param htmlContext the context information to render the representation.
78     * @param domainObject the domain object to render.
79     * @param entityStream the stream to write to.
80     */
81    public PropertyHtmlRepresentationRenderer(
82        final HtmlResourceContext htmlContext,
83        final ConfigurationProperty domainObject, final OutputStream entityStream)
84    {
85      super(htmlContext, entityStream);
86      this.domainObject = domainObject;
87    }
88  
89    // ****************************** Inner Classes *****************************
90  
91    // ********************************* Methods ********************************
92  
93    // --- init -----------------------------------------------------------------
94  
95    // --- get&set --------------------------------------------------------------
96  
97    @Override
98    protected String getTitle()
99    {
100     final DescribedProperty property = domainObject.getProperty();
101     return property.getName();
102   }
103 
104   // --- business -------------------------------------------------------------
105 
106   @Override
107   protected void bodyContents()
108   {
109     final Object value = domainObject.getPropertyValue();
110 
111     final String subTitle = ObjectUtils.toString(value, null);
112     renderPageTitle(subTitle);
113 
114     valueInformation();
115     descriptorInformation();
116   }
117 
118   private void valueInformation()
119   {
120     final DescribedProperty property = domainObject.getProperty();
121 
122     html.h2().text("Value").end();
123     html.table().classAttr(CSS_CLASS_TABLE);
124     html.tr().th().text("type").end().th().text("value").end().end();
125 
126     if (property instanceof ValidatedProperty)
127     {
128       final String resolvedValue =
129           ObjectUtils.toString(
130               ((ValidatedProperty) property).getValidatedValue(), null);
131       final String unresolvedValue = property.getValue();
132 
133       if (ObjectUtils.equals(unresolvedValue, resolvedValue))
134       {
135         renderValueFormInRow(property.getName(), property);
136       }
137       else if (property.getDescriptor().isSecured())
138       {
139         renderRow("unresolved value", property.getValue());
140         renderValueFormInRow(property.getName(), property);
141       }
142       else
143       {
144         renderRow("resolved value", resolvedValue);
145         renderValueFormInRow("unresolved value", property);
146       }
147     }
148     else
149     {
150       renderValueFormInRow("unresolved value", property);
151     }
152     renderRow("Source Configuration", property.getConfigurationKey());
153 
154     html.end();
155   }
156 
157   private void descriptorInformation()
158   {
159     final PropertyDescriptor descriptor = domainObject.getDescriptor();
160 
161     html.h2().text("Descriptor").end();
162     html.table().classAttr(CSS_CLASS_TABLE);
163     html.tr().th().text("name").end().th().text("value").end().end();
164     renderRow("mandatory", descriptor.isMandatory());
165     renderRow("access type", descriptor.getAccessType());
166     renderRow("use type", descriptor.getUseType().toString());
167     renderRow("categories", toString(descriptor.getCategories()));
168     renderRow("comment", descriptor.getComment());
169     renderRow("configuration time", descriptor.getConfigurationTime());
170     renderRow("update interval", descriptor.getUpdateIntervalInMs());
171     renderRow("default expression", descriptor.getDefaultExpression());
172     renderRow("value type", descriptor.getType());
173     renderRow("value range", descriptor.getValueRange());
174     renderRow("constraints", toString(descriptor.getConstraints()));
175     renderRow("declaring type", descriptor.getDeclaringType().getName());
176     renderRow("home page", descriptor.getContext().getHomePageUrl());
177     final String reportUrl =
178         descriptor.getContext().getPropertiesContext()
179             .createReportUrl(descriptor);
180     renderRow("Report", reportUrl);
181     html.end();
182 
183     html.p();
184     final String propertyKey = descriptor.getKey().toString();
185     final String configurationKey = domainObject.getConfigurationKey();
186     final URI url = createUrl(configurationKey, propertyKey);
187     html.a().id("asXml").rel(PROPERTY).href(url.toString())
188         .icon("icon-download-alt").text(" Download as XML").end();
189     html.end();
190   }
191 
192   private URI createUrl(final String configurationKey, final String propertyKey)
193   {
194     final URI url =
195         htmlContext.getContext().getUriInfo().getBaseUriBuilder()
196             .path(PropertyResource.class, "getAsDotXml")
197             .build(new Object[] { configurationKey, propertyKey }, false);
198     return url;
199   }
200 
201   private String toString(final PropertyCategories categories)
202   {
203     final List<Class<?>> types = categories.getCategories();
204     final StringBuilder buffer = new StringBuilder(64);
205     for (final Class<?> type : types)
206     {
207       buffer.append(type.getName()).append(' ');
208     }
209     return StringFunction.chop(buffer).toString();
210   }
211 
212   private Object toString(
213       final List<? extends PropertyConstraint<?>> constraints)
214   {
215     final StringBuilder buffer = new StringBuilder(64);
216 
217     for (final Object constraint : constraints)
218     {
219       if (constraint instanceof PropertyRangeConstraint)
220       {
221         continue;
222       }
223       buffer.append(' ').append(constraint);
224     }
225 
226     return buffer.toString();
227   }
228 
229   private void renderRow(final String label, final Object value)
230   {
231     if (isNotBlank(value))
232     {
233       html.tr();
234       html.td().text(label).end().td().text(String.valueOf(value)).end();
235       html.end();
236     }
237   }
238 
239   private void renderValueFormInRow(final String label,
240       final DescribedProperty property)
241   {
242     final String value =
243         (property instanceof ValidatedProperty)
244             && property.getDescriptor().isSecured() ? ObjectUtils
245             .toString(((ValidatedProperty) property).getValidatedValue())
246             : property.getValue();
247 
248     if (htmlContext.getContext().isUserInRole(Roles.EDIT_PROPERTY))
249     {
250       html.tr();
251       html.td().text(label).end().td();
252 
253       createForm(property, value);
254 
255       html.end();
256       html.end();
257     }
258     else
259     {
260       renderRow(label, value);
261     }
262   }
263 
264   private void createForm(final DescribedProperty property, final String value)
265   {
266     final PropertyDescriptor descriptor = domainObject.getDescriptor();
267     final boolean disabled = !descriptor.isRuntimeMutable();
268     html.form().classAttr("form-inline").method("POST");
269     if (disabled)
270     {
271       createOverrideButton();
272     }
273     createInputField(property, value, disabled);
274     createSubmitButton(disabled);
275 
276     if (property.getDescriptor().isSecured())
277     {
278       final LinkDescriptor link =
279           linkDescriptorFactory.createDescriptor(ApiResource.SECURITY,
280               "getAsHtml");
281       link.setTarget("smartics_properties_security");
282       html.link(link);
283     }
284 
285     html.end();
286   }
287 
288   private void createOverrideButton()
289   {
290     html.button()
291         .id("override")
292         .type("button")
293         .classAttr("btn btn-mini btn-default")
294         .onclick(
295             "var toggleButton = document.getElementById(\"override\"); "
296                 + "document.getElementById(\"submit\").disabled = false; "
297                 + "document.getElementById(\"" + Paths.PARAM_VALUE
298                 + "\").disabled = false; "
299                 + "toggleButton.style.display = 'none';").text("override!")
300         .end();
301   }
302 
303   private void createInputField(final DescribedProperty property,
304       final String value, final boolean disabled)
305   {
306     html.input().type("text").id(Paths.PARAM_VALUE).name(Paths.PARAM_VALUE)
307         .classAttr("input-xlarge");
308     addDisabledStatus(disabled);
309     if (isDefinedInThisConfiguration(property))
310     {
311       html.value(value);
312     }
313     else
314     {
315       html.attr("placeholder", value);
316     }
317     html.end();
318   }
319 
320   private void createSubmitButton(final boolean disabled)
321   {
322     html.button().type("submit").id("submit")
323         .classAttr("btn btn-mini btn-default");
324     addDisabledStatus(disabled);
325     html.text("update").end();
326   }
327 
328   private boolean isDefinedInThisConfiguration(final DescribedProperty property)
329   {
330     final ConfigurationKey<?> key = property.getConfigurationKey();
331     final String keyString = key != null ? key.toString() : null;
332     final boolean isDefined =
333         domainObject.getConfigurationKey().equals(keyString);
334     return isDefined;
335   }
336 
337   private void addDisabledStatus(final boolean disabled)
338   {
339     if (disabled)
340     {
341       html.disabled("disabled");
342     }
343   }
344 
345   private boolean isNotBlank(final Object value)
346   {
347     if (value == null)
348     {
349       return false;
350     }
351 
352     return StringUtils.isNotBlank(String.valueOf(value));
353   }
354 
355   @Override
356   protected List<LinkDescriptor> breadcrumbLinks()
357   {
358     return breadcrumb.property(domainObject.getConfigurationKey(),
359         domainObject.getPropertyKey());
360   }
361 
362   // --- object basics --------------------------------------------------------
363 
364 }