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: }