mirror of
https://github.com/eclipse-sailing-analytics/sailing-analytics.git
synced 2026-11-04 18:20:14 +00:00
bug6060: handle BrandingConfiguration service appearance/disappearance dynamically
This commit is contained in:
1 parent
9a5a4e091c
commit
4964ec9410
5 files changed
+127
-49
No files matched your search
+7
-10
@@ -3,8 +3,6 @@ package com.sap.sse.branding;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
|
||||
import com.sap.sse.branding.shared.BrandingConfiguration;
|
||||
|
||||
/**
|
||||
@@ -49,13 +47,6 @@ public interface BrandingConfigurationService {
|
||||
*/
|
||||
String JSP_PROPERTY_NAME_PREFIX = "clientConfigurationContext";
|
||||
|
||||
/**
|
||||
* Attribute name used in the {@link ServletContext}, value being a map from a pair of locale (e.g. "en") and
|
||||
* branding ID (see {@link BrandingConfiguration#getId()}) to a map of JSP properties that can be used to set it
|
||||
* to the {@link #JSP_PROPERTY_NAME_PREFIX} attribute in the {@link HttpServletRequest} scope.
|
||||
*/
|
||||
String JSP_PROPERTIES_BY_LOCALE_AND_BRANDING_ID = "clientConfigurationContextsByLocaleAndBrandingId";
|
||||
|
||||
public static enum BrandingConfigurationProperty {
|
||||
/**
|
||||
* The name of the JSP property, appended to the value of {@link #JSP_PROPERTY_NAME_PREFIX}, that contains the brand title
|
||||
@@ -134,5 +125,11 @@ public interface BrandingConfigurationService {
|
||||
* <p>
|
||||
* @param locale if present, the locale to use for the branding configuration properties, otherwise the default locale
|
||||
*/
|
||||
Map<BrandingConfigurationProperty, Object> getBrandingConfigurationPropertiesForJspContext(Optional<String> locale);
|
||||
Map<BrandingConfigurationProperty, Object> getBrandingConfigurationProperties(Optional<String> locale);
|
||||
|
||||
/**
|
||||
* Same as {@link #getBrandingConfigurationProperties(Optional)} but returns a map where the keys are
|
||||
* the property names as defined in {@link BrandingConfigurationProperty#getPropertyName()}.
|
||||
*/
|
||||
Map<String, Object> getBrandingConfigurationPropertiesForJspContext(Optional<String> locale);
|
||||
}
|
||||
+2
-30
@@ -1,10 +1,7 @@
|
||||
package com.sap.sse.branding;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.ServletRequestEvent;
|
||||
@@ -12,7 +9,6 @@ import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import com.sap.sse.branding.BrandingConfigurationService.BrandingConfigurationProperty;
|
||||
import com.sap.sse.branding.impl.Activator;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.rest.GwtLocaleFromHttpRequestUtil;
|
||||
|
||||
/**
|
||||
@@ -71,7 +67,7 @@ public class ClientConfigurationListener implements javax.servlet.ServletRequest
|
||||
* <p>
|
||||
*
|
||||
* The properties are constructed using
|
||||
* {@link BrandingConfigurationService#getBrandingConfigurationPropertiesForJspContext(Optional)} with the locale as
|
||||
* {@link BrandingConfigurationService#getBrandingConfigurationProperties(Optional)} with the locale as
|
||||
* argument, where the property names are derived from the {@link BrandingConfigurationProperty#getPropertyName()}
|
||||
* method which get appended to the {@link BrandingConfigurationService#JSP_PROPERTY_NAME_PREFIX} prefix.
|
||||
* <p>
|
||||
@@ -86,37 +82,13 @@ public class ClientConfigurationListener implements javax.servlet.ServletRequest
|
||||
final String path = httpServletRequest.getServletPath();
|
||||
// populate JSP scopes (applicationScope and requestScope) only for HTML pages or "/" requests
|
||||
if (path != null && (path.endsWith("/") || path.endsWith(".html"))) {
|
||||
final ServletContext servletContext = httpServletRequest.getServletContext();
|
||||
Optional<String> requestLocale = GwtLocaleFromHttpRequestUtil.getLocaleFromHttpRequest(httpServletRequest);
|
||||
final Map<String, Object> brandingProperties = getAndCacheBrandingConfigurationPropertiesFromServletContext(
|
||||
servletContext, requestLocale, Activator.getDefaultBrandingConfigurationService());
|
||||
final Map<String, Object> brandingProperties = Activator.getDefaultBrandingConfigurationService().getBrandingConfigurationPropertiesForJspContext(requestLocale);
|
||||
httpServletRequest.setAttribute(BrandingConfigurationService.JSP_PROPERTY_NAME_PREFIX, brandingProperties);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> getAndCacheBrandingConfigurationPropertiesFromServletContext(
|
||||
ServletContext servletContext, Optional<String> locale, BrandingConfigurationService brandingConfigurationService) {
|
||||
@SuppressWarnings("unchecked")
|
||||
ConcurrentMap<Pair<String, String>, Map<String, Object>> brandingProperties =
|
||||
(ConcurrentMap<Pair<String, String>, Map<String, Object>>) servletContext.getAttribute(BrandingConfigurationService.JSP_PROPERTIES_BY_LOCALE_AND_BRANDING_ID);
|
||||
if (brandingProperties == null) {
|
||||
brandingProperties = new ConcurrentHashMap<>();
|
||||
servletContext.setAttribute(BrandingConfigurationService.JSP_PROPERTIES_BY_LOCALE_AND_BRANDING_ID, brandingProperties);
|
||||
}
|
||||
final Pair<String, String> key = new Pair<>(locale.orElse(null),
|
||||
brandingConfigurationService.isBrandingActive() ? brandingConfigurationService.getActiveBrandingConfiguration().getId() : null);
|
||||
return brandingProperties.computeIfAbsent(key, k->computeBrandingConfigurationProperties(brandingConfigurationService, locale));
|
||||
}
|
||||
|
||||
private Map<String, Object> computeBrandingConfigurationProperties(BrandingConfigurationService brandingConfigurationService, Optional<String> requestLocale) {
|
||||
final Map<String, Object> brandingProperties = new HashMap<>(); // no concurrency control needed within single request
|
||||
brandingConfigurationService.getBrandingConfigurationPropertiesForJspContext(requestLocale).forEach((k, v) -> {
|
||||
brandingProperties.put(k.getPropertyName(), v);
|
||||
});
|
||||
return brandingProperties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDestroyed(ServletRequestEvent sre) {
|
||||
// intentionally left blank
|
||||
|
||||
+116
-8
@@ -1,29 +1,54 @@
|
||||
package com.sap.sse.branding.impl;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import org.json.simple.JSONObject;
|
||||
import org.osgi.framework.BundleContext;
|
||||
import org.osgi.framework.Constants;
|
||||
import org.osgi.framework.Filter;
|
||||
import org.osgi.framework.InvalidSyntaxException;
|
||||
import org.osgi.framework.ServiceReference;
|
||||
import org.osgi.util.tracker.ServiceTracker;
|
||||
import org.osgi.util.tracker.ServiceTrackerCustomizer;
|
||||
|
||||
import com.sap.sse.branding.BrandingConfigurationService;
|
||||
import com.sap.sse.branding.shared.BrandingConfiguration;
|
||||
import com.sap.sse.common.Util;
|
||||
import com.sap.sse.common.Util.Pair;
|
||||
import com.sap.sse.util.ServiceTrackerFactory;
|
||||
|
||||
public class BrandingConfigurationServiceImpl implements BrandingConfigurationService {
|
||||
private ServiceTracker<BrandingConfiguration, BrandingConfiguration> brandingConfigurationTracker;
|
||||
public class BrandingConfigurationServiceImpl implements BrandingConfigurationService, ServiceTrackerCustomizer<BrandingConfiguration, BrandingConfiguration> {
|
||||
private static final Logger logger = Logger.getLogger(BrandingConfigurationServiceImpl.class.getName());
|
||||
|
||||
private final ServiceTracker<BrandingConfiguration, BrandingConfiguration> brandingConfigurationTracker;
|
||||
|
||||
private final BundleContext bundleContext;
|
||||
|
||||
private final ConcurrentMap<Pair<String, String>, Map<String, Object>> brandingConfigurationsByIdAndLocale;
|
||||
|
||||
/**
|
||||
* Starts out as {@code null}. Will be set by {@link #setActiveBrandingConfigurationById(String)} if the
|
||||
* configuration by that ID is found through the {@link #brandingConfigurationTracker}. Furthermore,
|
||||
* a {@link ServiceTrackerCustomizer} is used to update this field whenever the service currently in
|
||||
* use is removed or modified, or a new service matching the ID is added.
|
||||
*/
|
||||
private BrandingConfiguration activeBrandingConfiguration;
|
||||
|
||||
private Filter filterForActiveBrandingConfigurationId;
|
||||
|
||||
public BrandingConfigurationServiceImpl(BundleContext bundleContext) {
|
||||
super();
|
||||
this.bundleContext = bundleContext;
|
||||
brandingConfigurationTracker = ServiceTrackerFactory.createAndOpen(bundleContext, BrandingConfiguration.class, this);
|
||||
brandingConfigurationsByIdAndLocale = new ConcurrentHashMap<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -33,18 +58,35 @@ public class BrandingConfigurationServiceImpl implements BrandingConfigurationSe
|
||||
|
||||
@Override
|
||||
public BrandingConfiguration setActiveBrandingConfigurationById(String brandingConfigurationId) {
|
||||
filterForActiveBrandingConfigurationId = createFilterForBrandingConfigurationId(brandingConfigurationId);
|
||||
activeBrandingConfiguration = brandingConfigurationTracker.getServiceReferences() == null ? null :
|
||||
Arrays.asList(brandingConfigurationTracker.getServiceReferences())
|
||||
.stream()
|
||||
.filter(ref -> filterForActiveBrandingConfigurationId.match(ref.getProperties()))
|
||||
.findFirst()
|
||||
.map(ref -> brandingConfigurationTracker.getService(ref))
|
||||
.orElse(null);
|
||||
if (activeBrandingConfiguration == null) {
|
||||
logger.warning("Couldn't find a branding configuration with ID " + brandingConfigurationId +
|
||||
" in the OSGi service registry. Branding is effectively deactivated.");
|
||||
} else {
|
||||
logger.info("Found active branding configuration: " + activeBrandingConfiguration.getId()+
|
||||
" with object ID "+System.identityHashCode(activeBrandingConfiguration));
|
||||
}
|
||||
return activeBrandingConfiguration;
|
||||
}
|
||||
|
||||
private Filter createFilterForBrandingConfigurationId(String brandingConfigurationId) {
|
||||
try {
|
||||
Filter filter = bundleContext.createFilter(
|
||||
return bundleContext.createFilter(
|
||||
String.format("(&(%s=%s)(%s=%s))",
|
||||
BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME, ""+brandingConfigurationId,
|
||||
Constants.OBJECTCLASS, BrandingConfiguration.class.getName()));
|
||||
brandingConfigurationTracker = ServiceTrackerFactory.createAndOpen(bundleContext, filter);
|
||||
return brandingConfigurationTracker.getService();
|
||||
} catch (InvalidSyntaxException e) {
|
||||
throw new RuntimeException("Internal error: Invalid filter syntax for BrandingConfigurationService", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BrandingConfiguration getActiveBrandingConfiguration() {
|
||||
return brandingConfigurationTracker == null ? null : brandingConfigurationTracker.getService();
|
||||
@@ -52,7 +94,7 @@ public class BrandingConfigurationServiceImpl implements BrandingConfigurationSe
|
||||
|
||||
|
||||
@Override
|
||||
public Map<BrandingConfigurationProperty, Object> getBrandingConfigurationPropertiesForJspContext(Optional<String> locale) {
|
||||
public Map<BrandingConfigurationProperty, Object> getBrandingConfigurationProperties(Optional<String> locale) {
|
||||
final BrandingConfiguration brandingConfiguration = getActiveBrandingConfiguration();
|
||||
final Map<BrandingConfigurationProperty, Object> map = new HashMap<>();
|
||||
final String title;
|
||||
@@ -64,7 +106,6 @@ public class BrandingConfigurationServiceImpl implements BrandingConfigurationSe
|
||||
title = "";
|
||||
whitelabeled = "-whitelabeled";
|
||||
}
|
||||
// TODO bug6060: figure out how to deal with i18n and the locale parameter
|
||||
map.put(BrandingConfigurationProperty.BRAND_TITLE_WITH_TRAILING_SPACE_JSP_PROPERTY_NAME, title);
|
||||
map.put(BrandingConfigurationProperty.DEBRANDING_ACTIVE_JSP_PROPERTY_NAME, !isBrandingActive());
|
||||
map.put(BrandingConfigurationProperty.BRANDING_ACTIVE_JSP_PROPERTY_NAME, isBrandingActive());
|
||||
@@ -73,6 +114,21 @@ public class BrandingConfigurationServiceImpl implements BrandingConfigurationSe
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getBrandingConfigurationPropertiesForJspContext(Optional<String> locale) {
|
||||
return brandingConfigurationsByIdAndLocale.computeIfAbsent(
|
||||
new Pair<>(locale.orElse(null), isBrandingActive() ? getActiveBrandingConfiguration().getId() : null),
|
||||
key -> computeBrandingConfigurationProperties(locale));
|
||||
}
|
||||
|
||||
private Map<String, Object> computeBrandingConfigurationProperties(Optional<String> requestLocale) {
|
||||
final Map<String, Object> brandingProperties = new HashMap<>(); // no concurrency control needed within single request
|
||||
getBrandingConfigurationProperties(requestLocale).forEach((k, v) -> {
|
||||
brandingProperties.put(k.getPropertyName(), v);
|
||||
});
|
||||
return brandingProperties;
|
||||
}
|
||||
|
||||
private Object generateScriptForClientConfigurationContext(Map<BrandingConfigurationProperty, Object> map) {
|
||||
final StringBuilder scriptBuilder = new StringBuilder();
|
||||
scriptBuilder.append("document.clientConfigurationContext=");
|
||||
@@ -84,4 +140,56 @@ public class BrandingConfigurationServiceImpl implements BrandingConfigurationSe
|
||||
scriptBuilder.append(";");
|
||||
return scriptBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public BrandingConfiguration addingService(ServiceReference<BrandingConfiguration> reference) {
|
||||
final BrandingConfiguration service = evictCachedPropertiesForBrandingServiceReference(reference);
|
||||
logger.info("Adding branding configuration service with ID: " + reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME) +
|
||||
" and object ID " + System.identityHashCode(service));
|
||||
if (service != null && filterForActiveBrandingConfigurationId.match(reference)) {
|
||||
logger.info("Added branding configuration service with ID " + reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME) +
|
||||
" is selected as the active one.");
|
||||
activeBrandingConfiguration = service;
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
private BrandingConfiguration evictCachedPropertiesForBrandingServiceReference(
|
||||
ServiceReference<BrandingConfiguration> reference) {
|
||||
final String brandingId = (String) reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME);
|
||||
final BrandingConfiguration service = bundleContext.getService(reference);
|
||||
for (final Iterator<Pair<String, String>> i=brandingConfigurationsByIdAndLocale.keySet().iterator(); i.hasNext(); ) {
|
||||
final Pair<String, String> cachedProperties = i.next();
|
||||
if (Util.equalsWithNull(cachedProperties.getB(), brandingId)) {
|
||||
logger.info("Removing cached branding properties from service with ID: " + brandingId + " and object ID " + System.identityHashCode(service));
|
||||
// remove the cached properties for this ID, so that they will be recomputed
|
||||
i.remove();
|
||||
}
|
||||
}
|
||||
return service;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void modifiedService(ServiceReference<BrandingConfiguration> reference, BrandingConfiguration service) {
|
||||
evictCachedPropertiesForBrandingServiceReference(reference);
|
||||
logger.info("Modified branding configuration service with ID: " + reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME) +
|
||||
" and object ID " + System.identityHashCode(service));
|
||||
if (service != null && filterForActiveBrandingConfigurationId.match(reference)) {
|
||||
logger.info("Modified branding configuration service with ID " + reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME) +
|
||||
", updating active branding configuration.");
|
||||
activeBrandingConfiguration = service;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removedService(ServiceReference<BrandingConfiguration> reference, BrandingConfiguration service) {
|
||||
evictCachedPropertiesForBrandingServiceReference(reference);
|
||||
logger.info("Removed branding configuration service with ID: " + reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME) +
|
||||
" and object ID " + System.identityHashCode(service));
|
||||
if (service == activeBrandingConfiguration) {
|
||||
logger.info("The active branding configuration service with ID " + reference.getProperty(BrandingConfigurationService.BRANDING_ID_PROPERTY_NAME) +
|
||||
" was removed, setting active branding configuration to null.");
|
||||
activeBrandingConfiguration = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ Require-Bundle: com.google.gwt.user;bundle-version="2.10.0";resolution:=optional
|
||||
Bundle-ActivationPolicy: lazy
|
||||
Web-ContextPath: /gwt-base
|
||||
Import-Package: com.sap.sse.branding.shared,
|
||||
com.sap.sse.security,
|
||||
com.sun.jersey.spi.container.servlet;version="[1.17.0,2.0.0)",
|
||||
javax.servlet;version="3.1.0",
|
||||
javax.servlet.descriptor;version="3.1.0",
|
||||
|
||||
@@ -20,7 +20,7 @@ import com.sap.sse.gwt.client.context.impl.ClientConfigurationContextDataFactory
|
||||
* document.clientConfigurationContext={"brandingActive":true,"brandTitle":"SAP ","debrandingActive":false,"whitelabeled":""};
|
||||
* </pre>
|
||||
* That can be accessed from here using the {@link ClientConfigurationContextDataJSO}. Responsible for the properties listed in the
|
||||
* object is {@link BrandingConfigurationService#getBrandingConfigurationPropertiesForJspContext(Optional)} and its
|
||||
* object is {@link BrandingConfigurationService#getBrandingConfigurationProperties(Optional)} and its
|
||||
* {@link BrandingConfigurationService#getActiveBrandingConfiguration() active branding configuration}, or none if the solution
|
||||
* is running without any branding.<p>
|
||||
*
|
||||
|
||||
Reference in new issue
Block a user