0001: /*
0002: * This file is part of PFIXCORE.
0003: *
0004: * PFIXCORE is free software; you can redistribute it and/or modify
0005: * it under the terms of the GNU Lesser General Public License as published by
0006: * the Free Software Foundation; either version 2 of the License, or
0007: * (at your option) any later version.
0008: *
0009: * PFIXCORE is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU Lesser General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU Lesser General Public License
0015: * along with PFIXCORE; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0017: *
0018: */
0019:
0020: package de.schlund.pfixxml.targets;
0021:
0022: import java.io.File;
0023: import java.io.IOException;
0024: import java.io.StringReader;
0025: import java.util.Collection;
0026: import java.util.Collections;
0027: import java.util.HashMap;
0028: import java.util.HashSet;
0029: import java.util.Iterator;
0030: import java.util.Set;
0031: import java.util.TreeMap;
0032:
0033: import javax.xml.transform.Transformer;
0034: import javax.xml.transform.TransformerConfigurationException;
0035: import javax.xml.transform.TransformerException;
0036: import javax.xml.transform.TransformerFactory;
0037: import javax.xml.transform.dom.DOMResult;
0038: import javax.xml.transform.dom.DOMSource;
0039: import javax.xml.transform.sax.SAXTransformerFactory;
0040: import javax.xml.transform.sax.TransformerHandler;
0041: import javax.xml.transform.stream.StreamSource;
0042:
0043: import org.apache.log4j.Logger;
0044: import org.apache.log4j.xml.DOMConfigurator;
0045: import org.w3c.dom.Attr;
0046: import org.w3c.dom.Document;
0047: import org.w3c.dom.Element;
0048: import org.w3c.dom.Node;
0049: import org.w3c.dom.NodeList;
0050: import org.xml.sax.InputSource;
0051: import org.xml.sax.SAXException;
0052: import org.xml.sax.XMLReader;
0053: import org.xml.sax.helpers.DefaultHandler;
0054: import org.xml.sax.helpers.XMLReaderFactory;
0055:
0056: import de.schlund.pfixcore.util.Meminfo;
0057: import de.schlund.pfixcore.workflow.NavigationFactory;
0058: import de.schlund.pfixxml.IncludeDocumentFactory;
0059: import de.schlund.pfixxml.XMLException;
0060: import de.schlund.pfixxml.config.BuildTimeProperties;
0061: import de.schlund.pfixxml.config.CustomizationHandler;
0062: import de.schlund.pfixxml.config.GlobalConfigurator;
0063: import de.schlund.pfixxml.config.includes.FileIncludeEvent;
0064: import de.schlund.pfixxml.config.includes.FileIncludeEventListener;
0065: import de.schlund.pfixxml.config.includes.IncludesResolver;
0066: import de.schlund.pfixxml.event.ConfigurationChangeEvent;
0067: import de.schlund.pfixxml.event.ConfigurationChangeListener;
0068: import de.schlund.pfixxml.resources.DocrootResource;
0069: import de.schlund.pfixxml.resources.FileResource;
0070: import de.schlund.pfixxml.resources.FileSystemResource;
0071: import de.schlund.pfixxml.resources.ResourceUtil;
0072: import de.schlund.pfixxml.targets.cachestat.SPCacheStatistic;
0073: import de.schlund.pfixxml.util.TransformerHandlerAdapter;
0074: import de.schlund.pfixxml.util.XPath;
0075: import de.schlund.pfixxml.util.Xml;
0076: import de.schlund.pfixxml.util.XsltVersion;
0077:
0078: /**
0079: * The TargetGenerator holds all the targets belonging to a certain
0080: * project (as defined by the config file used to init the Generator).
0081: *
0082: */
0083:
0084: public class TargetGenerator implements Comparable<TargetGenerator> {
0085:
0086: public static final String XSLPARAM_TG = "__target_gen";
0087:
0088: public static final String XSLPARAM_TKEY = "__target_key";
0089:
0090: public static final String XSLPARAM_NAVITREE = "__navitree";
0091:
0092: public static final String CACHEDIR = ".cache";
0093:
0094: private static final Logger LOG = Logger
0095: .getLogger(TargetGenerator.class);
0096:
0097: private static TargetGenerationReport report = new TargetGenerationReport();
0098:
0099: private PageTargetTree pagetree = new PageTargetTree();
0100:
0101: private HashMap<String, Target> alltargets = new HashMap<String, Target>();
0102:
0103: private boolean isGetModTimeMaybeUpdateSkipped = false;
0104:
0105: private long config_mtime = 0;
0106:
0107: private Set<FileResource> configFileDependencies = new HashSet<FileResource>();
0108:
0109: private String name;
0110:
0111: private XsltVersion xsltVersion = XsltVersion.XSLT1; //default, can be overridden in depend.xml
0112:
0113: private Themes global_themes;
0114:
0115: private String default_theme;
0116:
0117: private String language;
0118:
0119: /* All registered TargetGenerationListener */
0120: private Set<TargetGeneratorListener> generationListeners = new HashSet<TargetGeneratorListener>();
0121:
0122: private Set<ConfigurationChangeListener> configurationListeners = Collections
0123: .synchronizedSet(new HashSet<ConfigurationChangeListener>());
0124:
0125: private FileResource config_path;
0126:
0127: //--
0128:
0129: public TargetGenerator(FileResource confile) throws IOException,
0130: SAXException, XMLException {
0131: this .config_path = confile;
0132:
0133: Meminfo.print("TG: Before loading " + confile.toString());
0134: loadConfig(confile);
0135: Meminfo.print("TG: after loading targets for "
0136: + confile.toString());
0137: }
0138:
0139: //-- attributes
0140:
0141: public String getName() {
0142: return name;
0143: }
0144:
0145: public XsltVersion getXsltVersion() {
0146: return xsltVersion;
0147: }
0148:
0149: public Themes getGlobalThemes() {
0150: return global_themes;
0151: }
0152:
0153: public String getDefaultTheme() {
0154: return default_theme;
0155: }
0156:
0157: public String getLanguage() {
0158: return language;
0159: }
0160:
0161: public FileResource getDisccachedir() {
0162: return ResourceUtil.getFileResourceFromDocroot(CACHEDIR + "/"
0163: + getName());
0164: }
0165:
0166: public PageTargetTree getPageTargetTree() {
0167: return pagetree;
0168: }
0169:
0170: //-- targets
0171:
0172: public TreeMap<String, Target> getAllTargets() {
0173: synchronized (alltargets) {
0174: return new TreeMap<String, Target>(alltargets);
0175: }
0176: }
0177:
0178: public Target getTarget(String key) {
0179: synchronized (alltargets) {
0180: return (Target) alltargets.get(key);
0181: }
0182: }
0183:
0184: public Target createXMLLeafTarget(String key) {
0185: return createTarget(TargetType.XML_LEAF, key, null);
0186: }
0187:
0188: public Target createXSLLeafTarget(String key) {
0189: return createTarget(TargetType.XSL_LEAF, key, null);
0190: }
0191:
0192: //-- misc
0193:
0194: public void addListener(TargetGeneratorListener listener) {
0195: generationListeners.add(listener);
0196: }
0197:
0198: public void removeListener(TargetGeneratorListener listener) {
0199: generationListeners.remove(listener);
0200: }
0201:
0202: public void addListener(ConfigurationChangeListener listener) {
0203: configurationListeners.add(listener);
0204: }
0205:
0206: public void removeListener(ConfigurationChangeListener listener) {
0207: configurationListeners.remove(listener);
0208: }
0209:
0210: public String toString() {
0211: return "[TG: " + getName() + "; " + alltargets.size()
0212: + " targets defined.]";
0213: }
0214:
0215: // *******************************************************************************************
0216:
0217: public synchronized boolean tryReinit() throws Exception {
0218: if (needsReload()) {
0219: LOG.warn("\n\n###############################\n"
0220: + "#### Reloading depend file: "
0221: + this .config_path.toString() + "\n"
0222: + "###############################\n");
0223: synchronized (alltargets) {
0224: if (alltargets != null && !alltargets.isEmpty()) {
0225: TargetDependencyRelation.getInstance()
0226: .resetAllRelations(
0227: (Collection<Target>) alltargets
0228: .values());
0229: }
0230: }
0231: pagetree = new PageTargetTree();
0232: alltargets = new HashMap<String, Target>();
0233: loadConfig(this .config_path);
0234: this .fireConfigurationChangeEvent();
0235: return true;
0236: } else {
0237: return false;
0238: }
0239: }
0240:
0241: private boolean needsReload() {
0242: for (FileResource file : configFileDependencies) {
0243: if (file.lastModified() > config_mtime) {
0244: return true;
0245: }
0246: }
0247: return false;
0248: }
0249:
0250: protected long getConfigMaxModTime() {
0251: long tmptime = -1;
0252: for (FileResource file : configFileDependencies) {
0253: tmptime = Math.max(file.lastModified(), tmptime);
0254: }
0255: return tmptime;
0256: }
0257:
0258: private void fireConfigurationChangeEvent() {
0259: for (Iterator<ConfigurationChangeListener> i = this .configurationListeners
0260: .iterator(); i.hasNext();) {
0261: ConfigurationChangeListener listener = i.next();
0262: listener.configurationChanged(new ConfigurationChangeEvent(
0263: this ));
0264: }
0265: }
0266:
0267: private void loadConfig(FileResource configFile)
0268: throws XMLException, IOException, SAXException {
0269: config_mtime = System.currentTimeMillis();
0270: String path;
0271: if (configFile instanceof DocrootResource) {
0272: path = ((DocrootResource) configFile).getRelativePath();
0273: } else if (configFile instanceof FileSystemResource) {
0274: path = ((FileSystemResource) configFile)
0275: .getPathOnFileSystem();
0276: } else {
0277: path = configFile.toURI().toString();
0278: }
0279: LOG.warn("\n***** CAUTION! ***** loading config " + path
0280: + "...");
0281:
0282: Document config;
0283:
0284: // String containing the XML code with resolved includes
0285: String fullXml = null;
0286:
0287: Document confDoc = Xml.parseMutable(configFile);
0288: IncludesResolver iresolver = new IncludesResolver(null,
0289: "config-include");
0290: // Make sure list of dependencies only contains the file itself
0291: configFileDependencies.clear();
0292: configFileDependencies.add(configFile);
0293: FileIncludeEventListener listener = new FileIncludeEventListener() {
0294:
0295: public void fileIncluded(FileIncludeEvent event) {
0296: configFileDependencies.add(event.getIncludedFile());
0297: }
0298:
0299: };
0300: iresolver.registerListener(listener);
0301: iresolver.resolveIncludes(confDoc);
0302: fullXml = Xml.serialize(confDoc, false, true);
0303:
0304: XMLReader xreader = XMLReaderFactory.createXMLReader();
0305: TransformerFactory tf = TransformerFactory.newInstance();
0306: if (tf.getFeature(SAXTransformerFactory.FEATURE)) {
0307: SAXTransformerFactory stf = (SAXTransformerFactory) tf;
0308: TransformerHandler th;
0309: try {
0310: th = stf.newTransformerHandler();
0311: } catch (TransformerConfigurationException e) {
0312: throw new RuntimeException(
0313: "Failed to configure TransformerFactory!", e);
0314: }
0315: DOMResult dr = new DOMResult();
0316: DOMResult dr2 = new DOMResult();
0317: th.setResult(dr);
0318: DefaultHandler dh = new TransformerHandlerAdapter(th);
0319: DefaultHandler cushandler = new CustomizationHandler(dh);
0320: xreader.setContentHandler(cushandler);
0321: xreader.setDTDHandler(cushandler);
0322: xreader.setErrorHandler(cushandler);
0323: xreader.setEntityResolver(cushandler);
0324: xreader.parse(new InputSource(new StringReader(fullXml)));
0325: try {
0326: Transformer trans = tf.newTransformer(new StreamSource(
0327: ResourceUtil.getFileResourceFromDocroot(
0328: "core/build/create_depend.xsl").toURL()
0329: .toString()));
0330: trans.setParameter("projectsFile", ResourceUtil
0331: .getFileResourceFromDocroot(
0332: "servletconf/projects.xml").toURL()
0333: .toString());
0334: if (BuildTimeProperties.getProperties().getProperty(
0335: "mode").equals("prod")) {
0336: trans.setParameter("prohibitEdit", "yes");
0337: } else {
0338: trans.setParameter("prohibitEdit", "no");
0339: }
0340: trans.transform(new DOMSource(dr.getNode()), dr2);
0341: Node tempNode = dr2.getNode();
0342: config = tempNode.getOwnerDocument();
0343:
0344: // tempNode might already be the document and
0345: // getOwnerDocument() will return null in this case
0346: if (config == null) {
0347: if (tempNode.getNodeType() == Node.DOCUMENT_NODE) {
0348: config = (Document) tempNode;
0349: } else {
0350: throw new SAXException(
0351: "XML result is not a Document though it should be");
0352: }
0353: }
0354: } catch (TransformerException e) {
0355: throw new SAXException(e);
0356: }
0357: } else {
0358: throw new RuntimeException(
0359: "Could not get instance of SAXTransformerFactory!");
0360: }
0361:
0362: Element root = (Element) config.getElementsByTagName("make")
0363: .item(0);
0364:
0365: String versionStr = root.getAttribute("xsltversion");
0366: if (versionStr != null && !versionStr.equals("")) {
0367: try {
0368: xsltVersion = XsltVersion.valueOf("XSLT" + versionStr);
0369: } catch (IllegalArgumentException x) {
0370: throw new RuntimeException(
0371: "XSLT version not supported: " + versionStr);
0372: }
0373: }
0374:
0375: NodeList targetnodes = config.getElementsByTagName("target");
0376:
0377: name = root.getAttribute("project");
0378: if (name == null || name.length() == 0) {
0379: String relativePath;
0380: if (configFile instanceof DocrootResource) {
0381: relativePath = ((DocrootResource) configFile)
0382: .getRelativePath();
0383: } else {
0384: throw new XMLException(
0385: "project attribute is not set and depend.xml is not within docroot");
0386: }
0387: try {
0388: Document projectsXml = Xml
0389: .parse(
0390: XsltVersion.XSLT1,
0391: ResourceUtil
0392: .getFileResourceFromDocroot("servletconf/projects.xml"));
0393: Node attrNode = XPath.selectNode(projectsXml,
0394: "/projects/project[depend/text()='"
0395: + relativePath + "']/@name");
0396: if (attrNode == null) {
0397: throw new XMLException("Found no project for "
0398: + relativePath);
0399: }
0400: name = attrNode.getNodeValue();
0401: } catch (TransformerException e) {
0402: throw new XMLException("Could not read projects.xml", e);
0403: }
0404: }
0405:
0406: language = getAttribute(root, "lang");
0407:
0408: String gl_theme_str = null;
0409: String def_theme_str = null;
0410: if (root.hasAttribute("themes")) {
0411: gl_theme_str = getAttribute(root, "themes");
0412: }
0413: if (gl_theme_str == null || gl_theme_str.equals("")) {
0414: gl_theme_str = name + " default";
0415: } else if (!gl_theme_str.endsWith(" default")) {
0416: if (gl_theme_str.lastIndexOf(' ') == -1) {
0417: def_theme_str = gl_theme_str.trim();
0418: } else {
0419: def_theme_str = gl_theme_str.substring(
0420: gl_theme_str.lastIndexOf(' ')).trim();
0421: }
0422: gl_theme_str = gl_theme_str + " default";
0423: }
0424: if (def_theme_str == null) {
0425: def_theme_str = "default";
0426: }
0427:
0428: global_themes = new Themes(gl_theme_str);
0429: default_theme = def_theme_str;
0430:
0431: FileResource disccache = getDisccachedir();
0432: if (!disccache.exists()) {
0433: disccache.mkdirs();
0434: } else if (!disccache.isDirectory() || !disccache.canRead()) {
0435: throw new XMLException("Directory " + disccache
0436: + " is not readeable or is no directory");
0437: } else if (!disccache.canWrite()) {
0438: // When running in WAR mode this is okay
0439: LOG.warn("Directory " + disccache + " is not writable!");
0440: }
0441:
0442: HashSet<String> depxmls = new HashSet<String>();
0443: HashSet<String> depxsls = new HashSet<String>();
0444: HashMap<String, TargetStruct> allstructs = new HashMap<String, TargetStruct>();
0445:
0446: long start = System.currentTimeMillis();
0447: for (int i = 0; i < targetnodes.getLength(); i++) {
0448: Element node = (Element) targetnodes.item(i);
0449: String nameattr = node.getAttribute("name");
0450: String type = node.getAttribute("type");
0451: String themes = node.getAttribute("themes");
0452: String variant = node.getAttribute("variant");
0453: String pagename = node.getAttribute("page");
0454: TargetStruct struct = new TargetStruct(nameattr, type,
0455: themes, variant, pagename);
0456: HashMap<String, String> params = new HashMap<String, String>();
0457: HashSet<DocrootResource> depaux = new HashSet<DocrootResource>();
0458: Element xmlsub = (Element) node.getElementsByTagName(
0459: "depxml").item(0);
0460: Element xslsub = (Element) node.getElementsByTagName(
0461: "depxsl").item(0);
0462: NodeList allaux = node.getElementsByTagName("depaux");
0463: NodeList allpar = node.getElementsByTagName("param");
0464:
0465: if (xmlsub != null) {
0466: String xmldep = xmlsub.getAttribute("name");
0467: if (xmldep != null) {
0468: struct.setXMLDep(xmldep);
0469: depxmls.add(xmldep);
0470: } else {
0471: throw new XMLException("Defined VirtualTarget '"
0472: + nameattr + "' with depxml without a name");
0473: }
0474: } else {
0475: throw new XMLException("Defined VirtualTarget '"
0476: + nameattr + "' without [depxml]");
0477: }
0478: if (xslsub != null) {
0479: String xsldep = xslsub.getAttribute("name");
0480: if (xsldep != null) {
0481: struct.setXSLDep(xsldep);
0482: depxsls.add(xsldep);
0483: } else {
0484: throw new XMLException("Defined VirtualTarget '"
0485: + nameattr + "' with depxsl without a name");
0486: }
0487: } else {
0488: throw new XMLException("Defined VirtualTarget '"
0489: + nameattr + "' without [depxsl]");
0490: }
0491: for (int j = 0; j < allaux.getLength(); j++) {
0492: Element aux = (Element) allaux.item(j);
0493: DocrootResource auxname = ResourceUtil
0494: .getFileResourceFromDocroot(aux
0495: .getAttribute("name"));
0496: depaux.add(auxname);
0497: }
0498: struct.setDepaux(depaux);
0499: for (int j = 0; j < allpar.getLength(); j++) {
0500: Element par = (Element) allpar.item(j);
0501: String parname = par.getAttribute("name");
0502: if ("docroot".equals(parname)) {
0503: throw new XMLException(
0504: "The docroot parameter is no longer allowed! ["
0505: + nameattr + "]");
0506: }
0507: String value = par.getAttribute("value");
0508: params.put(parname, value);
0509: }
0510: // TODO Check that docroot really is not needed by targets
0511: // params.put("docroot", confile.getBase().getPath());
0512: struct.setParams(params);
0513: allstructs.put(nameattr, struct);
0514: }
0515: LOG.warn("\n=====> Preliminaries took "
0516: + (System.currentTimeMillis() - start)
0517: + "ms. Now looping over " + allstructs.keySet().size()
0518: + " targets");
0519: start = System.currentTimeMillis();
0520: String tgParam = configFile.toString();
0521: for (Iterator<String> i = allstructs.keySet().iterator(); i
0522: .hasNext();) {
0523: TargetStruct struct = allstructs.get(i.next());
0524: createTargetFromTargetStruct(struct, allstructs, depxmls,
0525: depxsls, tgParam);
0526: }
0527: LOG.warn("\n=====> Creating targets took "
0528: + (System.currentTimeMillis() - start)
0529: + "ms. Now init pagetree");
0530: start = System.currentTimeMillis();
0531: pagetree.initTargets();
0532: LOG
0533: .warn("\n=====> Init of Pagetree took "
0534: + (System.currentTimeMillis() - start)
0535: + "ms. Ready...");
0536: }
0537:
0538: private TargetRW createTargetFromTargetStruct(TargetStruct struct,
0539: HashMap<String, TargetStruct> allstructs,
0540: HashSet<String> depxmls, HashSet<String> depxsls,
0541: String tgParam) throws XMLException {
0542:
0543: String key = struct.getName();
0544: String type = struct.getType();
0545: TargetType reqtype = TargetType.getByTag(type);
0546: TargetRW tmp = getTargetRW(key);
0547:
0548: if (tmp != null) {
0549: if (reqtype == tmp.getType()) {
0550: return tmp;
0551: } else {
0552: throw new XMLException("Already have a target '" + key
0553: + "' with type " + tmp.getType()
0554: + ". Requested type was '" + reqtype + "'");
0555: }
0556: } else {
0557: String xmldep = struct.getXMLDep();
0558: String xsldep = struct.getXSLDep();
0559: TargetRW xmlsource = null;
0560: TargetRW xslsource = null;
0561:
0562: // We need to handle the xml/xsldep first.
0563: // Check if xmldep is a leaf node or virtual:
0564:
0565: if (!allstructs.containsKey(xmldep)) {
0566: xmlsource = createTarget(TargetType.XML_LEAF, xmldep,
0567: null);
0568: } else {
0569: xmlsource = createTargetFromTargetStruct(allstructs
0570: .get(xmldep), allstructs, depxmls, depxsls,
0571: tgParam);
0572: }
0573:
0574: // Check if xsldep is a leaf node or virtual:
0575: if (!allstructs.containsKey(xsldep)) {
0576: xslsource = createTarget(TargetType.XSL_LEAF, xsldep,
0577: null);
0578: } else {
0579: xslsource = createTargetFromTargetStruct(allstructs
0580: .get(xsldep), allstructs, depxmls, depxsls,
0581: tgParam);
0582: }
0583:
0584: String themes_str = struct.getThemes();
0585: Themes themes = null;
0586:
0587: if (themes_str != null && !themes_str.equals("")) {
0588: if (!themes_str.endsWith(" default")) {
0589: themes_str = themes_str + " default";
0590: }
0591: themes = new Themes(themes_str);
0592: } else {
0593: themes = global_themes;
0594: }
0595:
0596: VirtualTarget virtual = (VirtualTarget) createTarget(
0597: reqtype, key, themes);
0598: String variantname = struct.getVariant();
0599: String pagename = struct.getPage();
0600:
0601: virtual.setXMLSource(xmlsource);
0602: virtual.setXSLSource(xslsource);
0603:
0604: AuxDependencyManager manager = virtual
0605: .getAuxDependencyManager();
0606: HashSet<DocrootResource> auxdeps = struct.getDepaux();
0607: for (Iterator<DocrootResource> i = auxdeps.iterator(); i
0608: .hasNext();) {
0609: DocrootResource path = i.next();
0610: manager.addDependencyFile(path);
0611: }
0612:
0613: HashMap<String, String> params = struct.getParams();
0614: // we want to remove already defined params (needed when we do a reload)
0615: virtual.resetParams();
0616:
0617: for (Iterator<String> i = params.keySet().iterator(); i
0618: .hasNext();) {
0619: String pname = i.next();
0620: String value = params.get(pname);
0621: LOG.debug("* Adding Param " + pname + " with value "
0622: + value);
0623: virtual.addParam(pname, value);
0624: }
0625: virtual.addParam(XSLPARAM_TG, tgParam);
0626: virtual.addParam(XSLPARAM_TKEY, key);
0627: try {
0628: virtual.addParam(XSLPARAM_NAVITREE, NavigationFactory
0629: .getInstance().getNavigation(this .config_path,
0630: getXsltVersion())
0631: .getNavigationXMLElement());
0632: } catch (Exception e) {
0633: throw new XMLException("Cannot get navigation tree", e);
0634: }
0635:
0636: if (!depxmls.contains(key) && !depxsls.contains(key)) {
0637: // it's a toplevel target...
0638: if (pagename == null) {
0639: LOG
0640: .warn("*** WARNING *** Target '"
0641: + key
0642: + "' is top-level, but has no 'page' attribute set! Ignoring it... ***");
0643: } else {
0644: //CAT.warn("REGISTER " + pagename + " " + variantname);
0645: PageInfo info = PageInfoFactory.getInstance()
0646: .getPage(this , pagename, variantname);
0647: pagetree.addEntry(info, virtual);
0648: }
0649: } else if (pagename != null) {
0650: throw new RuntimeException(
0651: "*** ERROR *** Target '"
0652: + key
0653: + "' is NOT top-level, but has a 'page' attribute set! ***");
0654: }
0655: return virtual;
0656: }
0657: }
0658:
0659: // *******************************************************************************************
0660: private TargetRW getTargetRW(String key) {
0661: synchronized (alltargets) {
0662: return (TargetRW) alltargets.get(key);
0663: }
0664: }
0665:
0666: private TargetRW createTarget(TargetType type, String key,
0667: Themes themes) {
0668: TargetFactory tfac = TargetFactory.getInstance();
0669: TargetRW tmp = tfac.getTarget(type, this , key, themes);
0670: TargetRW tmp2 = getTargetRW(key);
0671:
0672: if (tmp2 == null) {
0673: synchronized (alltargets) {
0674: alltargets.put(tmp.getTargetKey(), tmp);
0675: }
0676: } else if (tmp != tmp2) {
0677: throw new RuntimeException("Requesting Target '" + key
0678: + "' of type " + tmp.getType()
0679: + ", but already have a Target of type "
0680: + tmp2.getType()
0681: + " with the same key in this Generator!");
0682: }
0683: return tmp;
0684: }
0685:
0686: private class TargetStruct {
0687:
0688: HashSet<DocrootResource> depaux;
0689:
0690: HashMap<String, String> params;
0691:
0692: String type;
0693:
0694: String name;
0695:
0696: String xsldep;
0697:
0698: String xmldep;
0699:
0700: String variant = null;
0701:
0702: String themes = null;
0703:
0704: String page = null;
0705:
0706: public TargetStruct(String name, String type, String themes,
0707: String variant, String page) {
0708: this .name = name;
0709: this .type = type;
0710: if (variant != null && !variant.equals("")) {
0711: this .variant = variant;
0712: }
0713: if (themes != null && !themes.equals("")) {
0714: this .themes = themes;
0715: }
0716: if (page != null && !page.equals("")) {
0717: this .page = page;
0718: }
0719: }
0720:
0721: public String getThemes() {
0722: return themes;
0723: }
0724:
0725: public String getVariant() {
0726: return variant;
0727: }
0728:
0729: public String getPage() {
0730: return page;
0731: }
0732:
0733: public String getXMLDep() {
0734: return xmldep;
0735: }
0736:
0737: public void setXMLDep(String in) {
0738: this .xmldep = in;
0739: }
0740:
0741: public String getXSLDep() {
0742: return xsldep;
0743: }
0744:
0745: public void setXSLDep(String in) {
0746: this .xsldep = in;
0747: }
0748:
0749: public HashSet<DocrootResource> getDepaux() {
0750: return depaux;
0751: }
0752:
0753: public void setDepaux(HashSet<DocrootResource> in) {
0754: this .depaux = in;
0755: }
0756:
0757: public HashMap<String, String> getParams() {
0758: return params;
0759: }
0760:
0761: public void setParams(HashMap<String, String> in) {
0762: this .params = in;
0763: }
0764:
0765: public String getName() {
0766: return name;
0767: }
0768:
0769: public String getType() {
0770: return type;
0771: }
0772: }
0773:
0774: // *******************************************************************************************
0775:
0776: public static void main(String[] args) {
0777: TargetGenerator gen = null;
0778:
0779: String log4jconfig = System.getProperty("log4jconfig");
0780: if (log4jconfig == null || log4jconfig.equals("")) {
0781: System.out
0782: .println("*** FATAL: Need the log4jconfig property. Exiting... ***");
0783: System.exit(-1);
0784: }
0785: DOMConfigurator.configure(log4jconfig);
0786:
0787: if (args.length > 1) {
0788: File docroot = new File(args[0]);
0789: if (!docroot.exists() || !docroot.isDirectory()) {
0790: throw new IllegalArgumentException(
0791: "*** First argument has to be the docroot directory! ***");
0792: }
0793: GlobalConfigurator.setDocroot(docroot.getPath());
0794:
0795: for (int i = 1; i < args.length; i++) {
0796: try {
0797: /* resetting the factories for better memory performance */
0798: TargetGenerator.resetFactories();
0799: System.gc();
0800:
0801: FileResource file = ResourceUtil
0802: .getFileResourceFromDocroot(args[i]);
0803: if (file.exists() && file.canRead()
0804: && file.isFile()) {
0805: gen = TargetGeneratorFactory.getInstance()
0806: .createGenerator(file);
0807: gen.setIsGetModTimeMaybeUpdateSkipped(false);
0808: System.out.println("---------- Doing "
0809: + args[i] + "...");
0810: gen.generateAll();
0811: System.out.println("---------- ...done ["
0812: + args[i] + "]");
0813: TargetGeneratorFactory.getInstance().remove(
0814: file);
0815: } else {
0816: LOG.error("Couldn't read configfile '"
0817: + args[i] + "'");
0818: throw (new XMLException("Oops!"));
0819: }
0820: } catch (Exception e) {
0821: LOG.error("Oops! TargetGenerator exit!", e);
0822: System.exit(-1);
0823: }
0824: }
0825:
0826: System.out.println(report.toString());
0827:
0828: } else {
0829: LOG.error("Need docroot and configfile(s) to work on");
0830: }
0831: }
0832:
0833: /**
0834: * Make sure this target generator object is properly configured before calling this method.
0835: * To obtain a propely configured TargetGenerator Object follow these steps:
0836: * <ul>
0837: * <li/><code>String log4jconfig = System.getProperty("log4jconfig"); DOMConfigurator.configure(log4jconfig);</code>
0838: * <li/>{@link TargetGenerator} gen = {@link TargetGeneratorFactory}.{@link TargetGeneratorFactory#getInstance()}.{@link TargetGeneratorFactory#createGenerator(String)};
0839: * <li/>gen.{@link TargetGenerator#setIsGetModTimeMaybeUpdateSkipped(boolean)};
0840: * </ul>
0841: * @throws Exception
0842: */
0843: public void generateAll() throws Exception {
0844: for (Iterator<String> e = getAllTargets().keySet().iterator(); e
0845: .hasNext();) {
0846: Target current = getTarget(e.next());
0847: generateTarget(current);
0848: /* if all listeners want to stop,
0849: * there is no point in continuing ... */
0850: if (needsToStop()) {
0851: break;
0852: }
0853: }
0854: }
0855:
0856: public void generateTarget(Target target) throws Exception {
0857: if (target.getType() != TargetType.XML_LEAF
0858: && target.getType() != TargetType.XSL_LEAF) {
0859: String path;
0860: if (getDisccachedir() instanceof DocrootResource) {
0861: path = ((DocrootResource) getDisccachedir())
0862: .getRelativePath();
0863: } else if (getDisccachedir() instanceof FileSystemResource) {
0864: path = ((FileSystemResource) getDisccachedir())
0865: .getPathOnFileSystem();
0866: } else {
0867: path = getDisccachedir().toURI().toString();
0868: }
0869: System.out.println(">>>>> Generating " + path
0870: + File.separator + target.getTargetKey() + " from "
0871: + target.getXMLSource().getTargetKey() + " and "
0872: + target.getXSLSource().getTargetKey());
0873:
0874: boolean needs_update = false;
0875: needs_update = target.needsUpdate();
0876: if (needs_update) {
0877: try {
0878: target.getValue();
0879: notifyListenerTargetDone(target);
0880: } catch (TargetGenerationException tgex) {
0881: notifyListenerTargetException(target, tgex);
0882: report.addError(tgex, getName());
0883: tgex.printStackTrace();
0884: }
0885: } else {
0886: notifyListenerTargetDone(target);
0887: }
0888: System.out.println("done.");
0889: } else {
0890: notifyListenerTargetDone(target);
0891: }
0892: }
0893:
0894: /**
0895: * This method checks, if a TargetGeneratorListener wants to stop,
0896: * if so he will get kicked out of the listener set.
0897: *
0898: * @return true if all listeners want to stop
0899: */
0900: private boolean needsToStop() {
0901: boolean result = false;
0902: if (generationListeners.size() > 0) {
0903: result = true;
0904: for (Iterator<TargetGeneratorListener> it = generationListeners
0905: .iterator(); it.hasNext();) {
0906: TargetGeneratorListener listener = it.next();
0907: if (listener.needsStop()) {
0908: result = result && true;
0909: it.remove();
0910: } else {
0911: result = false;
0912: }
0913: }
0914: }
0915: return result;
0916: }
0917:
0918: /**
0919: * This calls the finishedTarget method of all registered listeners
0920: * @param target the finished target
0921: */
0922: private void notifyListenerTargetDone(Target target) {
0923: for (Iterator<TargetGeneratorListener> it = generationListeners
0924: .iterator(); it.hasNext();) {
0925: TargetGeneratorListener listener = it.next();
0926: listener.finishedTarget(target);
0927: }
0928: }
0929:
0930: /**
0931: * This calls the generationException method of all registered listeners
0932: * @param target the finished target
0933: * @param tgex the exception!
0934: */
0935: private void notifyListenerTargetException(Target target,
0936: TargetGenerationException tgex) {
0937: for (Iterator<TargetGeneratorListener> it = generationListeners
0938: .iterator(); it.hasNext();) {
0939: TargetGeneratorListener listener = it.next();
0940: listener.generationException(target, tgex);
0941: }
0942: }
0943:
0944: /**
0945: * Returns the isGetModTimeMaybeUpdateSkipped.
0946: * @return boolean
0947: */
0948: public boolean isGetModTimeMaybeUpdateSkipped() {
0949: return isGetModTimeMaybeUpdateSkipped;
0950: }
0951:
0952: /**
0953: * Sets the isGetModTimeMaybeUpdateSkipped.
0954: * @param isGetModTimeMaybeUpdateSkipped The isGetModTimeMaybeUpdateSkipped to set
0955: */
0956: public void setIsGetModTimeMaybeUpdateSkipped(
0957: boolean isGetModTimeMaybeUpdateSkipped) {
0958: this .isGetModTimeMaybeUpdateSkipped = isGetModTimeMaybeUpdateSkipped;
0959: }
0960:
0961: /**
0962: * @return report containing sensilbe information after {@link #generateAll()}, not null
0963: */
0964: public static String getReportAsString() {
0965: return report.toString();
0966: }
0967:
0968: public static void resetGenerationReport() {
0969: report = new TargetGenerationReport();
0970: }
0971:
0972: public static void resetFactories() {
0973: SPCacheStatistic.reset();
0974: TargetGeneratorFactory.getInstance().reset();
0975: TargetFactory.getInstance().reset();
0976: IncludeDocumentFactory.getInstance().reset();
0977: PageInfoFactory.getInstance().reset();
0978: SharedLeafFactory.getInstance().reset();
0979: AuxDependencyFactory.getInstance().reset();
0980: TargetDependencyRelation.getInstance().reset();
0981: }
0982:
0983: //--
0984:
0985: private static String getAttribute(Element node, String name)
0986: throws XMLException {
0987: String value;
0988:
0989: value = getAttributeOpt(node, name);
0990: if (value == null) {
0991: throw new XMLException("missing attribute: " + name);
0992: }
0993: return value;
0994: }
0995:
0996: private static String getAttributeOpt(Element node, String name) {
0997: Attr attr;
0998:
0999: attr = node.getAttributeNode(name);
1000: if (attr == null) {
1001: return null;
1002: }
1003: return attr.getValue();
1004: }
1005:
1006: public int compareTo(TargetGenerator cmp) {
1007: return cmp.getName().compareTo(this .getName());
1008: }
1009:
1010: public FileResource getConfigPath() {
1011: return this.config_path;
1012: }
1013:
1014: }
|