Author: mthl
Date: Tue Feb 26 22:47:58 2019 New Revision: 1854429 URL: http://svn.apache.org/viewvc?rev=1854429&view=rev Log: Improved: Add ‘WebAppCache’ (OFBIZ-10606) This improves the cohesion of the ‘ComponentConfig’ class by extracting the webapps cache related methods into a separate ‘WebAppCache’ class. Added: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java (with props) Modified: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/HomeMenu.ftl ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/TopAppBar.ftl Modified: ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java?rev=1854429&r1=1854428&r2=1854429&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java (original) +++ ofbiz/ofbiz-framework/trunk/framework/base/src/main/java/org/apache/ofbiz/base/component/ComponentConfig.java Tue Feb 26 22:47:58 2019 @@ -25,12 +25,10 @@ import java.security.KeyStore; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.TreeMap; import org.apache.ofbiz.base.container.ContainerConfig; import org.apache.ofbiz.base.container.ContainerConfig.Configuration; @@ -55,12 +53,8 @@ public final class ComponentConfig { public static final String module = ComponentConfig.class.getName(); public static final String OFBIZ_COMPONENT_XML_FILENAME = "ofbiz-component.xml"; - /* Note: These Maps are not UtilCache instances because there is no strategy or implementation for reloading components. - * Also, we are using LinkedHashMap to maintain insertion order - which client code depends on. This means - * we will need to use synchronization code because there is no concurrent implementation of LinkedHashMap. - */ + // This map is not a UtilCache instance because there is no strategy or implementation for reloading components. private static final ComponentConfigCache componentConfigCache = new ComponentConfigCache(); - private static final Map<String, List<WebappInfo>> serverWebApps = new LinkedHashMap<>(); public static Boolean componentExists(String componentName) { Assert.notEmpty("componentName", componentName); @@ -187,55 +181,6 @@ public final class ComponentConfig { return webappInfos; } - public static List<WebappInfo> getAppBarWebInfos(String serverName) { - return ComponentConfig.getAppBarWebInfos(serverName, null, null); - } - - public static List<WebappInfo> getAppBarWebInfos(String serverName, Comparator<? super String> comp, String menuName) { - String serverWebAppsKey = serverName + menuName; - List<WebappInfo> webInfos = null; - synchronized (serverWebApps) { - webInfos = serverWebApps.get(serverWebAppsKey); - } - if (webInfos == null) { - Map<String, WebappInfo> tm = null; - // use a TreeMap to sort the components alpha by title - if (comp != null) { - tm = new TreeMap<>(comp); - } else { - tm = new TreeMap<>(); - } - for (ComponentConfig cc : getAllComponents()) { - for (WebappInfo wInfo : cc.getWebappInfos()) { - String key = UtilValidate.isNotEmpty(wInfo.position) ? wInfo.position : wInfo.title; - if (serverName.equals(wInfo.server) && wInfo.getAppBarDisplay()) { - if (UtilValidate.isNotEmpty(menuName)) { - if (menuName.equals(wInfo.menuName)) { - tm.put(key, wInfo); - } - } else { - tm.put(key, wInfo); - } - } if (!wInfo.getAppBarDisplay() && UtilValidate.isEmpty(menuName)) { - tm.put(key, wInfo); - } - } - } - webInfos = new ArrayList<>(tm.size()); - webInfos.addAll(tm.values()); - webInfos = Collections.unmodifiableList(webInfos); - synchronized (serverWebApps) { - // We are only preventing concurrent modification, we are not guaranteeing a singleton. - serverWebApps.put(serverWebAppsKey, webInfos); - } - } - return webInfos; - } - - public static List<WebappInfo> getAppBarWebInfos(String serverName, String menuName) { - return getAppBarWebInfos(serverName, null, menuName); - } - public static ComponentConfig getComponentConfig(String globalName) throws ComponentException { // TODO: we need to look up the rootLocation from the container config, or this will blow up return getComponentConfig(globalName, null); @@ -314,21 +259,6 @@ public final class ComponentConfig { return info; } - public static WebappInfo getWebappInfo(String serverName, String webAppName) { - WebappInfo webappInfo = null; - List<WebappInfo> webappsInfo = getAppBarWebInfos(serverName); - for(WebappInfo currApp : webappsInfo) { - String currWebAppName = currApp.getMountPoint().replace("/", "").replace("*", ""); - if (webAppName.equals(currWebAppName)) { - webappInfo = currApp; - break; - } - } - return webappInfo; - } - - - public static boolean isFileResourceLoader(String componentName, String resourceLoaderName) throws ComponentException { ComponentConfig cc = getComponentConfig(componentName); return cc.isFileResourceLoader(resourceLoaderName); Added: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java?rev=1854429&view=auto ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java (added) +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java Tue Feb 26 22:47:58 2019 @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.ofbiz.webapp; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import java.util.function.Supplier; + +import org.apache.ofbiz.base.component.ComponentConfig; +import org.apache.ofbiz.base.component.ComponentConfig.WebappInfo; +import org.apache.ofbiz.base.util.UtilValidate; + +/** + * Cache for web applications information retrieved from + * {@linkplain ComponentConfig component configurations}. + * <p> + * This improves performance by avoiding to retrieve web applications from + * component configurations each time. + * <p> + * This is a cache which doesn't implement any invalidation mechanism. Once a + * web applications is defined, it is <b>memoized</b> because it is not meant + * to change while OFBiz is running. + * + * @see <a href="https://en.wikipedia.org/wiki/Memoization">Memoization</a> + */ +public class WebAppCache { + // Synchronized map storing web applications. + // The LinkedHashMap is used to maintain insertion order (which client code depends on). + // There is no concurrent implementation of LinkedHashMap, so we are using manual synchronization instead. + private final LinkedHashMap<String, List<WebappInfo>> serverWebApps; + // Source for retrieving components configurations. + private final Supplier<Collection<ComponentConfig>> ccs; + + /** + * Constructs an empty web application cache. + * + * @param supplier the source from which components configurations + * are retrieved + */ + public WebAppCache(Supplier<Collection<ComponentConfig>>supplier) { + ccs = supplier; + serverWebApps = new LinkedHashMap<>(); + } + + /** + * Retrieves the web applications information that must be visible + * in the context of the server {@code serverName}. + * + * @param serverName the name of the server to match + * @return the corresponding web applications information + */ + public List<WebappInfo> getAppBarWebInfos(String serverName) { + return getAppBarWebInfos(serverName, null, null); + } + + /** + * Retrieves the web applications information that must be visible inside + * the menu {@code menuName} in the context of the server {@code serverName}. + * <p> + * When an empty string or {@code null} is used for {@code menuName}, + * all the web application information corresponding to {@code serverName} are matched. + * + * @param serverName the name of server to match + * @param menuName the name of the menu to match + * @return the corresponding web applications information + * @throws NullPointerException when {@code serverName} is {@code null} + */ + public List<WebappInfo> getAppBarWebInfos(String serverName, String menuName) { + return getAppBarWebInfos(serverName, null, menuName); + } + + /** + * Retrieves the web applications information that must be visible inside + * the menu {@code menuName} in the context of the server {@code serverName}. + * <p> + * When an empty string or {@code null} is used for {@code menuName}, + * all the web application information corresponding to {@code serverName} are matched. + * + * @param serverName the name of server to match + * @param comp the comparator used for ordering the results + * @param menuName the name of the menu to match + * @return the corresponding web applications information + * @throws NullPointerException when {@code serverName} is {@code null} + */ + private List<WebappInfo> getAppBarWebInfos(String serverName, Comparator<? super String> comp, String menuName) { + String serverWebAppsKey = serverName + menuName; + List<WebappInfo> webInfos = null; + synchronized (serverWebApps) { + webInfos = serverWebApps.get(serverWebAppsKey); + } + if (webInfos == null) { + Map<String, WebappInfo> tm = null; + // use a TreeMap to sort the components alpha by title + if (comp != null) { + tm = new TreeMap<>(comp); + } else { + tm = new TreeMap<>(); + } + for (ComponentConfig cc : ccs.get()) { + for (WebappInfo wInfo : cc.getWebappInfos()) { + String key = UtilValidate.isNotEmpty(wInfo.position) ? wInfo.position : wInfo.title; + if (serverName.equals(wInfo.server) && wInfo.getAppBarDisplay()) { + if (UtilValidate.isNotEmpty(menuName)) { + if (menuName.equals(wInfo.menuName)) { + tm.put(key, wInfo); + } + } else { + tm.put(key, wInfo); + } + } if (!wInfo.getAppBarDisplay() && UtilValidate.isEmpty(menuName)) { + tm.put(key, wInfo); + } + } + } + webInfos = new ArrayList<>(tm.size()); + webInfos.addAll(tm.values()); + webInfos = Collections.unmodifiableList(webInfos); + synchronized (serverWebApps) { + // We are only preventing concurrent modification, we are not guaranteeing a singleton. + serverWebApps.put(serverWebAppsKey, webInfos); + } + } + return webInfos; + } + + /** + * Retrieves the first web application information which mount point correspond to + * {@code webAppName} in the context of the server {@code serverName}. + * + * @param serverName the name of the server to match + * @param webAppName the name of the web application to match + * @return the corresponding web application information + * @throws NullPointerException when {@code serverName} or {@doc webAppName} are {@code null} + */ + public WebappInfo getWebappInfo(String serverName, String webAppName) { + WebappInfo webappInfo = null; + List<WebappInfo> webappsInfo = getAppBarWebInfos(serverName); + for(WebappInfo currApp : webappsInfo) { + String currWebAppName = currApp.getMountPoint().replace("/", "").replace("*", ""); + if (webAppName.equals(currWebAppName)) { + webappInfo = currApp; + break; + } + } + return webappInfo; + } + + // Instance of the cache shared by the loginWorker and Freemarker appbar rendering. + // TODO: Find a way to share this cache without relying on a global variable. + private static WebAppCache sharedCache = new WebAppCache(ComponentConfig::getAllComponents); + + /** + * Provides access to a shared instance of the webapp cache. + * + * @return the shared webapp cache. + */ + public static WebAppCache getShared() { + return sharedCache; + } +} Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/WebAppCache.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java?rev=1854429&r1=1854428&r2=1854429&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java (original) +++ ofbiz/ofbiz-framework/trunk/framework/webapp/src/main/java/org/apache/ofbiz/webapp/control/LoginWorker.java Tue Feb 26 22:47:58 2019 @@ -81,6 +81,7 @@ import org.apache.ofbiz.service.GenericS import org.apache.ofbiz.service.LocalDispatcher; import org.apache.ofbiz.service.ModelService; import org.apache.ofbiz.service.ServiceUtil; +import org.apache.ofbiz.webapp.WebAppCache; import org.apache.ofbiz.webapp.WebAppUtil; import org.apache.ofbiz.webapp.stats.VisitHandler; import org.apache.ofbiz.widget.model.ThemeFactory; @@ -97,6 +98,7 @@ public class LoginWorker { public static final String securityProperties = "security.properties"; private static final String keyValue = UtilProperties.getPropertyValue(securityProperties, "login.secret_key_string"); + private static final WebAppCache webapps = WebAppCache.getShared(); public static StringWrapper makeLoginUrl(PageContext pageContext) { return makeLoginUrl(pageContext, "checkLogin"); @@ -922,9 +924,9 @@ public class LoginWorker { Delegator delegator = (Delegator) request.getAttribute("delegator"); HttpSession session = request.getSession(); GenericValue userLogin = (GenericValue) session.getAttribute("userLogin"); - ServletContext context = request.getServletContext(); + String serverId = (String) request.getServletContext().getAttribute("_serverId"); String applicationName = UtilHttp.getApplicationName(request); - WebappInfo webappInfo = ComponentConfig.getWebappInfo((String) context.getAttribute("_serverId"), applicationName); + WebappInfo webappInfo = webapps.getWebappInfo(serverId, applicationName); if (userLogin != null && ((webappInfo != null && webappInfo.isAutologinCookieUsed()) @@ -932,7 +934,7 @@ public class LoginWorker { Cookie autoLoginCookie = new Cookie(getAutoLoginCookieName(request), userLogin.getString("userLoginId")); autoLoginCookie.setMaxAge(60 * 60 * 24 * 365); autoLoginCookie.setDomain(EntityUtilProperties.getPropertyValue("url", "cookie.domain", delegator)); - autoLoginCookie.setPath( applicationName.equals("root") ? "/" : request.getContextPath()); + autoLoginCookie.setPath(applicationName.equals("root") ? "/" : request.getContextPath()); autoLoginCookie.setSecure(true); autoLoginCookie.setHttpOnly(true); response.addCookie(autoLoginCookie); @@ -1368,7 +1370,7 @@ public class LoginWorker { * user is authorized to access */ public static Collection<ComponentConfig.WebappInfo> getAppBarWebInfos(Security security, GenericValue userLogin, String serverName, String menuName) { - Collection<ComponentConfig.WebappInfo> allInfos = ComponentConfig.getAppBarWebInfos(serverName, menuName); + Collection<ComponentConfig.WebappInfo> allInfos = webapps.getAppBarWebInfos(serverName, menuName); Collection<ComponentConfig.WebappInfo> allowedInfos = new ArrayList<ComponentConfig.WebappInfo>(allInfos.size()); for (ComponentConfig.WebappInfo info : allInfos) { if (hasApplicationPermission(info, security, userLogin)) { Modified: ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/HomeMenu.ftl URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/HomeMenu.ftl?rev=1854429&r1=1854428&r2=1854429&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/HomeMenu.ftl (original) +++ ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/HomeMenu.ftl Tue Feb 26 22:47:58 2019 @@ -21,8 +21,8 @@ under the License. <#if (externalLoginKey)?exists><#assign externalKeyParam = "?externalLoginKey=" + requestAttributes.externalLoginKey?if_exists></#if> <#assign ofbizServerName = application.getAttribute("_serverId")?default("default-server")> <#assign contextPath = request.getContextPath()> -<#assign displayApps = Static["org.apache.ofbiz.base.component.ComponentConfig"].getAppBarWebInfos(ofbizServerName, "main")> -<#assign displaySecondaryApps = Static["org.apache.ofbiz.base.component.ComponentConfig"].getAppBarWebInfos(ofbizServerName, "secondary")> +<#assign displayApps = Static["org.apache.ofbiz.webapp.WebAppCache"].getShared().getAppBarWebInfos(ofbizServerName, "main")> +<#assign displaySecondaryApps = Static["org.apache.ofbiz.webapp.WebAppCache"].getShared().getAppBarWebInfos(ofbizServerName, "secondary")> <#assign avatarList = EntityQuery.use(delegator).from("PartyContent").where("partyId", person.partyId!, "partyContentTypeId", "LGOIMGURL").queryList()!> <#if avatarList?has_content> <#assign avatar = Static["org.apache.ofbiz.entity.util.EntityUtil"].getFirst(avatarList)> Modified: ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/TopAppBar.ftl URL: http://svn.apache.org/viewvc/ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/TopAppBar.ftl?rev=1854429&r1=1854428&r2=1854429&view=diff ============================================================================== --- ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/TopAppBar.ftl (original) +++ ofbiz/ofbiz-framework/trunk/themes/rainbowstone/template/includes/TopAppBar.ftl Tue Feb 26 22:47:58 2019 @@ -20,8 +20,8 @@ under the License. <#if (externalLoginKey)?exists><#assign externalKeyParam = "?externalLoginKey=" + requestAttributes.externalLoginKey?if_exists></#if> <#assign ofbizServerName = application.getAttribute("_serverId")?default("default-server")> <#assign contextPath = request.getContextPath()> -<#assign displayApps = Static["org.apache.ofbiz.base.component.ComponentConfig"].getAppBarWebInfos(ofbizServerName, "main")> -<#assign displaySecondaryApps = Static["org.apache.ofbiz.base.component.ComponentConfig"].getAppBarWebInfos(ofbizServerName, "secondary")> +<#assign displayApps = Static["org.apache.ofbiz.webapp.WebAppCache"].getShared().getAppBarWebInfos(ofbizServerName, "main")> +<#assign displaySecondaryApps = Static["org.apache.ofbiz.webapp.WebAppCache"].getShared().getAppBarWebInfos(ofbizServerName, "secondary")> <#if person?has_content> <#assign avatarList = EntityQuery.use(delegator).from("PartyContent").where("partyId", person.partyId!, "partyContentTypeId", "LGOIMGURL").queryList()!> <#if avatarList?has_content> |
Free forum by Nabble | Edit this page |