Skip to content

Commit

Permalink
consider Accept-Language if provided; by default this feature is disa…
Browse files Browse the repository at this point in the history
…bled

#428
  • Loading branch information
teosarca committed Jun 1, 2017
1 parent b99acba commit ef14f80
Show file tree
Hide file tree
Showing 8 changed files with 101 additions and 34 deletions.
14 changes: 12 additions & 2 deletions src/main/java/de/metas/ui/web/cache/ETagResponseEntityBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,14 @@

import org.adempiere.util.lang.ExtendedMemorizingSupplier;
import org.springframework.http.CacheControl;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.WebRequest;

import com.google.common.collect.ImmutableMap;

import de.metas.i18n.ADLanguageList;
import de.metas.ui.web.window.datatypes.json.JSONOptions;
import lombok.NonNull;

Expand Down Expand Up @@ -70,14 +72,13 @@ public ETagResponseEntityBuilder<T, R> includeLanguageInETag()
includeLanguageInETag(true);
return this;
}

private ETagResponseEntityBuilder<T, R> includeLanguageInETag(final boolean includeLanguageInETag)
{
this.includeLanguageInETag = includeLanguageInETag;
return this;
}


public <R2> ETagResponseEntityBuilder<T, R2> map(@NonNull final Function<R, R2> resultMapper)
{
final Supplier<R> result = this.result;
Expand Down Expand Up @@ -137,10 +138,19 @@ public <JSONType> ResponseEntity<JSONType> toJson(final BiFunction<R, JSONOption

private final ResponseEntity.BodyBuilder newResponse(final HttpStatus status, final String etag)
{

ResponseEntity.BodyBuilder response = ResponseEntity.status(status)
.eTag(etag)
.cacheControl(CacheControl.maxAge(cacheMaxAgeSec, TimeUnit.SECONDS));

final String adLanguage = getJSONOptions().getAD_Language();
if (adLanguage != null && !adLanguage.isEmpty())
{
final String contentLanguage = ADLanguageList.toHttpLanguageTag(adLanguage);
response.header(HttpHeaders.CONTENT_LANGUAGE, contentLanguage);
response.header(HttpHeaders.VARY, HttpHeaders.ACCEPT_LANGUAGE); // advice browser to include ACCEPT_LANGUAGE in their caching key
}

return response;
}
}
9 changes: 9 additions & 0 deletions src/main/java/de/metas/ui/web/debug/DebugRestController.java
Original file line number Diff line number Diff line change
Expand Up @@ -371,5 +371,14 @@ public Map<String, Object> setHttpCacheMaxAge(@RequestParam("value") @ApiParam("
userSession.setHttpCacheMaxAge(httpCacheMaxAge);
return ImmutableMap.of("value", httpCacheMaxAge, "valueOld", httpCacheMaxAgeOld);
}

@GetMapping("http.use.AcceptLanguage")
public Map<String, Object> setUseHttpAcceptLanguage(@RequestParam("value") @ApiParam("Cache-control's max age in seconds") boolean useHttpAcceptLanguage)
{
final boolean useHttpAcceptLanguageOld = userSession.isUseHttpAcceptLanguage();
userSession.setUseHttpAcceptLanguage(useHttpAcceptLanguage);
return ImmutableMap.of("value", useHttpAcceptLanguage, "valueOld", useHttpAcceptLanguageOld);
}


}
13 changes: 2 additions & 11 deletions src/main/java/de/metas/ui/web/process/ProcessRestController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;

import javax.annotation.Nullable;

import org.compiere.util.Util;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
Expand Down Expand Up @@ -109,13 +107,7 @@ public ProcessRestController(final ApplicationContext context)

private JSONOptions newJSONOptions()
{
final String adLanguage = null; // N/A => use session language
return newJSONOptions(adLanguage);
}

private JSONOptions newJSONOptions(@Nullable final String adLanguage)
{
return JSONOptions.builder(userSession).setAD_LanguageIfNotEmpty(adLanguage).build();
return JSONOptions.builder(userSession).build();
}

public Stream<WebuiRelatedProcessDescriptor> streamDocumentRelatedProcesses(final IProcessPreconditionsContext preconditionsContext)
Expand Down Expand Up @@ -144,7 +136,6 @@ private Collection<IProcessInstancesRepository> getAllRepositories()
@RequestMapping(value = "/{processId}/layout", method = RequestMethod.GET)
public ResponseEntity<JSONProcessLayout> getLayout(
@PathVariable("processId") final String adProcessIdStr,
@RequestParam(name = "lang", required = false, defaultValue = "") final String adLanguage,
WebRequest request)
{
userSession.assertLoggedIn();
Expand All @@ -157,7 +148,7 @@ public ResponseEntity<JSONProcessLayout> getLayout(
.includeLanguageInETag()
.cacheMaxAge(userSession.getHttpCacheMaxAge())
.map(ProcessDescriptor::getLayout)
.jsonOptions(() -> newJSONOptions(adLanguage))
.jsonOptions(() -> newJSONOptions())
.toJson(JSONProcessLayout::of);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@
@Value("${metasfresh.webui.http.cache.maxAge:60}")
private int defaultHttpCacheMaxAge;
private int httpCacheMaxAge;

// TODO: set default to "true" after https://github.com/metasfresh/metasfresh-webui-frontend/issues/819
@Value("${metasfresh.webui.http.use.AcceptLanguage:false}")
private boolean defaultUseHttpAcceptLanguage;
private boolean useHttpAcceptLanguage;


//
public InternalUserSessionData()
Expand Down Expand Up @@ -117,6 +123,7 @@ public void afterPropertiesSet() throws Exception
setShowColumnNamesForCaption(defaultShowColumnNamesForCaption);
setAllowDeprecatedRestAPI(defaultAllowDeprecatedRestAPI);
setHttpCacheMaxAge(defaultHttpCacheMaxAge);
setUseHttpAcceptLanguage(defaultUseHttpAcceptLanguage);
}

@Override
Expand All @@ -128,6 +135,7 @@ public String toString()
.add("loggedIn", loggedIn)
.add("locale", locale)
.add("userPreferences", userPreference)
.add("defaultUseHttpAcceptLanguage", defaultUseHttpAcceptLanguage)
.toString();
}

Expand Down
12 changes: 12 additions & 0 deletions src/main/java/de/metas/ui/web/session/UserSession.java
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,18 @@ public Locale getLocale()
return data.getLocale();
}

public boolean isUseHttpAcceptLanguage()
{
return data.isUseHttpAcceptLanguage();
}

public void setUseHttpAcceptLanguage(final boolean useHttpAcceptLanguage)
{
final boolean useHttpAcceptLanguageOld = data.isUseHttpAcceptLanguage();
data.setUseHttpAcceptLanguage(useHttpAcceptLanguage);
logSettingChanged("UseHttpAcceptLanguage", useHttpAcceptLanguage, useHttpAcceptLanguageOld);
}

public int getAD_User_ID()
{
return data.getAD_User_ID();
Expand Down
13 changes: 2 additions & 11 deletions src/main/java/de/metas/ui/web/view/ViewRestController.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@
import java.util.Objects;
import java.util.stream.Stream;

import javax.annotation.Nullable;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand Down Expand Up @@ -99,13 +97,7 @@ public class ViewRestController

private JSONOptions newJSONOptions()
{
final String adLanguage = null; // N/A => use session language
return newJSONOptions(adLanguage);
}

private JSONOptions newJSONOptions(@Nullable final String adLanguage)
{
return JSONOptions.builder(userSession).setAD_LanguageIfNotEmpty(adLanguage).build();
return JSONOptions.builder(userSession).build();
}

@PostMapping
Expand Down Expand Up @@ -204,7 +196,6 @@ public JSONViewResult getViewData(
public ResponseEntity<JSONViewLayout> getViewLayout(
@PathVariable(PARAM_WindowId) final String windowIdStr,
@RequestParam(name = PARAM_ViewDataType, required = true) final JSONViewDataType viewDataType,
@RequestParam(name = "lang", required = false, defaultValue = "") final String adLanguage,
final WebRequest request)
{
userSession.assertLoggedIn();
Expand All @@ -215,7 +206,7 @@ public ResponseEntity<JSONViewLayout> getViewLayout(
return ETagResponseEntityBuilder.ofETagAware(request, viewLayout)
.includeLanguageInETag()
.cacheMaxAge(userSession.getHttpCacheMaxAge())
.jsonOptions(() -> newJSONOptions(adLanguage))
.jsonOptions(() -> newJSONOptions())
.toJson(JSONViewLayout::of);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ private JSONOptions.Builder newJSONOptions()
public ResponseEntity<JSONDocumentLayout> getLayout(
@PathVariable("windowId") final String windowIdStr,
@RequestParam(name = PARAM_Advanced, required = false, defaultValue = PARAM_Advanced_DefaultValue) final boolean advanced,
@RequestParam(name = "lang", required = false, defaultValue = "") final String adLanguage,
final WebRequest request)
{
userSession.assertLoggedIn();
Expand All @@ -147,7 +146,7 @@ public ResponseEntity<JSONDocumentLayout> getLayout(
.cacheMaxAge(userSession.getHttpCacheMaxAge())
.map(DocumentDescriptor::getLayout)
//
.jsonOptions(() -> newJSONOptions().setShowAdvancedFields(advanced).setAD_LanguageIfNotEmpty(adLanguage).build())
.jsonOptions(() -> newJSONOptions().setShowAdvancedFields(advanced).build())
.toJson(JSONDocumentLayout::ofHeaderLayout);
}

Expand All @@ -156,7 +155,6 @@ public ResponseEntity<JSONDocumentLayout> getLayout(
@PathVariable("windowId") final String windowIdStr,
@PathVariable("tabId") final String tabIdStr,
@RequestParam(name = PARAM_Advanced, required = false, defaultValue = PARAM_Advanced_DefaultValue) final boolean advanced,
@RequestParam(name = "lang", required = false, defaultValue = "") final String adLanguage,
final WebRequest request)
{
userSession.assertLoggedIn();
Expand All @@ -172,7 +170,7 @@ public ResponseEntity<JSONDocumentLayout> getLayout(
.cacheMaxAge(userSession.getHttpCacheMaxAge())
.map(desc -> desc.getLayout().getDetail(detailId))
//
.jsonOptions(() -> newJSONOptions().setShowAdvancedFields(advanced).setAD_LanguageIfNotEmpty(adLanguage).build())
.jsonOptions(() -> newJSONOptions().setShowAdvancedFields(advanced).build())
.toJson(JSONDocumentLayout::ofDetailTab);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,22 @@
import java.util.function.Predicate;
import java.util.function.Supplier;

import javax.servlet.http.HttpServletRequest;

import org.adempiere.ad.security.IUserRolePermissions;
import org.adempiere.util.Services;
import org.adempiere.util.lang.ExtendedMemorizingSupplier;
import org.springframework.http.HttpHeaders;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.common.base.MoreObjects;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;

import de.metas.i18n.ILanguageDAO;
import de.metas.printing.esb.base.util.Check;
import de.metas.ui.web.session.UserSession;
import de.metas.ui.web.window.WindowConstants;
Expand Down Expand Up @@ -351,12 +359,14 @@ public static final class Builder
private boolean showAdvancedFields = false;
private String dataFieldsListStr = null;
private String adLanguage;
private final String sessionADLanguage;
private NewRecordDescriptorsProvider newRecordDescriptorsProvider;

private Builder(final UserSession userSession)
{
super();
this._userSession = userSession;
_userSession = userSession;
sessionADLanguage = userSession != null ? userSession.getAD_Language() : null;
}

public JSONOptions build()
Expand All @@ -366,11 +376,11 @@ public JSONOptions build()

public Builder setAD_LanguageIfNotEmpty(final String adLanguage)
{
if(Check.isEmpty(adLanguage, true))
if (Check.isEmpty(adLanguage, true))
{
return this;
}

this.adLanguage = adLanguage.trim();
return this;
}
Expand All @@ -382,14 +392,52 @@ private String getAD_Language()
return adLanguage;
}

if (_userSession != null)
//
// Try fetching the AD_Language from "Accept-Language" HTTP header
if(_userSession != null && _userSession.isUseHttpAcceptLanguage())
{
return _userSession.getAD_Language();
HttpServletRequest httpServletRequest = getHttpServletRequest();
if (httpServletRequest != null)
{
final String httpAcceptLanguage = httpServletRequest.getHeader(HttpHeaders.ACCEPT_LANGUAGE);
if (!Check.isEmpty(httpAcceptLanguage, true))
{
final String requestLanguage = Services.get(ILanguageDAO.class).retrieveAvailableLanguages()
.getAD_LanguageFromHttpAcceptLanguage(httpAcceptLanguage, sessionADLanguage);
if (requestLanguage != null)
{
return requestLanguage;
}
}
}
}

//
// Use session language
if (sessionADLanguage != null)
{
return sessionADLanguage;
}

throw new IllegalStateException("Cannot detect the AD_Language");
}

private static final HttpServletRequest getHttpServletRequest()
{
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes == null)
{
return null;
}
if (!(requestAttributes instanceof ServletRequestAttributes))
{
return null;
}

final HttpServletRequest servletRequest = ((ServletRequestAttributes)requestAttributes).getRequest();
return servletRequest;
}

private Supplier<JSONDocumentPermissions> getPermissionsSupplier()
{
return createPermissionsSupplier(_userSession);
Expand Down Expand Up @@ -440,7 +488,7 @@ private NewRecordDescriptorsProvider getNewRecordDescriptorsProvider()
return newRecordDescriptorsProvider;
}

public Builder setNewRecordDescriptorsProvider(NewRecordDescriptorsProvider newRecordDescriptorsProvider)
public Builder setNewRecordDescriptorsProvider(final NewRecordDescriptorsProvider newRecordDescriptorsProvider)
{
this.newRecordDescriptorsProvider = newRecordDescriptorsProvider;
return this;
Expand Down

0 comments on commit ef14f80

Please sign in to comment.