    001: package bigjava;
    002:
    003: import java.sql.Connection;
    004: import java.sql.PreparedStatement;
    005: import java.sql.ResultSet;
    006: import java.sql.SQLException;
    007: import java.text.DateFormat;
    008: import java.util.ArrayList;
    009: import java.util.Date;
    010: import java.util.Map;
    011: import java.util.TimeZone;
    012: import java.util.TreeMap;
    013: import java.util.logging.Logger;
    014: import javax.naming.InitialContext;
    015: import javax.naming.NamingException;
    016: import javax.sql.DataSource;
    017:
    018: /**
    019:    This bean formats the local time of day for a given date
    020:    and city.
    021: */
    022: public class TimeZoneBean
    023: {
    024:    /**
    025:       Initializes the formatter.
    026:    */
    027:    public TimeZoneBean()
    028:    {
    029:       timeFormatter = DateFormat.getTimeInstance();
    030:       cities = new ArrayList<String>();
    031:    }
    032:
    033:    /**
    034:       Setter for city property.
    035:       @param aCity the city to add to the list of cities
    036:    */
    037:    public void setCity(String aCity)
    038:    {
    039:       city = aCity;
    040:       zone = getTimeZone(city);
    041:    }
    042:
    043:    /**
    044:       Getter for city property.
    045:       @return the city to add to the list of cities
    046:    */
    047:    public String getCity()
    048:    {
    049:       return city;
    050:    }
    051:
    052:    /**
    053:       Setter for the cityToRemove property
    054:       @param aCity the city to remove
    055:    */
    056:    public void setCityToRemove(String aCity)
    057:    {
    058:       cityToRemove = aCity;
    059:    }
    060:
    061:    /**
    062:       Getter for the cityToRemove property.
    063:       @return the empty string
    064:    */
    065:    public String getCityToRemove()
    066:    {
    067:       return cityToRemove;
    068:    }
    069:
    070:    /**
    071:       Read-only citiesAndTimes property.
    072:       @return a map containing the cities and formatted times
    073:    */
    074:    public Map<String, String> getCitiesAndTimes()
    075:    {
    076:       Date time = new Date();
    077:       Map<String, String> result = new TreeMap<String, String>();
    078:       for (int i = 0; i < cities.size(); i++)
    079:       {
    080:          String city = cities.get(i);
    081:          String label = city + ": ";
    082:          TimeZone zone = getTimeZone(city);
    083:          if (zone != null)
    084:          {
    085:             timeFormatter.setTimeZone(zone);
    086:             String timeString = timeFormatter.format(time);
    087:             label = label + timeString;
    088:          }
    089:          else
    090:             label = label + "unavailable";
    091:          result.put(label, city);
    092:       }
    093:
    094:       return result;
    095:    }
    096:
    097:    /**
    098:       Action for adding a city.
    099:       @return "available" if time zone information is available for the city,
    100:       "unavailable" otherwise
    101:    */
    102:    public String addCity()
    103:    {
    104:       if (zone == null) return "unavailable";
    105:       cities.add(city);
    106:       cityToRemove = city;
    107:       city = "";
    108:       return "available";
    109:    }
    110:
    111:    /**
    112:       Action for removing a city.
    113:       @return null if there are more cities to remove, "back" otherwise
    114:    */
    115:    public String removeCity()
    116:    {
    117:       cities.remove(cityToRemove);
    118:       if (cities.size() > 0) return null;
    119:       else return "back";
    120:    }
    121:
    122:    /**
    123:       Looks up the time zone for a city
    124:       @param aCity the city for which to find the time zone
    125:       @return the time zone or null if no match is found
    126:    */
    127:    private static TimeZone getTimeZone(String city)
    128:    {
    129:       String[] ids = TimeZone.getAvailableIDs();
    130:       for (int i = 0; i < ids.length; i++)
    131:          if (timeZoneIDmatch(ids[i], city))
    132:             return TimeZone.getTimeZone(ids[i]);
    133:       try
    134:       {
    135:          String id = getZoneNameFromDB(city);
    136:          if (id != null)
    137:             return TimeZone.getTimeZone(id);
    138:       }
    139:       catch (Exception exception)
    140:       {
    141:          Logger.global.info("Caught in TimeZone.getTimeZone: " + exception);
    142:       }
    143:       return null;
    144:    }
    145:
    146:    private static String getZoneNameFromDB(String city)
    147:       throws NamingException, SQLException
    148:    {
    149:       InitialContext ctx = new InitialContext();
    150:       DataSource source
    151:          = (DataSource) ctx.lookup("java:comp/env/jdbc/mydb");
    152:       Connection conn = source.getConnection();
    153:       try
    154:       {
    155:          PreparedStatement stat = conn.prepareStatement(
    156:             "SELECT Zone FROM CityZone WHERE City=?");
    157:          stat.setString(1, city);
    158:          ResultSet result = stat.executeQuery();
    159:          if (result.next())
    160:             return result.getString(1);
    161:          else
    162:             return null;
    163:       }
    164:       finally
    165:       {
    166:          conn.close();
    167:       }
    168:    }
    169:
    170:    /**
    171:       Checks whether a time zone ID matches a city
    172:       @param id the time zone ID (e.g. "America/Los_Angeles")
    173:       @param aCity the city to match (e.g. "Los Angeles")
    174:       @return true if the ID and city match
    175:    */
    176:    private static boolean timeZoneIDmatch(String id, String city)
    177:    {
    178:       String idCity = id.substring(id.indexOf('/') + 1);
    179:       return idCity.replace('_', ' ').equals(city);
    180:    }
    181:
    182:    private DateFormat timeFormatter;
    183:    private ArrayList<String> cities;
    184:    private String city;
    185:    private TimeZone zone;
    186:    private String cityToRemove;
    187: }