1/*
2******************************************************************************
3* Copyright (C) 2004-2015, International Business Machines Corporation and   *
4* others. All Rights Reserved.                                               *
5******************************************************************************
6*/
7
8package com.ibm.icu.impl;
9
10import java.io.InputStream;
11import java.util.ArrayList;
12import java.util.Collections;
13import java.util.Enumeration;
14import java.util.List;
15import java.util.MissingResourceException;
16import java.util.PropertyResourceBundle;
17import java.util.ResourceBundle;
18
19import com.ibm.icu.util.ULocale;
20import com.ibm.icu.util.UResourceBundle;
21
22/**
23 * just a wrapper for Java ListResourceBundles and
24 * @author ram
25 *
26 */
27public class ResourceBundleWrapper extends UResourceBundle {
28    private ResourceBundle bundle = null;
29    private String localeID = null;
30    private String baseName = null;
31    private List<String> keys = null;
32//    private int loadingStatus = -1;
33
34    private ResourceBundleWrapper(ResourceBundle bundle){
35        this.bundle=bundle;
36    }
37
38    protected void setLoadingStatus(int newStatus){
39//        loadingStatus = newStatus;
40    }
41
42    protected Object handleGetObject(String aKey){
43        ResourceBundleWrapper current = this;
44        Object obj = null;
45        while(current!=null){
46            try{
47                obj = current.bundle.getObject(aKey);
48                break;
49            }catch(MissingResourceException ex){
50                current = (ResourceBundleWrapper)current.getParent();
51            }
52        }
53        if (obj == null){
54            throw new MissingResourceException("Can't find resource for bundle "
55                                               +baseName
56                                               +", key "+aKey,
57                                               this.getClass().getName(),
58                                               aKey);
59        }
60        return obj;
61    }
62
63    public Enumeration<String> getKeys(){
64        return Collections.enumeration(keys);
65    }
66
67    private void initKeysVector(){
68        ResourceBundleWrapper current = this;
69        keys = new ArrayList<String>();
70        while(current!=null){
71            Enumeration<String> e = current.bundle.getKeys();
72            while(e.hasMoreElements()){
73                String elem = e.nextElement();
74                if(!keys.contains(elem)){
75                    keys.add(elem);
76                }
77            }
78            current = (ResourceBundleWrapper)current.getParent();
79        }
80    }
81    protected String getLocaleID(){
82        return localeID;
83    }
84
85    protected String getBaseName(){
86        return bundle.getClass().getName().replace('.','/');
87    }
88
89    public ULocale getULocale(){
90        return new ULocale(localeID);
91    }
92
93    public UResourceBundle getParent(){
94        return (UResourceBundle)parent;
95    }
96
97    // Flag for enabling/disabling debugging code
98    private static final boolean DEBUG = ICUDebug.enabled("resourceBundleWrapper");
99
100    // This method is for super class's instantiateBundle method
101    public static UResourceBundle getBundleInstance(String baseName, String localeID,
102                                                    ClassLoader root, boolean disableFallback){
103        UResourceBundle b = instantiateBundle(baseName, localeID, root, disableFallback);
104        if(b==null){
105            String separator ="_";
106            if(baseName.indexOf('/')>=0){
107                separator = "/";
108            }
109            throw new MissingResourceException("Could not find the bundle "+ baseName+separator+ localeID,"","");
110        }
111        return b;
112    }
113    // recursively build bundle and override the super-class method
114     protected static synchronized UResourceBundle instantiateBundle(String baseName, String localeID,
115                                                                    ClassLoader root, boolean disableFallback) {
116        if (root == null) {
117            root = ClassLoaderUtil.getClassLoader();
118        }
119        final ClassLoader cl = root;
120        String name = baseName;
121        ULocale defaultLocale = ULocale.getDefault();
122        if (localeID.length() != 0) {
123            name = name + "_" + localeID;
124        }
125
126        ResourceBundleWrapper b = (ResourceBundleWrapper)loadFromCache(cl, name, defaultLocale);
127        if(b==null){
128            ResourceBundleWrapper parent = null;
129            int i = localeID.lastIndexOf('_');
130
131            boolean loadFromProperties = false;
132            if (i != -1) {
133                String locName = localeID.substring(0, i);
134                parent = (ResourceBundleWrapper)loadFromCache(cl, baseName+"_"+locName,defaultLocale);
135                if(parent == null){
136                    parent = (ResourceBundleWrapper)instantiateBundle(baseName, locName , cl, disableFallback);
137                }
138            }else if(localeID.length()>0){
139                parent = (ResourceBundleWrapper)loadFromCache(cl, baseName,defaultLocale);
140                if(parent==null){
141                    parent = (ResourceBundleWrapper)instantiateBundle(baseName, "", cl, disableFallback);
142                }
143            }
144            try {
145                Class<? extends ResourceBundle> cls = cl.loadClass(name).asSubclass(ResourceBundle.class);
146                ResourceBundle bx = cls.newInstance();
147                b = new ResourceBundleWrapper(bx);
148                if (parent != null) {
149                    b.setParent(parent);
150                }
151                b.baseName=baseName;
152                b.localeID = localeID;
153
154            } catch (ClassNotFoundException e) {
155                loadFromProperties = true;
156            } catch (NoClassDefFoundError e) {
157                loadFromProperties = true;
158            } catch (Exception e) {
159                if (DEBUG)
160                    System.out.println("failure");
161                if (DEBUG)
162                    System.out.println(e);
163            }
164
165            if (loadFromProperties) {
166                try {
167                    final String resName = name.replace('.', '/') + ".properties";
168                    InputStream stream = java.security.AccessController.doPrivileged(
169                        new java.security.PrivilegedAction<InputStream>() {
170                            public InputStream run() {
171                                if (cl != null) {
172                                    return cl.getResourceAsStream(resName);
173                                } else {
174                                    return ClassLoader.getSystemResourceAsStream(resName);
175                                }
176                            }
177                        }
178                    );
179                    if (stream != null) {
180                        // make sure it is buffered
181                        stream = new java.io.BufferedInputStream(stream);
182                        try {
183                            b = new ResourceBundleWrapper(new PropertyResourceBundle(stream));
184                            if (parent != null) {
185                                b.setParent(parent);
186                            }
187                            b.baseName=baseName;
188                            b.localeID=localeID;
189                        } catch (Exception ex) {
190                            // throw away exception
191                        } finally {
192                            try {
193                                stream.close();
194                            } catch (Exception ex) {
195                                // throw away exception
196                            }
197                        }
198                    }
199
200                    // if a bogus locale is passed then the parent should be
201                    // the default locale not the root locale!
202                    if (b==null) {
203                        String defaultName = defaultLocale.toString();
204                        if (localeID.length()>0 && localeID.indexOf('_')< 0 && defaultName.indexOf(localeID) == -1) {
205                            b = (ResourceBundleWrapper)loadFromCache(cl,baseName+"_"+defaultName, defaultLocale);
206                            if(b==null){
207                                b = (ResourceBundleWrapper)instantiateBundle(baseName , defaultName, cl, disableFallback);
208                            }
209                        }
210                    }
211                    // if still could not find the bundle then return the parent
212                    if(b==null){
213                        b=parent;
214                    }
215                } catch (Exception e) {
216                    if (DEBUG)
217                        System.out.println("failure");
218                    if (DEBUG)
219                        System.out.println(e);
220                }
221            }
222            b = (ResourceBundleWrapper)addToCache(cl, name, defaultLocale, b);
223        }
224
225        if(b!=null){
226            b.initKeysVector();
227        }else{
228            if(DEBUG)System.out.println("Returning null for "+baseName+"_"+localeID);
229        }
230
231        return b;
232    }
233}
234