    001/*
    002@license.text@
    003 */
    004package com.hammurapi.common;
    005
    006import java.io.IOException;
    007import java.io.InputStream;
    008import java.net.URL;
    009import java.util.HashMap;
    010import java.util.Locale;
    011import java.util.Map;
    012import java.util.Properties;
    013
    014import com.hammurapi.convert.ConversionException;
    015import com.hammurapi.convert.ConvertingService;
    016
    017
    018public class ResourceLoaderImpl implements ResourceLoader {
    019
    020        private ResourceSet resourceSet;
    021        private String[] resolutionPaths;
    022
    023        public ResourceLoaderImpl(ResourceSet resourceSet, String... resolutionPaths) {
    024                this.resourceSet = resourceSet;
    025                this.resolutionPaths = resolutionPaths;
    026        }
    027
    028        /**
    029         *
    030         * @param profile Profile, can be null
    031         * @param extension Extension, can be null
    032         * @return
    033         */
    034        public InputStream getResourceStream(String scriptName, String extension) {
    035                return getResourceStream(scriptName, Locale.getDefault(), extension);
    036        }
    037
    038        @Override
    039        public URL getResource(String scriptName, String extension) {
    040                return getResource(scriptName, Locale.getDefault(), extension);
    041        }
    042
    043        private enum Variant {
    044                LOCALE, LANG_COUNTRY, LANG, GENERIC
    045        }
    046
    047        /**
    048         * @param scriptName
    049         * @param extension
    050         * @return
    051         */
    052        public InputStream getResourceStream(final String scriptName, final Locale locale, final String extension) {
    053                Locale actualLocale = locale==null ? Locale.getDefault() : locale;
    054                for (String path: resolutionPaths) {
    055                        for (Variant v: Variant.values()) {
    056                                String variant=path;
    057                                if (scriptName!=null) {
    058                                        variant+="!"+scriptName;
    059                                }
    060
    061                                switch (v) {
    062                                case LOCALE:
    063                                        variant+="_"+actualLocale;
    064                                        break;
    065                                case LANG_COUNTRY:
    066                                        variant+="_"+actualLocale.getLanguage();
    067                                        if (actualLocale.getCountry().length()!=0) {
    068                                                variant+="_"+actualLocale.getCountry();
    069                                        }
    070                                        break;
    071                                case LANG:
    072                                        variant+="_"+actualLocale.getLanguage();
    073                                        break;
    074                                case GENERIC:
    075                                        break;
    076                                }
    077
    078                                if (extension!=null) {
    079                                        variant+="."+extension;
    080                                }
    081
    082                                InputStream ret = resourceSet.getResourceStream(variant);
    083                                if (ret!=null) {
    084                                        return ret;
    085                                }
    086                        }
    087                }
    088
    089                return null;
    090        }
    091
    092        /**
    093         * @param scriptName
    094         * @param extension
    095         * @return
    096         */
    097        public URL getResource(final String scriptName, final Locale locale, final String extension) {
    098                Locale actualLocale = locale==null ? Locale.getDefault() : locale;
    099                for (String path: resolutionPaths) {
    100                        for (Variant v: Variant.values()) {
    101                                String variant=path;
    102                                if (scriptName!=null) {
    103                                        variant+="!"+scriptName;
    104                                }
    105
    106                                switch (v) {
    107                                case LOCALE:
    108                                        variant+="_"+actualLocale;
    109                                        break;
    110                                case LANG_COUNTRY:
    111                                        variant+="_"+actualLocale.getLanguage();
    112                                        if (actualLocale.getCountry().length()!=0) {
    113                                                variant+="_"+actualLocale.getCountry();
    114                                        }
    115                                        break;
    116                                case LANG:
    117                                        variant+="_"+actualLocale.getLanguage();
    118                                        break;
    119                                case GENERIC:
    120                                        break;
    121                                }
    122
    123                                if (extension!=null) {
    124                                        variant+="."+extension;
    125                                }
    126
    127                                URL ret = resourceSet.getResource(variant);
    128                                if (ret!=null) {
    129                                        return ret;
    130                                }
    131                        }
    132                }
    133
    134                return null;
    135        }
    136
    137        /**
    138         * Collects properties from class hierarchy.
    139         * @param profile Profile, can be null
    140         * @param extension Extension, can be null
    141         * @return
    142         */
    143        public Map<String, Object> getProperties(String profile, String extension) {
    144                return getProperties(profile, Locale.getDefault(), extension);
    145        }
    146
    147        /**
    148         * Collects properties from class hierarchy.
    149         * @param profile
    150         * @param extension
    151         * @return
    152         */
    153        public Map<String, Object> getProperties(final String profile, final Locale locale, final String extension) {
    154                return getProperties(profile, locale, extension, Thread.currentThread().getContextClassLoader());
    155        }
    156
    157        /**
    158         * Collects properties from class hierarchy. Property can have type. Type name is enclosed into parenthesis, e.g.
    159         * <code>attempts(java.lang.Integer)=33</code>. If property is defined with type then string value of the property is converted to the
    160         * target type. If not, property type is String.
    161         * @param profile
    162         * @param extension
    163         * @return
    164         */
    165        public Map<String, Object> getProperties(final String profile, final Locale locale, final String extension, ClassLoader classLoader) {
    166                Map<String, Object> ret = new HashMap<String, Object>();
    167                Locale actualLocale = locale==null ? Locale.getDefault() : locale;
    168                for (String path: resolutionPaths) {
    169                        for (Variant v: Variant.values()) {
    170                                String variant=path;
    171                                if (profile!=null) {
    172                                        variant+="!"+profile;
    173                                }
    174
    175                                switch (v) {
    176                                case LOCALE:
    177                                        variant+="_"+actualLocale;
    178                                        break;
    179                                case LANG_COUNTRY:
    180                                        variant+="_"+actualLocale.getLanguage();
    181                                        if (actualLocale.getCountry().length()!=0) {
    182                                                variant+="_"+actualLocale.getCountry();
    183                                        }
    184                                        break;
    185                                case LANG:
    186                                        variant+="_"+actualLocale.getLanguage();
    187                                        break;
    188                                case GENERIC:
    189                                        break;
    190                                }
    191                                if (extension!=null) {
    192                                        variant+="."+extension;
    193                                }
    194
    195                                InputStream s = resourceSet.getResourceStream(variant);
    196                                if (s!=null) {
    197                                        Properties cp=new Properties();
    198                                        try {
    199                                                cp.load(s);
    200                                                for (Map.Entry<Object, Object> entry: cp.entrySet()) {
    201                                                        String key = (String) entry.getKey();
    202                                                        Object value = entry.getValue();
    203                                                        int idx = key.charAt(key.length()-1)==')' ? key.lastIndexOf('(') : -1;
    204                                                        String propertyClassName = null;
    205                                                        if (idx>0) {
    206                                                                propertyClassName = key.substring(idx+1, key.length()-1);
    207                                                                key = key.substring(0, idx);
    208                                                        }
    209                                                        if (!ret.containsKey(key)) {
    210                                                                if (propertyClassName!=null) {
    211                                                                        try {
    212                                                                                Class<?> propertyClass = classLoader.loadClass(propertyClassName);
    213                                                                                value = ConvertingService.convert(value, propertyClass, classLoader);
    214                                                                        } catch (ClassNotFoundException e) {
    215                                                                                throw new ConversionException(e);
    216                                                                        }
    217                                                                }
    218                                                                ret.put(key, value);
    219                                                        }
    220                                                }
    221                                        } catch (IOException e) {
    222                                                throw new RuntimeException("Cannot load properties from resource "+variant, e);
    223                                        }
    224
    225                                        break;
    226                                }
    227                        }
    228                }
    229
    230
    231                return ret;
    232        }
    233}