View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.syncope.client.ui.commons.panels;
20  
21  import java.io.Serializable;
22  import java.lang.reflect.Field;
23  import java.lang.reflect.InvocationTargetException;
24  import java.util.ArrayList;
25  import java.util.List;
26  import java.util.Optional;
27  import org.apache.commons.lang3.StringUtils;
28  import org.apache.syncope.client.ui.commons.Constants;
29  import org.apache.wicket.Component;
30  import org.apache.wicket.PageReference;
31  import org.apache.wicket.core.util.lang.PropertyResolver;
32  import org.apache.wicket.markup.html.basic.Label;
33  import org.apache.wicket.markup.html.list.ListItem;
34  import org.apache.wicket.markup.html.list.ListView;
35  import org.apache.wicket.markup.html.panel.Panel;
36  import org.apache.wicket.model.ResourceModel;
37  import org.slf4j.Logger;
38  import org.slf4j.LoggerFactory;
39  
40  public abstract class SimpleListViewPanel<T extends Serializable> extends Panel {
41  
42      private static final long serialVersionUID = -7982691107029848579L;
43  
44      private static final Logger LOG = LoggerFactory.getLogger(SimpleListViewPanel.class);
45  
46      private final ListView<T> beans;
47  
48      private final List<T> listOfItems;
49  
50      /**
51       * Table view of a list of beans.
52       *
53       * @param id        id.
54       * @param list      list of item.
55       * @param reference list item reference class.
56       * @param includes  Used to sort and restrict the set of bean's fields to be shown.
57       */
58      private SimpleListViewPanel(
59              final String id,
60              final List<T> list,
61              final Class<T> reference,
62              final List<String> includes) {
63  
64          super(id);
65          setOutputMarkupId(true);
66  
67          final List<String> toBeIncluded;
68          if (includes == null || includes.isEmpty()) {
69              toBeIncluded = new ArrayList<>();
70              for (Field field : reference.getDeclaredFields()) {
71                  toBeIncluded.add(field.getName());
72              }
73          } else {
74              toBeIncluded = includes;
75          }
76  
77          if (toBeIncluded.isEmpty()) {
78              LOG.warn("No field has been retrieved from {}", reference.getName());
79              listOfItems = new ArrayList<>();
80          } else if (list == null || list.isEmpty()) {
81              LOG.info("No item to be shown");
82              listOfItems = new ArrayList<>();
83          } else {
84              listOfItems = list;
85              LOG.debug("Show fields {}", toBeIncluded);
86          }
87  
88          add(header(toBeIncluded));
89  
90          beans = new ListView<>("beans", listOfItems) {
91  
92              private static final long serialVersionUID = -9112553137618363167L;
93  
94              @Override
95              protected void populateItem(final ListItem<T> beanItem) {
96                  final T bean = beanItem.getModelObject();
97  
98                  final ListView<String> fields = new ListView<>("fields", toBeIncluded) {
99  
100                     private static final long serialVersionUID = -9112553137618363167L;
101 
102                     @Override
103                     protected void populateItem(final ListItem<String> fieldItem) {
104                         fieldItem.add(getValueComponent(fieldItem.getModelObject(), bean));
105                     }
106                 };
107 
108                 beanItem.add(fields);
109             }
110         };
111         add(beans.setOutputMarkupId(true).setRenderBodyOnly(true));
112     }
113 
114     protected ListView<String> header(final List<String> labels) {
115         return new ListView<>("names", labels) {
116 
117             private static final long serialVersionUID = -9112553137618363167L;
118 
119             @Override
120             protected void populateItem(final ListItem<String> item) {
121                 item.add(new Label(Constants.NAME_FIELD_NAME,
122                         new ResourceModel(item.getModelObject(), item.getModelObject())));
123             }
124         };
125     }
126 
127     /**
128      * SimpleListViewPanel builder.
129      *
130      * @param <T> list item reference type.
131      */
132     public static class Builder<T extends Serializable> implements Serializable {
133 
134         private static final long serialVersionUID = -3643771352897992172L;
135 
136         private final List<String> includes = new ArrayList<>();
137 
138         private List<T> items;
139 
140         private final Class<T> reference;
141 
142         private final PageReference pageReference;
143 
144         public Builder(final Class<T> reference, final PageReference pageRef) {
145             this.pageReference = pageRef;
146             this.reference = reference;
147             this.items = null;
148         }
149 
150         /**
151          * Sets list of items.
152          *
153          * @param items list of items.
154          * @return current builder object.
155          */
156         public Builder<T> setItems(final List<T> items) {
157             this.items = items;
158             return this;
159         }
160 
161         /**
162          * Adds item.
163          *
164          * @param item item.
165          * @return current builder object.
166          */
167         public Builder<T> addItem(final T item) {
168             if (item == null) {
169                 return this;
170             }
171 
172             if (this.items == null) {
173                 this.items = new ArrayList<>();
174             }
175 
176             this.items.add(item);
177             return this;
178         }
179 
180         /**
181          * Gives fields to be shown. It could be used to give an order as well.
182          *
183          * @param includes field names to be shown.
184          * @return current builder object.
185          */
186         public Builder<T> includes(final String... includes) {
187             for (String include : includes) {
188                 if (include != null && !this.includes.contains(include)) {
189                     this.includes.add(include);
190                 }
191             }
192             return this;
193         }
194 
195         /**
196          * Overridable method to generate field value rendering component.
197          *
198          * @param key  field key.
199          * @param bean source bean.
200          * @return field rendering component.
201          */
202         protected Component getValueComponent(final String key, final T bean) {
203             LOG.debug("Processing field {}", key);
204 
205             Object value;
206             try {
207                 value = includes.contains(key)
208                         ? PropertyResolver.getPropertyGetter(key, bean).invoke(bean)
209                         : StringUtils.EMPTY;
210             } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
211                 LOG.error("Error retrieving value for field {}", key, e);
212                 value = StringUtils.EMPTY;
213             }
214 
215             LOG.debug("Field value {}", value);
216 
217             return Optional.ofNullable(value)
218                     .map(o -> new Label("field", new ResourceModel(o.toString(), o.toString())))
219                     .orElseGet(() -> new Label("field", StringUtils.EMPTY));
220         }
221 
222         protected T getActualItem(final T item, final List<T> list) {
223             return item == null
224                     ? null
225                     : list.stream().filter(item::equals).findAny().orElse(null);
226         }
227 
228         public SimpleListViewPanel<T> build(final String id) {
229             return new SimpleListViewPanel<T>(id, items, reference, includes) {
230 
231                 @Override
232                 protected Component getValueComponent(final String key, final T bean) {
233                     return Builder.this.getValueComponent(key, bean);
234                 }
235 
236                 @Override
237                 protected T getActualItem(final T item, final List<T> list) {
238                     return Builder.this.getActualItem(item, list);
239                 }
240 
241             };
242         }
243 
244     }
245 
246     protected abstract T getActualItem(T item, List<T> list);
247 
248     protected abstract Component getValueComponent(String key, T bean);
249 
250 }