diff --git a/source/java/org/alfresco/web/forms/FormDataFunctions.java b/source/java/org/alfresco/web/forms/FormDataFunctions.java index 7cc3c6f343..ffbe79eed4 100644 --- a/source/java/org/alfresco/web/forms/FormDataFunctions.java +++ b/source/java/org/alfresco/web/forms/FormDataFunctions.java @@ -46,7 +46,7 @@ import org.xml.sax.SAXException; * of both the alfresco webapp and the virtualization server. * * @author Ariel Backenroth - * @author Arseny Kovalchuk (Fix of the bug reported in https://issues.alfresco.com/jira/browse/ETWOONE-241) + * @author Arseny Kovalchuk (Fix for the ETWOONE-241 and ETWOTWO-504 issues) */ public class FormDataFunctions { @@ -167,4 +167,92 @@ public class FormDataFunctions return result; } + + + /** + * Encodes invalid HTML characters. (Fix for ETWOTWO-504 issue) + * This code was adopted from WebDAVHelper.encodeHTML() method with some restrictions. + * @see press-relese.xsl for pattern. + * + * @param text to encode + * @return encoded text + * @throws IOException + * @throws SAXException + */ + public String encodeQuotes(String text) throws IOException, SAXException + { + if (text == null) + { + return ""; + } + + StringBuilder sb = null; //create on demand + String enc; + char c; + for (int i = 0; i < text.length(); i++) + { + enc = null; + c = text.charAt(i); + switch (c) + { + case '"': enc = """; break; //" + //case '&': enc = "&"; break; //& + //case '<': enc = "<"; break; //< + //case '>': enc = ">"; break; //> + + //german umlauts + case '\u00E4' : enc = "ä"; break; + case '\u00C4' : enc = "Ä"; break; + case '\u00F6' : enc = "ö"; break; + case '\u00D6' : enc = "Ö"; break; + case '\u00FC' : enc = "ü"; break; + case '\u00DC' : enc = "Ü"; break; + case '\u00DF' : enc = "ß"; break; + + //misc + //case 0x80: enc = "€"; break; sometimes euro symbol is ascii 128, should we suport it? + case '\u20AC': enc = "€"; break; + case '\u00AB': enc = "«"; break; + case '\u00BB': enc = "»"; break; + case '\u00A0': enc = " "; break; + + //case '': enc = "&trade"; break; + + default: + if (((int)c) >= 0x80) + { + //encode all non basic latin characters + enc = "&#" + ((int)c) + ";"; + } + break; + } + + if (enc != null) + { + if (sb == null) + { + String soFar = text.substring(0, i); + sb = new StringBuilder(i + 8); + sb.append(soFar); + } + sb.append(enc); + } + else + { + if (sb != null) + { + sb.append(c); + } + } + } + + if (sb == null) + { + return text; + } + else + { + return sb.toString(); + } + } } \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java index 455ec4bf88..0758065398 100644 --- a/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java +++ b/source/java/org/alfresco/web/forms/RenderingEngineTemplateImpl.java @@ -263,7 +263,9 @@ public class RenderingEngineTemplateImpl result = AVMUtil.buildPath(parentAVMPath, result, AVMUtil.PathRelation.SANDBOX_RELATIVE); - LOGGER.debug("processed pattern " + outputPathPattern + " as " + result); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("processed pattern " + outputPathPattern + " as " + result); + return result; } @@ -288,6 +290,7 @@ public class RenderingEngineTemplateImpl AVMUtil.makeAllDirectories(parentAVMPath); avmService.createFile(parentAVMPath, AVMNodeConverter.SplitBase(renditionAvmPath)[1]); + if (LOGGER.isDebugEnabled()) LOGGER.debug("Created file node for file: " + renditionAvmPath); @@ -391,9 +394,12 @@ public class RenderingEngineTemplateImpl RenderingEngineTemplateImpl.this.getServiceRegistry().getNodeService(); final NodeRef parentNodeRef = nodeService.getPrimaryParent(RenderingEngineTemplateImpl.this.getNodeRef()).getParentRef(); - LOGGER.debug("request to resolve resource " + name + - " webapp url is " + webappUrl + - " and data dictionary workspace is " + parentNodeRef); + if (LOGGER.isDebugEnabled()) + { + LOGGER.debug("request to resolve resource " + name + + " webapp url is " + webappUrl + + " and data dictionary workspace is " + parentNodeRef); + } final NodeRef result = nodeService.getChildByName(parentNodeRef, ContentModel.ASSOC_CONTAINS, name); if (result != null) { @@ -401,7 +407,9 @@ public class RenderingEngineTemplateImpl RenderingEngineTemplateImpl.this.getServiceRegistry().getContentService(); try { - LOGGER.debug("found " + name + " in data dictonary: " + result); + if (LOGGER.isDebugEnabled()) + LOGGER.debug("found " + name + " in data dictonary: " + result); + return contentService.getReader(result, ContentModel.PROP_CONTENT).getContentInputStream(); } catch (Exception e) @@ -419,13 +427,17 @@ public class RenderingEngineTemplateImpl } final URI uri = new URI(webappUrl + '/' + StringUtils.join(path, '/')); + if (LOGGER.isDebugEnabled()) LOGGER.debug("loading " + uri); + return uri.toURL().openStream(); } catch (Exception e) { - LOGGER.debug(e); + if (LOGGER.isDebugEnabled()) + LOGGER.debug(e); + return null; } } @@ -450,7 +462,39 @@ public class RenderingEngineTemplateImpl // add methods final FormDataFunctions fdf = this.getFormDataFunctions(); + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, + "encodeQuotes", + namespacePrefixResolver), + new RenderingEngine.TemplateProcessorMethod() + { + public Object exec(final Object[] arguments) + throws IOException, + SAXException + { + if (arguments.length != 1) + { + throw new IllegalArgumentException("expected 1 argument to encodeQuotes. got " + + arguments.length); + + } + if (! (arguments[0] instanceof String)) + { + throw new ClassCastException("expected arguments[0] to be a " + String.class.getName() + + ". got a " + arguments[0].getClass().getName() + "."); + } + String text = (String)arguments[0]; + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("tpm_encodeQuotes('" + text + "'), parentPath = " + parentPath); + + final String result = fdf.encodeQuotes(text); + return result; + } + }); + + + model.put(QName.createQName(NamespaceService.ALFRESCO_PREFIX, "parseXMLDocument", namespacePrefixResolver), new RenderingEngine.TemplateProcessorMethod() @@ -474,8 +518,10 @@ public class RenderingEngineTemplateImpl path = AVMUtil.buildPath(parentPath, path, AVMUtil.PathRelation.WEBAPP_RELATIVE); - LOGGER.debug("tpm_parseXMLDocument('" + path + - "'), parentPath = " + parentPath); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("tpm_parseXMLDocument('" + path + "'), parentPath = " + parentPath); + final Document d = fdf.parseXMLDocument(path); return d != null ? d.getDocumentElement() : null; } @@ -511,12 +557,17 @@ public class RenderingEngineTemplateImpl path, AVMUtil.PathRelation.WEBAPP_RELATIVE); final String formName = (String)arguments[0]; - LOGGER.debug("tpm_parseXMLDocuments('" + formName + "','" + path + - "'), parentPath = " + parentPath); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("tpm_parseXMLDocuments('" + formName + "','" + path + + "'), parentPath = " + parentPath); + final Map resultMap = fdf.parseXMLDocuments(formName, path); - LOGGER.debug("received " + resultMap.size() + - " documents in " + path + - " with form name " + formName); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("received " + resultMap.size() + + " documents in " + path + + " with form name " + formName); // create a root document for rooting all the results. we do this // so that each document root element has a common parent node @@ -564,7 +615,10 @@ public class RenderingEngineTemplateImpl } final String path = (String)arguments[0]; - LOGGER.debug("tpm_getAVMPAth('" + path + "'), parentPath = " + parentPath); + + if (LOGGER.isDebugEnabled()) + LOGGER.debug("tpm_getAVMPAth('" + path + "'), parentPath = " + parentPath); + return AVMUtil.buildPath(parentPath, path, AVMUtil.PathRelation.WEBAPP_RELATIVE); diff --git a/source/test-resources/xforms/demos/press-release/press-release.xsl b/source/test-resources/xforms/demos/press-release/press-release.xsl index 3fdea7746b..b836e5c8b5 100644 --- a/source/test-resources/xforms/demos/press-release/press-release.xsl +++ b/source/test-resources/xforms/demos/press-release/press-release.xsl @@ -59,7 +59,8 @@ Produces an html rendition of a press release

- + +

@@ -68,7 +69,8 @@ Produces an html rendition of a press release

About

-

+ +