diff --git a/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java b/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java index 659c2d41ac..f761631c8a 100644 --- a/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java +++ b/source/java/org/alfresco/web/app/servlet/PageRendererServlet.java @@ -155,7 +155,7 @@ public class PageRendererServlet extends WebScriptServlet try { // lookup template path from page config in website AVM store - PageDefinition pageDefinition = lookupPageDefinition(store, page); + PageDefinition pageDefinition = lookupPageDefinition(store, req.getContextPath(), page); // set response content type and charset res.setContentType(MIMETYPE_HTML); @@ -167,19 +167,24 @@ public class PageRendererServlet extends WebScriptServlet authenticate(getServletContext(), req, res); // set the web app context path for the template loader to use when rebuilding urls - this.webscriptTemplateLoader.setContextPath(req.getContextPath()); - this.webscriptTemplateLoader.setPageDefinition(pageDefinition); + LoaderPageContext context = new LoaderPageContext(); + context.Path = req.getContextPath(); + context.PageDef = pageDefinition; + context.AVMStore = store; + context.Theme = "default"; // TODO: where does this come from? + this.webscriptTemplateLoader.setContext(context); // Process the template page using our custom loader - the loader will find and buffer // individual included webscript output into the main writer for the servlet page. // TODO: where does the theme name come from!? same problem as where does store name come from... - String templatePath = getStoreSitePath(store) + '/' + "themes" + '/' + "default" + '/' + + String templatePath = getStoreSitePath(store, req.getContextPath()) + '/' + "themes" + '/' + "default" + '/' + "templates" + '/' + pageDefinition.TemplateName; if (logger.isDebugEnabled()) logger.debug("Page template resolved as: " + templatePath); - processTemplatePage(templatePath, req, res); + // execute the templte to render the page - based on the current page definition + processTemplatePage(templatePath, pageDefinition, req, res); } catch (Throwable err) { @@ -188,19 +193,24 @@ public class PageRendererServlet extends WebScriptServlet } } - private void processTemplatePage(String templatePath, HttpServletRequest req, HttpServletResponse res) + /** + * Execute the template to render the main page - based on the specified page definition config + * @throws IOException + */ + private void processTemplatePage(String templatePath, PageDefinition pageDef, HttpServletRequest req, HttpServletResponse res) throws IOException { NodeRef ref = AVMNodeConverter.ToNodeRef(-1, templatePath); - templateProcessor.process(ref.toString(), getModel(req), res.getWriter()); + templateProcessor.process(ref.toString(), getModel(pageDef, req), res.getWriter()); } - private Object getModel(HttpServletRequest req) + private Object getModel(PageDefinition pageDef, HttpServletRequest req) { // TODO: add the full template model here? // just a basic minimum model for now Map model = new HashMap(); model.put("url", new URLHelper(req.getContextPath())); + model.put("title", pageDef.Title); return model; } @@ -212,39 +222,20 @@ public class PageRendererServlet extends WebScriptServlet * * @return Path to the template content */ - private PageDefinition lookupPageDefinition(String store, String page) + private PageDefinition lookupPageDefinition(String store, String contextPath, String page) { - // Lookup page via standard Alfresco XML config - /*Config config = getConfig(); - if (config != null) - { - ConfigElement pagesConfig = config.getConfigElement("pages"); - for (ConfigElement pageConfig : pagesConfig.getChildren("page")) - { - String pageId = pageConfig.getAttribute("id"); - if (page.equals(pageId)) - { - // found page reference - if (logger.isDebugEnabled()) - logger.debug("Looked up page id: " + page + " as " + pageConfig.getValue()); - pageValue = pageConfig.getValue(); - break; - } - } - }*/ - // Lookup (and cache) config for default page-definition file in root PageDefinition defaultPageDef = defaultPageDefCache.get(store); if (defaultPageDef == null) { // read default config for the site and cache the result - String defaultConfigPath = getStoreSitePath(store) + '/' + "pages" + '/' + "page-definition.xml"; + String defaultConfigPath = getPageDefinitionPath(null, store, contextPath); defaultPageDef = readPageDefinitionConfig(defaultConfigPath, page, null); defaultPageDefCache.put(store, defaultPageDef); } // Lookup page xml config in AVM store using page name as location - String configPath = getStoreSitePath(store) + '/' + "pages" + '/' + page + '/' + "page-definition.xml"; + String configPath = getPageDefinitionPath(page, store, contextPath); // read the page definition and return it return readPageDefinitionConfig(configPath, page, defaultPageDef); @@ -276,6 +267,7 @@ public class PageRendererServlet extends WebScriptServlet throw new AlfrescoRuntimeException( "Expected 'page' root element in page-definition.xml config: " + configPath); } + String title = rootElement.attributeValue("title"); String templateName = null; if (defaultPageDef != null && defaultPageDef.TemplateName != null) @@ -299,6 +291,7 @@ public class PageRendererServlet extends WebScriptServlet // create config object for this page and store template name for this page pageDef = new PageDefinition(templateName); + pageDef.Title = title; // copy in component mappings from default config definitions first if (defaultPageDef != null) @@ -385,9 +378,25 @@ public class PageRendererServlet extends WebScriptServlet //auth.authenticateAsGuest(); } - private static String getStoreSitePath(String store) + /** + * @return the path to the site assets based on the avm store and webapp context path + */ + private static String getStoreSitePath(String store, String contextPath) { - return store + ":/" + JNDIConstants.DIR_DEFAULT_WWW + '/' + "avm_site"; + if (contextPath.length() == 0) + { + contextPath = "/ROOT"; // servlet ROOT- default hidden context path + } + return store + ":/" + JNDIConstants.DIR_DEFAULT_WWW + '/' + JNDIConstants.DIR_DEFAULT_APPBASE + contextPath; + } + + /** + * @return the page to a Page Definition config file for the specified avm store and page + */ + private static String getPageDefinitionPath(String page, String store, String contextPath) + { + return getStoreSitePath(store, contextPath) + '/' + "WEB-INF" + '/' + "pages" + '/' + + (page != null ? page + '/' : "") + "page-definition.xml"; } @@ -399,16 +408,21 @@ public class PageRendererServlet extends WebScriptServlet private String webScript; private String scriptUrl; private String encoding; + private String avmStore; + private PageComponent component; private ByteArrayOutputStream baOut = null; - PageRendererWebScriptRuntime(String webScript, String scriptUrl, String encoding) + PageRendererWebScriptRuntime( + PageComponent component, String avmStore, String webScript, String executeUrl, String encoding) { super(registry, serviceRegistry); - this.encoding = encoding; + this.component = component; + this.avmStore = avmStore; this.webScript = webScript; - this.scriptUrl = scriptUrl; + this.scriptUrl = executeUrl; + this.encoding = encoding; if (logger.isDebugEnabled()) - logger.debug("Constructing runtime for url: " + scriptUrl); + logger.debug("Constructing runtime for url: " + executeUrl); } @Override @@ -420,7 +434,12 @@ public class PageRendererServlet extends WebScriptServlet @Override protected WebScriptRequest createRequest(WebScriptMatch match) { - return new WebScriptPageRendererRequest(scriptUrl, match); + // set the component properties as the additional request attributes + Map attributes = new HashMap(); + attributes.putAll(component.Properties); + // add the well known attribute - such as avm store + attributes.put("store", this.avmStore); + return new WebScriptPageRendererRequest(scriptUrl, match, attributes); } @Override @@ -481,11 +500,38 @@ public class PageRendererServlet extends WebScriptServlet */ private class WebScriptPageRendererRequest extends WebScriptURLRequest { - WebScriptPageRendererRequest(String scriptUrl, WebScriptMatch match) + private Map attributes; + + WebScriptPageRendererRequest(String scriptUrl, WebScriptMatch match, Map attributes) { super(scriptUrl, match); + this.attributes = attributes; } + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return this.attributes.get(name); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeNames() + */ + public String[] getAttributeNames() + { + return this.attributes.keySet().toArray(new String[this.attributes.size()]); + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeValues() + */ + public Object[] getAttributeValues() + { + return this.attributes.values().toArray(new String[this.attributes.size()]); + } + public String getAgent() { return null; @@ -562,8 +608,7 @@ public class PageRendererServlet extends WebScriptServlet */ private class WebScriptTemplateLoader implements TemplateLoader { - private ThreadLocal pageDefinition = new ThreadLocal(); - private String contextPath; + private ThreadLocal context = new ThreadLocal(); private long last = 0L; public void closeTemplateSource(Object templateSource) throws IOException @@ -591,26 +636,7 @@ public class PageRendererServlet extends WebScriptServlet if (logger.isDebugEnabled()) logger.debug("Found webscript component key: " + key); - // lookup against component def config - PageComponent component = this.pageDefinition.get().Components.get(key); - if (component == null) - { - // TODO: if the lookup fails, exception or just ignore render and log...? - throw new AlfrescoRuntimeException("Failed to find component identified by key '" + key + - "' found in template: " + pageDefinition.get().TemplateName); - } - - // TODO: remove the /service prefix from all config files? - String url = component.Url; - if (url.lastIndexOf('?') != -1) - { - url = url.substring("/service".length(), url.lastIndexOf('?')); - } - else - { - url = url.substring("/service".length()); - } - return url; + return key; } else { @@ -625,10 +651,33 @@ public class PageRendererServlet extends WebScriptServlet public Reader getReader(Object templateSource, String encoding) throws IOException { + String key = templateSource.toString(); + + // lookup against component def config + LoaderPageContext context = this.context.get(); + PageComponent component = context.PageDef.Components.get(key); + if (component == null) + { + // TODO: if the lookup fails, exception or just ignore render and log...? + throw new AlfrescoRuntimeException("Failed to find component identified by key '" + key + + "' found in template: " + context.PageDef.TemplateName); + } + + // TODO: remove the /service prefix from all config files? + String webscript = component.Url; + if (webscript.lastIndexOf('?') != -1) + { + webscript = webscript.substring("/service".length(), webscript.lastIndexOf('?')); + } + else + { + webscript = webscript.substring("/service".length()); + } + // Execute the webscript and return a Reader to the textual content - String webscriptUrl = this.contextPath + "/service" + templateSource.toString(); + String executeUrl = context.Path + component.Url; PageRendererWebScriptRuntime runtime = new PageRendererWebScriptRuntime( - templateSource.toString(), webscriptUrl, encoding); + component, context.AVMStore, webscript, executeUrl, encoding); runtime.executeScript(); // Return a reader from the runtime that executed the webscript - this effectively @@ -640,25 +689,27 @@ public class PageRendererServlet extends WebScriptServlet } /** - * Setter to apply the current page definition for this template execution. A ThreadLocal is used + * Setter to apply the current context for this template execution. A ThreadLocal is used * to allow multiple servlet threads to execute using the same TemplateLoader (there can only be one) - * but with different page definitions for each thread. + * but with a different context for each thread. */ - public void setPageDefinition(PageDefinition pageDef) + public void setContext(LoaderPageContext context) { - this.pageDefinition.set(pageDef); - } - - /** - * Setter called by the servlet to ensure the loader has the full context path available - * Does not matter if called multiple times by multiple threads as value is always the same. - */ - public void setContextPath(String path) - { - this.contextPath = path; + this.context.set(context); } } + /** + * Simple structure class representing the current page context for the template loader + */ + private static class LoaderPageContext + { + PageDefinition PageDef; + String Path; + String AVMStore; + String Theme; + } + /** * Helper to return context path for generating urls */ @@ -677,9 +728,13 @@ public class PageRendererServlet extends WebScriptServlet } } + /** + * Simple structure class representing a single page definition + */ private static class PageDefinition { public String TemplateName; + public String Title; public Map Components = new HashMap(); PageDefinition(String templateId) @@ -688,6 +743,9 @@ public class PageRendererServlet extends WebScriptServlet } } + /** + * Simple structure class representing a single component definition for a page + */ private static class PageComponent { public String Id; diff --git a/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java b/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java index 7372adcc38..b8bca86968 100644 --- a/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java +++ b/source/java/org/alfresco/web/scripts/DeclarativeWebScript.java @@ -104,6 +104,13 @@ public class DeclarativeWebScript extends AbstractWebScript model.put("status", status); model.put("cache", cache); + // extract any request attributes and add them to the model - this is useful for requests + // that wish to pass further arbituary data into a webscript model + for (String name : req.getAttributeNames()) + { + model.put(name, req.getAttribute(name)); + } + // execute script if it exists if (executeScript != null) { @@ -119,7 +126,7 @@ public class DeclarativeWebScript extends AbstractWebScript } // create model for template rendering - Map templateModel = createTemplateModel(req, res, model); + Map templateModel = createTemplateModel(req, res, model); // is a redirect to a status specific template required? if (status.getRedirect()) diff --git a/source/java/org/alfresco/web/scripts/WebScriptRequest.java b/source/java/org/alfresco/web/scripts/WebScriptRequest.java index 2b9ae1871e..38eaf782c9 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptRequest.java +++ b/source/java/org/alfresco/web/scripts/WebScriptRequest.java @@ -118,6 +118,25 @@ public interface WebScriptRequest */ public String[] getParameterValues(String name); + /** + * + * @return + */ + public String[] getAttributeNames(); + + /** + * + * @param name + * @return + */ + public Object getAttribute(String name); + + /** + * + * @return + */ + public Object[] getAttributeValues(); + /** * Gets the path extension beyond the path registered for this service * diff --git a/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java index 1854f4c1f3..fd8e168386 100644 --- a/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java +++ b/source/java/org/alfresco/web/scripts/WebScriptServletRequest.java @@ -186,6 +186,30 @@ public class WebScriptServletRequest extends WebScriptRequestImpl { return req.getParameterValues(name); } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeNames() + */ + public String[] getAttributeNames() + { + return new String[0]; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeValues() + */ + public Object[] getAttributeValues() + { + return new String[0]; + } /** * Get User Agent diff --git a/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java b/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java index 98b5493c40..285a3449bc 100644 --- a/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java +++ b/source/java/org/alfresco/web/scripts/jsf/WebScriptJSFRequest.java @@ -84,4 +84,28 @@ public class WebScriptJSFRequest extends WebScriptURLRequest // NOTE: unknown in the JSF environment return null; } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeNames() + */ + public String[] getAttributeNames() + { + return new String[0]; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeValues() + */ + public Object[] getAttributeValues() + { + return new String[0]; + } } diff --git a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java index 6832a22759..2a94442bb8 100644 --- a/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java +++ b/source/java/org/alfresco/web/scripts/portlet/WebScriptPortletRequest.java @@ -116,4 +116,28 @@ public class WebScriptPortletRequest extends WebScriptURLRequest // NOTE: rely on default agent mappings return null; } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttribute(java.lang.String) + */ + public Object getAttribute(String name) + { + return null; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeNames() + */ + public String[] getAttributeNames() + { + return new String[0]; + } + + /* (non-Javadoc) + * @see org.alfresco.web.scripts.WebScriptRequest#getAttributeValues() + */ + public Object[] getAttributeValues() + { + return new String[0]; + } }