/* * The contents of this file are subject to the Mozilla Public License Version 1.1 * (the "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at . * * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT * WARRANTY OF ANY KIND, either express or implied. See the License for the specific * language governing rights and limitations under the License. * * The Original Code is the Venice Web Communities System. * * The Initial Developer of the Original Code is Eric J. Bowersox , * for Silverwrist Design Studios. Portions created by Eric J. Bowersox are * Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved. * * Contributor(s): */ package com.silverwrist.venice.servlets.format; import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import javax.xml.parsers.*; import org.apache.log4j.*; import org.w3c.dom.*; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import com.silverwrist.util.DOMElementHelper; import com.silverwrist.util.IOUtil; import com.silverwrist.util.StringUtil; import com.silverwrist.venice.core.AccessError; import com.silverwrist.venice.core.ConfigException; import com.silverwrist.venice.core.DataException; import com.silverwrist.venice.core.UserContext; import com.silverwrist.venice.core.VeniceEngine; import com.silverwrist.venice.servlets.Variables; import com.silverwrist.venice.servlets.format.menus.LeftMenu; import com.silverwrist.venice.servlets.format.sideboxes.SideBoxFactory; public class RenderConfig implements ColorSelectors { /*-------------------------------------------------------------------------------- * Static data values *-------------------------------------------------------------------------------- */ protected static final String ATTR_NAME = "com.silverwrist.venice.servlets.RenderConfig"; protected static final String CONFIG_FILE_PARAM = "render.config"; private static Category logger = Category.getInstance(RenderConfig.class); private static Map colornames_map; /*-------------------------------------------------------------------------------- * Attributes *-------------------------------------------------------------------------------- */ private Document config; private String site_title; private boolean want_comments; private boolean allow_gzip; private boolean no_smart_tags; private String font_face; private File stylesheet; private long stylesheet_time = 0; private String image_url; private String static_url; private String site_logo; private int site_logo_width = 140; private int site_logo_height = 80; private String site_logo_linkURL = null; private HashMap stock_messages; private HashMap menus; private String[] colors_array; private int footer_logo_scale; private Map sidebox_factories; /*-------------------------------------------------------------------------------- * Constructor *-------------------------------------------------------------------------------- */ protected RenderConfig(String config_file, String root_file_path) throws ConfigException { config = loadConfiguration(config_file); // Make sure the configuration is valid... Element root = config.getDocumentElement(); if (!(root.getTagName().equals("render-config"))) { // not the correct root tag name logger.fatal("config document is not a document (root tag: <" + root.getTagName() + "/>)"); throw new ConfigException("document is not a document",root); } // end if // Get the site name. DOMElementHelper root_h = new DOMElementHelper(root); site_title = root_h.getSubElementText("site-name"); if (site_title==null) { // no section - bail out now! logger.fatal("config document has no element"); throw new ConfigException("no section found in config file",root); } // end if if (logger.isDebugEnabled()) logger.debug("Site title: " + site_title); Element render_sect = root_h.getSubElement("rendering"); if (render_sect==null) { // no section - bail out now! logger.fatal("config document has no section"); throw new ConfigException("no section found in config file",root); } // end if DOMElementHelper render_sect_h = new DOMElementHelper(render_sect); want_comments = render_sect_h.hasChildElement("html-comments"); allow_gzip = render_sect_h.hasChildElement("gzip-output"); no_smart_tags = !(render_sect_h.hasChildElement("ms-copyright-violations")); if (logger.isDebugEnabled()) { // log the read values logger.debug("Use HTML comments: " + String.valueOf(want_comments)); logger.debug("Use GZIP encoding: " + String.valueOf(allow_gzip)); logger.debug("Disable IE Smart Tags: " + String.valueOf(no_smart_tags)); } // end if font_face = render_sect_h.getSubElementText("font"); if (font_face==null) { // no tag - bail out now! logger.fatal(" section has no element"); throw new ConfigException("no found in section",render_sect); } // end if if (logger.isDebugEnabled()) logger.debug("Font face: " + font_face); String stylesheet_loc = render_sect_h.getSubElementText("stylesheet"); if (stylesheet_loc!=null) { // we're using Cascading Stylesheets - load it and test for existence if (!(stylesheet_loc.startsWith("/"))) stylesheet_loc = root_file_path + stylesheet_loc; if (logger.isDebugEnabled()) logger.debug("Stylesheet location: " + stylesheet_loc); // Test to make sure the stylesheet is actually present. stylesheet = new File(stylesheet_loc); if (!(stylesheet.exists() && stylesheet.canRead())) { // it's not there - bail out! logger.fatal("unable to read stylesheet file: " + stylesheet_loc); throw new ConfigException("stylesheet " + stylesheet_loc + " cannot be read",render_sect); } // end if } // end if else // no stylesheet stylesheet = null; Element colors_sect = render_sect_h.getSubElement("colors"); if (colors_sect==null) { // no tag - bail out now! logger.fatal(" section has no element"); throw new ConfigException("no found in section",render_sect); } // end if colors_array = new String[colornames_map.size()]; int i; NodeList colors_nlist = colors_sect.getChildNodes(); for (i=0; i section - bail out now! logger.fatal("config document has no section"); throw new ConfigException("no section found in config file",root); } // end if DOMElementHelper paths_sect_h = new DOMElementHelper(paths_sect); image_url = paths_sect_h.getSubElementText("image"); if (image_url==null) { // no tag - bail out now! logger.fatal(" section has no element"); throw new ConfigException("no found in section",paths_sect); } // end if if (logger.isDebugEnabled()) logger.debug("Image path: " + image_url); static_url = paths_sect_h.getSubElementText("static"); if (static_url==null) { // no tag - bail out now! logger.fatal(" section has no element"); throw new ConfigException("no found in section",paths_sect); } // end if if (logger.isDebugEnabled()) logger.debug("Static files path: " + static_url); Element site_logo_elt = paths_sect_h.getSubElement("site-logo"); if (site_logo_elt==null) { // no tag - bail out now! logger.fatal(" section has no element"); throw new ConfigException("no found in section",paths_sect); } // end if DOMElementHelper site_logo_h = new DOMElementHelper(site_logo_elt); site_logo = site_logo_h.getElementText(); if (site_logo==null) { // no site logo specified - bail out now! logger.fatal(" section has no site logo element"); throw new ConfigException("no site logo found in section",paths_sect); } // end if // get logo width and height Integer fooint = site_logo_h.getAttributeInt("width"); if (fooint!=null) site_logo_width = fooint.intValue(); fooint = site_logo_h.getAttributeInt("height"); if (fooint!=null) site_logo_height = fooint.intValue(); // get logo link URL String tmp = site_logo_elt.getAttribute("href"); if (!(StringUtil.isStringEmpty(tmp))) site_logo_linkURL = tmp; if (logger.isDebugEnabled()) logger.debug("Site logo: " + site_logo); // Load the sidebox configuration information. String sidebox_config = paths_sect_h.getSubElementText("sidebox-config"); if (sidebox_config==null) { // the sidebox config was not present logger.fatal(" section has no element"); throw new ConfigException("no found in section",paths_sect); } // end if if (!(sidebox_config.startsWith("/"))) sidebox_config = root_file_path + sidebox_config; Document sb_doc = loadConfiguration(sidebox_config); Element sb_root = sb_doc.getDocumentElement(); if (!(sb_root.getTagName().equals("sidebox-config"))) { // the sidebox configuration file isn't the right type logger.fatal("config document is not a document (root tag: <" + sb_root.getTagName() + "/>)"); throw new ConfigException("document is not a document",sb_root); } // end if NodeList sb_nodes = sb_root.getChildNodes(); HashMap tmp_factories = new HashMap(); for (i=0; i specified with no ID!"); throw new ConfigException("no ID specified in ",sb); } // end if // convert to an integer which we'll be using later in the HashMap Integer id = new Integer(tmp); // get the name of the factory class DOMElementHelper sb_h = new DOMElementHelper(sb); tmp = sb_h.getSubElementText("factory-class"); if (StringUtil.isStringEmpty(tmp)) { // the factory class was not specified! logger.fatal(" config incomplete (missing )!"); throw new ConfigException("configuration of is not complete!",sb); } // end if Class factory_class = Class.forName(tmp); SideBoxFactory factory = (SideBoxFactory)(factory_class.newInstance()); factory.setConfiguration(sb); tmp_factories.put(id,factory); } // end if catch (NumberFormatException e1) { // ID value was not an integer logger.fatal(" ID not numeric!"); throw new ConfigException("non-numeric ID specified in ",sb); } // end catch catch (ClassNotFoundException e2) { // sidebox could not be configured logger.fatal(" config not valid!",e2); throw new ConfigException(" in is not a valid class!",sb); } // end catch catch (IllegalAccessException e3) { // could not access class and/or constructor logger.fatal(" is not accessible!",e3); throw new ConfigException(" in is not accessible!",sb); } // end catch catch (InstantiationException e4) { // unable to create the class logger.fatal(" could not be instantiated!",e4); throw new ConfigException(" in could not be created!",sb); } // end catch catch (ClassCastException e5) { // the class is not a SideBoxFactory implementor - cannot create logger.fatal(" is not a SideBoxFactory!",e5); throw new ConfigException(" in is not the correct type!",sb); } // end catch } // end if } // end for sidebox_factories = Collections.unmodifiableMap(tmp_factories); Element msg_sect = root_h.getSubElement("messages"); if (msg_sect==null) { // no section - bail out now! logger.fatal("config document has no section"); throw new ConfigException("no section found in config file",root); } // end if // Initialize the stock messages list. stock_messages = new HashMap(); NodeList msg_nodes = msg_sect.getChildNodes(); for (i=0; i section - bail out now! logger.fatal("config document has no section"); throw new ConfigException("no section found in config file",root); } // end if // Initialize the menus list. menus = new HashMap(); NodeList menu_nodes = menu_sect.getChildNodes(); for (i=0; i subnodes and use them to initialize menus Node mn = menu_nodes.item(i); if (mn.getNodeType()==Node.ELEMENT_NODE) { // found an element - now check it's name if (mn.getNodeName().equals("menudef")) { // root of a menu definition - get its ID, build it, and save it Element mel = (Element)mn; String menuid = mel.getAttribute("id"); if (menuid==null) { // no menu ID attribute logger.fatal(" seen with no \"id\" attribute"); throw new ConfigException(" seen with no \"id\" attribute",mel); } // end if // create the menu and add it to the mapping LeftMenu menu = new LeftMenu(mel,menuid); menus.put(menuid,menu); if (logger.isDebugEnabled()) logger.debug("menu \"" + menuid + "\" defined"); } // end if (found the root of a menu definition) else { // unknown element - bail out! logger.fatal("config document has unknown node <" + mn.getNodeName() + "/> inside "); throw new ConfigException("unknown node name <" + mn.getNodeName() + "/> in ", menu_sect); } // end else } // end if } // end for if (logger.isDebugEnabled()) logger.debug(menus.size() + " menu definitions loaded from config"); } // end constructor /*-------------------------------------------------------------------------------- * Internal functions *-------------------------------------------------------------------------------- */ private static Document loadConfiguration(String configname) throws ConfigException { try { // create a simple DOM parser by using the Java XML parsing API DocumentBuilderFactory fac = DocumentBuilderFactory.newInstance(); fac.setNamespaceAware(false); fac.setValidating(false); DocumentBuilder parser = fac.newDocumentBuilder(); // access the config file and parse it into our config data tree File configfile = new File(configname); Document rc = parser.parse(configfile); if (logger.isDebugEnabled()) logger.debug("configuration loaded successfully"); return rc; } // end try catch (FactoryConfigurationError e1) { // if the document builder factory could not be created logger.fatal("Parser factory configuration error: " + e1.getMessage(),e1); throw new ConfigException("XML parser factory could not be created - " + e1.getMessage()); } // end catch catch (ParserConfigurationException e2) { // if the XML parser itself could not be created logger.fatal("Parser configuration error: " + e2.getMessage(),e2); throw new ConfigException("XML parser could not be created - " + e2.getMessage(),e2); } // end catch catch (SAXException e3) { // if the XML parser choked on our document if (e3 instanceof SAXParseException) { // we have a detailed message - make a proper exception SAXParseException e3a = (SAXParseException)e3; logger.fatal("Config file error [" + configname + ":" + e3a.getLineNumber() + "," + e3a.getColumnNumber() + "]: " + e3a.getMessage(),e3a); throw new ConfigException("Configuration file error: " + e3a.getMessage() + " at line " + e3a.getLineNumber() + ", column " + e3a.getColumnNumber(),e3a); } // end if else { // generic exception - just send up a simple error message logger.fatal("Config file error [" + configname + "]: " + e3.getMessage(),e3); throw new ConfigException("Configuration file error - " + e3.getMessage(),e3); } // end else } // end catch catch (IOException e4) { // error reading the config file itself off the disk logger.fatal("IO error reading config: " + e4.getMessage(),e4); throw new ConfigException("unable to read config file \"" + configname + "\" - " + e4.getMessage(),e4); } // end catch } // end loadConfiguration /*-------------------------------------------------------------------------------- * External operations usable only by RenderData *-------------------------------------------------------------------------------- */ boolean useHTMLComments() { return want_comments; } // end useHTMLComments boolean isGZIPAllowed() { return allow_gzip; } // end isGZIPAllowed boolean noSmartTags() { return no_smart_tags; } // end noSmartTags String getFullImagePath(String name) { StringBuffer buf = new StringBuffer(); buf.append(image_url).append(name); return buf.toString(); } // end getFullImagePath String getStaticFilePath(String name) { StringBuffer buf = new StringBuffer(); buf.append(static_url).append(name); return buf.toString(); } // end getStaticFilePath String getTitleTag(String specific) { StringBuffer buf = new StringBuffer(); buf.append("").append(specific).append(" - ").append(site_title).append(""); return buf.toString(); } // end getTitleTag String getSiteImageTag(int hspace, int vspace) { StringBuffer buf = new StringBuffer(); if (site_logo_linkURL!=null) buf.append(""); buf.append("\"").append(site_title);0) buf.append(" HSPACE=").append(hspace); if (vspace>0) buf.append(" VSPACE=").append(vspace); buf.append('>'); if (site_logo_linkURL!=null) buf.append(""); return buf.toString(); } // end getSiteImageTag String getStdFontTag(String color, int size) { StringBuffer buf = new StringBuffer("'); return buf.toString(); } // end getStdFontTag String getStdFontTag(int selector, int size) { if ((selector<0) || (selector>=colors_array.length)) throw new IndexOutOfBoundsException("getStdColor(): invalid color selector value"); return getStdFontTag(colors_array[selector],size); } // end getStdFontTag String getStdBaseFontTag(int size) { StringBuffer buf = new StringBuffer("*"); return buf.toString(); } // end getRequiredBullet void writeContentHeader(Writer out, String primary, String secondary) throws IOException { out.write("" + getStdFontTag(colors_array[CONTENT_HEADER],5) + "" + StringUtil.encodeHTML(primary) + ""); if (secondary!=null) out.write("  " + getStdFontTag(colors_array[CONTENT_HEADER],3) + "" + StringUtil.encodeHTML(secondary) + ""); out.write("
\n"); } // end writeContentHeader String getStockMessage(String identifier) { return (String)(stock_messages.get(identifier)); } // end getStockMessage void writeStockMessage(Writer out, String identifier) throws IOException { String text = (String)(stock_messages.get(identifier)); out.write(StringUtil.encodeHTML(text)); } // end writeStockMessage String getStdColor(int selector) { if ((selector<0) || (selector>=colors_array.length)) throw new IndexOutOfBoundsException("getStdColor(): invalid color selector value"); return colors_array[selector]; } // end getStdColor int scaleFooterLogo(int param) { return (param * footer_logo_scale) / 100; } // end scaleFooterLogo public LeftMenu getLeftMenu(String identifier) { return (LeftMenu)(menus.get(identifier)); } // end getLeftMenu synchronized String loadStyleSheetData() throws IOException { if (stylesheet==null) return null; // Load the stylesheet data. StringBuffer raw_data = IOUtil.loadText(stylesheet); stylesheet_time = stylesheet.lastModified(); // Set up the replacements map to replace the various parameters. HashMap vars = new HashMap(); vars.put("font",font_face); vars.put("color.frame",colors_array[FRAME_BACKGROUND]); vars.put("color.top.background",colors_array[TITLE_BACKGROUND]); vars.put("color.top.foreground",colors_array[TITLE_FOREGROUND]); vars.put("color.top.link",colors_array[TITLE_LINK]); vars.put("color.left.background",colors_array[LEFT_BACKGROUND]); vars.put("color.left.foreground",colors_array[LEFT_FOREGROUND]); vars.put("color.left.link",colors_array[LEFT_LINK]); vars.put("color.content.background",colors_array[CONTENT_BACKGROUND]); vars.put("color.content.foreground",colors_array[CONTENT_FOREGROUND]); vars.put("color.content.header",colors_array[CONTENT_HEADER]); vars.put("color.disabled",colors_array[CONTENT_DISABLED]); vars.put("color.error",colors_array[CONTENT_ERROR]); vars.put("color.sidebox.top.background",colors_array[SIDEBOX_TITLE_BACKGROUND]); vars.put("color.sidebox.top.foreground",colors_array[SIDEBOX_TITLE_FOREGROUND]); vars.put("color.sidebox.background",colors_array[SIDEBOX_CONTENT_BACKGROUND]); vars.put("color.sidebox.foreground",colors_array[SIDEBOX_CONTENT_FOREGROUND]); vars.put("color.sidebox.link",colors_array[SIDEBOX_CONTENT_LINK]); vars.put("color.dlg.confirm.title.background",colors_array[CONFIRM_TITLE_BACKGROUND]); vars.put("color.dlg.confirm.title.foreground",colors_array[CONFIRM_TITLE_FOREGROUND]); vars.put("color.dlg.error.title.background",colors_array[ERROR_TITLE_BACKGROUND]); vars.put("color.dlg.error.title.foreground",colors_array[ERROR_TITLE_FOREGROUND]); return StringUtil.replaceAllVariables(raw_data.toString(),vars); } // end loadStyleSheet boolean hasStyleSheetChanged() { if (stylesheet==null) return false; return (stylesheet_time!=stylesheet.lastModified()); } // end hasStyleSheetChanged boolean useStyleSheet() { return (stylesheet!=null); } // end useStyleSheet VeniceContent createSideBox(int id, VeniceEngine engine, UserContext uc) throws AccessError, DataException { SideBoxFactory fact = (SideBoxFactory)(sidebox_factories.get(new Integer(id))); if (fact==null) throw new DataException("invalid sidebox ID!"); return fact.create(engine,uc); } // end createSideBox /*-------------------------------------------------------------------------------- * Static operations for use by VeniceServlet *-------------------------------------------------------------------------------- */ public static RenderConfig getRenderConfig(ServletContext ctxt) throws ServletException { // Look in the servlet attributes first. Object obj = ctxt.getAttribute(ATTR_NAME); if (obj!=null) return (RenderConfig)obj; // Get the root file path. String root_file_path = ctxt.getRealPath("/"); if (!(root_file_path.endsWith("/"))) root_file_path += "/"; // Get the parameter for the renderer's config file. String cfgfile = ctxt.getInitParameter(CONFIG_FILE_PARAM); if (!(cfgfile.startsWith("/"))) cfgfile = root_file_path + cfgfile; logger.info("Initializing Venice rendering using config file: " + cfgfile); try { // create the RenderConfig object and save it to attributes. RenderConfig rconf = new RenderConfig(cfgfile,root_file_path); ctxt.setAttribute(ATTR_NAME,rconf); return rconf; } // end try catch (ConfigException e) { // configuration failed! post an error message logger.fatal("Rendering configuration failed: " + e.getMessage(),e); throw new ServletException("Venice rendering configuration failed: " + e.getMessage(),e); } // end catch } // end getRenderConfig public static RenderData createRenderData(ServletContext ctxt, HttpServletRequest request, HttpServletResponse response) throws ServletException { UserContext uc = Variables.getUserContext(ctxt,request,request.getSession(true)); return new RenderData(getRenderConfig(ctxt),uc,ctxt,request,response); } // end createRenderData public static RenderData createRenderData(ServletContext ctxt, UserContext uc, HttpServletRequest request, HttpServletResponse response) throws ServletException { return new RenderData(getRenderConfig(ctxt),uc,ctxt,request,response); } // end createRenderData /*-------------------------------------------------------------------------------- * Static initializer *-------------------------------------------------------------------------------- */ static { // Initialize the mapping of color names from render-config.xml to color selector IDs. HashMap m = new HashMap(); m.put("frame-bg",new Integer(FRAME_BACKGROUND)); m.put("title-bg",new Integer(TITLE_BACKGROUND)); m.put("title-fg",new Integer(TITLE_FOREGROUND)); m.put("title-link",new Integer(TITLE_LINK)); m.put("left-bg",new Integer(LEFT_BACKGROUND)); m.put("left-fg",new Integer(LEFT_FOREGROUND)); m.put("left-link",new Integer(LEFT_LINK)); m.put("content-bg",new Integer(CONTENT_BACKGROUND)); m.put("content-fg",new Integer(CONTENT_FOREGROUND)); m.put("content-hdr",new Integer(CONTENT_HEADER)); m.put("content-disabled",new Integer(CONTENT_DISABLED)); m.put("content-error",new Integer(CONTENT_ERROR)); m.put("sidebox-title-bg",new Integer(SIDEBOX_TITLE_BACKGROUND)); m.put("sidebox-title-fg",new Integer(SIDEBOX_TITLE_FOREGROUND)); m.put("sidebox-content-bg",new Integer(SIDEBOX_CONTENT_BACKGROUND)); m.put("sidebox-content-fg",new Integer(SIDEBOX_CONTENT_FOREGROUND)); m.put("sidebox-content-link",new Integer(SIDEBOX_CONTENT_LINK)); m.put("confirm-title-bg",new Integer(CONFIRM_TITLE_BACKGROUND)); m.put("confirm-title-fg",new Integer(CONFIRM_TITLE_FOREGROUND)); m.put("error-title-bg",new Integer(ERROR_TITLE_BACKGROUND)); m.put("error-title-fg",new Integer(ERROR_TITLE_FOREGROUND)); colornames_map = Collections.unmodifiableMap(m); } // end static initializer } // end class RenderConfig