001: package de.schlund.pfixcore.util;
002:
003: import java.io.UnsupportedEncodingException;
004: import java.security.MessageDigest;
005: import java.security.NoSuchAlgorithmException;
006: import java.util.Iterator;
007: import java.util.TreeSet;
008:
009: import javax.xml.parsers.DocumentBuilderFactory;
010:
011: import org.apache.log4j.xml.DOMConfigurator;
012: import org.w3c.dom.Document;
013: import org.w3c.dom.Element;
014: import org.w3c.dom.NamedNodeMap;
015: import org.w3c.dom.Node;
016: import org.w3c.dom.NodeList;
017:
018: import de.schlund.pfixxml.IncludeDocumentFactory;
019: import de.schlund.pfixxml.config.GlobalConfigurator;
020: import de.schlund.pfixxml.resources.DocrootResource;
021: import de.schlund.pfixxml.resources.ResourceUtil;
022: import de.schlund.pfixxml.targets.AuxDependency;
023: import de.schlund.pfixxml.targets.AuxDependencyInclude;
024: import de.schlund.pfixxml.targets.DependencyType;
025: import de.schlund.pfixxml.targets.TargetDependencyRelation;
026: import de.schlund.pfixxml.targets.TargetGenerator;
027: import de.schlund.pfixxml.util.XPath;
028: import de.schlund.pfixxml.util.Xml;
029:
030: /**
031: * DumpText.java
032: *
033: * @author <a href="mailto:jtl@schlund.de">Jens Lautenbacher</a>
034: * @version 1.0
035: */
036:
037: public class DumpText implements IDumpText {
038: private final static DocumentBuilderFactory dbfac = DocumentBuilderFactory
039: .newInstance();
040: static {
041: dbfac.setNamespaceAware(true);
042: }
043:
044: public static void main(String[] args) throws Exception {
045: if (args.length < 2 || args.length > 3) {
046: System.err
047: .println("Usage: java de.schlund.pfixcore.util.DumpText DOCROOT DEPEND.XML <CLASSNAME>");
048: System.err
049: .println(" This will create a dump of all include parts");
050: System.err
051: .println(" that are used by the project that belongs to the");
052: System.err
053: .println(" given DEPEND.XML file. Note that the DEPEND.XML file");
054: System.err
055: .println(" must be given as a relative file name to DOCROOT.");
056: System.err
057: .println(" CLASSNAME is an optional class that implements the IDumpText interface that");
058: System.err
059: .println(" should be used instead of de.schlund.pfixcore.util.DumpText for processing");
060: System.exit(0);
061: }
062: String docroot = args[0];
063: String depend = args[1];
064: GlobalConfigurator.setDocroot(docroot);
065: IDumpText trans;
066: if (args.length == 3) {
067: Class<?> clazz = Class.forName(args[2]);
068: trans = (IDumpText) clazz.newInstance();
069: } else {
070: trans = new DumpText();
071: }
072:
073: DOMConfigurator.configure("core/conf/generator_quiet.xml");
074: trans.generateList(depend);
075: }
076:
077: /**
078: * <code>generateList</code> iterates over all includes. It will dump all the include parts
079: * that are used in the referenced project (which is identified by the given depend.xml file)
080: * into the output file "dump.xml".
081: *
082: * @param depend a <code>String</code> referencing the depend.xml file to process
083: * @exception Exception if an error occurs
084: */
085: public void generateList(String depend) throws Exception {
086: Document list = dbfac.newDocumentBuilder().newDocument();
087: Element root = list.createElement("dumpedincludeparts");
088: root.setAttribute("xmlns:pfx",
089: "http://www.schlund.de/pustefix/core");
090: root.setAttribute("xmlns:ixsl",
091: "http://www.w3.org/1999/XSL/Transform");
092: root.setAttribute("dependfile", depend);
093: addRootNodeAtributes(root);
094: list.appendChild(root);
095: root.appendChild(list.createTextNode("\n"));
096:
097: TargetGenerator gen = new TargetGenerator(ResourceUtil
098: .getFileResourceFromDocroot(depend));
099: TreeSet<AuxDependency> incs = TargetDependencyRelation
100: .getInstance().getProjectDependenciesForType(gen,
101: DependencyType.TEXT);
102: for (Iterator<AuxDependency> i = incs.iterator(); i.hasNext();) {
103: AuxDependencyInclude aux = (AuxDependencyInclude) i.next();
104: if (includePartOK(aux)) {
105: DocrootResource file = aux.getPath();
106: if (file.exists()) {
107: System.out.print(".");
108: handleInclude(root, aux);
109: }
110: }
111: }
112: root.appendChild(list.createTextNode("\n"));
113: Xml.serialize(list, "dump.xml", false, true);
114: System.out.print("\n");
115: }
116:
117: /**
118: * Overwrite this method to add more attributes to the root node (the dumpincludeparts tag).
119: * Typically used for adding more xmlns:xxx attributes.
120: * @param root
121: */
122: public void addRootNodeAtributes(Element root) {
123: // You may add more namespaces here...
124: // root.setAttribute("xmlns:xxx", "http:/yyy.zzz");
125: }
126:
127: /**
128: * The method <code>includePartOK</code> can be overridden in derived classes to
129: * select based on the include part given as input if this part should be dumped or not.
130: * The default implementation just returns true.
131: * @param aux - The AuxDependencyInclude to check
132: * @return true, if the include part should be dunped, false if otherwise
133: */
134: public boolean includePartOK(AuxDependencyInclude aux) {
135: // String path = aux.getPath().getRelativePath();
136: // String part = aux.getPart();
137: // String theme = aux.getTheme();
138: return true;
139: }
140:
141: /**
142: * The method <code>retrieveTheme</code> can be overridden to decide which theme
143: * to use in the declaration of the dumped content (this is important so you can
144: * change the theme from the current one to another for the import process).
145: * The default implementation returns aux.getTheme().
146: * @param aux
147: * @return the String to be used in the theme attribute of the dumped
148: */
149: public String retrieveTheme(AuxDependencyInclude aux) {
150: // String path = aux.getPath().getRelativePath();
151: // String part = aux.getPart();
152: return aux.getTheme();
153: }
154:
155: private void handleInclude(Element root, AuxDependencyInclude aux)
156: throws Exception {
157: DocrootResource path = aux.getPath();
158: String part = aux.getPart();
159: String theme = aux.getTheme();
160: Document doc = root.getOwnerDocument();
161:
162: IncludeDocumentFactory incfac = IncludeDocumentFactory
163: .getInstance();
164: Document incdoc = incfac.getIncludeDocument(null, path, true)
165: .getDocument();
166: Node extpart = XPath.selectNode(incdoc,
167: "/include_parts/part[@name = '" + part + "']");
168:
169: if (extpart != null) {
170:
171: Element partelem = doc.createElement("USEDINCLUDE");
172: partelem.setAttribute("PART", part);
173: partelem.setAttribute("PATH", path.getRelativePath());
174:
175: root.appendChild(doc.createTextNode("\n"));
176: root.appendChild(doc.createTextNode(" "));
177: root.appendChild(partelem);
178:
179: NodeList nl = extpart.getChildNodes();
180:
181: Element themenode = null;
182:
183: for (int i = 0; i < nl.getLength(); i++) {
184: if (nl.item(i) instanceof Element) {
185: Element elem = (Element) nl.item(i);
186: if (elem.getNodeName().equals("theme")) {
187: if (elem.getAttribute("name").equals(theme)) {
188: themenode = elem;
189: break;
190: }
191: }
192: }
193: }
194: if (themenode != null) {
195: String check = md5ForNode(themenode);
196: partelem.setAttribute("CHECK", check);
197: partelem.setAttribute("THEME", retrieveTheme(aux));
198: NodeList nlist = themenode.getChildNodes();
199: for (int i = 0; i < nlist.getLength(); i++) {
200: Node node = (Node) doc.importNode(nlist.item(i),
201: true);
202: partelem.appendChild(node);
203: }
204: } else {
205: System.out
206: .print("\nDidn't find matching theme in part "
207: + part + "@" + path.getRelativePath()
208: + " for theme " + theme + "!");
209: }
210: }
211: }
212:
213: public static String md5ForNode(Node root) throws Exception {
214: StringBuffer check = new StringBuffer();
215: stringForNode(root, check);
216: // System.out.println("->" + check.toString() + "<-");
217: return DumpText.format(check.toString());
218: }
219:
220: private static void stringForNode(Node root,
221: StringBuffer checkstring) throws Exception {
222: NodeList nl = root.getChildNodes();
223: int length = nl.getLength();
224: for (int m = 0; m < length; m++) {
225: Node node = (Node) nl.item(m);
226: if (node.getNodeType() == Node.ELEMENT_NODE) {
227: checkstring.append(node.getNodeName());
228: NamedNodeMap map = node.getAttributes();
229: for (int k = 0; k < map.getLength(); k++) {
230: Node attr = map.item(k);
231: String attrname = attr.getNodeName();
232: // We should better discard "alt" and "title" for the checksum...
233: if (!attrname.equals("alt")
234: && !attrname.equals("title")) {
235: checkstring.append(attrname + "="
236: + attr.getNodeValue());
237: }
238: }
239: stringForNode(node, checkstring);
240: checkstring.append("/" + node.getNodeName());
241: }
242: }
243: }
244:
245: private static String format(String check)
246: throws NoSuchAlgorithmException,
247: UnsupportedEncodingException {
248: check = check.replaceAll(" ", "");
249: MessageDigest md5 = MessageDigest.getInstance("MD5");
250: md5.update(check.getBytes("ISO-8859-1"));
251: byte[] end = md5.digest();
252: String digest = "";
253: for (int i = 0; i < end.length; i++) {
254: digest += ((end[i] & 0xff) < 16 ? "0" : "")
255: + Integer.toHexString(end[i] & 0xff);
256: }
257: return digest;
258: }
259: }
|