/* * Copyright (C) 2012 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.cas.lib.proarc.webapp.server.rest; import cz.cas.lib.proarc.common.i18n.BundleName; import cz.cas.lib.proarc.webapp.shared.rest.LocalizationResourceApi; import java.text.Collator; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.EnumSet; import java.util.List; import java.util.Locale; import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.ResourceBundle.Control; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.ws.rs.DefaultValue; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.xml.bind.annotation.XmlAccessType; import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; /** * * @author Jan Pokorsky */ @Path(LocalizationResourceApi.PATH) public class LocalizationResource { private static final Logger LOG = Logger.getLogger(LocalizationResource.class.getName()); private final HttpHeaders httpHeaders; public LocalizationResource( @Context HttpHeaders httpHeaders ) { this.httpHeaders = httpHeaders; } /** * Gets localization bundle. * * @param bundleNames name of bundle. If {@code null} all bundles are included. * @param locale optional locale. If {@code null} HTTP headers are queried for acceptable language * @param sorted optional flag to partially sort result bundle items by value. * Default is {@code true}. * @return the bundle */ @GET @Produces({MediaType.APPLICATION_JSON}) public SmartGwtResponse<Item> getBundle( @QueryParam(LocalizationResourceApi.ITEM_BUNDLENAME) Set<BundleName> bundleNames, @DefaultValue("") @QueryParam(LocalizationResourceApi.GETBUNDLE_LOCALE_PARAM) String locale, @DefaultValue("true") @QueryParam(LocalizationResourceApi.GETBUNDLE_SORTED_PARAM) boolean sorted) { if (bundleNames == null || bundleNames.isEmpty()) { bundleNames = EnumSet.allOf(BundleName.class); } Locale localeObj; if (locale == null || locale.isEmpty()) { List<Locale> acceptableLanguages = httpHeaders.getAcceptableLanguages(); localeObj = acceptableLanguages.isEmpty() ? Locale.ENGLISH : acceptableLanguages.get(0); } else { localeObj = new Locale(locale); } Control control = ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_PROPERTIES); ArrayList<Item> result = new ArrayList<Item>(); for (BundleName bundleName : bundleNames) { try { if (!BundleName.PROPERTIES.equals(bundleName.getFormat())) { continue; } result.addAll(readBundle(bundleName, localeObj, control, sorted)); } catch (MissingResourceException ex) { LOG.log(Level.WARNING, bundleNames.toString(), ex); throw RestException.plainNotFound( LocalizationResourceApi.ITEM_BUNDLENAME, bundleName.toString()); } } return new SmartGwtResponse<Item>(result); } private ArrayList<Item> readBundle(BundleName bundleName, Locale localeObj, Control control, boolean sorted) { // to read properties file in UTF-8 use PropertyResourceBundle(Reader) ResourceBundle rb = ResourceBundle.getBundle(bundleName.toString(), localeObj, control); ArrayList<Item> result = new ArrayList<Item>(); for (String key : rb.keySet()) { result.add(new Item(key, rb.getString(key), bundleName.toString())); } if (sorted) { Collections.sort(result, new LocalizedItemComparator(localeObj)); } return result; } @XmlAccessorType(XmlAccessType.FIELD) public static class Item { @XmlElement(name = LocalizationResourceApi.ITEM_KEY) private String key; @XmlElement(name = LocalizationResourceApi.ITEM_VALUE) private String value; @XmlElement(name = LocalizationResourceApi.ITEM_BUNDLENAME) private String bundleName; public Item(String key, String value, String bundleName) { this.key = key; this.value = value; this.bundleName = bundleName; } public Item() { } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public String getValue() { return value; } public void setValue(String value) { this.value = value; } public String getBundleName() { return bundleName; } public void setBundleName(String bundleName) { this.bundleName = bundleName; } @Override public String toString() { return "Item{" + "code=" + key + ", value=" + value + '}'; } } private static final class LocalizedItemComparator implements Comparator<Item> { private final Collator collator; public LocalizedItemComparator(Locale locale) { collator = Collator.getInstance(locale); } @Override public int compare(Item o1, Item o2) { return collator.compare(o1.value, o2.value); } } }