KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > opensymphony > oscache > web > tag > CacheTag


1 /*
2  * Copyright (c) 2002-2003 by OpenSymphony
3  * All rights reserved.
4  */

5 package com.opensymphony.oscache.web.tag;
6
7 import com.opensymphony.oscache.base.Cache;
8 import com.opensymphony.oscache.base.NeedsRefreshException;
9 import com.opensymphony.oscache.util.StringUtil;
10 import com.opensymphony.oscache.web.ServletCacheAdministrator;
11 import com.opensymphony.oscache.web.WebEntryRefreshPolicy;
12
13 import org.apache.commons.logging.Log;
14 import org.apache.commons.logging.LogFactory;
15
16 import java.io.IOException JavaDoc;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.List JavaDoc;
20
21 import javax.servlet.http.HttpServletRequest JavaDoc;
22 import javax.servlet.jsp.JspTagException JavaDoc;
23 import javax.servlet.jsp.PageContext JavaDoc;
24 import javax.servlet.jsp.tagext.BodyTagSupport JavaDoc;
25 import javax.servlet.jsp.tagext.TryCatchFinally JavaDoc;
26
27 /**
28  * CacheTag is a tag that allows for server-side caching of post-processed JSP content.<p>
29  *
30  * It also gives great programatic control over refreshing, flushing and updating the cache.<p>
31  *
32  * Usage Example:
33  * <pre><code>
34  * &lt;%@ taglib uri="oscache" prefix="cache" %&gt;
35  * &lt;cache:cache key="mycache"
36  * scope="application"
37  * refresh="false"
38  * time="30">
39  * jsp content here... refreshed every 30 seconds
40  * &lt;/cache:cache&gt;
41  * </code></pre>
42  *
43  * @author <a HREF="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
44  * @author <a HREF="mailto:tgochenour@peregrine.com">Todd Gochenour</a>
45  * @author <a HREF="mailto:fbeauregard@pyxis-tech.com">Francois Beauregard</a>
46  * @author <a HREF="mailto:abergevin@pyxis-tech.com">Alain Bergevin</a>
47  * @version $Revision: 1.2 $
48  */

49 public class CacheTag extends BodyTagSupport JavaDoc implements TryCatchFinally JavaDoc {
50     /**
51     * Constants for time computation
52     */

53     private final static int SECOND = 1;
54     private final static int MINUTE = 60 * SECOND;
55     private final static int HOUR = 60 * MINUTE;
56     private final static int DAY = 24 * HOUR;
57     private final static int WEEK = 7 * DAY;
58     private final static int MONTH = 30 * DAY;
59     private final static int YEAR = 365 * DAY;
60
61     /**
62     * The key under which the tag counter will be stored in the request
63     */

64     private final static String JavaDoc CACHE_TAG_COUNTER_KEY = "__oscache_tag_counter";
65
66     /**
67     * Constants for refresh time
68     */

69     final static private int ONE_MINUTE = 60;
70     final static private int ONE_HOUR = 60 * ONE_MINUTE;
71     final static private int DEFAULT_TIMEOUT = ONE_HOUR;
72     private static transient Log log = LogFactory.getLog(CacheTag.class);
73
74     /**
75     * Cache modes
76     */

77     final static private int SILENT_MODE = 1;
78
79     /**
80     * A flag to indicate whether a NeedsRefreshException was thrown and
81     * the update needs to be cancelled
82     */

83     boolean cancelUpdateRequired = false;
84     private Cache cache = null;
85
86     /**
87     * If no groups are specified, the cached content does not get put into any groups
88     */

89     private List JavaDoc groups = null;
90     private ServletCacheAdministrator admin = null;
91
92     /**
93     * The actual key to use. This is generated based on the supplied key, scope etc.
94     */

95     private String JavaDoc actualKey = null;
96
97     /**
98     * The content that was retrieved from cache
99     */

100     private String JavaDoc content = null;
101
102     /**
103     * The cron expression that is used to expire cache entries at specific dates and/or times.
104     */

105     private String JavaDoc cron = null;
106
107     /**
108     * if cache key is null, the request URI is used
109     */

110     private String JavaDoc key = null;
111
112     /**
113     * The ISO-639 language code to distinguish different pages in application scope
114     */

115     private String JavaDoc language = null;
116
117     /**
118     * Class used to handle the refresh policy logic
119     */

120     private String JavaDoc refreshPolicyClass = null;
121
122     /**
123     * Parameters that will be passed to the init method of the
124     * refresh policy instance.
125     */

126     private String JavaDoc refreshPolicyParam = null;
127
128     /**
129     * Whether the cache should be refreshed instantly
130     */

131     private boolean refresh = false;
132
133     /**
134     * used for subtags to tell this tag that we should use the cached version
135     */

136     private boolean useBody = true;
137
138     /**
139     * The cache mode. Valid values are SILENT_MODE
140     */

141     private int mode = 0;
142
143     /**
144     * The cache scope to use
145     */

146     private int scope = PageContext.APPLICATION_SCOPE;
147
148     /**
149     * time (in seconds) before cache should be refreshed
150     */

151     private int time = DEFAULT_TIMEOUT;
152
153     /**
154     * Set the time this cache entry will be cached for. A date and/or time in
155     * either ISO-8601 format or a simple format can be specified. The acceptable
156     * syntax for the simple format can be any one of the following:
157     *
158     * <ul>
159     * <li>0 (seconds)
160     * <li>0s (seconds)
161     * <li>0m (minutes)
162     * <li>0h (hours)
163     * <li>0d (days)
164     * <li>0w (weeks)
165     * </ul>
166     *
167     * @param duration The duration to cache this content (using either the simple
168     * or the ISO-8601 format). Passing in a duration of zero will turn off the
169     * caching, while a negative value will result in the cached content never
170     * expiring (ie, the cached content will always be served as long as it is
171     * present).
172     */

173     public void setDuration(String JavaDoc duration) {
174         try {
175             // Try Simple Date Format Duration first because it's faster
176
this.time = parseDuration(duration);
177         } catch (Exception JavaDoc ex) {
178             if (log.isDebugEnabled()) {
179                 log.debug("Failed parsing simple duration format '" + duration + "' (" + ex.getMessage() + "). Trying ISO-8601 format...");
180             }
181
182             try {
183                 // Try ISO-8601 Duration
184
this.time = parseISO_8601_Duration(duration);
185             } catch (Exception JavaDoc ex1) {
186                 // An invalid duration entered, not much impact.
187
// The default timeout will be used
188
log.warn("The requested cache duration '" + duration + "' is invalid (" + ex1.getMessage() + "). Reverting to the default timeout");
189                 this.time = DEFAULT_TIMEOUT;
190             }
191         }
192     }
193
194     /**
195     * Sets the cron expression that should be used to expire content at specific
196     * dates and/or times.
197     */

198     public void setCron(String JavaDoc cron) {
199         this.cron = cron;
200     }
201
202     /**
203      * Sets the groups for this cache entry. Any existing groups will
204      * be replaced.
205      *
206      * @param groups A comma-delimited list of groups that the cache entry belongs to.
207      */

208     public void setGroups(String JavaDoc groups) {
209         // FIXME: ArrayList doesn't avoid duplicates
210
this.groups = StringUtil.split(groups, ',');
211     }
212
213     /**
214      * Adds to the groups for this cache entry.
215      *
216      * @param group A group to which the cache entry should belong.
217      */

218     void addGroup(String JavaDoc group) {
219         if (groups == null) {
220             // FIXME: ArrayList doesn't avoid duplicates
221
groups = new ArrayList JavaDoc();
222         }
223
224         groups.add(group);
225     }
226
227     /**
228      * Adds comma-delimited list of groups that the cache entry belongs to.
229      *
230      * @param groups A comma-delimited list of groups that the cache entry belongs to also.
231      */

232     void addGroups(String JavaDoc groupsString) {
233         if (groups == null) {
234             // FIXME: ArrayList doesn't avoid duplicates
235
groups = new ArrayList JavaDoc();
236         }
237
238         groups.addAll(StringUtil.split(groupsString, ','));
239     }
240
241     /**
242     * Set the key for this cache entry.
243     *
244     * @param key The key for this cache entry.
245     */

246     public void setKey(String JavaDoc key) {
247         this.key = key;
248     }
249
250     /**
251     * Set the ISO-639 language code to distinguish different pages in application scope
252     *
253     * @param language The language code for this cache entry.
254     */

255     public void setLanguage(String JavaDoc language) {
256         this.language = language;
257     }
258
259     /**
260     * This method allows the user to programatically decide whether the cached
261     * content should be refreshed immediately.
262     *
263     * @param refresh Whether or not to refresh this cache entry immediately.
264     */

265     public void setRefresh(boolean refresh) {
266         this.refresh = refresh;
267     }
268
269     /**
270     * Setting this to <code>true</code> prevents the cache from writing any output
271     * to the response, however the JSP content is still cached as normal.
272     * @param mode The cache mode to use.
273     */

274     public void setMode(String JavaDoc mode) {
275         if ("silent".equalsIgnoreCase(mode)) {
276             this.mode = SILENT_MODE;
277         } else {
278             this.mode = 0;
279         }
280     }
281
282     /**
283     * Class used to handle the refresh policy logic
284     */

285     public void setRefreshpolicyclass(String JavaDoc refreshPolicyClass) {
286         this.refreshPolicyClass = refreshPolicyClass;
287     }
288
289     /**
290     * Parameters that will be passed to the init method of the
291     * refresh policy instance.
292     */

293     public void setRefreshpolicyparam(String JavaDoc refreshPolicyParam) {
294         this.refreshPolicyParam = refreshPolicyParam;
295     }
296
297     // ----------- setMethods ------------------------------------------------------
298

299     /**
300     * Set the scope of this cache.
301     * <p>
302     * @param scope The scope of this cache. Either "application" (default) or "session".
303     */

304     public void setScope(String JavaDoc scope) {
305         if (scope.equalsIgnoreCase(ServletCacheAdministrator.SESSION_SCOPE_NAME)) {
306             this.scope = PageContext.SESSION_SCOPE;
307         } else {
308             this.scope = PageContext.APPLICATION_SCOPE;
309         }
310     }
311
312     /**
313     * Set the time this cache entry will be cached for (in seconds)
314     *
315     * @param time The time to cache this content (in seconds). Passing in
316     * a time of zero will turn off the caching. A negative value for the
317     * time will result in the cached content never expiring (ie, the cached
318     * content will always be served if it is present)
319     */

320     public void setTime(int time) {
321         this.time = time;
322     }
323
324     /**
325     * This controls whether or not the body of the tag is evaluated or used.<p>
326     *
327     * It is most often called by the &lt;UseCached /&gt; tag to tell this tag to
328     * use the cached content.
329     *
330     * @see UseCachedTag
331     * @param useBody Whether or not to use the cached content.
332     */

333     public void setUseBody(boolean useBody) {
334         if (log.isDebugEnabled()) {
335             log.debug("<cache>: Set useBody to " + useBody);
336         }
337
338         this.useBody = useBody;
339     }
340
341     /**
342     * After the cache body, either update the cache, serve new cached content or
343     * indicate an error.
344     *
345     * @throws JspTagException The standard exception thrown.
346     * @return The standard BodyTag return.
347     */

348     public int doAfterBody() throws JspTagException JavaDoc {
349         String JavaDoc body = null;
350
351         try {
352             // if we have a body, and we have not been told to use the cached version
353
if ((bodyContent != null) && (useBody || (time == 0)) && ((body = bodyContent.getString()) != null)) {
354                 if ((time != 0) || (refreshPolicyClass != null)) {
355                     // Instantiate custom refresh policy if needed
356
WebEntryRefreshPolicy policy = null;
357
358                     if (refreshPolicyClass != null) {
359                         try {
360                             policy = (WebEntryRefreshPolicy) Class.forName(refreshPolicyClass).newInstance();
361                             policy.init(actualKey, refreshPolicyParam);
362                         } catch (Exception JavaDoc e) {
363                             if (log.isInfoEnabled()) {
364                                 log.info("<cache>: Problem instantiating or initializing refresh policy : " + refreshPolicyClass);
365                             }
366                         }
367                     }
368
369                     if (log.isDebugEnabled()) {
370                         log.debug("<cache>: Updating cache entry with new content : " + actualKey);
371                     }
372
373                     cancelUpdateRequired = false;
374
375                     if ((groups == null) || groups.isEmpty()) {
376                         cache.putInCache(actualKey, body, policy);
377                     } else {
378                         String JavaDoc[] groupArray = new String JavaDoc[groups.size()];
379                         groups.toArray(groupArray);
380                         cache.putInCache(actualKey, body, groupArray, policy, null);
381                     }
382                 }
383             }
384             // otherwise if we have been told to use the cached content and we have cached content
385
else {
386                 if (!useBody && (content != null)) {
387                     if (log.isInfoEnabled()) {
388                         log.info("<cache>: Using cached version as instructed, useBody = false : " + actualKey);
389                     }
390
391                     body = content;
392                 }
393                 // either the cached entry is blank and a subtag has said don't useBody, or body is null
394
else {
395                     if (log.isInfoEnabled()) {
396                         log.info("<cache>: Missing cached content : " + actualKey);
397                     }
398
399                     body = "Missing cached content";
400                 }
401             }
402
403             // Only display anything if we're not running in silent mode
404
if (mode != SILENT_MODE) {
405                 bodyContent.clearBody();
406                 bodyContent.write(body);
407                 bodyContent.writeOut(bodyContent.getEnclosingWriter());
408             }
409         } catch (java.io.IOException JavaDoc e) {
410             throw new JspTagException JavaDoc("IO Error: " + e.getMessage());
411         }
412
413         return SKIP_BODY;
414     }
415
416     public void doCatch(Throwable JavaDoc throwable) throws Throwable JavaDoc {
417         throw throwable;
418     }
419
420     /**
421     * The end tag - clean up variables used.
422     *
423     * @throws JspTagException The standard exception thrown.
424     * @return The standard BodyTag return.
425     */

426     public int doEndTag() throws JspTagException JavaDoc {
427         return EVAL_PAGE;
428     }
429
430     public void doFinally() {
431         if (cancelUpdateRequired && (actualKey != null)) {
432             cache.cancelUpdate(actualKey);
433         }
434         
435         // reset all states, CACHE-144
436
groups = null;
437         scope = PageContext.APPLICATION_SCOPE;
438         cron = null;
439         key = null;
440         language = null;
441         refreshPolicyClass = null;
442         refreshPolicyParam = null;
443         time = DEFAULT_TIMEOUT;
444         refresh = false;
445         mode = 0;
446     }
447
448     /**
449     * The start of the tag.
450     * <p>
451     * Grabs the administrator, the cache, the specific cache entry, then decides
452     * whether to refresh.
453     * <p>
454     * If no refresh is needed, this serves the cached content directly.
455     *
456     * @throws JspTagException The standard exception thrown.
457     * @return The standard doStartTag() return.
458     */

459     public int doStartTag() throws JspTagException JavaDoc {
460         cancelUpdateRequired = false;
461         useBody = true;
462         content = null;
463
464         // We can only skip the body if the cache has the data
465
int returnCode = EVAL_BODY_BUFFERED;
466
467         if (admin == null) {
468             admin = ServletCacheAdministrator.getInstance(pageContext.getServletContext());
469         }
470
471         // Retrieve the cache
472
if (scope == PageContext.SESSION_SCOPE) {
473             cache = admin.getSessionScopeCache(((HttpServletRequest JavaDoc) pageContext.getRequest()).getSession(true));
474         } else {
475             cache = admin.getAppScopeCache(pageContext.getServletContext());
476         }
477
478         // This allows to have multiple cache tags on a single page without
479
// having to specify keys. However, nested cache tags are not supported.
480
// In that case you would have to supply a key.
481
String JavaDoc suffix = null;
482
483         if (key == null) {
484             synchronized (pageContext.getRequest()) {
485                 Object JavaDoc o = pageContext.getRequest().getAttribute(CACHE_TAG_COUNTER_KEY);
486
487                 if (o == null) {
488                     suffix = "1";
489                 } else {
490                     suffix = Integer.toString(Integer.parseInt((String JavaDoc) o) + 1);
491                 }
492             }
493
494             pageContext.getRequest().setAttribute(CACHE_TAG_COUNTER_KEY, suffix);
495         }
496
497         // Generate the actual cache key
498
actualKey = admin.generateEntryKey(key, (HttpServletRequest JavaDoc) pageContext.getRequest(), scope, language, suffix);
499
500         /*
501         if
502         - refresh is not set,
503         - the cacheEntry itself does not need to be refreshed before 'time' and
504         - the administrator has not had the cache entry's scope flushed
505
506         send out the cached version!
507         */

508         try {
509             if (refresh) {
510                 // Force a refresh
511
content = (String JavaDoc) cache.getFromCache(actualKey, 0, cron);
512             } else {
513                 // Use the specified refresh period
514
content = (String JavaDoc) cache.getFromCache(actualKey, time, cron);
515             }
516
517             try {
518                 if (log.isDebugEnabled()) {
519                     log.debug("<cache>: Using cached entry : " + actualKey);
520                 }
521
522                 // Ensure that the cache returns the data correctly. Else re-evaluate the body
523
if ((content != null)) {
524                     if (mode != SILENT_MODE) {
525                         pageContext.getOut().write(content);
526                     }
527
528                     returnCode = SKIP_BODY;
529                 }
530             } catch (IOException JavaDoc e) {
531                 throw new JspTagException JavaDoc("IO Exception: " + e.getMessage());
532             }
533         } catch (NeedsRefreshException nre) {
534             cancelUpdateRequired = true;
535             content = (String JavaDoc) nre.getCacheContent();
536         }
537
538         if (returnCode == EVAL_BODY_BUFFERED) {
539             if (log.isDebugEnabled()) {
540                 log.debug("<cache>: Cached content not used: New cache entry, cache stale or scope flushed : " + actualKey);
541             }
542         }
543
544         return returnCode;
545     }
546
547     /**
548     * Convert a SimpleDateFormat string to seconds
549     * Acceptable format are :
550     * <ul>
551     * <li>0s (seconds)
552     * <li>0m (minute)
553     * <li>0h (hour)
554     * <li>0d (day)
555     * <li>0w (week)
556     * </ul>
557     * @param duration The simple date time to parse
558     * @return The value in seconds
559     */

560     private int parseDuration(String JavaDoc duration) {
561         int time = 0;
562
563         //Detect if the factor is specified
564
try {
565             time = Integer.parseInt(duration);
566         } catch (Exception JavaDoc ex) {
567             //Extract number and ajust this number with the time factor
568
for (int i = 0; i < duration.length(); i++) {
569                 if (!Character.isDigit(duration.charAt(i))) {
570                     time = Integer.parseInt(duration.substring(0, i));
571
572                     switch ((int) duration.charAt(i)) {
573                         case (int) 's':
574                             time *= SECOND;
575                             break;
576                         case (int) 'm':
577                             time *= MINUTE;
578                             break;
579                         case (int) 'h':
580                             time *= HOUR;
581                             break;
582                         case (int) 'd':
583                             time *= DAY;
584                             break;
585                         case (int) 'w':
586                             time *= WEEK;
587                             break;
588                         default:
589                         //no defined use as is
590
}
591
592                     break;
593                 }
594
595                 // if
596
}
597
598             // for
599
}
600
601         // catch
602
return time;
603     }
604
605     /**
606     * Parse an ISO-8601 format date and return it's value in seconds
607     *
608     * @param duration The ISO-8601 date
609     * @return The equivalent number of seconds
610     * @throws Exception
611     */

612     private int parseISO_8601_Duration(String JavaDoc duration) throws Exception JavaDoc {
613         int years = 0;
614         int months = 0;
615         int days = 0;
616         int hours = 0;
617         int mins = 0;
618         int secs = 0;
619
620         // If there is a negative sign, it must be first
621
// If it is present, we will ignore it
622
int index = duration.indexOf("-");
623
624         if (index > 0) {
625             throw new Exception JavaDoc("Invalid duration (- must be at the beginning)");
626         }
627
628         // First caracter must be P
629
String JavaDoc workValue = duration.substring(index + 1);
630
631         if (workValue.charAt(0) != 'P') {
632             throw new Exception JavaDoc("Invalid duration (P must be at the beginning)");
633         }
634
635         // Must contain a value
636
workValue = workValue.substring(1);
637
638         if (workValue.length() == 0) {
639             throw new Exception JavaDoc("Invalid duration (nothing specified)");
640         }
641
642         // Check if there is a T
643
index = workValue.indexOf('T');
644
645         String JavaDoc timeString = "";
646
647         if (index > 0) {
648             timeString = workValue.substring(index + 1);
649
650             // Time cannot be empty
651
if (timeString.equals("")) {
652                 throw new Exception JavaDoc("Invalid duration (T with no time)");
653             }
654
655             workValue = workValue.substring(0, index);
656         } else if (index == 0) {
657             timeString = workValue.substring(1);
658             workValue = "";
659         }
660
661         if (!workValue.equals("")) {
662             validateDateFormat(workValue);
663
664             int yearIndex = workValue.indexOf('Y');
665             int monthIndex = workValue.indexOf('M');
666             int dayIndex = workValue.indexOf('D');
667
668             if ((yearIndex != -1) && (monthIndex != -1) && (yearIndex > monthIndex)) {
669                 throw new Exception JavaDoc("Invalid duration (Date part not properly specified)");
670             }
671
672             if ((yearIndex != -1) && (dayIndex != -1) && (yearIndex > dayIndex)) {
673                 throw new Exception JavaDoc("Invalid duration (Date part not properly specified)");
674             }
675
676             if ((dayIndex != -1) && (monthIndex != -1) && (monthIndex > dayIndex)) {
677                 throw new Exception JavaDoc("Invalid duration (Date part not properly specified)");
678             }
679
680             if (yearIndex >= 0) {
681                 years = (new Integer JavaDoc(workValue.substring(0, yearIndex))).intValue();
682             }
683
684             if (monthIndex >= 0) {
685                 months = (new Integer JavaDoc(workValue.substring(yearIndex + 1, monthIndex))).intValue();
686             }
687
688             if (dayIndex >= 0) {
689                 if (monthIndex >= 0) {
690                     days = (new Integer JavaDoc(workValue.substring(monthIndex + 1, dayIndex))).intValue();
691                 } else {
692                     if (yearIndex >= 0) {
693                         days = (new Integer JavaDoc(workValue.substring(yearIndex + 1, dayIndex))).intValue();
694                     } else {
695                         days = (new Integer JavaDoc(workValue.substring(0, dayIndex))).intValue();
696                     }
697                 }
698             }
699         }
700
701         if (!timeString.equals("")) {
702             validateHourFormat(timeString);
703
704             int hourIndex = timeString.indexOf('H');
705             int minuteIndex = timeString.indexOf('M');
706             int secondIndex = timeString.indexOf('S');
707
708             if ((hourIndex != -1) && (minuteIndex != -1) && (hourIndex > minuteIndex)) {
709                 throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
710             }
711
712             if ((hourIndex != -1) && (secondIndex != -1) && (hourIndex > secondIndex)) {
713                 throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
714             }
715
716             if ((secondIndex != -1) && (minuteIndex != -1) && (minuteIndex > secondIndex)) {
717                 throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
718             }
719
720             if (hourIndex >= 0) {
721                 hours = (new Integer JavaDoc(timeString.substring(0, hourIndex))).intValue();
722             }
723
724             if (minuteIndex >= 0) {
725                 mins = (new Integer JavaDoc(timeString.substring(hourIndex + 1, minuteIndex))).intValue();
726             }
727
728             if (secondIndex >= 0) {
729                 if (timeString.length() != (secondIndex + 1)) {
730                     throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
731                 }
732
733                 if (minuteIndex >= 0) {
734                     timeString = timeString.substring(minuteIndex + 1, timeString.length() - 1);
735                 } else {
736                     if (hourIndex >= 0) {
737                         timeString = timeString.substring(hourIndex + 1, timeString.length() - 1);
738                     } else {
739                         timeString = timeString.substring(0, timeString.length() - 1);
740                     }
741                 }
742
743                 if (timeString.indexOf('.') == (timeString.length() - 1)) {
744                     throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
745                 }
746
747                 secs = (new Double JavaDoc(timeString)).intValue();
748             }
749         }
750
751         // Compute Value
752
return secs + (mins * MINUTE) + (hours * HOUR) + (days * DAY) + (months * MONTH) + (years * YEAR);
753     }
754
755     /**
756     * Validate the basic date format
757     *
758     * @param basicDate The string to validate
759     * @throws Exception
760     */

761     private void validateDateFormat(String JavaDoc basicDate) throws Exception JavaDoc {
762         int yearCounter = 0;
763         int monthCounter = 0;
764         int dayCounter = 0;
765
766         for (int counter = 0; counter < basicDate.length(); counter++) {
767             // Check if there's any other caracters than Y, M, D and numbers
768
if (!Character.isDigit(basicDate.charAt(counter)) && (basicDate.charAt(counter) != 'Y') && (basicDate.charAt(counter) != 'M') && (basicDate.charAt(counter) != 'D')) {
769                 throw new Exception JavaDoc("Invalid duration (Date part not properly specified)");
770             }
771
772             // Check if the allowed caracters are present more than 1 time
773
if (basicDate.charAt(counter) == 'Y') {
774                 yearCounter++;
775             }
776
777             if (basicDate.charAt(counter) == 'M') {
778                 monthCounter++;
779             }
780
781             if (basicDate.charAt(counter) == 'D') {
782                 dayCounter++;
783             }
784         }
785
786         if ((yearCounter > 1) || (monthCounter > 1) || (dayCounter > 1)) {
787             throw new Exception JavaDoc("Invalid duration (Date part not properly specified)");
788         }
789     }
790
791     /**
792     * Validate the basic hour format
793     *
794     * @param basicHour The string to validate
795     * @throws Exception
796     */

797     private void validateHourFormat(String JavaDoc basicHour) throws Exception JavaDoc {
798         int minuteCounter = 0;
799         int secondCounter = 0;
800         int hourCounter = 0;
801
802         for (int counter = 0; counter < basicHour.length(); counter++) {
803             if (!Character.isDigit(basicHour.charAt(counter)) && (basicHour.charAt(counter) != 'H') && (basicHour.charAt(counter) != 'M') && (basicHour.charAt(counter) != 'S') && (basicHour.charAt(counter) != '.')) {
804                 throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
805             }
806
807             if (basicHour.charAt(counter) == 'H') {
808                 hourCounter++;
809             }
810
811             if (basicHour.charAt(counter) == 'M') {
812                 minuteCounter++;
813             }
814
815             if (basicHour.charAt(counter) == 'S') {
816                 secondCounter++;
817             }
818         }
819
820         if ((hourCounter > 1) || (minuteCounter > 1) || (secondCounter > 1)) {
821             throw new Exception JavaDoc("Invalid duration (Time part not properly specified)");
822         }
823     }
824 }
825
Popular Tags