View Javadoc

1   /*
2    * This file is part of Domingo
3    * an Open Source Java-API to Lotus Notes/Domino
4    * hosted at http://domingo.sourceforge.net
5    *
6    * Copyright (c) 2003-2007 Beck et al. projects GmbH Munich, Germany (http://www.bea.de)
7    *
8    * This library is free software; you can redistribute it and/or
9    * modify it under the terms of the GNU Lesser General Public
10   * License as published by the Free Software Foundation; either
11   * version 2.1 of the License, or (at your option) any later version.
12   *
13   * This library is distributed in the hope that it will be useful,
14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   * Lesser General Public License for more details.
17   *
18   * You should have received a copy of the GNU Lesser General Public
19   * License along with this library; if not, write to the Free Software
20   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21   */
22  
23  package de.bea.domingo.http;
24  
25  import java.io.UnsupportedEncodingException;
26  import java.net.URLEncoder;
27  import java.util.ArrayList;
28  import java.util.Calendar;
29  import java.util.Date;
30  import java.util.List;
31  
32  import org.apache.commons.httpclient.Cookie;
33  
34  /***
35   * Domino regional preferences.
36   *
37   * @author <a href=mailto:kriede@users.sourceforge.net>Kurt Riede</a>
38   */
39  public final class DominoPreferences {
40  
41      /*** Number of years that a preferences cookie is valid. */
42      public static final int EXPIRY_YEARS = 30;
43  
44      /*** Default encoding (UTF-8) for cookie values. */
45      public static final String ENCODING_UTF_8 = "UTF-8";
46  
47      /*** Default time zone search string. */
48      public static final String DEFAULT_TIME_ZONE = "Pacific Time (US & Canada)";
49  
50      /*** The locale settings. */
51      public static final DominoLocale DEFAULT_LOCALE = DominoLocale.get("en-US");
52  
53      /*** List of {@link org.apache.commons.httpclient.Header}s. */
54      private List fCookies = new ArrayList();
55  
56      /*** Domain of the generated cookies. */
57      private final String fDomain;
58  
59      /*** path of the generated cookies. */
60      private String fPath = "/";
61  
62      /*** The time zone. */
63      private DominoTimeZone fTimeZone = DominoTimeZone.searchTimeZone(DEFAULT_TIME_ZONE);
64  
65      /*** Indicates whether the time format reflects daylight savings time. */
66      private boolean fDst;
67  
68      /*** locale string. */
69      private String fLocaleString;
70  
71      /*** Indicates whether the order of the date format is day-month-year, month-day-year or year-month-day. */
72      private String fDateComponentOrder;
73  
74      /*** The character used to separate months, days, and years, for example, the slash.. */
75      private String fDateSeparator;
76  
77      /*** The character used to separate hours, minutes, and seconds, for example, the colon.. */
78      private String fTimeSeparator;
79  
80      /*** Indicates whether the time format is 24-hour. */
81      private boolean fClock24Hour;
82  
83      /*** The string that denotes AM time, for example, "AM" in English. */
84      private String fAmString;
85  
86      /*** The string that denotes PM time, for example, "PM" in English. */
87      private String fPmString;
88  
89      /*** Indicates whether the AM/PM symbol follows the time in the time format. */
90      private boolean fAmPmSuffix;
91  
92      /*** The decimal separator for number format, for example, the decimal point. */
93      private String fDecimalSeparator;
94  
95      /*** The thousand separator in number format, for example, the comma. */
96      private String fThousandSeparator;
97  
98      /*** Year format. */
99      private String fYearFormat;
100 
101     /*** Indicates whether fractions have a zero before the decimal point in number format. */
102     private boolean fNumberLeadingZero;
103 
104     /*** The symbol that indicates a number is currency, for example, the dollar sign. */
105     private String fCurrencySymbol;
106 
107     /*** Indicates whether the currency symbol follows the number in the currency format. */
108     private boolean fCurrencySuffix;
109 
110     /*** Indicates whether the currency format has a space between the currency symbol and the number.. */
111     private boolean fCurrencySpace;
112 
113     /*** The date/time when thre preferences will expire. */
114     private final Date fExpiryDate;
115 
116     /*** The cookie that represents the time zone settings. */
117     private Cookie fTimeZoneCookie;
118 
119     /*** The cookie that represents the locale settings. */
120     private Cookie fRegionalCookie;
121 
122     /***
123      * Constructor.
124      *
125      * @param domain the domain to that this preferences belong to
126      */
127     public DominoPreferences(final String domain) {
128         this(domain, "/");
129     }
130 
131     /***
132      * Constructor.
133      *
134      * @param domain the domain to that this preferences belong to
135      * @param path the path defining the subset of URLs in a domain for which the cookie is valid
136      */
137     public DominoPreferences(final String domain, final String path) {
138         fDomain = domain;
139         fPath = path;
140         Calendar creationDate = Calendar.getInstance();
141         creationDate.add(Calendar.YEAR, EXPIRY_YEARS);
142         fExpiryDate = creationDate.getTime();
143         setLocale("en-US", true);
144         fTimeZoneCookie = newTimeZoneCookie();
145         fRegionalCookie = newRegionalCookie();
146     }
147 
148     /***
149      * Sets the time zone.
150      *
151      * @param timeZone Domino time zone
152      */
153     public void setTimeZone(final DominoTimeZone timeZone) {
154         fTimeZone = timeZone;
155     }
156 
157     /***
158      * Sets whether to observe daylight saving time or not.
159      *
160      * @param dst observe daylight saving time or not
161      */
162     public void setObserverDST(final boolean dst) {
163         fDst = dst;
164     }
165 
166     /***
167      * @param locale The locale to set.
168      */
169     public void setLocale(final String locale) {
170         setLocale(locale, false);
171     }
172 
173     /***
174      * @param localeString The locale to set as a string.
175      * @param loadDefault if <code>true</code>, load all default values for
176      *            this locale
177      */
178     public void setLocale(final String localeString, final boolean loadDefault) {
179         fLocaleString = localeString;
180         DominoLocale locale = (DominoLocale) DominoLocale.get(localeString);
181         if (locale == null) {
182             throw new NotesHttpRuntimeException("unsupported locale: " + localeString);
183         }
184         fLocaleString = locale.getLocale();
185         fDateComponentOrder = locale.getDateComponentOrder();
186         fDateSeparator = locale.getDateSeparator();
187         fTimeSeparator = locale.getTimeSeparator();
188         fClock24Hour = "".equals(locale.getClock24Hour());
189         fAmString = locale.getAmString();
190         fPmString = locale.getPmString();
191         fAmPmSuffix = "1".indexOf(locale.getAmPmSuffix()) >= 0;
192         fDecimalSeparator = locale.getDecimalSeparator();
193         fNumberLeadingZero = "1".equals(locale.getNumberLeadingZero());
194         fCurrencySymbol = locale.getCurrencySymbol();
195         fCurrencySuffix = "1".equals(locale.getCurrencySuffix());
196         fCurrencySpace = "1".equals(locale.getCurrencySpace());
197         fThousandSeparator = locale.getThousandSeparator();
198         fYearFormat = locale.getYearFormat();
199     }
200 
201     /***
202      * @param amString The amString to set.
203      */
204     public void setAmString(final String amString) {
205         fAmString = amString;
206     }
207 
208     /***
209      * @param currencySpace The currencySpace to set.
210      */
211     public void setCurrencySpace(final boolean currencySpace) {
212         fCurrencySpace = currencySpace;
213     }
214 
215     /***
216      * @param currencySymbol The currencySymbol to set.
217      */
218     public void setCurrencySymbol(final String currencySymbol) {
219         fCurrencySymbol = currencySymbol;
220     }
221 
222     /***
223      * @param dateSeperator The dateSeperator to set.
224      */
225     public void setDateSeperator(final String dateSeperator) {
226         fDateSeparator = dateSeperator;
227     }
228 
229     /***
230      * @param decimalSeperator The decimalSeperator to set.
231      */
232     public void setDecimalSeperator(final String decimalSeperator) {
233         fDecimalSeparator = decimalSeperator;
234     }
235 
236     /***
237      * @param cookies The cookies to set.
238      */
239     public void setCookies(final List cookies) {
240         fCookies = cookies;
241     }
242 
243     /***
244      * @param dst The dst to set.
245      */
246     public void setDst(final boolean dst) {
247         fDst = dst;
248     }
249 
250     /***
251      * @param hour24Format The hourFormat to set.
252      */
253     public void setHourFormat(final boolean hour24Format) {
254         fClock24Hour = hour24Format;
255     }
256 
257     /***
258      * @param leadingDecimalZeros The leadingDecimalZeros to set.
259      */
260     public void setLeadingDecimalZeros(final boolean leadingDecimalZeros) {
261         fNumberLeadingZero = leadingDecimalZeros;
262     }
263 
264     /***
265      * @param pmString The pmString to set.
266      */
267     public void setPmString(final String pmString) {
268         fPmString = pmString;
269     }
270 
271     /***
272      * @param amPmSuffix The amPmSuffix to set.
273      */
274     public void setAmPmSuffix(final boolean amPmSuffix) {
275         fAmPmSuffix = amPmSuffix;
276     }
277 
278     /***
279      * @param currencySuffix The currencySuffix to set.
280      */
281     public void setPositionCurrencySymbol(final boolean currencySuffix) {
282         fCurrencySuffix = currencySuffix;
283     }
284 
285     /***
286      * @param thousandsSeperator The thousandsSeperator to set.
287      */
288     public void setThousandsSeperator(final String thousandsSeperator) {
289         fThousandSeparator = thousandsSeperator;
290     }
291 
292     /***
293      * @param timeSeperator The timeSeperator to set.
294      */
295     public void setTimeSeperator(final String timeSeperator) {
296         fTimeSeparator = timeSeperator;
297     }
298 
299     /***
300      * Returns a list of cookies for the current regional settings.
301      *
302      * @return cookies for regional settings
303      */
304     public List getRegionalCookies() {
305         return fCookies;
306     }
307 
308     /***
309      * @see java.lang.Object#toString()
310      *
311      * @return  a string representation of the object.
312      */
313     public String toString() {
314         StringBuffer buffer = new StringBuffer();
315         buffer.append(fLocaleString + ":");
316         buffer.append(fDateComponentOrder + ":");
317         buffer.append(fDateSeparator + ":");
318         buffer.append(fTimeSeparator + ":");
319         buffer.append(fClock24Hour + ":");
320         buffer.append(fAmString + ":");
321         buffer.append(fPmString + ":");
322         buffer.append(fAmPmSuffix + ":");
323         buffer.append(fDecimalSeparator + ":");
324         buffer.append(fNumberLeadingZero + ":");
325         buffer.append(fCurrencySymbol + ":");
326         buffer.append(fCurrencySuffix + ":");
327         buffer.append(fCurrencySpace + ":");
328         buffer.append(fThousandSeparator + ":");
329         buffer.append(fYearFormat + ":");
330         return buffer.toString();
331     }
332 
333     /***
334      * Creates the time zone cookie of Lotus Domino.
335      *
336      * <p>Format:</p>
337      * <dl>
338      * <dt>Name</dt><dd><tt>DomTimeZonePrfM</tt></dd>
339      * <dt>Format</dt><dd><tt>flag : version  : zone-name : zone-offset : dst-law : dst</tt></dd>
340      * <dt>flag</dt><dd><tt>"+"</tt> for valid cookies, any other char otherwise</dd>
341      * <dt>version</dt><dd>version number <tt>"6"</tt></dd>
342      * <dt>zone-name</dt><dd>conventional Notes/Domino TimeZone name, ignored</dd>
343      * <dt>zone-offset</dt><dd>encoded time zone offset in the form: <tt>[-][mm][h]h</tt>.
344      * Offset is negative for TimeZones east to greenwich</dd>
345      * <dt>dst-law</dt><dd>Daylight Savings Time turning on/off rule in the form:
346      *     <tt>(BMonth,BDay,BWeekDay,EMonth,EDay,EWeekDay) | 0</tt> when does not exist
347      *     <ul>
348      *     <li>BMonth, EMonth take values 1...12, where 1 is January
349      *     <li>BDay, EDay - the date in that month, 1 means first, 2 means second, -1 means last
350      *     <li> BWeekDay, EWeekDay - 1-based day of a week, 1 means Sunday
351      *     </ul></dd>
352      * <dt>dst</dt><dd>Daylight Savings Time offset - either 1 (when used) or 0 otherwise</dd>
353      * </dl>
354      */
355     private Cookie newTimeZoneCookie() {
356         Cookie cookie = new Cookie(fDomain, "DomTimeZonePrfM", "", fPath, fExpiryDate, false);
357         cookie.setValue("+:6" + ":" + fTimeZone.getValue() + ":" + encode(fDst));
358         return cookie;
359         // TODO check version number of coockies on different versions of Domino
360     }
361 
362     /***
363      * Creates the regional cookie of Lotus Domino.
364      *
365      * <dl>
366      * <dt>Name</dt><dd><tt>DomRegionalPrfM</tt></dd>
367      * <dt>Format</dt><dd><tt>flag : version : encoding : Locale :  DateOrder : DateSeperator : TimeSeperator : Hour24Format :
368      * AmString : PmString : AmPmSuffix : DecimalSeperator : LeadingDecimalZeros : CurrencySymbol : CurrencySuffix :
369      * CurrencySpace : ThousandsSeperator "1"</tt></dd>
370      * <dt>encoding</dt><dd>must be "UTF-8"</dd>
371      * <dt>locale</dt><dd>a Lotus Domino locale string, e.g. <tt>"en-US"</tt> or <tt>"de-DE"</tt></dd>
372      * <dt>date-order</dt><dd>Order of date components. <tt>"0"</tt> for weekday-month-day-year,
373      *   <tt>"1"</tt> for weekday-day-month-year,
374      *   <tt>"2"</tt> for year-month-day-weekday</dd>
375      * <dt>date-seperator</dt><dd>the seperater character for date components, e.g. <tt>"/"</tt> for locale
376      *   <tt>en_US</tt> or <tt>"."</tt> for locale <tt>de_DE</tt></dd>
377      * <dt>time-seperator</dt><dd>the seperater character for time components, e.g. <tt>":"</dd>>
378      * <dt>24-hour-format</dt><dd>Whether to us 24 hour format or not. <tt>"0"</tt> for 12-hour format with AM/OM strings or
379      *   <tt>"1"</tt> for 24-hour format</dd>
380      * <dt>AM-string</dt><dd>The string identifying times before noon</dd>
381      * <dt>PM-string</dt><dd>The string identifying times after noon</dd>
382      * <dt>AM-PM-suffix</dt><dd>Position of AM/PM string. <tt>"0"</tt> for preceeding the time,
383      *   <tt>"1"</tt> for a suffix of the time</dd>
384      * <dt>decimal-seperator</dt><dd>The decimal seperator for seperating the fractional part of decimal numbers, e.g.
385      *   <tt>"."</tt> for locale <tt>en_US</tt> or <tt>","</tt> for locale <tt>de_DE</tt></dd>
386      * <dt>leading-decimal-zeros</dt><dd>Whether to use a leading zero in decimal fractions,
387      *   <tt>1</tt> for using a leading zero</dd>
388      * <dt>currency-symbol</dt><dd>The currency symbol, e.g. <tt>"$"</tt> for locale <tt>en_US</tt> or
389      *   <tt>"&#0128;"</tt> for locale <tt>de_DE</tt></dd>
390      * <dt>currency-suffix</dt><dd>Whether the currency symbol is displayed before or after the currency value.
391      *   <tt>"0"</tt> for before, <tt>"1"</tt> for after</dd>
392      * <dt>currency-space</dt><dd>Whether to insert a space between currency value and cuurency symbol.
393      *   <tt>"0"</tt> for not using a space, <tt>"1"</tt> for using a space</dd>
394      * <dt>thousands-seperator</dt><dd>The thousands seperator in number formats, e.g.
395      *   <tt>","</tt> for locale <tt>en_US</tt> or <tt>"."</tt> for locale <tt>de_DE</tt></dd>
396      * </dl>
397      */
398     private Cookie newRegionalCookie() {
399         Cookie cookie = new Cookie(fDomain, "DomRegionalPrfM", "", fPath, fExpiryDate, false);
400         List list = new ArrayList();
401         list.add("+");
402         list.add("6");
403         list.add("UTF-8");
404         list.add(fLocaleString);
405         list.add(fDateComponentOrder);
406         list.add(encode(fDateSeparator));
407         list.add(encode(fTimeSeparator));
408         list.add(encode(fClock24Hour));
409         list.add(encode(fAmString));
410         list.add(encode(fPmString));
411         list.add(encode(fAmPmSuffix));
412         list.add(encode(fDecimalSeparator));
413         list.add(encode(fNumberLeadingZero));
414         list.add(encode(fCurrencySymbol));
415         list.add(encode(fCurrencySuffix));
416         list.add(encode(fCurrencySpace));
417         list.add(encode(fThousandSeparator));
418         list.add(encode(fYearFormat));
419         cookie.setValue(implode(list, ":"));
420         return cookie;
421     }
422 
423     /***
424      * Combines the elements of a string array to a single string using a given
425      * seperator.
426      *
427      * @param stringList a list of strings
428      * @param delimiter the delimiting string
429      * @return combined string
430      */
431     public static String implode(final List stringList, final String delimiter) {
432         StringBuffer buffer = new StringBuffer();
433         for (int i = 0; i < stringList.size(); i++) {
434             buffer.append((i > 0 ? delimiter : "") + stringList.get(i));
435         }
436         return buffer.toString();
437     }
438 
439     /***
440      * Returns a new Lotus Domino time zone cookie.
441      *
442      * @return Lotus Domino time zone cookie
443      */
444     public Cookie getTimeZoneCookie() {
445         return fTimeZoneCookie;
446     }
447 
448     /***
449      * Returns a new Lotus Domino regional cookie.
450      *
451      * @return Lotus Domino regional cookie
452      */
453     public Cookie getRegionalCookie() {
454         return fRegionalCookie;
455     }
456 
457     /***
458      * Encodes a boolean value to <tt>"1"</tt> for <code>true</code> and
459      * <tt>"0"</tt> for <code>false</code>.
460      *
461      * @param booleanValue the boolean value to encode
462      * @return encoded boolean value
463      */
464     static String encode(final boolean booleanValue) {
465         return (booleanValue ? "1" : "0");
466     }
467 
468     /***
469      * URL-encodes a string.
470      *
471      * @param text the test to encode
472      * @return URL-encoded text
473      */
474     static String encode(final String text) {
475         try {
476             return URLEncoder.encode(text, ENCODING_UTF_8);
477         } catch (UnsupportedEncodingException e) {
478             // cannot happen since UTF-8 must be supported on all platforms
479             throw new NotesHttpRuntimeException("Unsupported encoding: " + ENCODING_UTF_8, e);
480         }
481     }
482 }