001: /*---------------------------------------------------------------------------*\
002: $Id: CurnConfig.java 7041 2007-09-09 01:04:47Z bmc $
003: ---------------------------------------------------------------------------
004: This software is released under a BSD-style license:
005:
006: Copyright (c) 2004-2007 Brian M. Clapper. All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without
009: modification, are permitted provided that the following conditions are
010: met:
011:
012: 1. Redistributions of source code must retain the above copyright notice,
013: this list of conditions and the following disclaimer.
014:
015: 2. The end-user documentation included with the redistribution, if any,
016: must include the following acknowlegement:
017:
018: "This product includes software developed by Brian M. Clapper
019: (bmc@clapper.org, http://www.clapper.org/bmc/). That software is
020: copyright (c) 2004-2007 Brian M. Clapper."
021:
022: Alternately, this acknowlegement may appear in the software itself,
023: if wherever such third-party acknowlegements normally appear.
024:
025: 3. Neither the names "clapper.org", "curn", nor any of the names of the
026: project contributors may be used to endorse or promote products
027: derived from this software without prior written permission. For
028: written permission, please contact bmc@clapper.org.
029:
030: 4. Products derived from this software may not be called "curn", nor may
031: "clapper.org" appear in their names without prior written permission
032: of Brian M. Clapper.
033:
034: THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
036: MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
037: NO EVENT SHALL BRIAN M. CLAPPER BE LIABLE FOR ANY DIRECT, INDIRECT,
038: INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
039: NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
040: DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
041: THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
042: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
043: THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
044: \*---------------------------------------------------------------------------*/
045:
046: package org.clapper.curn;
047:
048: import java.io.File;
049: import java.io.IOException;
050: import java.io.FileNotFoundException;
051: import java.io.InputStream;
052: import java.io.PrintWriter;
053:
054: import java.util.ArrayList;
055: import java.util.Collection;
056: import java.util.Collections;
057: import java.util.HashMap;
058: import java.util.List;
059: import java.util.Map;
060:
061: import java.net.URL;
062: import java.net.MalformedURLException;
063:
064: import org.clapper.util.config.Configuration;
065: import org.clapper.util.config.ConfigurationException;
066: import org.clapper.util.config.NoSuchSectionException;
067: import org.clapper.util.config.NoSuchVariableException;
068:
069: import org.clapper.util.logging.Logger;
070:
071: /**
072: * <p><tt>CurnConfig</tt> uses the <tt>Configuration</tt> class (part of
073: * the <i>clapper.org</i> Java Utility library) to parse and validate the
074: * <i>curn</i> configuration file, holding the results in memory for easy
075: * access.</p>
076: *
077: * @version <tt>$Revision: 7041 $</tt>
078: */
079: public class CurnConfig extends Configuration {
080: /*----------------------------------------------------------------------*\
081: Public Constants
082: \*----------------------------------------------------------------------*/
083:
084: /**
085: * Variable names
086: */
087: public static final String VAR_NO_CACHE_UPDATE = "NoCacheUpdate";
088: public static final String VAR_MAIL_SUBJECT = "Subject";
089: public static final String VAR_DAYS_TO_CACHE = "DaysToCache";
090: public static final String VAR_PARSER_CLASS_NAME = "ParserClass";
091: public static final String VAR_SHOW_RSS_VERSION = "ShowRSSVersion";
092: public static final String VAR_FEED_URL = "URL";
093: public static final String VAR_CLASS = "Class";
094: public static final String VAR_MAX_THREADS = "MaxThreads";
095: public static final String VAR_FORCE_ENCODING = "ForceEncoding";
096: public static final String VAR_FORCE_CHAR_ENCODING = "ForceCharacterEncoding";
097: public static final String VAR_DISABLED = "Disabled";
098:
099: /**
100: * Configuration variable: allow embedded HTML. Not used here. Used by
101: * a plug-in and by output handlers.
102: */
103: public static final String CFG_ALLOW_EMBEDDED_HTML = "AllowEmbeddedHTML";
104:
105: /**
106: * Default values
107: */
108: public static final int DEF_DAYS_TO_CACHE = 365;
109: public static final boolean DEF_NO_CACHE_UPDATE = false;
110: public static final boolean DEF_SHOW_RSS_VERSION = false;
111: public static final boolean DEF_SAVE_ONLY = false;
112: public static final String DEF_PARSER_CLASS_NAME = "org.clapper.curn.parser.rome.RSSParserAdapter";
113: public static final int DEF_MAX_THREADS = 5;
114:
115: /**
116: * Others
117: */
118: public static final String NO_LIMIT_VALUE = "NoLimit";
119:
120: /**
121: * Main section name
122: */
123: public static final String MAIN_SECTION = "curn";
124:
125: /*----------------------------------------------------------------------*\
126: Private Constants
127: \*----------------------------------------------------------------------*/
128:
129: /**
130: * Prefix for sections that describing individual feeds.
131: */
132: private static final String FEED_SECTION_PREFIX = "Feed";
133:
134: /**
135: * Prefix for output handler sections.
136: */
137: private static final String OUTPUT_HANDLER_PREFIX = "OutputHandler";
138:
139: /**
140: * Original default parser; mapped to new default, for backward
141: * compatibility.
142: */
143: private static final String OLD_DEF_PARSER_CLASS_NAME = "org.clapper.curn.parser.minirss.MiniRSSParser";
144:
145: /*----------------------------------------------------------------------*\
146: Private Data Items
147: \*----------------------------------------------------------------------*/
148:
149: private int defaultCacheDays = DEF_DAYS_TO_CACHE;
150: private boolean updateCache = true;
151: private boolean showRSSFormat = false;
152: private Collection<FeedInfo> feeds = new ArrayList<FeedInfo>();
153: private Map<URL, FeedInfo> feedMap = new HashMap<URL, FeedInfo>();
154: private String parserClassName = DEF_PARSER_CLASS_NAME;
155: private List<ConfiguredOutputHandler> outputHandlers = new ArrayList<ConfiguredOutputHandler>();
156: private int maxThreads = DEF_MAX_THREADS;
157: private PrintWriter err;
158:
159: /**
160: * For log messages
161: */
162: private static final Logger log = new Logger(CurnConfig.class);
163:
164: /*----------------------------------------------------------------------*\
165: Constructor
166: \*----------------------------------------------------------------------*/
167:
168: /**
169: * Construct an <tt>CurnConfig</tt> object. You must call one of the
170: * {@link #load(File)} methods to load the configuration.
171: *
172: * @param err where to write errors
173: */
174: CurnConfig(PrintWriter err) {
175: super ();
176: this .err = err;
177: }
178:
179: /*----------------------------------------------------------------------*\
180: Public Methods
181: \*----------------------------------------------------------------------*/
182:
183: /**
184: * Get the name of the RSS parser class to use. The caller is responsible
185: * for loading the returned class name and verifying that it implements
186: * the appropriate interface(s).
187: *
188: * @return the full class name
189: */
190: public String getRSSParserClassName() {
191: return parserClassName;
192: }
193:
194: /**
195: * Gets the list of output handlers from the configuration, in the order
196: * they appeared in the configuration.
197: *
198: * @return an unmodifiable <tt>Collection</tt> of
199: * <tt>ConfiguredOutputHandler</tt> objects. The collection will
200: * be empty, but never null, if no output handlers were configured.
201: */
202: public Collection<ConfiguredOutputHandler> getOutputHandlers() {
203: return Collections.unmodifiableList(outputHandlers);
204: }
205:
206: /**
207: * Return the total number of configured output handlers.
208: *
209: * @return the total number of configured output handlers, or 0 if there
210: * aren't any
211: */
212: public int totalOutputHandlers() {
213: return outputHandlers.size();
214: }
215:
216: /**
217: * Determine whether the cache should be updated.
218: *
219: * @return <tt>true</tt> if the cache should be updated, <tt>false</tt>
220: * if it should not.
221: * @see #setMustUpdateFeedMetadata
222: */
223: public boolean mustUpdateFeedMetadata() {
224: return updateCache;
225: }
226:
227: /**
228: * Get the maximum number of concurrent threads to spawn when retrieving
229: * RSS feeds.
230: *
231: * @return the maximum number of threads
232: *
233: * @see #setMaxThreads
234: */
235: public int getMaxThreads() {
236: return maxThreads;
237: }
238:
239: /**
240: * Set the maximum number of concurrent threads to spawn when retrieving
241: * RSS feeds.
242: *
243: * @param newValue the maximum number of threads
244: *
245: * @throws ConfigurationException bad value
246: *
247: * @see #getMaxThreads
248: */
249: public void setMaxThreads(final int newValue)
250: throws ConfigurationException {
251: if (newValue <= 0) {
252: throw new ConfigurationException(Constants.BUNDLE_NAME,
253: "CurnConfig.badPositiveInteger",
254: "The \"{0}\" configuration "
255: + "parameter cannot be set to "
256: + "{1}. It must have a positive "
257: + "integer value.", new Object[] {
258: VAR_MAX_THREADS, String.valueOf(newValue) });
259: }
260:
261: this .maxThreads = newValue;
262: }
263:
264: /**
265: * Change the "update cache" flag.
266: *
267: * @param val <tt>true</tt> if the cache should be updated, <tt>false</tt>
268: * if it should not
269: * @see #mustUpdateFeedMetadata
270: */
271: public void setMustUpdateFeedMetadata(final boolean val) {
272: updateCache = val;
273: }
274:
275: /**
276: * Return the value of "show RSS version" flag.
277: *
278: * @return <tt>true</tt> if flag is set, <tt>false</tt> if it isn't
279: *
280: * @see #setShowRSSVersionFlag
281: */
282: public boolean showRSSVersion() {
283: return showRSSFormat;
284: }
285:
286: /**
287: * Set the value of the "show RSS version" flag.
288: *
289: * @param val <tt>true</tt> to set the flag,
290: * <tt>false</tt> to clear it
291: *
292: * @see #showRSSVersion
293: */
294: public void setShowRSSVersionFlag(final boolean val) {
295: this .showRSSFormat = val;
296: }
297:
298: /**
299: * Get the configured RSS feeds. The feeds are returned in the order
300: * they were specified in the configuration file.
301: *
302: * @return a <tt>Collection</tt> of <tt>FeedInfo</tt> objects.
303: *
304: * @see #hasFeed
305: * @see #getFeedInfoMap
306: */
307: public Collection<FeedInfo> getFeeds() {
308: return Collections.unmodifiableCollection(feeds);
309: }
310:
311: /**
312: * Determine whether the specified URL is one of the configured RSS
313: * feeds.
314: *
315: * @param url the URL
316: *
317: * @return <tt>true</tt> if it's there, <tt>false</tt> if not
318: *
319: * @see #getFeeds
320: * @see #getFeedInfoMap()
321: */
322: public boolean hasFeed(final URL url) {
323: return feedMap.containsKey(url.toString());
324: }
325:
326: /**
327: * Get the {@link FeedInfo} map.
328: *
329: * @return A <tt>Map</tt> of {@link FeedInfo} objects, indexed by
330: * channel (or feed) URL.
331: *
332: * @see #getFeeds
333: * @see #hasFeed
334: * @see FeedInfo
335: */
336: public Map<URL, FeedInfo> getFeedInfoMap() {
337: return feedMap;
338: }
339:
340: /**
341: * Utility method that retrieves a "deprecated parameter" warning.
342: *
343: * @param badParam the deprecated parameter
344: * @param goodParam the parameter that should be used, or null for none
345: *
346: * @return the message
347: */
348: public String getDeprecatedParamMessage(final String badParam,
349: final String goodParam) {
350: StringBuilder buf = new StringBuilder();
351:
352: buf.append("Warning: Configuration file ");
353:
354: URL configURL = getConfigurationFileURL();
355: if (configURL != null) {
356: buf.append('"');
357: buf.append(configURL.toString());
358: buf.append('"');
359: }
360:
361: buf.append(" uses deprecated \"");
362: buf.append(badParam);
363: buf.append("\" parameter");
364:
365: if (goodParam == null)
366: buf.append(".");
367:
368: else {
369: buf.append(", instead of new \"");
370: buf.append(goodParam);
371: buf.append("\" parameter.");
372: }
373:
374: return buf.toString();
375: }
376:
377: /**
378: * Load configuration from a path. Any existing data is discarded.
379: *
380: * @param path the path
381: *
382: * @throws IOException read error
383: * @throws ConfigurationException parse error
384: */
385: public void load(final String path) throws FileNotFoundException,
386: IOException, ConfigurationException {
387: super .load(path);
388: try {
389: validate();
390: }
391:
392: catch (CurnException ex) {
393: throw new ConfigurationException(ex);
394: }
395: }
396:
397: /**
398: * Load configuration from an open <tt>InputStream</tt>.
399: * Any existing data is discarded.
400: *
401: * @param iStream open input stream
402: *
403: * @throws IOException read error
404: * @throws ConfigurationException parse error
405: */
406: public void load(final InputStream iStream) throws IOException,
407: ConfigurationException {
408: super .load(iStream);
409: try {
410: validate();
411: }
412:
413: catch (CurnException ex) {
414: throw new ConfigurationException(ex);
415: }
416: }
417:
418: /**
419: * Load configuration from a URL. Any existing data is discarded.
420: *
421: * @param url the URL
422: *
423: * @throws IOException read error
424: * @throws ConfigurationException parse error
425: */
426: public void load(final URL url) throws IOException,
427: ConfigurationException {
428: super .load(url);
429: try {
430: validate();
431: }
432:
433: catch (CurnException ex) {
434: throw new ConfigurationException(ex);
435: }
436: }
437:
438: /**
439: * Load configuration from a file. Any existing data is discarded.
440: *
441: * @param file the file
442: *
443: * @throws IOException read error
444: * @throws ConfigurationException parse error
445: */
446: public void load(final File file) throws IOException,
447: ConfigurationException {
448: super .load(file);
449: try {
450: validate();
451: }
452:
453: catch (CurnException ex) {
454: throw new ConfigurationException(ex);
455: }
456: }
457:
458: /*----------------------------------------------------------------------*\
459: Private Methods
460: \*----------------------------------------------------------------------*/
461:
462: /**
463: * Validate the loaded configuration.
464: *
465: * @throws ConfigurationException configuration error
466: * @throws CurnException some other error
467: */
468: private void validate() throws ConfigurationException,
469: CurnException {
470: // First, verify that the main section is there and process it.
471:
472: processMainSection();
473:
474: // Process the remaining sections. Skip ones we don't recognize.
475:
476: for (String sectionName : getSectionNames()) {
477: if (sectionName.startsWith(FEED_SECTION_PREFIX))
478: processFeedSection(sectionName);
479:
480: else if (sectionName.startsWith(OUTPUT_HANDLER_PREFIX))
481: processOutputHandlerSection(sectionName);
482:
483: else
484: processUnknownSection(sectionName);
485: }
486: }
487:
488: /**
489: * Verify existence of main section and process it.
490: *
491: * @throws ConfigurationException configuration error
492: * @throws CurnException some other error
493: */
494: private void processMainSection() throws ConfigurationException,
495: CurnException {
496: if (!this .containsSection(MAIN_SECTION)) {
497: throw new ConfigurationException(Constants.BUNDLE_NAME,
498: "CurnConfig.missingReqSection",
499: "The configuration file is "
500: + "missing the required \"{0}\" "
501: + "section.", new Object[] { MAIN_SECTION });
502: }
503:
504: for (String varName : getVariableNames(MAIN_SECTION)) {
505: try {
506: processMainSectionVariable(varName);
507: }
508:
509: catch (NoSuchVariableException ex) {
510: throw new ConfigurationException(Constants.BUNDLE_NAME,
511: "CurnConfig.missingReqVar",
512: "The configuration file is missing required variable "
513: + "\"{0}\" in section\"{1}\".",
514: new Object[] { ex.getVariableName(),
515: ex.getSectionName() }, ex);
516: }
517: }
518: }
519:
520: /**
521: * Process a single variable from the main section
522: *
523: * @param varName the variable name
524: *
525: * @throws ConfigurationException configuration error
526: * @throws CurnException some other error
527: */
528: private void processMainSectionVariable(final String varName)
529: throws ConfigurationException, CurnException {
530: String val = null;
531:
532: if (varName.equals(VAR_DAYS_TO_CACHE)) {
533: defaultCacheDays = parseMaxDaysParameter(MAIN_SECTION,
534: varName, DEF_DAYS_TO_CACHE);
535: val = String.valueOf(defaultCacheDays);
536: }
537:
538: else if (varName.equals(VAR_NO_CACHE_UPDATE)) {
539: updateCache = (!getOptionalBooleanValue(MAIN_SECTION,
540: varName, DEF_NO_CACHE_UPDATE));
541: val = String.valueOf(updateCache);
542: }
543:
544: else if (varName.equals(VAR_SHOW_RSS_VERSION)) {
545: showRSSFormat = getOptionalBooleanValue(MAIN_SECTION,
546: varName, DEF_SHOW_RSS_VERSION);
547: val = String.valueOf(showRSSFormat);
548: }
549:
550: else if (varName.equals(VAR_PARSER_CLASS_NAME)) {
551: parserClassName = getOptionalStringValue(MAIN_SECTION,
552: varName, DEF_PARSER_CLASS_NAME);
553:
554: // Backward compatibility hack.
555:
556: if (parserClassName.equals(OLD_DEF_PARSER_CLASS_NAME)) {
557: StringBuilder buf = new StringBuilder();
558: buf.append("Warning: The \"");
559: buf.append(parserClassName);
560: buf
561: .append("\" RSS parser class is deprecated. Using \"");
562: buf.append(DEF_PARSER_CLASS_NAME);
563: buf.append("\" instead.");
564: parserClassName = DEF_PARSER_CLASS_NAME;
565:
566: String msg = buf.toString();
567: err.println(msg);
568: log.warn(msg);
569: }
570:
571: val = String.valueOf(parserClassName);
572: }
573:
574: else if (varName.equals(VAR_MAX_THREADS)) {
575: int maxThreads = getOptionalCardinalValue(MAIN_SECTION,
576: varName, DEF_MAX_THREADS);
577: setMaxThreads(maxThreads);
578: val = String.valueOf(maxThreads);
579: }
580:
581: else {
582: val = getOptionalStringValue(MAIN_SECTION, varName, null);
583: }
584:
585: if (val != null) {
586: MetaPlugIn.getMetaPlugIn().runMainConfigItemPlugIn(
587: MAIN_SECTION, varName, this );
588: }
589: }
590:
591: /**
592: * Process a section that identifies an RSS feed to be polled.
593: *
594: * @param sectionName the section name
595: *
596: * @throws ConfigurationException configuration error
597: * @throws CurnException some other error
598: */
599: private void processFeedSection(final String sectionName)
600: throws ConfigurationException, CurnException {
601: FeedInfo feedInfo = null;
602: String feedURLString = null;
603: URL url = null;
604: MetaPlugIn metaPlugIn = MetaPlugIn.getMetaPlugIn();
605: boolean keepFeed = false;
606:
607: feedURLString = getConfigurationValue(sectionName, VAR_FEED_URL);
608:
609: try {
610: url = CurnUtil.normalizeURL(feedURLString);
611: String urlString = url.toString();
612: log.debug("Configured feed: URL=\"" + urlString + "\"");
613: feedInfo = new FeedInfo(url);
614: metaPlugIn.runFeedConfigItemPlugIn(sectionName,
615: VAR_FEED_URL, this , feedInfo);
616: }
617:
618: catch (MalformedURLException ex) {
619: throw new ConfigurationException(Constants.BUNDLE_NAME,
620: "CurnConfig.badFeedURL",
621: "Configuration file section "
622: + "\"{0}\" specifies a bad RSS "
623: + "feed URL \"{1}\"", new Object[] {
624: sectionName, feedURLString });
625: }
626:
627: feedInfo.setDaysToCache(defaultCacheDays);
628:
629: for (String varName : getVariableNames(sectionName)) {
630: String value = null;
631:
632: if (varName.equals(VAR_DAYS_TO_CACHE)) {
633: int maxDays = parseMaxDaysParameter(sectionName,
634: varName, defaultCacheDays);
635: feedInfo.setDaysToCache(maxDays);
636: value = String.valueOf(maxDays);
637: }
638:
639: else if (varName.equals(VAR_FORCE_ENCODING)
640: || varName.equals(VAR_FORCE_CHAR_ENCODING)) {
641: value = getConfigurationValue(sectionName, varName);
642: feedInfo.setForcedCharacterEncoding(value);
643: }
644:
645: else {
646: value = getConfigurationValue(sectionName, varName);
647: }
648:
649: if (value != null) {
650: keepFeed = metaPlugIn.runFeedConfigItemPlugIn(
651: sectionName, varName, this , feedInfo);
652: if (!keepFeed) {
653: log.debug("A plug-in said to skip feed ["
654: + sectionName + "\"");
655: }
656: }
657:
658: if (!keepFeed)
659: break;
660: }
661:
662: if (url == null) {
663: throw new ConfigurationException(Constants.BUNDLE_NAME,
664: "CurnConfig.missingReqVar",
665: "The configuration file is "
666: + "missing required variable "
667: + "\"{0}\" in section \"{1}\"",
668: new Object[] { VAR_FEED_URL, sectionName });
669: }
670:
671: if (keepFeed) {
672: feeds.add(feedInfo);
673: feedMap.put(url, feedInfo);
674: }
675: }
676:
677: /**
678: * Process a section that identifies an output handler.
679: *
680: * @param sectionName the section name
681: *
682: * @throws ConfigurationException configuration error
683: * @throws CurnException some other error
684: */
685: private void processOutputHandlerSection(final String sectionName)
686: throws ConfigurationException, CurnException {
687: // Get the required class name.
688:
689: String className;
690: ConfiguredOutputHandler handlerWrapper;
691: MetaPlugIn metaPlugIn = MetaPlugIn.getMetaPlugIn();
692: boolean keep = true;
693:
694: className = getConfigurationValue(sectionName, VAR_CLASS);
695: handlerWrapper = new ConfiguredOutputHandler(sectionName,
696: sectionName, className);
697:
698: keep = metaPlugIn.runOutputHandlerConfigItemPlugIn(sectionName,
699: VAR_CLASS, this , handlerWrapper);
700: if (keep) {
701: for (String variableName : getVariableNames(sectionName)) {
702: // Skip the ones we've already processed.
703:
704: if (variableName.equals(VAR_CLASS))
705: continue;
706:
707: String value = getConfigurationValue(sectionName,
708: variableName);
709: handlerWrapper.addExtraVariable(variableName, value);
710:
711: keep = metaPlugIn
712: .runOutputHandlerConfigItemPlugIn(sectionName,
713: variableName, this , handlerWrapper);
714:
715: if (!keep) {
716: log.debug("A plug-in has disabled output handler ["
717: + sectionName + "]");
718: break;
719: }
720: }
721:
722: if (keep) {
723: log.debug("Saving output handler \""
724: + handlerWrapper.getName() + "\" of type "
725: + handlerWrapper.getClassName());
726: outputHandlers.add(handlerWrapper);
727: }
728: }
729: }
730:
731: /**
732: * Process an unknown section (passing its values to the plug-ins).
733: *
734: * @param sectionName the section name
735: *
736: * @throws ConfigurationException configuration error
737: * @throws CurnException some other error
738: */
739: private void processUnknownSection(final String sectionName)
740: throws ConfigurationException, CurnException {
741: for (String varName : getVariableNames(sectionName)) {
742: String value = getConfigurationValue(sectionName, varName);
743: if (value != null) {
744: MetaPlugIn.getMetaPlugIn()
745: .runUnknownSectionConfigItemPlugIn(sectionName,
746: varName, this );
747: }
748: }
749: }
750:
751: /**
752: * Parse an optional MaxDaysToCache parameter.
753: *
754: * @param sectionName the section name
755: * @param variableName the variable name
756: * @param def the default
757: *
758: * @return the value
759: *
760: * @throws NoSuchSectionException no such section
761: * @throws ConfigurationException bad numeric value
762: */
763: private int parseMaxDaysParameter(final String sectionName,
764: final String variableName, final int def)
765: throws NoSuchSectionException, ConfigurationException {
766: int result = def;
767: String value = getOptionalStringValue(sectionName,
768: variableName, null);
769: if (value != null) {
770: if (value.equalsIgnoreCase(NO_LIMIT_VALUE))
771: result = Integer.MAX_VALUE;
772:
773: else {
774: try {
775: result = Integer.parseInt(value);
776: }
777:
778: catch (NumberFormatException ex) {
779: throw new ConfigurationException(
780: Constants.BUNDLE_NAME,
781: "CurnConfig.badNumericValue",
782: "Bad numeric value \"{0}\" for "
783: + "variable \"{1}\" in section "
784: + "\"{2}\"", new Object[] { value,
785: variableName, sectionName });
786: }
787:
788: if (result < 0) {
789: throw new ConfigurationException(
790: Constants.BUNDLE_NAME,
791: "CurnConfig.negativeCardinalValue",
792: "Unexpected negative numeric value "
793: + "{0} for variable \"{1}\" in section "
794: + "\"{2}\"", new Object[] { value,
795: variableName, sectionName });
796: }
797: }
798: }
799:
800: return result;
801: }
802: }
|