diff --git a/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java b/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java index 93b2779ca4..6ac84defcc 100644 --- a/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java +++ b/source/java/org/alfresco/rest/api/search/impl/SearchMapper.java @@ -46,6 +46,7 @@ import org.alfresco.rest.api.search.model.FacetFields; import org.alfresco.rest.api.search.model.FacetQuery; import org.alfresco.rest.api.search.model.FilterQuery; import org.alfresco.rest.api.search.model.Limits; +import org.alfresco.rest.api.search.model.Localization; import org.alfresco.rest.api.search.model.Pivot; import org.alfresco.rest.api.search.model.Query; import org.alfresco.rest.api.search.model.Scope; @@ -78,6 +79,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.ListIterator; +import java.util.Locale; +import java.util.Locale.Builder; import java.util.Map; import java.util.Optional; import java.util.Set; @@ -115,11 +118,11 @@ public class SearchMapper SearchParameters sp = new SearchParameters(); setDefaults(sp); + fromLocalization(sp, searchQuery.getLocalization()); fromQuery(sp, searchQuery.getQuery()); fromPaging(sp, params.getPaging()); fromSort(sp, searchQuery.getSort()); fromTemplate(sp, searchQuery.getTemplates()); - fromTimezone(sp, searchQuery.getTimezone()); validateInclude(searchQuery.getInclude()); fromDefault(sp, searchQuery.getDefaults()); fromFilterQuery(sp, searchQuery.getFilterQueries()); @@ -691,44 +694,65 @@ public class SearchMapper * @param sp SearchParameters * @param timezoneId a valid java.time.ZoneId */ - public void fromTimezone(SearchParameters sp, String timezoneId) + public void fromLocalization(SearchParameters sp, Localization localization) { - /* - * java.util.TimeZone will not error if you set an invalid timezone - * it just falls back to GMT without telling you. - * - * So I am using java.time.ZoneId because that throws an error, - * if I then convert a ZoneId to Timezone I have the same problem (silently uses GMT) - * so - * I am converting using both methods: - * If a timezoneId is invalid then an Invalid error is thrown - * If its not possible to take a java.time.ZoneId and convert it to a java.util.TimeZone then an Incompatible error is thrown - * - */ - if (timezoneId!= null && !timezoneId.isEmpty()) + if (localization != null) { - ZoneId validZoneId = null; - TimeZone timeZone = null; - try + if (!localization.getLocales().isEmpty()) { - validZoneId = ZoneId.of(timezoneId); - timeZone = TimeZone.getTimeZone(timezoneId); - } - catch (Exception e) - { - throw new IllegalArgumentException("Invalid timezoneId "+timezoneId); + try + { + localization.getLocales().forEach(localeStr -> { + if (localeStr != null) localeStr = localeStr.replace('_','-'); + sp.addLocale(Locale.forLanguageTag(localeStr)); + }); + } + catch (Exception e) + { + throw new IllegalArgumentException("Invalid locale " + localization.getLocales()); + } + } - if (validZoneId.getId().equals(timeZone.getID())) + /* + * java.util.TimeZone will not error if you set an invalid timezone + * it just falls back to GMT without telling you. + * + * So I am using java.time.ZoneId because that throws an error, + * if I then convert a ZoneId to Timezone I have the same problem (silently uses GMT) + * so + * I am converting using both methods: + * If a timezoneId is invalid then an Invalid error is thrown + * If its not possible to take a java.time.ZoneId and convert it to a java.util.TimeZone then an Incompatible error is thrown + * + */ + String timezoneId = localization.getTimezone(); + if (timezoneId != null && !timezoneId.isEmpty()) { - sp.setTimezone(validZoneId.getId()); - } - else - { - throw new IllegalArgumentException("Incompatible timezoneId "+timezoneId); - } + ZoneId validZoneId = null; + TimeZone timeZone = null; + try + { + validZoneId = ZoneId.of(timezoneId); + timeZone = TimeZone.getTimeZone(timezoneId); + } + catch (Exception e) + { + throw new IllegalArgumentException("Invalid timezoneId " + timezoneId); + } + + if (validZoneId.getId().equals(timeZone.getID())) + { + sp.setTimezone(validZoneId.getId()); + } + else + { + throw new IllegalArgumentException("Incompatible timezoneId " + timezoneId); + } + + } } } diff --git a/source/java/org/alfresco/rest/api/search/model/Localization.java b/source/java/org/alfresco/rest/api/search/model/Localization.java new file mode 100644 index 0000000000..060f06ec44 --- /dev/null +++ b/source/java/org/alfresco/rest/api/search/model/Localization.java @@ -0,0 +1,59 @@ +/*- + * #%L + * Alfresco Remote API + * %% + * Copyright (C) 2005 - 2016 Alfresco Software Limited + * %% + * This file is part of the Alfresco software. + * If the software was purchased under a paid Alfresco license, the terms of + * the paid license agreement will prevail. Otherwise, the software is + * provided under the following open source license terms: + * + * Alfresco is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Alfresco 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Alfresco. If not, see . + * #L% + */ +package org.alfresco.rest.api.search.model; + +import org.codehaus.jackson.annotate.JsonCreator; +import org.codehaus.jackson.annotate.JsonProperty; + +import java.util.Collections; +import java.util.List; + +/** + * POJO class representing Localization parameters + */ +public class Localization +{ + private final String timezone; + private final List locales; + + @JsonCreator + public Localization(@JsonProperty("timezone") String timezone, + @JsonProperty("locales") List locales) + { + this.timezone = timezone; + this.locales = locales == null? Collections.emptyList():locales; + } + + public String getTimezone() + { + return timezone; + } + + public List getLocales() + { + return locales; + } +} diff --git a/source/java/org/alfresco/rest/api/search/model/SearchQuery.java b/source/java/org/alfresco/rest/api/search/model/SearchQuery.java index cd42b9c999..6245147d84 100644 --- a/source/java/org/alfresco/rest/api/search/model/SearchQuery.java +++ b/source/java/org/alfresco/rest/api/search/model/SearchQuery.java @@ -62,7 +62,7 @@ public class SearchQuery private final List pivots; private final List stats; private final List ranges; - private final String timezone; + private final Localization localization; public static final SearchQuery EMPTY = new SearchQuery(null, null, null, null, null, null, null,null, null, null, null,null, null, null, null, @@ -88,7 +88,7 @@ public class SearchQuery @JsonProperty("pivots") List pivots, @JsonProperty("stats") List stats, @JsonProperty("ranges") List ranges, - @JsonProperty("timezone") String timezone) + @JsonProperty("localization") Localization localization) { this.query = query; this.includeRequest = includeRequest==null?false:includeRequest; @@ -109,7 +109,7 @@ public class SearchQuery this.pivots = pivots; this.stats = stats; this.ranges = ranges; - this.timezone = timezone; + this.localization = localization; } public Query getQuery() @@ -206,8 +206,9 @@ public class SearchQuery return ranges; } - public String getTimezone() + public Localization getLocalization() { - return timezone; + return localization; } + } diff --git a/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java b/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java index 4ced0f4666..a5b6acfda3 100644 --- a/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java +++ b/source/test-java/org/alfresco/rest/api/search/SearchMapperTests.java @@ -43,6 +43,7 @@ import org.alfresco.rest.api.search.model.FacetFields; import org.alfresco.rest.api.search.model.FacetQuery; import org.alfresco.rest.api.search.model.FilterQuery; import org.alfresco.rest.api.search.model.Limits; +import org.alfresco.rest.api.search.model.Localization; import org.alfresco.rest.api.search.model.Pivot; import org.alfresco.rest.api.search.model.Query; import org.alfresco.rest.api.search.model.Scope; @@ -71,6 +72,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Set; /** @@ -518,49 +520,49 @@ public class SearchMapperTests { SearchParameters searchParameters = new SearchParameters(); //Doesn't error - searchMapper.fromTimezone(searchParameters, null); - searchMapper.fromTimezone(searchParameters, ""); + searchMapper.fromLocalization(searchParameters, null); + searchMapper.fromLocalization(searchParameters, new Localization("", null)); try { - searchMapper.fromTimezone(searchParameters, "nonsense"); + searchMapper.fromLocalization(searchParameters, new Localization("nonsense", null)); + fail(); + } catch (IllegalArgumentException iae) + { + assertTrue(iae.getLocalizedMessage().contains( "Invalid timezone")); + } + + try + { + searchMapper.fromLocalization(searchParameters, new Localization("GMT+25", null)); fail(); } catch (IllegalArgumentException iae) { assertTrue(iae.getLocalizedMessage().contains("Invalid timezone")); } - try - { - searchMapper.fromTimezone(searchParameters, "GMT+25"); - fail(); - } catch (IllegalArgumentException iae) - { - assertTrue(iae.getLocalizedMessage().contains("Invalid timezone")); - } - - searchMapper.fromTimezone(searchParameters, "America/New_York"); + searchMapper.fromLocalization(searchParameters, new Localization("America/New_York", null)); assertEquals("America/New_York", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "America/Denver"); + searchMapper.fromLocalization(searchParameters, new Localization("America/Denver", null)); assertEquals("America/Denver", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "America/Los_Angeles"); + searchMapper.fromLocalization(searchParameters, new Localization("America/Los_Angeles", null)); assertEquals("America/Los_Angeles", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "Europe/Madrid"); + searchMapper.fromLocalization(searchParameters, new Localization("Europe/Madrid", null)); assertEquals("Europe/Madrid", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "GMT+1"); + searchMapper.fromLocalization(searchParameters, new Localization("GMT+1", null)); assertEquals("GMT+01:00", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "GMT+01:00"); + searchMapper.fromLocalization(searchParameters, new Localization("GMT+01:00", null)); assertEquals("GMT+01:00", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "GMT-9"); + searchMapper.fromLocalization(searchParameters, new Localization("GMT-9", null)); assertEquals("GMT-09:00", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "GMT+08:00"); + searchMapper.fromLocalization(searchParameters, new Localization("GMT+08:00", null)); assertEquals("GMT+08:00", searchParameters.getTimezone()); - searchMapper.fromTimezone(searchParameters, "GMT-12:00"); + searchMapper.fromLocalization(searchParameters, new Localization("GMT-12:00", null)); assertEquals("GMT-12:00", searchParameters.getTimezone()); try { - searchMapper.fromTimezone(searchParameters, "UTC+5"); + searchMapper.fromLocalization(searchParameters, new Localization("UTC+5", null)); fail(); } catch (IllegalArgumentException iae) @@ -570,7 +572,7 @@ public class SearchMapperTests try { - searchMapper.fromTimezone(searchParameters, "UTC+06:00"); + searchMapper.fromLocalization(searchParameters, new Localization("UTC+06:00", null)); fail(); } catch (IllegalArgumentException iae) @@ -579,6 +581,61 @@ public class SearchMapperTests } } + @Test + public void fromLocales() throws Exception + { + SearchParameters searchParameters = new SearchParameters(); + //Doesn't error + searchMapper.fromLocalization(searchParameters, null); + searchMapper.fromLocalization(searchParameters, new Localization(null, null)); + List testLocales = new ArrayList<>(); + testLocales.add(null); + try + { + searchMapper.fromLocalization(searchParameters, new Localization(null, testLocales)); + fail(); + } + catch (IllegalArgumentException iae) + { + assertTrue(iae.getLocalizedMessage().contains("Invalid locale")); + } + + //Unfortunately this isn't validated, language can be anything. + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("NOTTHIS"))); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("fr"))); + assertEquals(Locale.FRENCH, searchParameters.getLocales().get(0)); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("fr_FR"))); + assertEquals(Locale.FRANCE, searchParameters.getLocales().get(0)); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("fr-FR"))); + assertEquals(Locale.FRANCE, searchParameters.getLocales().get(0)); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("fr-fr"))); + assertEquals(Locale.FRANCE, searchParameters.getSortLocale()); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("fr-ca"))); + assertEquals(Locale.CANADA_FRENCH, searchParameters.getSortLocale()); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("fr_ca"))); + assertEquals(Locale.CANADA_FRENCH, searchParameters.getSortLocale()); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("en-gb"))); + assertEquals(Locale.UK, searchParameters.getSortLocale()); + + searchParameters = new SearchParameters(); + searchMapper.fromLocalization(searchParameters, new Localization(null, Arrays.asList("en-us"))); + assertEquals(Locale.US, searchParameters.getSortLocale()); + } + @Test public void fromFacetFields() throws Exception {