/** * Return the configuration properties from the resource. * * <p>The default location of the variant configuration resource is: * * <pre> * "$java.home/lib/" + resource-name * </pre> * * @param resource the name of the calendar property resource * @return a Properties containing the properties read from the resource. * @throws Exception if access to the property resource fails */ private static Properties readConfigProperties(final String resource) throws Exception { try { return AccessController.doPrivileged( (j86.java.security.PrivilegedExceptionAction<Properties>) () -> { String libDir = System.getProperty("java.home") + File.separator + "lib"; File file = new File(libDir, resource); Properties props = new Properties(); try (InputStream is = new FileInputStream(file)) { props.load(is); } return props; }); } catch (PrivilegedActionException pax) { throw pax.getException(); } }
/** * Create a HijrahChronology for the named variant. The resource and calendar type are retrieved * from properties in the {@code calendars.properties}. The property names are {@code * "calendar.hijrah." + id} and {@code "calendar.hijrah." + id + ".type"} * * @param id the id of the calendar * @throws DateTimeException if the calendar type is missing from the properties file. * @throws IllegalArgumentException if the id is empty */ private HijrahChronology(String id) throws DateTimeException { if (id.isEmpty()) { throw new IllegalArgumentException("calendar id is empty"); } String propName = PROP_PREFIX + id + PROP_TYPE_SUFFIX; String calType = calendarProperties.getProperty(propName); if (calType == null || calType.isEmpty()) { throw new DateTimeException("calendarType is missing or empty for: " + propName); } this.typeId = id; this.calendarType = calType; }
/** * For each Hijrah variant listed, create the HijrahChronology and register it. Exceptions during * initialization are logged but otherwise ignored. */ private static void registerVariants() { for (String name : calendarProperties.stringPropertyNames()) { if (name.startsWith(PROP_PREFIX)) { String id = name.substring(PROP_PREFIX.length()); if (id.indexOf('.') >= 0) { continue; // no name or not a simple name of a calendar } if (id.equals(INSTANCE.getId())) { continue; // do not duplicate the default } try { // Create and register the variant HijrahChronology chrono = new HijrahChronology(id); AbstractChronology.registerChrono(chrono); } catch (DateTimeException ex) { // Log error and continue PlatformLogger logger = PlatformLogger.getLogger("j86.java.time.chrono"); logger.severe("Unable to initialize Hijrah calendar: " + id, ex); } } } }
/** * Loads and processes the Hijrah calendar properties file for this calendarType. The starting * Hijrah date and the corresponding ISO date are extracted and used to calculate the epochDate * offset. The version number is identified and ignored. Everything else is the data for a year * with containing the length of each of 12 months. * * @throws DateTimeException if initialization of the calendar data from the resource fails */ private void loadCalendarData() { try { String resourceName = calendarProperties.getProperty(PROP_PREFIX + typeId); Objects.requireNonNull( resourceName, "Resource missing for calendar: " + PROP_PREFIX + typeId); Properties props = readConfigProperties(resourceName); Map<Integer, int[]> years = new HashMap<>(); int minYear = Integer.MAX_VALUE; int maxYear = Integer.MIN_VALUE; String id = null; String type = null; String version = null; int isoStart = 0; for (Map.Entry<Object, Object> entry : props.entrySet()) { String key = (String) entry.getKey(); switch (key) { case KEY_ID: id = (String) entry.getValue(); break; case KEY_TYPE: type = (String) entry.getValue(); break; case KEY_VERSION: version = (String) entry.getValue(); break; case KEY_ISO_START: { int[] ymd = parseYMD((String) entry.getValue()); isoStart = (int) LocalDate.of(ymd[0], ymd[1], ymd[2]).toEpochDay(); break; } default: try { // Everything else is either a year or invalid int year = Integer.valueOf(key); int[] months = parseMonths((String) entry.getValue()); years.put(year, months); maxYear = Math.max(maxYear, year); minYear = Math.min(minYear, year); } catch (NumberFormatException nfe) { throw new IllegalArgumentException("bad key: " + key); } } } if (!getId().equals(id)) { throw new IllegalArgumentException("Configuration is for a different calendar: " + id); } if (!getCalendarType().equals(type)) { throw new IllegalArgumentException( "Configuration is for a different calendar type: " + type); } if (version == null || version.isEmpty()) { throw new IllegalArgumentException("Configuration does not contain a version"); } if (isoStart == 0) { throw new IllegalArgumentException("Configuration does not contain a ISO start date"); } // Now create and validate the array of epochDays indexed by epochMonth hijrahStartEpochMonth = minYear * 12; minEpochDay = isoStart; hijrahEpochMonthStartDays = createEpochMonths(minEpochDay, minYear, maxYear, years); maxEpochDay = hijrahEpochMonthStartDays[hijrahEpochMonthStartDays.length - 1]; // Compute the min and max year length in days. for (int year = minYear; year < maxYear; year++) { int length = getYearLength(year); minYearLength = Math.min(minYearLength, length); maxYearLength = Math.max(maxYearLength, length); } } catch (Exception ex) { // Log error and throw a DateTimeException PlatformLogger logger = PlatformLogger.getLogger("j86.java.time.chrono"); logger.severe("Unable to initialize Hijrah calendar proxy: " + typeId, ex); throw new DateTimeException("Unable to initialize HijrahCalendar: " + typeId, ex); } }