001 /* 002 * Copyright 2001-2005 Stephen Colebourne 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 package org.joda.time.convert; 017 018 import org.joda.time.JodaTimePermission; 019 020 /** 021 * ConverterManager controls the date and time converters. 022 * <p> 023 * This class enables additional conversion classes to be added via 024 * {@link #addInstantConverter(InstantConverter)}, which may replace an 025 * existing converter. Similar methods exist for duration, time period and 026 * interval converters. 027 * <p> 028 * This class is threadsafe, so adding/removing converters can be done at any 029 * time. Updating the set of convertors is relatively expensive, and so should 030 * not be performed often. 031 * <p> 032 * The default instant converters are: 033 * <ul> 034 * <li>ReadableInstant 035 * <li>String 036 * <li>Calendar 037 * <li>Date (includes sql package subclasses) 038 * <li>Long (milliseconds) 039 * <li>null (now) 040 * </ul> 041 * 042 * The default partial converters are: 043 * <ul> 044 * <li>ReadablePartial 045 * <li>ReadableInstant 046 * <li>String 047 * <li>Calendar 048 * <li>Date (includes sql package subclasses) 049 * <li>Long (milliseconds) 050 * <li>null (now) 051 * </ul> 052 * 053 * The default duration converters are: 054 * <ul> 055 * <li>ReadableDuration 056 * <li>ReadableInterval 057 * <li>String 058 * <li>Long (milliseconds) 059 * <li>null (zero ms) 060 * </ul> 061 * 062 * The default time period converters are: 063 * <ul> 064 * <li>ReadablePeriod 065 * <li>ReadableInterval 066 * <li>String 067 * <li>null (zero) 068 * </ul> 069 * 070 * The default interval converters are: 071 * <ul> 072 * <li>ReadableInterval 073 * <li>String 074 * <li>null (zero-length from now to now) 075 * </ul> 076 * 077 * @author Stephen Colebourne 078 * @author Brian S O'Neill 079 * @since 1.0 080 */ 081 public final class ConverterManager { 082 083 /** 084 * Singleton instance, lazily loaded to avoid class loading. 085 */ 086 private static ConverterManager INSTANCE; 087 088 public static ConverterManager getInstance() { 089 if (INSTANCE == null) { 090 INSTANCE = new ConverterManager(); 091 } 092 return INSTANCE; 093 } 094 095 private ConverterSet iInstantConverters; 096 private ConverterSet iPartialConverters; 097 private ConverterSet iDurationConverters; 098 private ConverterSet iPeriodConverters; 099 private ConverterSet iIntervalConverters; 100 101 /** 102 * Restricted constructor. 103 */ 104 protected ConverterManager() { 105 super(); 106 107 iInstantConverters = new ConverterSet(new Converter[] { 108 ReadableInstantConverter.INSTANCE, 109 StringConverter.INSTANCE, 110 CalendarConverter.INSTANCE, 111 DateConverter.INSTANCE, 112 LongConverter.INSTANCE, 113 NullConverter.INSTANCE, 114 }); 115 116 iPartialConverters = new ConverterSet(new Converter[] { 117 ReadablePartialConverter.INSTANCE, 118 ReadableInstantConverter.INSTANCE, 119 StringConverter.INSTANCE, 120 CalendarConverter.INSTANCE, 121 DateConverter.INSTANCE, 122 LongConverter.INSTANCE, 123 NullConverter.INSTANCE, 124 }); 125 126 iDurationConverters = new ConverterSet(new Converter[] { 127 ReadableDurationConverter.INSTANCE, 128 ReadableIntervalConverter.INSTANCE, 129 StringConverter.INSTANCE, 130 LongConverter.INSTANCE, 131 NullConverter.INSTANCE, 132 }); 133 134 iPeriodConverters = new ConverterSet(new Converter[] { 135 ReadableDurationConverter.INSTANCE, 136 ReadablePeriodConverter.INSTANCE, 137 ReadableIntervalConverter.INSTANCE, 138 StringConverter.INSTANCE, 139 NullConverter.INSTANCE, 140 }); 141 142 iIntervalConverters = new ConverterSet(new Converter[] { 143 ReadableIntervalConverter.INSTANCE, 144 StringConverter.INSTANCE, 145 NullConverter.INSTANCE, 146 }); 147 } 148 149 //----------------------------------------------------------------------- 150 /** 151 * Gets the best converter for the object specified. 152 * 153 * @param object the object to convert 154 * @return the converter to use 155 * @throws IllegalArgumentException if no suitable converter 156 * @throws IllegalStateException if multiple converters match the type 157 * equally well 158 */ 159 public InstantConverter getInstantConverter(Object object) { 160 InstantConverter converter = 161 (InstantConverter)iInstantConverters.select(object == null ? null : object.getClass()); 162 if (converter != null) { 163 return converter; 164 } 165 throw new IllegalArgumentException("No instant converter found for type: " + 166 (object == null ? "null" : object.getClass().getName())); 167 } 168 169 //----------------------------------------------------------------------- 170 /** 171 * Gets a copy of the set of converters. 172 * 173 * @return the converters, a copy of the real data, never null 174 */ 175 public InstantConverter[] getInstantConverters() { 176 ConverterSet set = iInstantConverters; 177 InstantConverter[] converters = new InstantConverter[set.size()]; 178 set.copyInto(converters); 179 return converters; 180 } 181 182 /** 183 * Adds a converter to the set of converters. If a matching converter is 184 * already in the set, the given converter replaces it. If the converter is 185 * exactly the same as one already in the set, no changes are made. 186 * <p> 187 * The order in which converters are added is not relevent. The best 188 * converter is selected by examining the object hierarchy. 189 * 190 * @param converter the converter to add, null ignored 191 * @return replaced converter, or null 192 */ 193 public InstantConverter addInstantConverter(InstantConverter converter) 194 throws SecurityException { 195 196 checkAlterInstantConverters(); 197 if (converter == null) { 198 return null; 199 } 200 InstantConverter[] removed = new InstantConverter[1]; 201 iInstantConverters = iInstantConverters.add(converter, removed); 202 return removed[0]; 203 } 204 205 /** 206 * Removes a converter from the set of converters. If the converter was 207 * not in the set, no changes are made. 208 * 209 * @param converter the converter to remove, null ignored 210 * @return replaced converter, or null 211 */ 212 public InstantConverter removeInstantConverter(InstantConverter converter) 213 throws SecurityException { 214 215 checkAlterInstantConverters(); 216 if (converter == null) { 217 return null; 218 } 219 InstantConverter[] removed = new InstantConverter[1]; 220 iInstantConverters = iInstantConverters.remove(converter, removed); 221 return removed[0]; 222 } 223 224 /** 225 * Checks whether the user has permission 'ConverterManager.alterInstantConverters'. 226 * 227 * @throws SecurityException if the user does not have the permission 228 */ 229 private void checkAlterInstantConverters() throws SecurityException { 230 SecurityManager sm = System.getSecurityManager(); 231 if (sm != null) { 232 sm.checkPermission(new JodaTimePermission("ConverterManager.alterInstantConverters")); 233 } 234 } 235 236 //----------------------------------------------------------------------- 237 /** 238 * Gets the best converter for the object specified. 239 * 240 * @param object the object to convert 241 * @return the converter to use 242 * @throws IllegalArgumentException if no suitable converter 243 * @throws IllegalStateException if multiple converters match the type 244 * equally well 245 */ 246 public PartialConverter getPartialConverter(Object object) { 247 PartialConverter converter = 248 (PartialConverter)iPartialConverters.select(object == null ? null : object.getClass()); 249 if (converter != null) { 250 return converter; 251 } 252 throw new IllegalArgumentException("No partial converter found for type: " + 253 (object == null ? "null" : object.getClass().getName())); 254 } 255 256 //----------------------------------------------------------------------- 257 /** 258 * Gets a copy of the set of converters. 259 * 260 * @return the converters, a copy of the real data, never null 261 */ 262 public PartialConverter[] getPartialConverters() { 263 ConverterSet set = iPartialConverters; 264 PartialConverter[] converters = new PartialConverter[set.size()]; 265 set.copyInto(converters); 266 return converters; 267 } 268 269 /** 270 * Adds a converter to the set of converters. If a matching converter is 271 * already in the set, the given converter replaces it. If the converter is 272 * exactly the same as one already in the set, no changes are made. 273 * <p> 274 * The order in which converters are added is not relevent. The best 275 * converter is selected by examining the object hierarchy. 276 * 277 * @param converter the converter to add, null ignored 278 * @return replaced converter, or null 279 */ 280 public PartialConverter addPartialConverter(PartialConverter converter) 281 throws SecurityException { 282 283 checkAlterPartialConverters(); 284 if (converter == null) { 285 return null; 286 } 287 PartialConverter[] removed = new PartialConverter[1]; 288 iPartialConverters = iPartialConverters.add(converter, removed); 289 return removed[0]; 290 } 291 292 /** 293 * Removes a converter from the set of converters. If the converter was 294 * not in the set, no changes are made. 295 * 296 * @param converter the converter to remove, null ignored 297 * @return replaced converter, or null 298 */ 299 public PartialConverter removePartialConverter(PartialConverter converter) 300 throws SecurityException { 301 302 checkAlterPartialConverters(); 303 if (converter == null) { 304 return null; 305 } 306 PartialConverter[] removed = new PartialConverter[1]; 307 iPartialConverters = iPartialConverters.remove(converter, removed); 308 return removed[0]; 309 } 310 311 /** 312 * Checks whether the user has permission 'ConverterManager.alterPartialConverters'. 313 * 314 * @throws SecurityException if the user does not have the permission 315 */ 316 private void checkAlterPartialConverters() throws SecurityException { 317 SecurityManager sm = System.getSecurityManager(); 318 if (sm != null) { 319 sm.checkPermission(new JodaTimePermission("ConverterManager.alterPartialConverters")); 320 } 321 } 322 323 //----------------------------------------------------------------------- 324 /** 325 * Gets the best converter for the object specified. 326 * 327 * @param object the object to convert 328 * @return the converter to use 329 * @throws IllegalArgumentException if no suitable converter 330 * @throws IllegalStateException if multiple converters match the type 331 * equally well 332 */ 333 public DurationConverter getDurationConverter(Object object) { 334 DurationConverter converter = 335 (DurationConverter)iDurationConverters.select(object == null ? null : object.getClass()); 336 if (converter != null) { 337 return converter; 338 } 339 throw new IllegalArgumentException("No duration converter found for type: " + 340 (object == null ? "null" : object.getClass().getName())); 341 } 342 343 //----------------------------------------------------------------------- 344 /** 345 * Gets a copy of the list of converters. 346 * 347 * @return the converters, a copy of the real data, never null 348 */ 349 public DurationConverter[] getDurationConverters() { 350 ConverterSet set = iDurationConverters; 351 DurationConverter[] converters = new DurationConverter[set.size()]; 352 set.copyInto(converters); 353 return converters; 354 } 355 356 /** 357 * Adds a converter to the set of converters. If a matching converter is 358 * already in the set, the given converter replaces it. If the converter is 359 * exactly the same as one already in the set, no changes are made. 360 * <p> 361 * The order in which converters are added is not relevent. The best 362 * converter is selected by examining the object hierarchy. 363 * 364 * @param converter the converter to add, null ignored 365 * @return replaced converter, or null 366 */ 367 public DurationConverter addDurationConverter(DurationConverter converter) 368 throws SecurityException { 369 370 checkAlterDurationConverters(); 371 if (converter == null) { 372 return null; 373 } 374 DurationConverter[] removed = new DurationConverter[1]; 375 iDurationConverters = iDurationConverters.add(converter, removed); 376 return removed[0]; 377 } 378 379 /** 380 * Removes a converter from the set of converters. If the converter was 381 * not in the set, no changes are made. 382 * 383 * @param converter the converter to remove, null ignored 384 * @return replaced converter, or null 385 */ 386 public DurationConverter removeDurationConverter(DurationConverter converter) 387 throws SecurityException { 388 389 checkAlterDurationConverters(); 390 if (converter == null) { 391 return null; 392 } 393 DurationConverter[] removed = new DurationConverter[1]; 394 iDurationConverters = iDurationConverters.remove(converter, removed); 395 return removed[0]; 396 } 397 398 /** 399 * Checks whether the user has permission 'ConverterManager.alterDurationConverters'. 400 * 401 * @throws SecurityException if the user does not have the permission 402 */ 403 private void checkAlterDurationConverters() throws SecurityException { 404 SecurityManager sm = System.getSecurityManager(); 405 if (sm != null) { 406 sm.checkPermission(new JodaTimePermission("ConverterManager.alterDurationConverters")); 407 } 408 } 409 410 //----------------------------------------------------------------------- 411 /** 412 * Gets the best converter for the object specified. 413 * 414 * @param object the object to convert 415 * @return the converter to use 416 * @throws IllegalArgumentException if no suitable converter 417 * @throws IllegalStateException if multiple converters match the type 418 * equally well 419 */ 420 public PeriodConverter getPeriodConverter(Object object) { 421 PeriodConverter converter = 422 (PeriodConverter)iPeriodConverters.select(object == null ? null : object.getClass()); 423 if (converter != null) { 424 return converter; 425 } 426 throw new IllegalArgumentException("No period converter found for type: " + 427 (object == null ? "null" : object.getClass().getName())); 428 } 429 430 //----------------------------------------------------------------------- 431 /** 432 * Gets a copy of the list of converters. 433 * 434 * @return the converters, a copy of the real data, never null 435 */ 436 public PeriodConverter[] getPeriodConverters() { 437 ConverterSet set = iPeriodConverters; 438 PeriodConverter[] converters = new PeriodConverter[set.size()]; 439 set.copyInto(converters); 440 return converters; 441 } 442 443 /** 444 * Adds a converter to the set of converters. If a matching converter is 445 * already in the set, the given converter replaces it. If the converter is 446 * exactly the same as one already in the set, no changes are made. 447 * <p> 448 * The order in which converters are added is not relevent. The best 449 * converter is selected by examining the object hierarchy. 450 * 451 * @param converter the converter to add, null ignored 452 * @return replaced converter, or null 453 */ 454 public PeriodConverter addPeriodConverter(PeriodConverter converter) 455 throws SecurityException { 456 457 checkAlterPeriodConverters(); 458 if (converter == null) { 459 return null; 460 } 461 PeriodConverter[] removed = new PeriodConverter[1]; 462 iPeriodConverters = iPeriodConverters.add(converter, removed); 463 return removed[0]; 464 } 465 466 /** 467 * Removes a converter from the set of converters. If the converter was 468 * not in the set, no changes are made. 469 * 470 * @param converter the converter to remove, null ignored 471 * @return replaced converter, or null 472 */ 473 public PeriodConverter removePeriodConverter(PeriodConverter converter) 474 throws SecurityException { 475 476 checkAlterPeriodConverters(); 477 if (converter == null) { 478 return null; 479 } 480 PeriodConverter[] removed = new PeriodConverter[1]; 481 iPeriodConverters = iPeriodConverters.remove(converter, removed); 482 return removed[0]; 483 } 484 485 /** 486 * Checks whether the user has permission 'ConverterManager.alterPeriodConverters'. 487 * 488 * @throws SecurityException if the user does not have the permission 489 */ 490 private void checkAlterPeriodConverters() throws SecurityException { 491 SecurityManager sm = System.getSecurityManager(); 492 if (sm != null) { 493 sm.checkPermission(new JodaTimePermission("ConverterManager.alterPeriodConverters")); 494 } 495 } 496 497 //----------------------------------------------------------------------- 498 /** 499 * Gets the best converter for the object specified. 500 * 501 * @param object the object to convert 502 * @return the converter to use 503 * @throws IllegalArgumentException if no suitable converter 504 * @throws IllegalStateException if multiple converters match the type 505 * equally well 506 */ 507 public IntervalConverter getIntervalConverter(Object object) { 508 IntervalConverter converter = 509 (IntervalConverter)iIntervalConverters.select(object == null ? null : object.getClass()); 510 if (converter != null) { 511 return converter; 512 } 513 throw new IllegalArgumentException("No interval converter found for type: " + 514 (object == null ? "null" : object.getClass().getName())); 515 } 516 517 //----------------------------------------------------------------------- 518 /** 519 * Gets a copy of the list of converters. 520 * 521 * @return the converters, a copy of the real data, never null 522 */ 523 public IntervalConverter[] getIntervalConverters() { 524 ConverterSet set = iIntervalConverters; 525 IntervalConverter[] converters = new IntervalConverter[set.size()]; 526 set.copyInto(converters); 527 return converters; 528 } 529 530 /** 531 * Adds a converter to the set of converters. If a matching converter is 532 * already in the set, the given converter replaces it. If the converter is 533 * exactly the same as one already in the set, no changes are made. 534 * <p> 535 * The order in which converters are added is not relevent. The best 536 * converter is selected by examining the object hierarchy. 537 * 538 * @param converter the converter to add, null ignored 539 * @return replaced converter, or null 540 */ 541 public IntervalConverter addIntervalConverter(IntervalConverter converter) 542 throws SecurityException { 543 544 checkAlterIntervalConverters(); 545 if (converter == null) { 546 return null; 547 } 548 IntervalConverter[] removed = new IntervalConverter[1]; 549 iIntervalConverters = iIntervalConverters.add(converter, removed); 550 return removed[0]; 551 } 552 553 /** 554 * Removes a converter from the set of converters. If the converter was 555 * not in the set, no changes are made. 556 * 557 * @param converter the converter to remove, null ignored 558 * @return replaced converter, or null 559 */ 560 public IntervalConverter removeIntervalConverter(IntervalConverter converter) 561 throws SecurityException { 562 563 checkAlterIntervalConverters(); 564 if (converter == null) { 565 return null; 566 } 567 IntervalConverter[] removed = new IntervalConverter[1]; 568 iIntervalConverters = iIntervalConverters.remove(converter, removed); 569 return removed[0]; 570 } 571 572 /** 573 * Checks whether the user has permission 'ConverterManager.alterIntervalConverters'. 574 * 575 * @throws SecurityException if the user does not have the permission 576 */ 577 private void checkAlterIntervalConverters() throws SecurityException { 578 SecurityManager sm = System.getSecurityManager(); 579 if (sm != null) { 580 sm.checkPermission(new JodaTimePermission("ConverterManager.alterIntervalConverters")); 581 } 582 } 583 584 //----------------------------------------------------------------------- 585 /** 586 * Gets a debug representation of the object. 587 */ 588 public String toString() { 589 return "ConverterManager[" + 590 iInstantConverters.size() + " instant," + 591 iPartialConverters.size() + " partial," + 592 iDurationConverters.size() + " duration," + 593 iPeriodConverters.size() + " period," + 594 iIntervalConverters.size() + " interval]"; 595 } 596 597 }