001    /*
002     *  Copyright 2006 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.contrib.i18n;
017    
018    import java.io.BufferedInputStream;
019    import java.io.ByteArrayInputStream;
020    import java.io.ByteArrayOutputStream;
021    import java.io.IOException;
022    import java.io.InputStream;
023    import java.io.ObjectInputStream;
024    
025    import org.joda.time.DateTimeZone;
026    
027    /**
028     * Provides time data for a specific territory, typically a country.
029     * <p>
030     * Many pieces of data used in dates and times varies by territory.
031     * This class provides access to that data.
032     */
033    public class CLDRTerritory extends Territory {
034    
035        /** The raw CLDR data. */
036        private static final byte[] cRawData = loadRawData();
037    
038        /** The territory id, as per CLDR. */
039        private String iID;
040        /** The zones. */
041        private DateTimeZone[] iZones;
042        /** The first day of week. */
043        private int iFirstDOW;
044        /** The first day of the business week. */
045        private int iFirstBusinessDOW;
046        /** The last day of the business week. */
047        private int iLastBusinessDOW;
048        /** The first day of the weekend. */
049        private int iFirstWeekendDOW;
050        /** The last day of the weekend. */
051        private int iLastWeekendDOW;
052    
053        //-----------------------------------------------------------------------
054        /**
055         * Loads the data from file.
056         *
057         * @return the array of bytes
058         */
059        private static byte[] loadRawData() {
060            String path = "org/joda/time/contrib/i18n/CLDRTerritoryData.dat";
061            InputStream baseStream = null;
062            ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
063            try {
064                // open the file
065                baseStream = CLDRTerritory.class.getClassLoader().getResourceAsStream(path);
066                if (baseStream == null) {
067                    throw new IOException("Resource not found " + path);
068                }
069                byte[] bytes = new byte[1024];
070                int result = 0;
071                while (result != -1) {
072                    baos.write(bytes, 0, result);
073                    result = baseStream.read(bytes, 0, 1024);
074                }
075                return baos.toByteArray();
076                
077            } catch (IOException ex) {
078                throw new IllegalArgumentException("Territory data could not be loaded: " + ex.getMessage());
079            } finally {
080                if (baseStream != null) {
081                    try {
082                        baseStream.close();
083                    } catch (IOException ex) {
084                        // ignore
085                    }
086                }
087            }
088        }
089    
090        //-----------------------------------------------------------------------
091        /**
092         * Constructor.
093         *
094         * @param id  the territory id, not null
095         */
096        CLDRTerritory(String id) {
097            super();
098            init(id);
099        }
100    
101        //-----------------------------------------------------------------------
102        /**
103         * Initialises the data for this id.
104         *
105         * @param id  the territory id, not null
106         * @throws IOException if an error occurs
107         */
108        private void init(String id) {
109            try {
110                // open the file
111                ByteArrayInputStream bais = new ByteArrayInputStream(cRawData);
112                ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(bais));
113                byte version = in.readByte();
114                if (version != 1) {
115                    throw new IllegalArgumentException("Unknown file version: " + version);
116                }
117                
118                // loop through file to find the id
119                String inputId = in.readUTF();
120                while (inputId.equals(id) == false) {
121                    byte zoneCount = in.readByte();
122                    for (int i = 0; i < zoneCount; i++) {
123                        in.readUTF();
124                    }
125                    in.skip(5);
126                    inputId = in.readUTF();
127                    if (inputId.length() == 0) {
128                        throw new IllegalArgumentException("Territory " + id + " could not be loaded");
129                    }
130                }
131                
132                // found matching id
133                iID = id;
134                byte zoneCount = in.readByte();
135                iZones = new DateTimeZone[zoneCount];
136                for (int i = 0; i < zoneCount; i++) {
137                    String zoneID = in.readUTF();
138                    try {
139                        iZones[i] = DateTimeZone.forID(zoneID);
140                    } catch (IllegalArgumentException ex) {
141                        // ignore unless primary, allowing different timezone data files to work
142                        if (i == 0) {
143                            throw ex;
144                        }
145                    }
146                }
147                iFirstDOW = in.readByte();
148                iFirstBusinessDOW = in.readByte();
149                iLastBusinessDOW = in.readByte();
150                iFirstWeekendDOW = in.readByte();
151                iLastWeekendDOW = in.readByte();
152                
153            } catch (IOException ex) {
154                throw new IllegalArgumentException("Territory " + id + " could not be loaded: " + ex.getMessage());
155            }
156        }
157    
158        //-----------------------------------------------------------------------
159        public String getID() {
160            return iID;
161        }
162    
163        //-----------------------------------------------------------------------
164            public DateTimeZone[] getZones() {
165            return (DateTimeZone[]) iZones.clone();
166        }
167    
168        public int getFirstDayOfWeek() {
169            return iFirstDOW;
170        }
171    
172        public int getBusinessWeekStart() {
173            return iFirstBusinessDOW;
174        }
175    
176        public int getBusinessWeekEnd() {
177            return iLastBusinessDOW;
178        }
179    
180        public int getWeekendStart() {
181            return iFirstWeekendDOW;
182        }
183    
184        public int getWeekendEnd() {
185            return iLastWeekendDOW;
186        }
187    
188    }