From 3d6221f39e643b3dd63433ff0974076ec8611643 Mon Sep 17 00:00:00 2001 From: Ariel Backenroth Date: Tue, 24 Oct 2006 22:43:05 +0000 Subject: [PATCH] update to press release component of sample website - adding sub navigation to press release page to generate navigation by category in xsl (demoware for virgin) - adding sub navigation to index.jsp to generate navigation by category (also demoware for virgin) - cleanup of freemarker template and all sorts of fancy xpath stuff - putting the company footer data type directly in the press release.xsd rather than having a seperate xsd. while this makes the form creation process a bit confusing, it demonstrates why the root element name field is there, and minimizes files. also forced me to clean up some major overloading of pr:company_footer. changes to form data functions - renamed getXMLDocument and getXMLDocuments to parseXMLDocument since it's now returning the document element rather than documents so that xpath traversal works (also since the document is completely useless in the context of templates) adding bsf.jar so that hopefully someday i can write extension functions in javascript within xsl templates (couldn't get it to work). git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/WCM-DEV2/root@4217 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261 --- project-build.xml | 3 + .../web/forms/AbstractRenderingEngine.java | 21 ++- .../alfresco/web/forms/FormDataFunctions.java | 4 +- .../org/alfresco/web/forms/FormsService.java | 12 +- .../web/forms/FreeMarkerRenderingEngine.java | 51 +++-- ...ervletContextFormDataFunctionsAdapter.java | 10 +- .../web/forms/XSLTRenderingEngine.java | 86 ++++++--- .../alfresco/web/pr/CompanyFooterBean.java | 15 +- .../org/alfresco/web/pr/PressReleaseBean.java | 174 +++++++++++++----- .../websites/alfresco/ROOT/WEB-INF/pr.tld | 16 +- .../websites/alfresco/ROOT/WEB-INF/web.xml | 2 +- ...et_company_footer_choices_simple_type.jsp} | 8 +- .../alfresco/ROOT/media/releases/index.jsp | 21 ++- .../demos/press-release/company-footer.xsd | 14 -- .../press-release-plain-text.ftl | 31 ++-- .../demos/press-release/press-release.xsd | 43 ++++- .../demos/press-release/press-release.xsl | 91 +++++++-- .../output-method-callout.ftl | 24 ++- .../output-method-callout.xsl | 19 +- 19 files changed, 459 insertions(+), 186 deletions(-) rename source/test-resources/websites/alfresco/ROOT/media/releases/{get_company_footer_simple_type.jsp => get_company_footer_choices_simple_type.jsp} (91%) delete mode 100644 source/test-resources/xforms/demos/press-release/company-footer.xsd diff --git a/project-build.xml b/project-build.xml index 07b7cb4d65..1ecf12e851 100644 --- a/project-build.xml +++ b/project-build.xml @@ -106,6 +106,9 @@ + + + diff --git a/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java b/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java index b8c2cfcefc..a85faff8f6 100644 --- a/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/AbstractRenderingEngine.java @@ -83,18 +83,25 @@ public abstract class AbstractRenderingEngine protected static String toAVMPath(final String parentAVMPath, final String path) { String parent = parentAVMPath; - if (path != null && path.length() != 0 && path.charAt(0) == '/') + if (path == null || + path.length() == 0 || + ".".equals(path) || + "./".equals(path)) { + return parentAVMPath; + } + + if (path.charAt(0) == '/') + { + //XXXarielb this doesn't work with context paths for the website parent = parentAVMPath.substring(0, parentAVMPath.indexOf(':') + ('/' + AVMConstants.DIR_APPBASE + - '/' + AVMConstants.DIR_WEBAPPS).length() + 1); + '/' + AVMConstants.DIR_WEBAPPS).length()); } - if (parent.endsWith("/")) - { - parent = parent.substring(0, parent.length() - 1); - } - final String result = parent + '/' + path; + + final String result = + parent + (parent.endsWith("/") || path.startsWith("/") ? path : '/' + path); LOGGER.debug("built full avmPath " + result + " for parent " + parentAVMPath + " and request path " + path); diff --git a/source/java/org/alfresco/web/forms/FormDataFunctions.java b/source/java/org/alfresco/web/forms/FormDataFunctions.java index d301403f9f..915275debc 100644 --- a/source/java/org/alfresco/web/forms/FormDataFunctions.java +++ b/source/java/org/alfresco/web/forms/FormDataFunctions.java @@ -57,7 +57,7 @@ public class FormDataFunctions * @param avmPath a path within the avm repository. * @return the parsed document. */ - public Document getXMLDocument(final String avmPath) + public Document parseXMLDocument(final String avmPath) throws IOException, SAXException { @@ -85,7 +85,7 @@ public class FormDataFunctions * @param avmPath a path within the avm repository. * @return the parsed document. */ - public Map getXMLDocuments(final String formName, final String avmPath) + public Map parseXMLDocuments(final String formName, final String avmPath) throws IOException, SAXException { diff --git a/source/java/org/alfresco/web/forms/FormsService.java b/source/java/org/alfresco/web/forms/FormsService.java index cf79e42e77..401fb93a14 100644 --- a/source/java/org/alfresco/web/forms/FormsService.java +++ b/source/java/org/alfresco/web/forms/FormsService.java @@ -280,7 +280,7 @@ public final class FormsService final OutputStreamWriter out = new OutputStreamWriter(fileOut); final HashMap parameters = - this.getOutputMethodParameters(formInstanceDataFileName, + this.getRenderingEngineParameters(formInstanceDataFileName, renditionFileName, parentPath); re.generate(formInstanceData, parameters, out); @@ -356,7 +356,7 @@ public final class FormsService final OutputStreamWriter writer = new OutputStreamWriter(out); final HashMap parameters = - this.getOutputMethodParameters(formInstanceDataFileName, + this.getRenderingEngineParameters(formInstanceDataFileName, renditionFileName, parentPath); re.generate(formInstanceData, parameters, writer); @@ -366,15 +366,17 @@ public final class FormsService } } - private static HashMap getOutputMethodParameters(final String formInstanceDataFileName, - final String renditionFileName, - final String parentAvmPath) + private static HashMap getRenderingEngineParameters(final String formInstanceDataFileName, + final String renditionFileName, + final String parentAvmPath) { final HashMap parameters = new HashMap(); parameters.put("avm_sandbox_url", AVMConstants.buildAVMStoreUrl(parentAvmPath)); parameters.put("form_instance_data_file_name", formInstanceDataFileName); parameters.put("rendition_file_name", renditionFileName); parameters.put("parent_path", parentAvmPath); + final FacesContext fc = FacesContext.getCurrentInstance(); + parameters.put("request_context_path", fc.getExternalContext().getRequestContextPath()); return parameters; } diff --git a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java index d6aad22495..2e94caad45 100644 --- a/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/FreeMarkerRenderingEngine.java @@ -23,6 +23,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import javax.xml.parsers.DocumentBuilder; import org.alfresco.model.ContentModel; import org.alfresco.service.cmr.repository.ContentReader; import org.alfresco.service.cmr.repository.ContentService; @@ -48,8 +49,8 @@ public class FreeMarkerRenderingEngine private static final Log LOGGER = LogFactory.getLog(FreeMarkerRenderingEngine.class); public FreeMarkerRenderingEngine(final NodeRef nodeRef, - final NodeService nodeService, - final ContentService contentService) + final NodeService nodeService, + final ContentService contentService) { super(nodeRef, nodeService, contentService); } @@ -78,7 +79,7 @@ public class FreeMarkerRenderingEngine final TemplateHashModel instanceDataModel = NodeModel.wrap(xmlContent); // build models for each of the extension functions - final TemplateModel getXMLDocumentModel = new TemplateMethodModel() + final TemplateModel parseXMLDocumentModel = new TemplateMethodModel() { public Object exec(final List args) throws TemplateModelException @@ -87,8 +88,9 @@ public class FreeMarkerRenderingEngine { final FormDataFunctions ef = FreeMarkerRenderingEngine.getFormDataFunctions(); final String path = FreeMarkerRenderingEngine.toAVMPath(parameters.get("parent_path"), - (String)args.get(0)); - return ef.getXMLDocument(path); + (String)args.get(0)); + final Document d = ef.parseXMLDocument(path); + return d != null ? d.getDocumentElement() : null; } catch (Exception e) { @@ -96,7 +98,7 @@ public class FreeMarkerRenderingEngine } } }; - final TemplateModel getXMLDocumentsModel = new TemplateMethodModel() + final TemplateModel parseXMLDocumentsModel = new TemplateMethodModel() { public Object exec(final List args) throws TemplateModelException @@ -104,20 +106,35 @@ public class FreeMarkerRenderingEngine try { final FormDataFunctions ef = FreeMarkerRenderingEngine.getFormDataFunctions(); - final String path = FreeMarkerRenderingEngine.toAVMPath(parameters.get("parent_path"), - args.size() == 1 ? "" : (String)args.get(1)); - final Map resultMap = ef.getXMLDocuments((String)args.get(0), path); + final String path = + FreeMarkerRenderingEngine.toAVMPath(parameters.get("parent_path"), + args.size() == 1 ? "" : (String)args.get(1)); + final Map resultMap = ef.parseXMLDocuments((String)args.get(0), path); LOGGER.debug("received " + resultMap.size() + " documents in " + path); + + // create a root document for rooting all the results. we do this + // so that each document root element has a common parent node + // and so that xpath axes work properly + final FormsService fs = FormsService.getInstance(); + final DocumentBuilder documentBuilder = fs.getDocumentBuilder(); + final Document rootNodeDocument = documentBuilder.newDocument(); + final Element rootNodeDocumentEl = + rootNodeDocument.createElementNS(ALFRESCO_NS, + ALFRESCO_NS_PREFIX + ":file_list"); + rootNodeDocumentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); + rootNodeDocument.appendChild(rootNodeDocumentEl); + final List result = new ArrayList(resultMap.size()); for (Map.Entry e : resultMap.entrySet()) { - final Document d = e.getValue(); - final Element documentEl = d.getDocumentElement(); + final Element documentEl = e.getValue().getDocumentElement(); documentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); documentEl.setAttributeNS(ALFRESCO_NS, - ALFRESCO_NS_PREFIX + ":file-name", + ALFRESCO_NS_PREFIX + ":file_name", e.getKey()); - result.add(NodeModel.wrap(d)); + final Node n = rootNodeDocument.importNode(documentEl, true); + rootNodeDocumentEl.appendChild(n); + result.add(NodeModel.wrap(n)); } return result; } @@ -135,13 +152,13 @@ public class FreeMarkerRenderingEngine public TemplateModel get(final String key) throws TemplateModelException { - if ("getXMLDocument".equals(key)) + if ("parseXMLDocument".equals(key)) { - return getXMLDocumentModel; + return parseXMLDocumentModel; } - if ("getXMLDocuments".equals(key)) + if ("parseXMLDocuments".equals(key)) { - return getXMLDocumentsModel; + return parseXMLDocumentsModel; } return super.get(key); } diff --git a/source/java/org/alfresco/web/forms/ServletContextFormDataFunctionsAdapter.java b/source/java/org/alfresco/web/forms/ServletContextFormDataFunctionsAdapter.java index e3543c7138..42ab1a9e89 100644 --- a/source/java/org/alfresco/web/forms/ServletContextFormDataFunctionsAdapter.java +++ b/source/java/org/alfresco/web/forms/ServletContextFormDataFunctionsAdapter.java @@ -48,18 +48,18 @@ public class ServletContextFormDataFunctionsAdapter return path; } - public Document getXMLDocument(final String path) + public Document parseXMLDocument(final String path) throws IOException, SAXException { - return super.getXMLDocument(this.toAVMPath(path)); + return super.parseXMLDocument(this.toAVMPath(path)); } - public Map getXMLDocuments(final String formName, - final String path) + public Map parseXMLDocuments(final String formName, + final String path) throws IOException, SAXException { - return super.getXMLDocuments(formName, this.toAVMPath(path)); + return super.parseXMLDocuments(formName, this.toAVMPath(path)); } } \ No newline at end of file diff --git a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java index 588b5b289a..3e2925404d 100644 --- a/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java +++ b/source/java/org/alfresco/web/forms/XSLTRenderingEngine.java @@ -20,6 +20,7 @@ import java.io.*; import java.net.URI; import java.net.URISyntaxException; import java.util.*; +import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.Source; import javax.xml.transform.Templates; @@ -37,6 +38,7 @@ import org.alfresco.model.WCMModel; import org.alfresco.service.cmr.repository.ContentService; import org.alfresco.service.cmr.repository.NodeRef; import org.alfresco.service.cmr.repository.NodeService; +import org.alfresco.web.forms.FormsService; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xalan.extensions.ExpressionContext; @@ -46,7 +48,14 @@ import org.w3c.dom.*; import org.w3c.dom.traversal.NodeFilter; import org.w3c.dom.traversal.NodeIterator; import org.xml.sax.SAXException; +import org.apache.bsf.BSFManager; +/** + * A rendering engine which uses xsl templates to generate renditions of + * form instance data. + * + * @author Ariel Backenroth + */ public class XSLTRenderingEngine extends AbstractRenderingEngine { @@ -54,8 +63,8 @@ public class XSLTRenderingEngine private static final Log LOGGER = LogFactory.getLog(XSLTRenderingEngine.class); public XSLTRenderingEngine(final NodeRef nodeRef, - final NodeService nodeService, - final ContentService contentService) + final NodeService nodeService, + final ContentService contentService) { super(nodeRef, nodeService, contentService); } @@ -67,37 +76,60 @@ public class XSLTRenderingEngine return o == null ? null : XSLTRenderingEngine.toAVMPath(o.toString(), path); } - public static Document getXMLDocument(final ExpressionContext ec, final String path) + public static Node parseXMLDocument(final ExpressionContext ec, final String path) throws TransformerException, IOException, SAXException { final FormDataFunctions ef = XSLTRenderingEngine.getFormDataFunctions(); - return ef.getXMLDocument(XSLTRenderingEngine.toAVMPath(ec, path)); + final Document d = ef.parseXMLDocument(XSLTRenderingEngine.toAVMPath(ec, path)); + return d != null ? d.getDocumentElement() : null; } - public static NodeIterator getXMLDocuments(final ExpressionContext ec, - final String formName) + public static NodeIterator parseXMLDocuments(final ExpressionContext ec, + final String formName) throws TransformerException, IOException, SAXException { - return XSLTRenderingEngine.getXMLDocuments(ec, formName, ""); + return XSLTRenderingEngine.parseXMLDocuments(ec, formName, ""); } - public static NodeIterator getXMLDocuments(final ExpressionContext ec, - final String formName, - String path) + public static NodeIterator parseXMLDocuments(final ExpressionContext ec, + final String formName, + String path) throws TransformerException, IOException, SAXException { final FormDataFunctions ef = XSLTRenderingEngine.getFormDataFunctions(); path = XSLTRenderingEngine.toAVMPath(ec, path); - final Map resultMap = ef.getXMLDocuments(formName, path); + final Map resultMap = ef.parseXMLDocuments(formName, path); LOGGER.debug("received " + resultMap.size() + " documents in " + path); - final List> documents = - new ArrayList>(resultMap.entrySet()); + + // create a root document for rooting all the results. we do this + // so that each document root element has a common parent node + // and so that xpath axes work properly + final FormsService fs = FormsService.getInstance(); + final DocumentBuilder documentBuilder = fs.getDocumentBuilder(); + final Document rootNodeDocument = documentBuilder.newDocument(); + final Element rootNodeDocumentEl = + rootNodeDocument.createElementNS(ALFRESCO_NS, + ALFRESCO_NS_PREFIX + ":file_list"); + rootNodeDocumentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); + rootNodeDocument.appendChild(rootNodeDocumentEl); + + final List documents = new ArrayList(resultMap.size()); + for (Map.Entry mapEntry : resultMap.entrySet()) + { + final Element documentEl = mapEntry.getValue().getDocumentElement(); + documentEl.setAttributeNS(ALFRESCO_NS, + ALFRESCO_NS_PREFIX + ":file_name", + mapEntry.getKey()); + final Node n = rootNodeDocument.importNode(documentEl, true); + documents.add(n); + rootNodeDocumentEl.appendChild(n); + } return new NodeIterator() { @@ -130,8 +162,7 @@ public class XSLTRenderingEngine public Node getRoot() { - LOGGER.error("NodeIterator.getRoot() unexpectedly called"); - throw new UnsupportedOperationException(); + return rootNodeDocumentEl; } public int getWhatToShow() @@ -147,7 +178,7 @@ public class XSLTRenderingEngine throw new DOMException(DOMException.INVALID_STATE_ERR, null); if (index == documents.size()) return null; - return this.getNodeAt(index++); + return documents.get(index++); } public Node previousNode() @@ -158,18 +189,7 @@ public class XSLTRenderingEngine throw new DOMException(DOMException.INVALID_STATE_ERR, null); if (index == -1) return null; - return this.getNodeAt(index--); - } - - private Document getNodeAt(int index) - { - final Document d = documents.get(index).getValue(); - final Element documentEl = d.getDocumentElement(); - documentEl.setAttribute("xmlns:" + ALFRESCO_NS_PREFIX, ALFRESCO_NS); - documentEl.setAttributeNS(ALFRESCO_NS, - ALFRESCO_NS_PREFIX + ":file-name", - documents.get(index).getKey()); - return d; + return documents.get(index--); } }; } @@ -214,8 +234,8 @@ public class XSLTRenderingEngine throws IOException, RenderingEngine.RenderingException { - // XXXarielb - dirty - fix this - final String sandBoxUrl = (String)parameters.get("avm_store_url"); + System.setProperty("org.apache.xalan.extensions.bsf.BSFManager", + BSFManager.class.getName()); final TransformerFactory tf = TransformerFactory.newInstance(); final FormsService ts = FormsService.getInstance(); Document xslDocument = null; @@ -243,11 +263,17 @@ public class XSLTRenderingEngine LOGGER.error(tce); throw new RenderingEngine.RenderingException(tce); } + + // create a uri resolver to resolve document() calls to the virtualized + // web application t.setURIResolver(new URIResolver() { public Source resolve(final String href, final String base) throws TransformerException { + // XXXarielb - dirty - fix this + final String sandBoxUrl = (String)parameters.get("avm_sandbox_url"); + URI uri = null; try { diff --git a/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/CompanyFooterBean.java b/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/CompanyFooterBean.java index 64cc8d64f4..3a080bbce3 100644 --- a/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/CompanyFooterBean.java +++ b/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/CompanyFooterBean.java @@ -23,9 +23,10 @@ import org.alfresco.web.forms.*; /** * Bean for getting data for company footers which are included within press release forms. - * It's used by /media/releases/get_company_footer_simple_type.jsp to aggregate all - * forms created by company-footer.xsd in /media/releases/content and generate an - * xsd simpleType enumeration which is used within the press release form (press-release.xsd). + * It's used by /media/releases/get_company_footer_choices_simple_type.jsp to aggregate all + * forms created by press-release.xsd with company_footer as the root tag name + * in /media/releases/content and generate an xsd simpleType enumeration which is used within + * the press release form. * press-release.xsl then uses the selected company footers and loads the xml assets and * includes their content within the generated press release renditions. */ @@ -42,20 +43,20 @@ public class CompanyFooterBean * * @return a list of populated CompanyFooterBeans. */ - public static List getCompanyFooters(final PageContext pageContext) + public static List getCompanyFooterChoices(final PageContext pageContext) throws Exception { final FormDataFunctions ef = new ServletContextFormDataFunctionsAdapter(pageContext.getServletContext()); - final Map entries = ef.getXMLDocuments("company-footer", - "/media/releases/content"); + final Map entries = + ef.parseXMLDocuments("company-footer", "/media/releases/content"); final List result = new ArrayList(entries.size()); for (Map.Entry entry : entries.entrySet()) { final String fileName = entry.getKey(); final Document d = entry.getValue(); - final Element n = (Element)d.getElementsByTagName("alfresco:name").item(0); + final Element n = (Element)d.getElementsByTagName("pr:name").item(0); result.add(new CompanyFooterBean(n.getFirstChild().getNodeValue(), fileName)); } diff --git a/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/PressReleaseBean.java b/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/PressReleaseBean.java index b811b80da6..877c324770 100644 --- a/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/PressReleaseBean.java +++ b/source/test-resources/websites/alfresco/ROOT/WEB-INF/classes/org/alfresco/web/pr/PressReleaseBean.java @@ -38,73 +38,145 @@ public class PressReleaseBean * * @return a list of populated PressReleaseBeans. */ - public static List getPressReleases(final PageContext pageContext) - throws Exception - { - final FormDataFunctions ef = - new ServletContextFormDataFunctionsAdapter(pageContext.getServletContext()); + public static List getPressReleases(final PageContext pageContext) + throws Exception + { + final FormDataFunctions ef = + new ServletContextFormDataFunctionsAdapter(pageContext.getServletContext()); - final Map entries = ef.getXMLDocuments("press-release", "/media/releases/content"); - final List result = new ArrayList(entries.size()); - for (Map.Entry entry : entries.entrySet() ) - { - final String fileName = entry.getKey(); - final Document d = entry.getValue(); - final Element t = (Element)d.getElementsByTagName("alfresco:title").item(0); - final Element a = (Element)d.getElementsByTagName("alfresco:abstract").item(0); - final Element dateEl = (Element)d.getElementsByTagName("alfresco:launch_date").item(0); - final Date date = new SimpleDateFormat("yyyy-MM-dd").parse(dateEl.getFirstChild().getNodeValue()); - String href = "/media/releases/content/" + fileName; - href = href.replaceAll(".xml$", ".html"); - result.add(new PressReleaseBean(t.getFirstChild().getNodeValue(), - a.getFirstChild().getNodeValue(), - date, - href)); - } - return result; - } + final Map entries = + ef.parseXMLDocuments("press-release", "/media/releases/content"); + final List result = new ArrayList(entries.size()); + for (Map.Entry entry : entries.entrySet()) + { + result.add(PressReleaseBean.loadPressRelease(entry.getValue(), entry.getKey())); + } + return result; + } - private final String title; - private final String theAbstract; - private final Date launchDate; - private final String href; + /** + * Provides a list of press releases for a specified category. + * + * @param pageContext the page context from the jsp + * @param category the category to search for + * + * @return all press releases within the specified category. + */ + public static List getPressReleasesInCategory(final PageContext pageContext, + final String category) + throws Exception + { + final FormDataFunctions ef = + new ServletContextFormDataFunctionsAdapter(pageContext.getServletContext()); - public PressReleaseBean(final String title, - final String theAbstract, - final Date launchDate, - final String href) - { - this.title = title; - this.theAbstract = theAbstract; - this.launchDate = launchDate; - this.href = href; - } + final Map entries = + ef.parseXMLDocuments("press-release", "/media/releases/content"); + final List result = new ArrayList(entries.size()); + for (Map.Entry entry : entries.entrySet()) + { + final Document d = entry.getValue(); + final Element cEl = (Element) + d.getElementsByTagName("pr:category").item(0); + + if (category.equals(cEl.getFirstChild().getNodeValue())) + { + result.add(PressReleaseBean.loadPressRelease(d, entry.getKey())); + } + } + return result; + } + + /** + * Returns a set of unique categories used by the press releases in sorted order. + * + * @param pageContext the page context variable from the jsp + * + * @return a set of unique categories used by the press releases in sorted order. + */ + public static Set getPressReleaseCategories(final PageContext pageContext) + throws Exception + { + final FormDataFunctions ef = + new ServletContextFormDataFunctionsAdapter(pageContext.getServletContext()); + + final TreeSet result = new TreeSet(); + final Map entries = + ef.parseXMLDocuments("press-release", "/media/releases/content"); + for (Map.Entry entry : entries.entrySet()) + { + final Element cEl = (Element) + entry.getValue().getElementsByTagName("pr:category").item(0); + result.add(cEl.getFirstChild().getNodeValue()); + } + return result; + } + + /** + * Utility function to create an instance of a press release using + * form instance data. + * + * @param d the xml document + * @param fileName the filename of the file from which the document was loaded. + * + * @return a press release representing the content of the file. + */ + private static PressReleaseBean loadPressRelease(final Document d, + final String fileName) + throws Exception + { + final Element t = (Element)d.getElementsByTagName("pr:title").item(0); + final Element a = (Element)d.getElementsByTagName("pr:abstract").item(0); + final Element dateEl = (Element)d.getElementsByTagName("pr:launch_date").item(0); + final Date date = new SimpleDateFormat("yyyy-MM-dd").parse(dateEl.getFirstChild().getNodeValue()); + String href = "/media/releases/content/" + fileName; + href = href.replaceAll(".xml$", ".html"); + return new PressReleaseBean(t.getFirstChild().getNodeValue(), + a.getFirstChild().getNodeValue(), + date, + href); + } + + private final String title; + private final String theAbstract; + private final Date launchDate; + private final String href; + + public PressReleaseBean(final String title, + final String theAbstract, + final Date launchDate, + final String href) + { + this.title = title; + this.theAbstract = theAbstract; + this.launchDate = launchDate; + this.href = href; + } /** * The title of the press release as defined in the xml asset. */ - public String getTitle() - { - return this.title; - } + public String getTitle() + { + return this.title; + } /** * The abstract of the press release as defined in the xml asset. */ - public String getAbstract() - { - return this.theAbstract; - } + public String getAbstract() + { + return this.theAbstract; + } /** * The launch date of the press release as defined in the xml asset. */ - public Date getLaunchDate() - { - return this.launchDate; - } + public Date getLaunchDate() + { + return this.launchDate; + } - /** + /** * Returns the url within the webapp to the xml file describing this press release * * @return the url to the xml file which will be something like /media/releases/content/[filename].xml diff --git a/source/test-resources/websites/alfresco/ROOT/WEB-INF/pr.tld b/source/test-resources/websites/alfresco/ROOT/WEB-INF/pr.tld index a39468dda3..cf4e645d30 100644 --- a/source/test-resources/websites/alfresco/ROOT/WEB-INF/pr.tld +++ b/source/test-resources/websites/alfresco/ROOT/WEB-INF/pr.tld @@ -7,15 +7,25 @@ 1.0 pr - http://www.alfresco.org/pr + http://www.alfresco.org/alfresco/pr getPressReleases org.alfresco.web.pr.PressReleaseBean java.util.List getPressReleases(javax.servlet.jsp.PageContext) - getCompanyFooters + getPressReleasesInCategory + org.alfresco.web.pr.PressReleaseBean + java.util.List getPressReleasesInCategory(javax.servlet.jsp.PageContext, java.lang.String) + + + getPressReleaseCategories + org.alfresco.web.pr.PressReleaseBean + java.util.Set getPressReleaseCategories(javax.servlet.jsp.PageContext) + + + getCompanyFooterChoices org.alfresco.web.pr.CompanyFooterBean - java.util.List getCompanyFooters(javax.servlet.jsp.PageContext) + java.util.List getCompanyFooterChoices(javax.servlet.jsp.PageContext) diff --git a/source/test-resources/websites/alfresco/ROOT/WEB-INF/web.xml b/source/test-resources/websites/alfresco/ROOT/WEB-INF/web.xml index 712e01ee63..804de313f7 100644 --- a/source/test-resources/websites/alfresco/ROOT/WEB-INF/web.xml +++ b/source/test-resources/websites/alfresco/ROOT/WEB-INF/web.xml @@ -39,7 +39,7 @@ - http://www.alfresco.org/pr + http://www.alfresco.org/alfresco/pr /WEB-INF/pr.tld diff --git a/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_simple_type.jsp b/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp similarity index 91% rename from source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_simple_type.jsp rename to source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp index 272faee9d0..bfd325a692 100644 --- a/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_simple_type.jsp +++ b/source/test-resources/websites/alfresco/ROOT/media/releases/get_company_footer_choices_simple_type.jsp @@ -21,7 +21,7 @@ which wants to update the list of available company footers dynamically. + xmlns:pr="http://www.alfresco.org/alfresco/pr"> @@ -31,7 +31,7 @@ which wants to update the list of available company footers dynamically. - + @@ -54,10 +54,10 @@ which wants to update the list of available company footers dynamically. - + - + diff --git a/source/test-resources/websites/alfresco/ROOT/media/releases/index.jsp b/source/test-resources/websites/alfresco/ROOT/media/releases/index.jsp index af839ea24d..624f2cd28f 100644 --- a/source/test-resources/websites/alfresco/ROOT/media/releases/index.jsp +++ b/source/test-resources/websites/alfresco/ROOT/media/releases/index.jsp @@ -19,7 +19,7 @@ Produces the index page for the press release page. @@ -82,6 +82,25 @@ Produces the index page for the press release page.
+

Press Releases By Category

+
    + + +
  • + +
      + +
    • + + + + +
    • +
      +
    +
  • +
    +

Press Release Archive

  • View Archived Releases
  • diff --git a/source/test-resources/xforms/demos/press-release/company-footer.xsd b/source/test-resources/xforms/demos/press-release/company-footer.xsd deleted file mode 100644 index 2741233fdf..0000000000 --- a/source/test-resources/xforms/demos/press-release/company-footer.xsd +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - diff --git a/source/test-resources/xforms/demos/press-release/press-release-plain-text.ftl b/source/test-resources/xforms/demos/press-release/press-release-plain-text.ftl index 54339547a7..e88481d403 100644 --- a/source/test-resources/xforms/demos/press-release/press-release-plain-text.ftl +++ b/source/test-resources/xforms/demos/press-release/press-release-plain-text.ftl @@ -1,22 +1,31 @@ -<#ftl ns_prefixes={"alfresco", "http://www.alfresco.org/alfresco"}> ---- ${.vars["/alfresco:press_release/alfresco:title"]} --- +<#ftl ns_prefixes={"D", "http://www.alfresco.org/alfresco/pr"}> --- ${.vars["/alfresco:press_release/alfresco:abstract"]} -- -<#list .vars["/alfresco:press_release/alfresco:body"] as body> +<#macro show_heading heading> +${heading} +<#list 1..heading?length as index>- + + +<@show_heading heading="Title: ${press_release.title}"/> + +<@show_heading heading="Abstract: ${press_release.abstract}"/> + +<#list press_release.body as body> <#if body_index = 0> -${.vars["/alfresco:press_release/alfresco:location"]}--${.vars["/alfresco:press_release/alfresco:launch_date"]}-- +${press_release.location}--${press_release.launch_date}-- ${body?trim} -<#list .vars["/alfresco:press_release/alfresco:include_company_footer"] as cf> -<#assign cf_document=alfresco.getXMLDocument(cf)> --- About ${cf_document["/alfresco:company_footer/alfresco:name"]} -- - <#list cf_document["/alfresco:company_footer/alfresco:body"] as body> +<#list press_release.include_company_footer as cf> +<#assign cf_document=alfresco.parseXMLDocument(cf)> + +<@show_heading heading="About ${cf_document.name}"/> + <#list cf_document.body as body> ${body?trim} -<#if .vars["/alfresco:press_release/alfresco:include_media_contacts"] = "true"> --- Media Contacts -- +<#if press_release.include_media_contacts = "true"> + +<@show_heading heading="Media Contacts"/> John Newton Alfresco Software Inc. +44 1628 860639 diff --git a/source/test-resources/xforms/demos/press-release/press-release.xsd b/source/test-resources/xforms/demos/press-release/press-release.xsd index 7239b4a160..089a15044f 100644 --- a/source/test-resources/xforms/demos/press-release/press-release.xsd +++ b/source/test-resources/xforms/demos/press-release/press-release.xsd @@ -1,9 +1,30 @@ + - + + + + @@ -13,6 +34,18 @@ + + + + + + + + + + + + @@ -20,10 +53,10 @@ - + - + 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 c6017b81bf..a7d99f2693 100644 --- a/source/test-resources/xforms/demos/press-release/press-release.xsl +++ b/source/test-resources/xforms/demos/press-release/press-release.xsl @@ -21,7 +21,7 @@ Produces an html rendition of a press release #include virtual="/assets/include_in_head.html" - <xsl:value-of select="/alfresco:press_release/alfresco:title"/> + <xsl:value-of select="/pr:press_release/pr:title"/> - +