1 /*
2  * JasperReports - Free Java Reporting Library.
3  * Copyright (C) 2001 - 2019 TIBCO Software Inc. All rights reserved.
4  * http://www.jaspersoft.com
5  *
6  * Unless you have purchased a commercial license agreement from Jaspersoft,
7  * the following license terms apply:
8  *
9  * This program is part of JasperReports.
10  *
11  * JasperReports is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License as published by
13  * the Free Software Foundation, either version 3 of the License, or
14  * (at your option) any later version.
15  *
16  * JasperReports is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19  * GNU Lesser General Public License for more details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with JasperReports. If not, see <http://www.gnu.org/licenses/>.
23  */

24 package net.sf.jasperreports.engine.util;
25
26 import java.lang.reflect.InvocationTargetException;
27 import java.text.DateFormat;
28 import java.text.DecimalFormat;
29 import java.text.NumberFormat;
30 import java.text.SimpleDateFormat;
31 import java.util.Locale;
32 import java.util.TimeZone;
33
34 import net.sf.jasperreports.engine.JRRuntimeException;
35
36
37 /**
38  * @author Teodor Danciu (teodord@users.sourceforge.net)
39  */

40 public class DefaultFormatFactory implements FormatFactory
41 {
42     public static final String EXCEPTION_MESSAGE_KEY_FACTORY_INSTANCE_ERROR = "util.format.factory.instance.error";
43     public static final String EXCEPTION_MESSAGE_KEY_FACTORY_LOADING_ERROR = "util.format.factory.loading.error";
44
45     /**
46      * Used in the date pattern to specify the default style.
47      * @see java.text.DateFormat#DEFAULT
48      */

49     public static final String STANDARD_DATE_FORMAT_DEFAULT = "default";
50
51     /**
52      * Used in the date pattern to specify the short style.
53      * @see java.text.DateFormat#SHORT
54      */

55     public static final String STANDARD_DATE_FORMAT_SHORT = "short";
56
57     /**
58      * Used in the date pattern to specify the medium style.
59      * @see java.text.DateFormat#MEDIUM
60      */

61     public static final String STANDARD_DATE_FORMAT_MEDIUM = "medium";
62
63     /**
64      * Used in the date pattern to specify the long style.
65      * @see java.text.DateFormat#LONG
66      */

67     public static final String STANDARD_DATE_FORMAT_LONG = "long";
68
69     /**
70      * Used in the date pattern to specify the full style.
71      * @see java.text.DateFormat#FULL
72      */

73     public static final String STANDARD_DATE_FORMAT_FULL = "full";
74
75     /**
76      * Used in the date pattern to specify that the date or time should not be included.
77      */

78     public static final String STANDARD_DATE_FORMAT_HIDE = "hide";
79
80     /**
81      * Used in the date format pattern to separate the date and time styles.
82      */

83     public static final String STANDARD_DATE_FORMAT_SEPARATOR = ",";
84
85     /**
86      * Number pattern to show integer value as duration expressed in hours:minutes:seconds.
87      */

88     public static final String STANDARD_NUMBER_FORMAT_DURATION = "[h]:mm:ss";
89
90
91     @Override
92     public DateFormat createDateFormat(String pattern, Locale locale, TimeZone tz)
93     {
94         int[] dateStyle = null;
95         int[] timeStyle = null;
96         if (pattern != null && pattern.trim().length() > 0)
97         {            
98             int sepIdx = pattern.indexOf(STANDARD_DATE_FORMAT_SEPARATOR);
99             String dateTok = sepIdx < 0 ? pattern : pattern.substring(0, sepIdx);
100             dateStyle = getDateStyle(dateTok);
101             if (dateStyle != null)
102             {
103                 if (sepIdx >= 0)
104                 {
105                     String timeTok = pattern.substring(sepIdx + STANDARD_DATE_FORMAT_SEPARATOR.length());
106                     timeStyle = getDateStyle(timeTok);
107                 }
108                 else
109                 {
110                     timeStyle = dateStyle;
111                 }
112             }
113         }
114         
115         DateFormat format;
116         if (dateStyle != null && timeStyle != null)
117         {
118             format = getDateFormat(dateStyle, timeStyle, locale);
119         }
120         else
121         {            
122             if (locale == null)
123             {
124                 format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
125             }
126             else
127             {
128                 format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT, locale);
129             }
130             if (
131                 pattern != null && pattern.trim().length() > 0
132                 && format instanceof SimpleDateFormat
133                 )
134             {
135                 ((SimpleDateFormat) format).applyPattern(pattern);
136             }
137         }
138         
139         if (tz != null)
140         {
141             format.setTimeZone(tz);
142         }
143
144         return format;
145     }
146
147
148     protected static int[] getDateStyle(String pattern)
149     {
150         if (pattern.equalsIgnoreCase(STANDARD_DATE_FORMAT_DEFAULT))
151         {
152             return new int[]{DateFormat.DEFAULT};
153         }
154         else if (pattern.equalsIgnoreCase(STANDARD_DATE_FORMAT_SHORT))
155         {
156             return new int[]{DateFormat.SHORT};
157         }
158         else if (pattern.equalsIgnoreCase(STANDARD_DATE_FORMAT_MEDIUM))
159         {
160             return new int[]{DateFormat.MEDIUM};
161         }
162         else if (pattern.equalsIgnoreCase(STANDARD_DATE_FORMAT_LONG))
163         {
164             return new int[]{DateFormat.LONG};
165         }
166         else if (pattern.equalsIgnoreCase(STANDARD_DATE_FORMAT_FULL))
167         {
168             return new int[]{DateFormat.FULL};
169         }
170         else if (pattern.equalsIgnoreCase(STANDARD_DATE_FORMAT_HIDE))
171         {
172             return new int[0];
173         }
174         else
175         {
176             return null;
177         }
178     }
179
180     
181     protected static DateFormat getDateFormat(int[] dateStyle, int[] timeStyle, Locale locale)
182     {
183         if (dateStyle.length == 0)
184         {
185             if (timeStyle.length == 0)
186             {
187                 return new SimpleDateFormat("");
188             }
189
190             return locale == null ? 
191                     DateFormat.getTimeInstance(timeStyle[0]) :
192                         DateFormat.getTimeInstance(timeStyle[0], locale);
193         }
194
195         if (timeStyle.length == 0)
196         {
197             return locale == null ? 
198                     DateFormat.getDateInstance(dateStyle[0]) :
199                     DateFormat.getDateInstance(dateStyle[0], locale);
200         }
201
202         return locale == null ? 
203                 DateFormat.getDateTimeInstance(dateStyle[0], timeStyle[0]) :
204                 DateFormat.getDateTimeInstance(dateStyle[0], timeStyle[0], locale);
205     }
206     
207     
208     @Override
209     public NumberFormat createNumberFormat(String pattern, Locale locale)
210     {
211         NumberFormat format = null;
212         if (pattern != null && pattern.trim().length() > 0)
213         {
214             if (STANDARD_NUMBER_FORMAT_DURATION.equals(pattern))
215             {
216                 format = new DurationNumberFormat();
217             }
218             else
219             {
220                 if (locale == null)
221                 {
222                     format = NumberFormat.getNumberInstance();
223                 }
224                 else
225                 {
226                     format = NumberFormat.getNumberInstance(locale);
227                 }
228                 
229                 if (format instanceof DecimalFormat)
230                 {
231                     ((DecimalFormat) format).applyPattern(pattern);
232                 }
233             }
234         }
235         return format;
236     }
237     
238     
239     public static FormatFactory createFormatFactory(String formatFactoryClassName)
240     {
241         FormatFactory formatFactory = null;
242         
243         if (formatFactoryClassName != null)
244         {
245             try
246             {
247                 Class<?> formatFactoryClass = JRClassLoader.loadClassForName(formatFactoryClassName);    
248                 formatFactory = (FormatFactory) formatFactoryClass.getDeclaredConstructor().newInstance();
249             }
250             catch (ClassNotFoundException e)
251             {
252                 throw 
253                     new JRRuntimeException(
254                         EXCEPTION_MESSAGE_KEY_FACTORY_LOADING_ERROR,
255                         new Object[]{formatFactoryClassName},
256                         e);
257             }
258             catch (NoSuchMethodException | InvocationTargetException 
259                 | IllegalAccessException | InstantiationException e)
260             {
261                 throw 
262                     new JRRuntimeException(
263                         EXCEPTION_MESSAGE_KEY_FACTORY_INSTANCE_ERROR,
264                         new Object[]{formatFactoryClassName},
265                         e);
266             }
267         }
268         else
269         {
270             formatFactory = new DefaultFormatFactory();
271         }
272         
273         return formatFactory;
274     }
275
276
277 }
278