1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 package org.openoffice.setup.SetupData;
25 
26 import org.openoffice.setup.InstallData;
27 import org.openoffice.setup.Util.FileExtensionFilter;
28 import java.io.File;
29 import java.io.IOException;
30 import java.util.Enumeration;
31 import java.util.Hashtable;
32 import java.util.Stack;
33 import java.util.Vector;
34 import javax.xml.parsers.ParserConfigurationException;
35 import javax.xml.parsers.SAXParser;
36 import javax.xml.parsers.SAXParserFactory;
37 import org.xml.sax.Attributes;
38 import org.xml.sax.SAXException;
39 import org.xml.sax.SAXParseException;
40 import org.xml.sax.helpers.DefaultHandler;
41 public class XMLPackageDescription {
42 
43     /**
44      * fill the package description tree by handling the SAXParser events
45      */
46     private class PackageDescriptionHandler extends DefaultHandler {
47 
48         private XMLPackageDescription root;
49         private Stack stack;
50 
PackageDescriptionHandler(XMLPackageDescription base)51         public PackageDescriptionHandler(XMLPackageDescription base) {
52             root  = base;
53             stack = new Stack();
54         }
55 
PackageDescriptionHandler()56         private PackageDescriptionHandler() {
57             /* forbidden */
58         }
59 
getDescription()60         public XMLPackageDescription getDescription() {
61             return root;
62         }
63 
64         /* implement the DefaultHandler interface */
65 
characters(char[] ch, int start, int length)66         public void characters(char[] ch, int start, int length) {
67             XMLPackageDescription entity = (XMLPackageDescription) stack.peek();
68             entity.value = entity.value == null ? new String(ch, start, length)
69                                                 : entity.value + new String(ch, start, length);
70         }
startDocument()71         public void startDocument() {
72             stack.push(root);
73         }
endDocument()74         public void endDocument() {
75             stack.pop();
76         }
startElement(String uri, String localName, String qName, Attributes attributes)77         public void startElement(String uri, String localName, String qName, Attributes attributes) {
78             XMLPackageDescription parent = (XMLPackageDescription) stack.peek();
79             XMLPackageDescription entity = new XMLPackageDescription();
80 
81             entity.key = qName;
82             for (int i = 0; i < attributes.getLength(); i++) {
83                 entity.attributes.put(attributes.getQName(i), attributes.getValue(i));
84             }
85 
86             parent.add(entity);
87             stack.push(entity);
88         }
endElement(String uri, String localName, String qName)89         public void endElement(String uri, String localName, String qName) {
90             stack.pop();
91         }
error(SAXParseException e)92         public void error(SAXParseException e) {
93             System.err.println("Parse Error:" + e);
94         }
processingInstruction(String target, String data)95         public void processingInstruction(String target, String data) {
96             /* ignore */
97         }
skippedEntity(String name)98         public void skippedEntity(String name) {
99             /* ignore */
100         }
warning(SAXParseException e)101         public void warning(SAXParseException e) {
102             System.err.println("Warning:" + e);
103         }
104     }
105 
106     /**
107      * general storage for XML elements
108      */
109 
110     private String key;             /* XML element name       */
111     private String value;           /* XML element characters */
112     private Hashtable attributes;   /* XML element attributes */
113     private Vector children;        /* children are of type XMLPackageDescription */
114 
XMLPackageDescription()115     protected XMLPackageDescription() {
116         key        = "";
117         value      = null;
118         attributes = new Hashtable();
119         children   = new Vector();
120     }
121 
add(XMLPackageDescription p)122     private void add(XMLPackageDescription p) {
123         children.add(p);
124     }
125 
126     /**
127      * helper routines to find content information
128      */
getKey()129     protected String getKey() {
130         return key;
131     }
getAttribute(String key)132     protected String getAttribute(String key) {
133         return (String) attributes.get(key);
134     }
getValue()135     protected String getValue() {
136         return value;
137     }
getElement(String key)138     protected XMLPackageDescription getElement(String key) {
139         return getElement(key, null, null);
140     }
getElement(String key, String attrKey, String attrValue)141     protected XMLPackageDescription getElement(String key, String attrKey, String attrValue) {
142         for (Enumeration e = children.elements(); e.hasMoreElements();) {
143             XMLPackageDescription child = (XMLPackageDescription) e.nextElement();
144             if (child.key.equals(key)) {
145                 if (attrKey == null) {
146                     return child;
147                 } else if (attrValue.equals(child.getAttribute(attrKey))) {
148                     return child;
149                 }
150             }
151         }
152         return null;
153     }
154 
155     /**
156      * find a PackageDescription of type package that has the given name,
157      * recurses into the children
158      */
findPackage(String name)159     private XMLPackageDescription findPackage(String name) {
160         String self = (String) attributes.get("name");
161 
162         if ((self != null) && self.equals(name))
163             return this;
164 
165         XMLPackageDescription found = null;
166         for (Enumeration e = children.elements(); e.hasMoreElements();) {
167             XMLPackageDescription child = (XMLPackageDescription) e.nextElement();
168             if (child.getAttribute("parent") != null) {
169                 found = child.findPackage(name);
170                 if (found != null) {
171                     break;
172                 }
173             }
174         }
175         return found;
176     }
177 
178     /**
179      * adjust the tree so that all children have a matching parent and not just
180      * the ones they got by reading files in random order
181      */
adjust(XMLPackageDescription root)182     private void adjust(XMLPackageDescription root) {
183         String self = (String) attributes.get("name");
184 
185         for (int i = children.size() - 1; i >= 0; --i) {
186             XMLPackageDescription child = (XMLPackageDescription) children.elementAt(i);
187             String childParentName = child.getAttribute("parent");
188             if (childParentName != null) {
189 
190                 child.adjust(root);
191 
192                 if ((childParentName != null) && (childParentName.length() > 0) && (! childParentName.equals(self))) {
193                     XMLPackageDescription newParent = root.findPackage(childParentName);
194                     if (newParent != null) {
195                         newParent.add(child);
196                         children.remove(i);
197                     }
198                 }
199             }
200         }
201     }
202 
read()203     protected void read() {
204         PackageDescriptionHandler handler = new PackageDescriptionHandler(this);
205 
206         try {
207             SAXParserFactory factory = SAXParserFactory.newInstance();
208             SAXParser parser = factory.newSAXParser();
209 
210             InstallData data = InstallData.getInstance();
211             File xpdRoot = data.getInfoRoot("xpd");
212 
213             if ( xpdRoot != null ) {
214                 File[] file = xpdRoot.listFiles(new FileExtensionFilter("xpd"));
215 
216                 if (file != null) {
217                     for (int i = 0; i < file.length; i++) {
218                         parser.parse(file[i], handler);
219                     }
220                 } else {
221                     key   = "";
222                     value = "no package file found";
223                 }
224             }
225             else {
226                 System.err.println("Did not find xpd directory");
227             }
228         } catch (ParserConfigurationException ex) {
229             ex.printStackTrace();
230         } catch (IOException ex) {
231             ex.printStackTrace();
232         } catch (SAXException ex) {
233             ex.printStackTrace();
234         }
235 
236         adjust(this);
237     }
238 
239     /* provide an iterator through the children */
240     protected class Elements implements Enumeration {
241 
242         Enumeration e;
243 
Elements()244         protected Elements() {
245             e = children.elements();
246         }
hasMoreElements()247         public boolean hasMoreElements() {
248             return e.hasMoreElements();
249         }
nextElement()250         public Object nextElement() {
251             return e.nextElement();
252         }
253     }
254 
elements()255     protected Enumeration elements() {
256         return new Elements();
257     }
258 
259 
260     // FIXME: remove it, dump() is for testing only
dump()261     public void dump() {
262         dump("");
263     }
264 
265     // FIXME: remove it, dump(String) is for testing only
dump(String indent)266     public void dump(String indent) {
267         final String space = "    ";
268         if (key != null) {
269             System.out.print(indent + "<" + key);
270         }
271         for (Enumeration e = attributes.keys() ; e.hasMoreElements() ;) {
272             String key   = (String) e.nextElement();
273             String value = (String) attributes.get(key);
274             System.out.print(" " + key + "=\"" + value + "\"");
275         }
276         if (key != null) {
277             System.out.print(">");
278         }
279 
280         if ((value != null) && (value.length() > 0)) {
281             String trimmedValue = value.trim();
282             if (trimmedValue.length() > 60) {
283                 trimmedValue = trimmedValue.substring(0, 57) + "...";
284             }
285             if (trimmedValue.length() > 0) {
286                 System.out.print(trimmedValue);
287             }
288         }
289 
290         for (Enumeration e = children.elements() ; e.hasMoreElements() ;) {
291             XMLPackageDescription current = (XMLPackageDescription) e.nextElement();
292             System.out.println();
293             current.dump(indent + space);
294         }
295         if (children.size() > 0) {
296             System.out.println();
297             System.out.print(indent);
298         }
299         if (key != null) {
300            System.out.print("</" + key + ">");
301         }
302     }
303 }
304