001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.portlet;
016    
017    import com.liferay.portal.kernel.util.AggregateResourceBundle;
018    import com.liferay.portal.kernel.util.ResourceBundleUtil;
019    import com.liferay.portal.kernel.util.ResourceBundleUtil.ResourceBundleLoader;
020    import com.liferay.registry.collections.ServiceReferenceMapperFactory;
021    import com.liferay.registry.collections.ServiceTrackerCollections;
022    import com.liferay.registry.collections.ServiceTrackerMap;
023    import com.liferay.registry.collections.ServiceTrackerMapListener;
024    
025    import java.io.Closeable;
026    
027    import java.util.Iterator;
028    import java.util.List;
029    import java.util.Map;
030    import java.util.ResourceBundle;
031    import java.util.Set;
032    import java.util.concurrent.ConcurrentHashMap;
033    
034    /**
035     * @author Raymond Aug??
036     * @author Tomas Polesovsky
037     * @author Carlos Sierra Andr??s
038     */
039    public class ResourceBundleTracker implements Closeable {
040    
041            public ResourceBundleTracker(String portletId) {
042                    _serviceTrackerMap = ServiceTrackerCollections.openMultiValueMap(
043                            ResourceBundle.class,
044                            "(&(javax.portlet.name=" + portletId + ")(language.id=*))",
045                            ServiceReferenceMapperFactory.<String, Object>create("language.id"),
046                            new ResourceBundleTrackerServiceTrackerMapListener());
047            }
048    
049            @Override
050            public void close() {
051                    _serviceTrackerMap.close();
052            }
053    
054            public ResourceBundle getResourceBundle(String languageId) {
055                    ResourceBundle resourceBundle = _resourceBundles.get(languageId);
056    
057                    if (resourceBundle != null) {
058                            return resourceBundle;
059                    }
060    
061                    synchronized (_resourceBundles) {
062                            resourceBundle = _resourceBundles.get(languageId);
063    
064                            if (resourceBundle == null) {
065                                    ResourceBundleUtil.loadResourceBundles(
066                                            _resourceBundles, languageId,
067                                            new ResourceBundleLoader() {
068    
069                                                    @Override
070                                                    public ResourceBundle loadResourceBundle(
071                                                            String languageId) {
072    
073                                                            List<ResourceBundle> resourceBundles =
074                                                                    _serviceTrackerMap.getService(languageId);
075    
076                                                            if ((resourceBundles == null) ||
077                                                                    resourceBundles.isEmpty()) {
078    
079                                                                    return null;
080                                                            }
081    
082                                                            int size = resourceBundles.size();
083    
084                                                            if (size == 1) {
085                                                                    return resourceBundles.get(0);
086                                                            }
087    
088                                                            return new AggregateResourceBundle(
089                                                                    resourceBundles.toArray(
090                                                                            new ResourceBundle[size]));
091                                                    }
092    
093                                            });
094    
095                                    resourceBundle = _resourceBundles.get(languageId);
096                            }
097                    }
098    
099                    return resourceBundle;
100            }
101    
102            private final Map<String, ResourceBundle> _resourceBundles =
103                    new ConcurrentHashMap<>();
104            private final ServiceTrackerMap<String, List<ResourceBundle>>
105                    _serviceTrackerMap;
106    
107            private class ResourceBundleTrackerServiceTrackerMapListener
108                    implements ServiceTrackerMapListener
109                            <String, ResourceBundle, List<ResourceBundle>> {
110    
111                    @Override
112                    public void keyEmitted(
113                            ServiceTrackerMap<String, List<ResourceBundle>>
114                                    serviceTrackerMap,
115                            String languageId, ResourceBundle resourceBundle,
116                            List<ResourceBundle> resourceBundles) {
117    
118                            synchronized (_resourceBundles) {
119                                    Set<String> keySet = _resourceBundles.keySet();
120                                    Iterator<String> iterator = keySet.iterator();
121    
122                                    while (iterator.hasNext()) {
123                                            String sublanguageId = iterator.next();
124    
125                                            if (!languageId.equals(sublanguageId) &&
126                                                    sublanguageId.startsWith(languageId)) {
127    
128                                                    iterator.remove();
129                                            }
130                                    }
131                            }
132                    }
133    
134                    @Override
135                    public void keyRemoved(
136                            ServiceTrackerMap<String, List<ResourceBundle>>
137                                    serviceTrackerMap,
138                            String languageId, ResourceBundle resourceBundle,
139                            List<ResourceBundle> resourceBundles) {
140    
141                            synchronized (_resourceBundles) {
142                                    Set<String> keySet = _resourceBundles.keySet();
143                                    Iterator<String> iterator = keySet.iterator();
144    
145                                    while (iterator.hasNext()) {
146                                            String sublanguageId = iterator.next();
147    
148                                            if (sublanguageId.startsWith(languageId)) {
149                                                    iterator.remove();
150                                            }
151                                    }
152                            }
153                    }
154    
155            }
156    
157    }