Added: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java?rev=1535171&view=auto ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java (added) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java Wed Oct 23 20:48:36 2013 @@ -0,0 +1,231 @@ +/******************************************************************************* + * 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.ofbiz.product.category.ftl; + +import java.io.IOException; +import java.io.Writer; +import java.util.Iterator; +import java.util.Map; + +import javax.servlet.ServletContext; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + +import org.apache.oro.text.regex.Pattern; +import org.apache.oro.text.regex.Perl5Matcher; +import org.ofbiz.base.util.Debug; +import org.ofbiz.entity.GenericValue; +import org.ofbiz.product.category.UrlRegexpConfigUtil; +import org.ofbiz.webapp.control.RequestHandler; + +import freemarker.core.Environment; +import freemarker.ext.beans.BeanModel; +import freemarker.template.SimpleScalar; +import freemarker.template.TemplateScalarModel; +import freemarker.template.TemplateTransformModel; + +/** + * UrlRegexpTransform - Freemarker Transform for Products URLs (links) + * + */ +public class UrlRegexpTransform implements TemplateTransformModel { + + private static final String module = UrlRegexpTransform.class.getName(); + + public boolean checkArg(Map args, String key, boolean defaultValue) { + if (!args.containsKey(key)) { + return defaultValue; + } else { + Object o = args.get(key); + if (o instanceof SimpleScalar) { + SimpleScalar s = (SimpleScalar) o; + return "true".equalsIgnoreCase(s.getAsString()); + } + return defaultValue; + } + } + + public Writer getWriter(final Writer out, Map args) { + final StringBuffer buf = new StringBuffer(); + final boolean fullPath = checkArg(args, "fullPath", false); + final boolean secure = checkArg(args, "secure", false); + final boolean encode = checkArg(args, "encode", true); + + return new Writer(out) { + + public void write(char cbuf[], int off, int len) { + buf.append(cbuf, off, len); + } + + public void flush() throws IOException { + out.flush(); + } + + public void close() throws IOException { + try { + Environment env = Environment.getCurrentEnvironment(); + BeanModel req = (BeanModel) env.getVariable("request"); + BeanModel res = (BeanModel) env.getVariable("response"); + Object prefix = env.getVariable("urlPrefix"); + if (req != null) { + HttpServletRequest request = (HttpServletRequest) req.getWrappedObject(); + ServletContext ctx = (ServletContext) request.getAttribute("servletContext"); + HttpServletResponse response = null; + if (res != null) { + response = (HttpServletResponse) res.getWrappedObject(); + } + HttpSession session = request.getSession(); + GenericValue userLogin = (GenericValue) session.getAttribute("userLogin"); + + // anonymous shoppers are not logged in + if (userLogin != null && "anonymous".equals(userLogin.getString("userLoginId"))) { + userLogin = null; + } + + RequestHandler rh = (RequestHandler) ctx.getAttribute("_REQUEST_HANDLER_"); + out.write(seoUrl(rh.makeLink(request, response, buf.toString(), fullPath, secure, encode), userLogin == null)); + } else if (prefix != null) { + if (prefix instanceof TemplateScalarModel) { + TemplateScalarModel s = (TemplateScalarModel) prefix; + String prefixString = s.getAsString(); + String bufString = buf.toString(); + boolean prefixSlash = prefixString.endsWith("/"); + boolean bufSlash = bufString.startsWith("/"); + if (prefixSlash && bufSlash) { + bufString = bufString.substring(1); + } else if (!prefixSlash && !bufSlash) { + bufString = "/" + bufString; + } + out.write(prefixString + bufString); + } + } else { + out.write(buf.toString()); + } + } catch (Exception e) { + throw new IOException(e.getMessage()); + } + } + }; + } + + /** + * Transform a url according to seo pattern regular expressions. + * + * @param url + * , String to do the seo transform + * @param isAnon + * , boolean to indicate whether it's an anonymous visit. + * + * @return String, the transformed url. + */ + public static String seoUrl(String url, boolean isAnon) { + Perl5Matcher matcher = new Perl5Matcher(); + if (UrlRegexpConfigUtil.checkUseUrlRegexp() && matcher.matches(url, UrlRegexpConfigUtil.getGeneralRegexpPattern())) { + Iterator<String> keys = UrlRegexpConfigUtil.getSeoPatterns().keySet().iterator(); + boolean foundMatch = false; + while (keys.hasNext()) { + String key = keys.next(); + Pattern pattern = UrlRegexpConfigUtil.getSeoPatterns().get(key); + if (pattern.getPattern().contains(";jsessionid=")) { + if (isAnon) { + if (UrlRegexpConfigUtil.isJSessionIdAnonEnabled()) { + continue; + } + } else { + if (UrlRegexpConfigUtil.isJSessionIdUserEnabled()) { + continue; + } else { + boolean foundException = false; + for (int i = 0; i < UrlRegexpConfigUtil.getUserExceptionPatterns().size(); i++) { + if (matcher.matches(url, UrlRegexpConfigUtil.getUserExceptionPatterns().get(i))) { + foundException = true; + break; + } + } + if (foundException) { + continue; + } + } + } + } + String replacement = UrlRegexpConfigUtil.getSeoReplacements().get(key); + if (matcher.matches(url, pattern)) { + for (int i = 1; i < matcher.getMatch().groups(); i++) { + replacement = replacement.replaceAll("\\$" + i, matcher.getMatch().group(i)); + } + // break if found any matcher + url = replacement; + foundMatch = true; + break; + } + } + if (!foundMatch && UrlRegexpConfigUtil.isDebugEnabled()) { + Debug.logInfo("Can NOT find a seo transform pattern for this url: " + url, module); + } + } + return url; + } + + static { + UrlRegexpConfigUtil.init(); + } + + /** + * Forward a uri according to forward pattern regular expressions. Note: this is developed for Filter usage. + * + * @param uri + * String to reverse transform + * @return String + */ + public static boolean forwardUri(HttpServletResponse response, String uri) { + Perl5Matcher matcher = new Perl5Matcher(); + boolean foundMatch = false; + Integer responseCodeInt = null; + if (UrlRegexpConfigUtil.checkUseUrlRegexp() && UrlRegexpConfigUtil.getForwardPatterns() != null && UrlRegexpConfigUtil.getForwardReplacements() != null) { + Iterator<String> keys = UrlRegexpConfigUtil.getForwardPatterns().keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + Pattern pattern = UrlRegexpConfigUtil.getForwardPatterns().get(key); + String replacement = UrlRegexpConfigUtil.getForwardReplacements().get(key); + if (matcher.matches(uri, pattern)) { + for (int i = 1; i < matcher.getMatch().groups(); i++) { + replacement = replacement.replaceAll("\\$" + i, matcher.getMatch().group(i)); + } + // break if found any matcher + uri = replacement; + responseCodeInt = UrlRegexpConfigUtil.getForwardResponseCodes().get(key); + foundMatch = true; + break; + } + } + } + if (foundMatch) { + if (responseCodeInt == null) { + response.setStatus(UrlRegexpConfigUtil.DEFAULT_RESPONSECODE); + } else { + response.setStatus(responseCodeInt.intValue()); + } + response.setHeader("Location", uri); + } else if (UrlRegexpConfigUtil.isDebugEnabled()) { + Debug.logInfo("Can NOT forward this url: " + uri, module); + } + return foundMatch; + } +}
Propchange: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java ------------------------------------------------------------------------------ svn:keywords = Date Rev Author URL Id Propchange: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/applications/product/src/org/ofbiz/product/category/ftl/UrlRegexpTransform.java ------------------------------------------------------------------------------ svn:mime-type = text/plain Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java?rev=1535171&r1=1535157&r2=1535171&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/framework/webapp/src/org/ofbiz/webapp/control/RequestHandler.java Wed Oct 23 20:48:36 2013 @@ -58,6 +58,7 @@ import org.ofbiz.webapp.stats.ServerHitB import org.ofbiz.webapp.view.ViewFactory; import org.ofbiz.webapp.view.ViewHandler; import org.ofbiz.webapp.view.ViewHandlerException; +import org.ofbiz.webapp.website.WebSiteProperties; import org.ofbiz.webapp.website.WebSiteWorker; import org.owasp.esapi.errors.EncodingException; @@ -857,7 +858,7 @@ public class RequestHandler { } private void renderView(String view, boolean allowExtView, HttpServletRequest req, HttpServletResponse resp, String saveName) throws RequestHandlerException { GenericValue userLogin = (GenericValue) req.getSession().getAttribute("userLogin"); - // workaraound if we are in the root webapp + // workaround if we are in the root webapp String cname = UtilHttp.getApplicationName(req); String oldView = view; @@ -868,7 +869,10 @@ public class RequestHandler { // if the view name starts with the control servlet name and a /, then it was an // attempt to override the default view with a call back into the control servlet, // so just get the target view name and use that - String servletName = req.getServletPath().substring(1); + String servletName = req.getServletPath(); + if (UtilValidate.isNotEmpty(servletName) && servletName.length() > 1) { + servletName = servletName.substring(1); + } if (Debug.infoOn()) Debug.logInfo("Rendering View [" + view + "], sessionId=" + UtilHttp.getSessionId(req), module); if (view.startsWith(servletName + "/")) { Modified: ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/web.xml URL: http://svn.apache.org/viewvc/ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/web.xml?rev=1535171&r1=1535157&r2=1535171&view=diff ============================================================================== --- ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/web.xml (original) +++ ofbiz/branches/OFBIZ-5312-ofbiz-ecommerce-seo-2013-10-23/specialpurpose/ecommerce/webapp/ecommerce/WEB-INF/web.xml Wed Oct 23 20:48:36 2013 @@ -52,17 +52,23 @@ under the License. frequently switch between http and https. </description> </context-param> + <context-param> + <param-name>defaultPage</param-name> + <param-value>/main</param-value> + <description>Default page uri. Important: please DO add or remove /control to match url-pattern of SeoControlServlet. + </description> + </context-param> <filter> - <filter-name>CatalogUrlFilter</filter-name> - <display-name>CatalogUrlFilter</display-name> - <filter-class>org.ofbiz.product.category.CatalogUrlFilter</filter-class> + <filter-name>SeoCatalogUrlFilter</filter-name> + <display-name>SeoCatalogUrlFilter</display-name> + <filter-class>org.ofbiz.product.category.SeoCatalogUrlFilter</filter-class> <init-param><param-name>defaultLocaleString</param-name><param-value>en_US</param-value></init-param> </filter> <filter> - <filter-name>ContentUrlFilter</filter-name> - <display-name>ContentUrlFilter</display-name> - <filter-class>org.ofbiz.content.content.ContentUrlFilter</filter-class> + <filter-name>SeoContentUrlFilter</filter-name> + <display-name>SeoContentUrlFilter</display-name> + <filter-class>org.ofbiz.product.category.SeoContentUrlFilter</filter-class> <init-param> <param-name>defaultLocaleString</param-name> <param-value>en_US</param-value> @@ -70,9 +76,9 @@ under the License. <init-param><param-name>viewRequest</param-name><param-value>ViewBlogArticle</param-value></init-param> </filter> <filter> - <filter-name>ContextFilter</filter-name> - <display-name>ContextFilter</display-name> - <filter-class>org.ofbiz.webapp.control.ContextFilter</filter-class> + <filter-name>SeoContextFilter</filter-name> + <display-name>SeoContextFilter</display-name> + <filter-class>org.ofbiz.product.category.SeoContextFilter</filter-class> <init-param> <param-name>disableContextSecurity</param-name> <param-value>N</param-value> @@ -83,15 +89,15 @@ under the License. </init-param> </filter> <filter-mapping> - <filter-name>CatalogUrlFilter</filter-name> + <filter-name>SeoCatalogUrlFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> - <filter-name>ContentUrlFilter</filter-name> + <filter-name>SeoContentUrlFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <filter-mapping> - <filter-name>ContextFilter</filter-name> + <filter-name>SeoContextFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> @@ -105,10 +111,10 @@ under the License. <listener><listener-class>org.ofbiz.webapp.control.LoginEventListener</listener-class></listener> <servlet> - <servlet-name>ControlServlet</servlet-name> - <display-name>ControlServlet</display-name> - <description>Main Control Servlet</description> - <servlet-class>org.ofbiz.webapp.control.ControlServlet</servlet-class> + <servlet-name>SeoControlServlet</servlet-name> + <display-name>SeoControlServlet</display-name> + <description>Main SEO Control Servlet</description> + <servlet-class>org.ofbiz.product.category.SeoControlServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <!-- un-comment for Worldpay @@ -121,16 +127,16 @@ under the License. </servlet> --> <servlet> - <servlet-name>CatalogUrlServlet</servlet-name> - <display-name>CatalogUrlServlet</display-name> - <description>Catalog (Category/Product) URL Servlet</description> - <servlet-class>org.ofbiz.product.category.CatalogUrlServlet</servlet-class> + <servlet-name>SeoCatalogUrlServlet</servlet-name> + <display-name>SeoCatalogUrlServlet</display-name> + <description>SEO Catalog (Category/Product) URL Servlet</description> + <servlet-class>org.ofbiz.product.category.SeoCatalogUrlServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> - <servlet-name>ControlServlet</servlet-name> - <url-pattern>/control/*</url-pattern> + <servlet-name>SeoControlServlet</servlet-name> + <url-pattern>/*</url-pattern> </servlet-mapping> <!-- un-comment for Worldpay <servlet-mapping> @@ -139,7 +145,7 @@ under the License. </servlet-mapping> --> <servlet-mapping> - <servlet-name>CatalogUrlServlet</servlet-name> + <servlet-name>SeoCatalogUrlServlet</servlet-name> <url-pattern>/products/*</url-pattern> </servlet-mapping>