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