001/* 002 * The MIT License 003 * Copyright (c) 2012 Microsoft Corporation 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining a copy 006 * of this software and associated documentation files (the "Software"), to deal 007 * in the Software without restriction, including without limitation the rights 008 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 009 * copies of the Software, and to permit persons to whom the Software is 010 * furnished to do so, subject to the following conditions: 011 * 012 * The above copyright notice and this permission notice shall be included in 013 * all copies or substantial portions of the Software. 014 * 015 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 016 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 017 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 018 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 019 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 020 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 021 * THE SOFTWARE. 022 */ 023 024package microsoft.exchange.webservices.data.property.complex.time; 025 026import microsoft.exchange.webservices.data.core.EwsServiceXmlReader; 027import microsoft.exchange.webservices.data.core.EwsServiceXmlWriter; 028import microsoft.exchange.webservices.data.core.EwsUtilities; 029import microsoft.exchange.webservices.data.core.XmlAttributeNames; 030import microsoft.exchange.webservices.data.core.XmlElementNames; 031import microsoft.exchange.webservices.data.core.exception.service.local.InvalidOrUnsupportedTimeZoneDefinitionException; 032import microsoft.exchange.webservices.data.core.exception.service.local.ServiceLocalException; 033import microsoft.exchange.webservices.data.core.exception.service.local.ServiceXmlSerializationException; 034import microsoft.exchange.webservices.data.misc.TimeSpan; 035import microsoft.exchange.webservices.data.property.complex.ComplexProperty; 036 037import java.util.ArrayList; 038import java.util.List; 039 040/** 041 * Represents a group of time zone period transitions. 042 */ 043public class TimeZoneTransitionGroup extends ComplexProperty { 044 045 /** 046 * The time zone definition. 047 */ 048 private TimeZoneDefinition timeZoneDefinition; 049 050 /** 051 * The id. 052 */ 053 private String id; 054 055 /** 056 * The transitions. 057 */ 058 private List<TimeZoneTransition> transitions = 059 new ArrayList<TimeZoneTransition>(); 060 061 /** 062 * The transition to standard. 063 */ 064 private TimeZoneTransition transitionToStandard; 065 066 /** 067 * The transition to daylight. 068 */ 069 private TimeZoneTransition transitionToDaylight; 070 071 /** 072 * The Constant PeriodTarget. 073 */ 074 private final static String PeriodTarget = "Period"; 075 076 /** 077 * The Constant GroupTarget. 078 */ 079 private final static String GroupTarget = "Group"; 080 081 082 /** 083 * Loads from XML. 084 * 085 * @param reader the reader 086 * @throws Exception the exception 087 */ 088 public void loadFromXml(EwsServiceXmlReader reader) throws Exception { 089 this.loadFromXml(reader, XmlElementNames.TransitionsGroup); 090 } 091 092 /** 093 * Writes to XML. 094 * 095 * @param writer the writer 096 * @throws Exception the exception 097 */ 098 public void writeToXml(EwsServiceXmlWriter writer) throws Exception { 099 this.writeToXml(writer, XmlElementNames.TransitionsGroup); 100 } 101 102 /** 103 * Reads the attribute from XML. 104 * 105 * @param reader the reader 106 * @throws Exception the exception 107 */ 108 @Override 109 public void readAttributesFromXml(EwsServiceXmlReader reader) 110 throws Exception { 111 this.id = reader.readAttributeValue(XmlAttributeNames.Id); 112 } 113 114 /** 115 * Writes the attribute to XML. 116 * 117 * @param writer the writer 118 * @throws ServiceXmlSerializationException the service xml serialization exception 119 */ 120 @Override 121 public void writeAttributesToXml(EwsServiceXmlWriter writer) 122 throws ServiceXmlSerializationException { 123 writer.writeAttributeValue(XmlAttributeNames.Id, this.id); 124 } 125 126 /** 127 * Writes the attribute to XML. 128 * 129 * @param reader the reader 130 * @return true, if successful 131 * @throws Exception the exception 132 */ 133 @Override 134 public boolean tryReadElementFromXml(EwsServiceXmlReader reader) 135 throws Exception { 136 reader.ensureCurrentNodeIsStartElement(); 137 138 TimeZoneTransition transition = TimeZoneTransition.create( 139 this.timeZoneDefinition, reader.getLocalName()); 140 141 transition.loadFromXml(reader); 142 143 EwsUtilities 144 .ewsAssert(transition.getTargetPeriod() != null, "TimeZoneTransitionGroup.TryReadElementFromXml", 145 "The transition's target period is null."); 146 147 this.transitions.add(transition); 148 149 return true; 150 } 151 152 /** 153 * Writes elements to XML. 154 * 155 * @param writer the writer 156 * @throws Exception the exception 157 */ 158 @Override 159 public void writeElementsToXml(EwsServiceXmlWriter writer) 160 throws Exception { 161 for (TimeZoneTransition transition : this.transitions) { 162 transition.writeToXml(writer); 163 } 164 } 165 166 /** 167 * Validates this transition group. 168 * 169 * @throws InvalidOrUnsupportedTimeZoneDefinitionException thrown when time zone definition is not valid. 170 */ 171 public void validate() throws ServiceLocalException { 172 // There must be exactly one or two transitions in the group. 173 if (this.transitions.size() < 1 || this.transitions.size() > 2) { 174 throw new InvalidOrUnsupportedTimeZoneDefinitionException(); 175 } 176 177 // If there is only one transition, it must be of type 178 // TimeZoneTransition 179 if (this.transitions.size() == 1 180 && !(this.transitions.get(0).getClass() == 181 TimeZoneTransition.class)) { 182 throw new InvalidOrUnsupportedTimeZoneDefinitionException(); 183 } 184 185 // If there are two transitions, none of them should be of type 186 // TimeZoneTransition 187 if (this.transitions.size() == 2) { 188 for (TimeZoneTransition transition : this.transitions) { 189 if (transition.getClass() == TimeZoneTransition.class) { 190 throw new InvalidOrUnsupportedTimeZoneDefinitionException(); 191 } 192 } 193 } 194 195 // All the transitions in the group must be to a period. 196 for (TimeZoneTransition transition : this.transitions) { 197 if (transition.getTargetPeriod() == null) { 198 throw new InvalidOrUnsupportedTimeZoneDefinitionException(); 199 } 200 } 201 } 202 203 /** 204 * The Class CustomTimeZoneCreateParams. 205 */ 206 protected static class CustomTimeZoneCreateParams { 207 208 /** 209 * The base offset to utc. 210 */ 211 private TimeSpan baseOffsetToUtc; 212 213 /** 214 * The standard display name. 215 */ 216 private String standardDisplayName; 217 218 /** 219 * The daylight display name. 220 */ 221 private String daylightDisplayName; 222 223 /** 224 * Initializes a new instance of the class. 225 */ 226 protected CustomTimeZoneCreateParams() { 227 } 228 229 /** 230 * Gets the base offset to UTC. 231 * 232 * @return the base offset to utc 233 */ 234 protected TimeSpan getBaseOffsetToUtc() { 235 return this.baseOffsetToUtc; 236 } 237 238 /** 239 * Sets the base offset to utc. 240 * 241 * @param baseOffsetToUtc the new base offset to utc 242 */ 243 protected void setBaseOffsetToUtc(TimeSpan baseOffsetToUtc) { 244 this.baseOffsetToUtc = baseOffsetToUtc; 245 } 246 247 /** 248 * Gets the display name of the standard period. 249 * 250 * @return the standard display name 251 */ 252 protected String getStandardDisplayName() { 253 return this.standardDisplayName; 254 } 255 256 /** 257 * Sets the standard display name. 258 * 259 * @param standardDisplayName the new standard display name 260 */ 261 protected void setStandardDisplayName(String standardDisplayName) { 262 this.standardDisplayName = standardDisplayName; 263 } 264 265 /** 266 * Gets the display name of the daylight period. 267 * 268 * @return the daylight display name 269 */ 270 protected String getDaylightDisplayName() { 271 return this.daylightDisplayName; 272 } 273 274 /** 275 * Sets the daylight display name. 276 * 277 * @param daylightDisplayName the new daylight display name 278 */ 279 protected void setDaylightDisplayName(String daylightDisplayName) { 280 this.daylightDisplayName = daylightDisplayName; 281 } 282 283 /** 284 * Gets a value indicating whether the custom time zone should have a 285 * daylight period. <value> <c>true</c> if the custom time zone should 286 * have a daylight period; otherwise, <c>false</c>. </value> 287 * 288 * @return the checks for daylight period 289 */ 290 protected boolean getHasDaylightPeriod() { 291 return (!(this.daylightDisplayName == null || 292 this.daylightDisplayName.isEmpty())); 293 } 294 } 295 296 /** 297 * Gets a value indicating whether this group contains a transition to the 298 * Daylight period. <value><c>true</c> if this group contains a transition 299 * to daylight; otherwise, <c>false</c>.</value> 300 * 301 * @return the supports daylight 302 */ 303 protected boolean getSupportsDaylight() { 304 return this.transitions.size() == 2; 305 } 306 307 /** 308 * Initializes the private members holding references to the transitions to 309 * the Daylight and Standard periods. 310 * 311 * @throws InvalidOrUnsupportedTimeZoneDefinitionException thrown when time zone definition is not valid. 312 */ 313 private void initializeTransitions() throws ServiceLocalException { 314 if (this.transitionToStandard == null) { 315 for (TimeZoneTransition transition : this.transitions) { 316 if (transition.getTargetPeriod().isStandardPeriod() || 317 (this.transitions.size() == 1)) { 318 this.transitionToStandard = transition; 319 } else { 320 this.transitionToDaylight = transition; 321 } 322 } 323 } 324 325 // If we didn't find a Standard period, this is an invalid time zone 326 // group. 327 if (this.transitionToStandard == null) { 328 throw new InvalidOrUnsupportedTimeZoneDefinitionException(); 329 } 330 } 331 332 /** 333 * Gets the transition to the Daylight period. 334 * 335 * @return the transition to daylight 336 * @throws ServiceLocalException the service local exception 337 */ 338 private TimeZoneTransition getTransitionToDaylight() 339 throws ServiceLocalException { 340 this.initializeTransitions(); 341 return this.transitionToDaylight; 342 } 343 344 /** 345 * Gets the transition to the Standard period. 346 * 347 * @return the transition to standard 348 * @throws ServiceLocalException the service local exception 349 */ 350 private TimeZoneTransition getTransitionToStandard() 351 throws ServiceLocalException { 352 this.initializeTransitions(); 353 return this.transitionToStandard; 354 } 355 356 /** 357 * Gets the offset to UTC based on this group's transitions. 358 * 359 * @return the custom time zone creation params 360 */ 361 protected CustomTimeZoneCreateParams getCustomTimeZoneCreationParams() { 362 CustomTimeZoneCreateParams result = new CustomTimeZoneCreateParams(); 363 364 if (this.transitionToDaylight != null) { 365 result.setDaylightDisplayName(this.transitionToDaylight 366 .getTargetPeriod().getName()); 367 } 368 369 result.setStandardDisplayName(this.transitionToStandard 370 .getTargetPeriod().getName()); 371 372 // Assume that the standard period's offset is the base offset to UTC. 373 // EWS returns a positive offset for time zones that are behind UTC, and 374 // a negative one for time zones ahead of UTC. TimeZoneInfo does it the 375 // other 376 // way around. 377 // result.BaseOffsetToUtc = 378 // -this.TransitionToStandard.TargetPeriod.Bias; 379 380 return result; 381 } 382 383 /** 384 * Initializes a new instance of the class. 385 * 386 * @param timeZoneDefinition the time zone definition 387 */ 388 public TimeZoneTransitionGroup(TimeZoneDefinition timeZoneDefinition) { 389 super(); 390 this.timeZoneDefinition = timeZoneDefinition; 391 } 392 393 /** 394 * Initializes a new instance of the class. 395 * 396 * @param timeZoneDefinition the time zone definition 397 * @param id the id 398 */ 399 public TimeZoneTransitionGroup(TimeZoneDefinition timeZoneDefinition, String id) { 400 this(timeZoneDefinition); 401 this.id = id; 402 } 403 404 /** 405 * Gets the id of this group. 406 * 407 * @return the id 408 */ 409 public String getId() { 410 return this.id; 411 } 412 413 /** 414 * Sets the id. 415 * 416 * @param id the new id 417 */ 418 public void setId(String id) { 419 this.id = id; 420 } 421 422 /** 423 * Gets the transitions in this group. 424 * 425 * @return the transitions 426 */ 427 public List<TimeZoneTransition> getTransitions() { 428 return this.transitions; 429 } 430}