View Javadoc

1   package org.apache.maven.continuum.web.view.jsp.ui;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import com.opensymphony.xwork2.ActionContext;
23  import com.opensymphony.xwork2.TextProvider;
24  import com.opensymphony.xwork2.util.ValueStack;
25  
26  import java.io.IOException;
27  import java.text.SimpleDateFormat;
28  import java.util.ArrayList;
29  import java.util.Calendar;
30  import java.util.Date;
31  import java.util.List;
32  
33  import javax.servlet.jsp.JspException;
34  
35  import org.apache.struts2.views.jsp.ui.TextareaTag;
36  
37  /**
38   * First attempt at creating a date tag for the webwork framework. The tag will
39   * format a date by using either a specified format attribute, or by falling
40   * back on to a globally defined 'webwork.date' property.
41   * When nice="true" is specified, it will return a human readable string (in 2 hours, 3 minutes).
42   * <p/>
43   * From http://jira.opensymphony.com/browse/WW-805
44   *
45   * @author <a href="mailto:philip.luppens@gmail.com">Philip Luppens</a>
46   */
47  public class DateTag
48      extends TextareaTag
49  {
50      /*
51       * the name of our property which we will use if the optional format
52       * parameter is not specified.
53       */
54      public final static String DATETAG_PROPERTY = "webwork.date";
55  
56      public final static String DATETAG_PROPERTY_PAST = "webwork.date.format.past";
57  
58      public final static String DATETAG_DEFAULT_PAST = "{0} ago";
59  
60      public final static String DATETAG_PROPERTY_FUTURE = "webwork.date.format.future";
61  
62      public final static String DATETAG_DEFAULT_FUTURE = "in {0}";
63  
64      public final static String DATETAG_PROPERTY_SECONDS = "webwork.date.format.seconds";
65  
66      public final static String DATETAG_DEFAULT_SECONDS = "an instant";
67  
68      public final static String DATETAG_PROPERTY_MINUTES = "webwork.date.format.minutes";
69  
70      public final static String DATETAG_DEFAULT_MINUTES = "{0,choice,1#one minute|1<{0} minutes}";
71  
72      public final static String DATETAG_PROPERTY_HOURS = "webwork.date.format.hours";
73  
74      public final static String DATETAG_DEFAULT_HOURS =
75          "{0,choice,1#one hour|1<{0} hours}{1,choice,0#|1#, one minute|1<, {1} minutes}";
76  
77      public final static String DATETAG_PROPERTY_DAYS = "webwork.date.format.days";
78  
79      public final static String DATETAG_DEFAULT_DAYS =
80          "{0,choice,1#one day|1<{0} days}{1,choice,0#|1#, one hour|1<, {1} hours}";
81  
82      public final static String DATETAG_PROPERTY_YEARS = "webwork.date.format.years";
83  
84      public final static String DATETAG_DEFAULT_YEARS =
85          "{0,choice,1#one year|1<{0} years}{1,choice,0#|1#, one day|1<, {1} days}";
86  
87      //our optional format parameter
88      private String format;
89  
90      private String nameAttr;
91  
92      private boolean nice;
93  
94      private Date date;
95  
96      private TextProvider tp;
97  
98      public int doEndTag()
99          throws JspException
100     {
101         String actualName = findString( nameAttr );
102         String msg = null;
103         ValueStack stack = getStack();
104         //find the name on the valueStack, and cast it to a date
105         Object dateObj = stack.findValue( actualName );
106 
107         if ( dateObj != null )
108         {
109             if ( dateObj instanceof Date )
110             {
111                 date = (Date) dateObj;
112             }
113             else if ( dateObj instanceof Long )
114             {
115                 Calendar cal = Calendar.getInstance();
116                 cal.setTimeInMillis( (Long) dateObj );
117                 date = cal.getTime();
118             }
119             else
120             {
121                 throw new JspException( "Could not cast the requested object " + nameAttr + " to a java.util.Date" );
122             }
123         }
124 
125         if ( date != null && date.getTime() > 0 )
126         {
127             tp = findProviderInStack();
128 
129             if ( tp == null )
130             {
131                 throw new JspException( "Could not find a TextProvider on the stack." );
132             }
133 
134             if ( nice )
135             {
136                 msg = formatTime( date );
137             }
138             else
139             {
140                 if ( format == null )
141                 {
142                     String globalFormat;
143                     //if the format is not specified, fall back using the defined
144                     // property DATETAG_PROPERTY
145 
146                     globalFormat = tp.getText( DATETAG_PROPERTY );
147 
148                     if ( globalFormat != null )
149                     {
150                         msg =
151                             new SimpleDateFormat( globalFormat, ActionContext.getContext().getLocale() ).format( date );
152                     }
153                     else
154                     {
155                         //fall back using the xwork date format ?
156                     }
157                 }
158                 else
159                 {
160                     msg = new SimpleDateFormat( format, ActionContext.getContext().getLocale() ).format( date );
161                 }
162             }
163         }
164 
165         if ( msg != null )
166         {
167             try
168             {
169                 //if we used the id attribute, we will store the formatted date
170                 // in the valuestack, otherwise, we write it to the
171                 // outputstream.
172                 if ( getId() == null )
173                 {
174                     pageContext.getOut().write( msg );
175                 }
176                 else
177                 {
178                     stack.getContext().put( getId(), msg );
179                 }
180             }
181             catch ( IOException e )
182             {
183                 throw new JspException( e );
184             }
185         }
186         return EVAL_PAGE;
187     }
188 
189     private TextProvider findProviderInStack()
190     {
191         for ( Object o : getStack().getRoot() )
192         {
193             if ( o instanceof TextProvider )
194             {
195                 return (TextProvider) o;
196             }
197 
198         }
199         return null;
200     }
201 
202     public String formatTime( Date date )
203     {
204         StringBuffer sb = new StringBuffer();
205         List<Object> args = new ArrayList<Object>();
206         long secs = ( new Date().getTime() - date.getTime() ) / 1000;
207         long mins = secs / 60;
208         int min = (int) mins % 60;
209         long hours = mins / 60;
210         int hour = (int) hours % 24;
211         int days = (int) hours / 24;
212         int day = days % 365;
213         int years = days / 365;
214 
215         if ( Math.abs( secs ) < 60 )
216         {
217             args.add( secs );
218             args.add( sb );
219             args.add( null );
220             sb.append( tp.getText( DATETAG_PROPERTY_SECONDS, DATETAG_DEFAULT_SECONDS, args ) );
221 
222         }
223         else if ( hours == 0 )
224         {
225             args.add( (long) min );
226             args.add( sb );
227             args.add( null );
228             sb.append( tp.getText( DATETAG_PROPERTY_MINUTES, DATETAG_DEFAULT_MINUTES, args ) );
229 
230         }
231         else if ( days == 0 )
232         {
233             args.add( (long) hour );
234             args.add( (long) min );
235             args.add( sb );
236             args.add( null );
237             sb.append( tp.getText( DATETAG_PROPERTY_HOURS, DATETAG_DEFAULT_HOURS, args ) );
238         }
239         else if ( years == 0 )
240         {
241             args.add( (long) days );
242             args.add( (long) hour );
243             args.add( sb );
244             args.add( null );
245             sb.append( tp.getText( DATETAG_PROPERTY_DAYS, DATETAG_DEFAULT_DAYS, args ) );
246         }
247         else
248         {
249             args.add( new Object[]{(long) years} );
250             args.add( new Object[]{(long) day} );
251             args.add( sb );
252             args.add( null );
253 
254             sb.append( tp.getText( DATETAG_PROPERTY_YEARS, DATETAG_DEFAULT_YEARS, args ) );
255         }
256         args.clear();
257         args.add( sb.toString() );
258         if ( date.before( new Date() ) )
259         {
260             //looks like this date is passed
261             return tp.getText( DATETAG_PROPERTY_PAST, DATETAG_DEFAULT_PAST, args );
262         }
263         else
264         {
265             return tp.getText( DATETAG_PROPERTY_FUTURE, DATETAG_DEFAULT_FUTURE, args );
266         }
267     }
268 
269     public void setName( String name )
270     {
271         this.nameAttr = name;
272     }
273 
274     public String getFormat()
275     {
276         return format;
277     }
278 
279     public void setFormat( String format )
280     {
281         this.format = format;
282     }
283 
284     public boolean isNice()
285     {
286         return nice;
287     }
288 
289     public void setNice( boolean nice )
290     {
291         this.nice = nice;
292     }
293 }