diff --git a/5.Code Inspection/src/ProductConfigItemContentWrapper.java b/5.Code Inspection/src/ProductConfigItemContentWrapper.java new file mode 100644 index 0000000..a3adcee --- /dev/null +++ b/5.Code Inspection/src/ProductConfigItemContentWrapper.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * 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.product.config; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.ofbiz.base.util.Debug; +import org.apache.ofbiz.base.util.GeneralException; +import org.apache.ofbiz.base.util.StringUtil; +import org.apache.ofbiz.base.util.StringUtil.StringWrapper; +import org.apache.ofbiz.base.util.UtilCodec; +import org.apache.ofbiz.base.util.UtilHttp; +import org.apache.ofbiz.base.util.UtilValidate; +import org.apache.ofbiz.base.util.cache.UtilCache; +import org.apache.ofbiz.content.content.ContentWorker; +import org.apache.ofbiz.content.content.ContentWrapper; +import org.apache.ofbiz.entity.Delegator; +import org.apache.ofbiz.entity.DelegatorFactory; +import org.apache.ofbiz.entity.GenericValue; +import org.apache.ofbiz.entity.model.ModelEntity; +import org.apache.ofbiz.entity.model.ModelUtil; +import org.apache.ofbiz.entity.util.EntityQuery; +import org.apache.ofbiz.entity.util.EntityUtilProperties; +import org.apache.ofbiz.service.LocalDispatcher; +import org.apache.ofbiz.service.ServiceContainer; + +/** + * Product Config Item Content Worker: gets product content to display + */ +public class ProductConfigItemContentWrapper implements ContentWrapper { + + public static final String module = ProductConfigItemContentWrapper.class.getName(); + public static final String SEPARATOR = "::"; // cache key separator + private static final UtilCache configItemContentCache = UtilCache.createUtilCache("configItem.content", true); // use soft reference to free up memory if needed + + protected transient LocalDispatcher dispatcher; + protected String dispatcherName; + protected transient Delegator delegator; + protected String delegatorName; + protected GenericValue productConfigItem; + protected Locale locale; + protected String mimeTypeId; + + + public static ProductConfigItemContentWrapper makeProductConfigItemContentWrapper(GenericValue productConfigItem, HttpServletRequest request) { + return new ProductConfigItemContentWrapper(productConfigItem, request); + } + + public ProductConfigItemContentWrapper(LocalDispatcher dispatcher, GenericValue productConfigItem, Locale locale, String mimeTypeId) { + this.dispatcher = dispatcher; + this.dispatcherName = dispatcher.getName(); + this.delegator = productConfigItem.getDelegator(); + this.delegatorName = delegator.getDelegatorName(); + this.productConfigItem = productConfigItem; + this.locale = locale; + this.mimeTypeId = mimeTypeId; + } + + public ProductConfigItemContentWrapper(GenericValue productConfigItem, HttpServletRequest request) { + this.dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); + this.dispatcherName = dispatcher.getName(); + this.delegator = (Delegator) request.getAttribute("delegator"); + this.delegatorName = delegator.getDelegatorName(); + this.productConfigItem = productConfigItem; + this.locale = UtilHttp.getLocale(request); + this.mimeTypeId = EntityUtilProperties.getPropertyValue("content", "defaultMimeType", "text/html; charset=utf-8", this.delegator); + } + + public StringWrapper get(String confItemContentTypeId, String encoderType) { + return StringUtil.makeStringWrapper(getProductConfigItemContentAsText(productConfigItem, confItemContentTypeId, locale, mimeTypeId, getDelegator(), getDispatcher(), encoderType)); + } + + public Delegator getDelegator() { + if (delegator == null) { + delegator = DelegatorFactory.getDelegator(delegatorName); + } + return delegator; + } + + public LocalDispatcher getDispatcher() { + if (dispatcher == null) { + dispatcher = ServiceContainer.getLocalDispatcher(dispatcherName, this.getDelegator()); + } + return dispatcher; + } + + public static String getProductConfigItemContentAsText(GenericValue productConfigItem, String confItemContentTypeId, HttpServletRequest request, String encoderType) { + LocalDispatcher dispatcher = (LocalDispatcher) request.getAttribute("dispatcher"); + String mimeTypeId = EntityUtilProperties.getPropertyValue("content", "defaultMimeType", "text/html; charset=utf-8", productConfigItem.getDelegator()); + return getProductConfigItemContentAsText(productConfigItem, confItemContentTypeId, UtilHttp.getLocale(request), mimeTypeId, productConfigItem.getDelegator(), dispatcher, encoderType); + } + + public static String getProductConfigItemContentAsText(GenericValue productConfigItem, String confItemContentTypeId, Locale locale, LocalDispatcher dispatcher, String encoderType) { + return getProductConfigItemContentAsText(productConfigItem, confItemContentTypeId, locale, null, null, dispatcher, encoderType); + } + + public static String getProductConfigItemContentAsText(GenericValue productConfigItem, String confItemContentTypeId, Locale locale, String mimeTypeId, Delegator delegator, LocalDispatcher dispatcher, String encoderType) { + UtilCodec.SimpleEncoder encoder = UtilCodec.getEncoder(encoderType); + String candidateFieldName = ModelUtil.dbNameToVarName(confItemContentTypeId); + String cacheKey = confItemContentTypeId + SEPARATOR + locale + SEPARATOR + mimeTypeId + SEPARATOR + productConfigItem.get("configItemId") + SEPARATOR + encoderType + SEPARATOR + delegator; + try { + String cachedValue = configItemContentCache.get(cacheKey); + if (cachedValue != null) { + return cachedValue; + } + Writer outWriter = new StringWriter(); + getProductConfigItemContentAsText(null, productConfigItem, confItemContentTypeId, locale, mimeTypeId, delegator, dispatcher, outWriter, false); + String outString = outWriter.toString(); + if (UtilValidate.isEmpty(outString)) { + outString = productConfigItem.getModelEntity().isField(candidateFieldName) ? productConfigItem.getString(candidateFieldName): ""; + outString = outString == null? "" : outString; + } + outString = encoder.sanitize(outString); + if (configItemContentCache != null) { + configItemContentCache.put(cacheKey, outString); + } + return outString; + } catch (GeneralException e) { + Debug.logError(e, "Error rendering ProdConfItemContent, inserting empty String", module); + String candidateOut = productConfigItem.getModelEntity().isField(candidateFieldName) ? productConfigItem.getString(candidateFieldName): ""; + return candidateOut == null? "" : encoder.sanitize(candidateOut); + } catch (IOException e) { + Debug.logError(e, "Error rendering ProdConfItemContent, inserting empty String", module); + String candidateOut = productConfigItem.getModelEntity().isField(candidateFieldName) ? productConfigItem.getString(candidateFieldName): ""; + return candidateOut == null? "" : encoder.sanitize(candidateOut); + } + } + + public static void getProductConfigItemContentAsText(String configItemId, GenericValue productConfigItem, String confItemContentTypeId, Locale locale, String mimeTypeId, Delegator delegator, LocalDispatcher dispatcher, Writer outWriter) throws GeneralException, IOException { + getProductConfigItemContentAsText(configItemId, productConfigItem, confItemContentTypeId, locale, mimeTypeId, delegator, dispatcher, outWriter, true); + } + + public static void getProductConfigItemContentAsText(String configItemId, GenericValue productConfigItem, String confItemContentTypeId, Locale locale, String mimeTypeId, Delegator delegator, LocalDispatcher dispatcher, Writer outWriter, boolean cache) throws GeneralException, IOException { + if (configItemId == null && productConfigItem != null) { + configItemId = productConfigItem.getString("configItemId"); + } + + if (delegator == null && productConfigItem != null) { + delegator = productConfigItem.getDelegator(); + } + + if (UtilValidate.isEmpty(mimeTypeId)) { + mimeTypeId = EntityUtilProperties.getPropertyValue("content", "defaultMimeType", "text/html; charset=utf-8", delegator); + } + + GenericValue productConfigItemContent = EntityQuery.use(delegator).from("ProdConfItemContent") + .where("configItemId", configItemId, "confItemContentTypeId", confItemContentTypeId) + .orderBy("-fromDate") + .cache(cache) + .filterByDate() + .queryFirst(); + if (productConfigItemContent != null) { + // when rendering the product config item content, always include the ProductConfigItem and ProdConfItemContent records that this comes from + Map inContext = new HashMap(); + inContext.put("productConfigItem", productConfigItem); + inContext.put("productConfigItemContent", productConfigItemContent); + ContentWorker.renderContentAsText(dispatcher, delegator, productConfigItemContent.getString("contentId"), outWriter, inContext, locale, mimeTypeId, null, null, cache); + return; + } + + String candidateFieldName = ModelUtil.dbNameToVarName(confItemContentTypeId); + ModelEntity productConfigItemModel = delegator.getModelEntity("ProductConfigItem"); + if (productConfigItemModel.isField(candidateFieldName)) { + if (productConfigItem == null) { + productConfigItem = EntityQuery.use(delegator).from("ProductConfigItem").where("configItemId", configItemId).cache().queryOne(); + } + if (productConfigItem != null) { + String candidateValue = productConfigItem.getString(candidateFieldName); + if (UtilValidate.isNotEmpty(candidateValue)) { + outWriter.write(candidateValue); + return; + } + } + } + } +} + diff --git a/5.Code Inspection/src/SeoTransform.java b/5.Code Inspection/src/SeoTransform.java new file mode 100644 index 0000000..922fe0e --- /dev/null +++ b/5.Code Inspection/src/SeoTransform.java @@ -0,0 +1,189 @@ +/******************************************************************************* + * 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.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.apache.ofbiz.base.util.Debug; +import org.apache.ofbiz.entity.GenericValue; +import org.apache.ofbiz.product.category.SeoConfigUtil; +import org.apache.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; + +/** + * SeoTransform - Freemarker Transform for URLs (links) + * + */ +public class SeoTransform implements TemplateTransformModel { + + private static final String module = SeoTransform.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 (SeoConfigUtil.checkUseUrlRegexp() && matcher.matches(url, SeoConfigUtil.getGeneralRegexpPattern())) { + Iterator keys = SeoConfigUtil.getSeoPatterns().keySet().iterator(); + boolean foundMatch = false; + while (keys.hasNext()) { + String key = keys.next(); + Pattern pattern = SeoConfigUtil.getSeoPatterns().get(key); + if (pattern.getPattern().contains(";jsessionid=")) { + if (isAnon) { + if (SeoConfigUtil.isJSessionIdAnonEnabled()) { + continue; + } + } else { + if (SeoConfigUtil.isJSessionIdUserEnabled()) { + continue; + } else { + boolean foundException = false; + for (int i = 0; i < SeoConfigUtil.getUserExceptionPatterns().size(); i++) { + if (matcher.matches(url, SeoConfigUtil.getUserExceptionPatterns().get(i))) { + foundException = true; + break; + } + } + if (foundException) { + continue; + } + } + } + } + String replacement = SeoConfigUtil.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) { + Debug.logVerbose("Can NOT find a seo transform pattern for this url: " + url, module); + } + } + return url; + } + + static { + if (!SeoConfigUtil.isInitialed()) { + SeoConfigUtil.init(); + } + } +} diff --git a/5.Code Inspection/src/UrlRegexpTransform.java b/5.Code Inspection/src/UrlRegexpTransform.java new file mode 100644 index 0000000..700ec53 --- /dev/null +++ b/5.Code Inspection/src/UrlRegexpTransform.java @@ -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.apache.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.apache.ofbiz.base.util.Debug; +import org.apache.ofbiz.entity.GenericValue; +import org.apache.ofbiz.product.category.SeoConfigUtil; +import org.apache.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 || request.isSecure() , 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 (SeoConfigUtil.checkUseUrlRegexp() && matcher.matches(url, SeoConfigUtil.getGeneralRegexpPattern())) { + Iterator keys = SeoConfigUtil.getSeoPatterns().keySet().iterator(); + boolean foundMatch = false; + while (keys.hasNext()) { + String key = keys.next(); + Pattern pattern = SeoConfigUtil.getSeoPatterns().get(key); + if (pattern.getPattern().contains(";jsessionid=")) { + if (isAnon) { + if (SeoConfigUtil.isJSessionIdAnonEnabled()) { + continue; + } + } else { + if (SeoConfigUtil.isJSessionIdUserEnabled()) { + continue; + } else { + boolean foundException = false; + for (int i = 0; i < SeoConfigUtil.getUserExceptionPatterns().size(); i++) { + if (matcher.matches(url, SeoConfigUtil.getUserExceptionPatterns().get(i))) { + foundException = true; + break; + } + } + if (foundException) { + continue; + } + } + } + } + String replacement = SeoConfigUtil.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) { + Debug.logVerbose("Can NOT find a seo transform pattern for this url: " + url, module); + } + } + return url; + } + + static { + SeoConfigUtil.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 (SeoConfigUtil.checkUseUrlRegexp() && SeoConfigUtil.getSeoPatterns() != null && SeoConfigUtil.getForwardReplacements() != null) { + Iterator keys = SeoConfigUtil.getSeoPatterns().keySet().iterator(); + while (keys.hasNext()) { + String key = keys.next(); + Pattern pattern = SeoConfigUtil.getSeoPatterns().get(key); + String replacement = SeoConfigUtil.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 = SeoConfigUtil.getForwardResponseCodes().get(key); + foundMatch = true; + break; + } + } + } + if (foundMatch) { + if (responseCodeInt == null) { + response.setStatus(SeoConfigUtil.getDefaultResponseCode()); + } else { + response.setStatus(responseCodeInt.intValue()); + } + response.setHeader("Location", uri); + } else { + Debug.logInfo("Can NOT forward this url: " + uri, module); + } + return foundMatch; + } +}