View Javadoc
1   /*
2    * Copyright (c) 2002-2022, City of Paris
3    * All rights reserved.
4    *
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions
7    * are met:
8    *
9    *  1. Redistributions of source code must retain the above copyright notice
10   *     and the following disclaimer.
11   *
12   *  2. Redistributions in binary form must reproduce the above copyright notice
13   *     and the following disclaimer in the documentation and/or other materials
14   *     provided with the distribution.
15   *
16   *  3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its
17   *     contributors may be used to endorse or promote products derived from
18   *     this software without specific prior written permission.
19   *
20   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
24   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30   * POSSIBILITY OF SUCH DAMAGE.
31   *
32   * License 1.0
33   */
34  package fr.paris.lutece.util.bean;
35  
36  import fr.paris.lutece.portal.service.i18n.I18nService;
37  import fr.paris.lutece.portal.service.util.AppException;
38  import fr.paris.lutece.portal.service.util.AppLogService;
39  import fr.paris.lutece.util.date.DateUtil;
40  
41  import org.apache.commons.beanutils.BeanUtilsBean;
42  import org.apache.commons.beanutils.PropertyUtils;
43  import org.apache.commons.beanutils.SuppressPropertiesBeanIntrospector;
44  import org.apache.commons.beanutils.converters.DateConverter;
45  import org.apache.commons.beanutils.converters.SqlTimeConverter;
46  
47  import java.lang.reflect.Field;
48  import java.lang.reflect.InvocationTargetException;
49  
50  import java.sql.Date;
51  import java.sql.Timestamp;
52  import java.util.HashMap;
53  import java.util.Locale;
54  import java.util.Map;
55  import java.util.Map.Entry;
56  
57  import javax.servlet.http.HttpServletRequest;
58  
59  /**
60   * Bean Utils
61   */
62  public final class BeanUtil
63  {
64      private static final char UNDERSCORE = '_';
65  
66      static
67      {
68          PropertyUtils.addBeanIntrospector( SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS );
69      }
70  
71      private static Map<String, BeanUtilsBean> _mapBeanUtilsBeans;
72  
73      /**
74       * BeanUtil initialization, considering Lutèce availables locales and date format properties
75       */
76      public static void init( )
77      {
78          _mapBeanUtilsBeans = new HashMap<>( );
79  
80          for ( Locale locale : I18nService.getAdminAvailableLocales( ) )
81          {
82              BeanUtilsBean beanUtilsBean = new BeanUtilsBean( );
83              beanUtilsBean.getPropertyUtils( ).addBeanIntrospector( SuppressPropertiesBeanIntrospector.SUPPRESS_CLASS );
84  
85              DateConverter dateConverter = new DateConverter( null );
86              dateConverter.setPatterns( new String[] { DateUtil.ISO_PATTERN_DATE, I18nService.getDateFormatShortPattern( locale ) } );
87              beanUtilsBean.getConvertUtils( ).register( dateConverter, Date.class );
88  
89              SqlTimeConverter sqlTimeConverter = new SqlTimeConverter( null );
90              beanUtilsBean.getConvertUtils( ).register( sqlTimeConverter, Timestamp.class );
91  
92              _mapBeanUtilsBeans.put( locale.getLanguage( ), beanUtilsBean );
93          }
94      }
95  
96      /** Private constructor */
97      private BeanUtil( )
98      {
99      }
100 
101     /**
102      * Populate a bean using parameters in http request
103      * 
104      * @param bean
105      * @param request
106      */
107     public static void populate( Object bean, HttpServletRequest request )
108     {
109         populate( bean, request, null );
110     }
111 
112     /**
113      * Populate a bean using parameters in http request, with locale date format controls
114      *
115      * @param bean
116      *            bean to populate
117      * @param request
118      *            http request
119      * @param locale
120      */
121     public static void populate( Object bean, HttpServletRequest request, Locale locale )
122     {
123         for ( Field field : bean.getClass( ).getDeclaredFields( ) )
124         {
125             try
126             {
127                 // for all boolean field, init to false
128                 if ( Boolean.class.isAssignableFrom( field.getType( ) ) || boolean.class.isAssignableFrom( field.getType( ) ) )
129                 {
130                     field.setAccessible( true );
131                     field.set( bean, false );
132                 }
133             }
134             catch( Exception e )
135             {
136                 String error = "La valeur du champ " + field.getName( ) + " de la classe " + bean.getClass( ).getName( ) + " n'a pas pu être récupéré ";
137                 AppLogService.error( error, e );
138                 throw new AppException( error, e );
139             }
140         }
141 
142         try
143         {
144             BeanUtilsBean beanUtilsBean;
145             if ( locale != null && _mapBeanUtilsBeans != null )
146             {
147                 beanUtilsBean = _mapBeanUtilsBeans.get( locale.getLanguage( ) );
148             }
149             else
150             {
151                 beanUtilsBean = BeanUtilsBean.getInstance( );
152             }
153 
154             beanUtilsBean.populate( bean, convertMap( request.getParameterMap( ) ) );
155         }
156         catch( InvocationTargetException | IllegalAccessException e )
157         {
158             AppLogService.error( "Unable to fetch data from request", e );
159         }
160     }
161 
162     /**
163      * Convert map by casifying parameters names.
164      * 
165      * @param mapInput
166      *            The input map
167      * @return The output map
168      */
169     public static Map<String, Object> convertMap( Map<String, String [ ]> mapInput )
170     {
171         Map<String, Object> mapOutput = new HashMap<>( );
172 
173         for ( Entry<String, String [ ]> entry : mapInput.entrySet( ) )
174         {
175             mapOutput.put( convertUnderscores( entry.getKey( ) ), entry.getValue( ) );
176         }
177 
178         return mapOutput;
179     }
180 
181     /**
182      * Remove underscore and set the next letter in caps
183      * 
184      * @param strSource
185      *            The source
186      * @return The converted string
187      */
188     public static String convertUnderscores( String strSource )
189     {
190         StringBuilder sb = new StringBuilder( );
191         boolean bCapitalizeNext = false;
192 
193         for ( char c : strSource.toCharArray( ) )
194         {
195             if ( c == UNDERSCORE )
196             {
197                 bCapitalizeNext = true;
198             }
199             else
200             {
201                 if ( bCapitalizeNext )
202                 {
203                     sb.append( Character.toUpperCase( c ) );
204                     bCapitalizeNext = false;
205                 }
206                 else
207                 {
208                     sb.append( c );
209                 }
210             }
211         }
212 
213         return sb.toString( );
214     }
215 }