View Javadoc

1   /*
2    * $Id$
3    *
4    * The contents of this file are subject to the Mozilla Public License 
5    * Version 1.1 (the "License"); you may not use this file except in 
6    * compliance with the License. You may obtain a copy of the License at 
7    * http://www.mozilla.org/MPL/ 
8    *
9    * Software distributed under the License is distributed on an "AS IS" basis, 
10   * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
11   * for the specific language governing rights and limitations under the License.
12   *
13   * The Original Code is XML Hammer code. (org.xmlhammer.*)
14   *
15   * The Initial Developer of the Original Code is Edwin Dankert. Portions created 
16   * by the Initial Developer are Copyright (C) 2005 - 2006 the Initial Developer. 
17   * All Rights Reserved.
18   *
19   * Contributor(s): Edwin Dankert <edankert@gmail.com>
20   */
21  
22  package org.xmlhammer.gui.xpath;
23  
24  import java.io.IOException;
25  import java.net.URI;
26  import java.util.ArrayList;
27  
28  import javax.xml.namespace.QName;
29  import javax.xml.parsers.DocumentBuilder;
30  import javax.xml.parsers.DocumentBuilderFactory;
31  import javax.xml.parsers.ParserConfigurationException;
32  import javax.xml.xpath.XPathConstants;
33  import javax.xml.xpath.XPathExpression;
34  import javax.xml.xpath.XPathExpressionException;
35  import javax.xml.xpath.XPathFactoryConfigurationException;
36  
37  import org.apache.log4j.Logger;
38  import org.bounce.util.URIUtils;
39  import org.w3c.dom.Attr;
40  import org.w3c.dom.Comment;
41  import org.w3c.dom.Document;
42  import org.w3c.dom.Element;
43  import org.w3c.dom.Node;
44  import org.w3c.dom.NodeList;
45  import org.w3c.dom.ProcessingInstruction;
46  import org.w3c.dom.Text;
47  import org.xml.sax.InputSource;
48  import org.xml.sax.SAXException;
49  import org.xml.sax.SAXParseException;
50  import org.xmlhammer.DefaultErrorHandler;
51  import org.xmlhammer.Module;
52  import org.xmlhammer.ResultModel;
53  import org.xmlhammer.DefaultErrorHandler.Error;
54  import org.xmlhammer.DefaultErrorHandler.Fatal;
55  import org.xmlhammer.DefaultErrorHandler.Problem;
56  import org.xmlhammer.DefaultErrorHandler.Warning;
57  import org.xmlhammer.gui.status.StatusModel;
58  import org.xmlhammer.model.preferences.Preferences;
59  import org.xmlhammer.model.project.Project;
60  
61  /***
62   * Put comment...
63   * 
64   * @version $Revision$, $Date$
65   * @author Edwin Dankert <edankert@gmail.com>
66   */
67  public class XPathSearchModule extends Module {
68  	private XPathExpression expression = null;
69      private DocumentBuilder builder = null;
70  
71  	public XPathSearchModule(Preferences preferences, Project project, Logger logger, boolean logSettings) throws XPathExpressionException, ParserConfigurationException, SAXException {
72          super(preferences, project, logger, logSettings);
73  
74          // Compile the expression
75          try {
76              logSettings("\t[xpath-expression] "+project.getXPath().getExpression());
77              this.expression = getXPath().compile(project.getXPath().getExpression());
78          } catch (XPathExpressionException e) {
79              Throwable cause = e;
80  
81              while (cause.getCause() != null) {
82                  cause = cause.getCause();
83              }
84      
85              logError(cause);
86              
87              throw e;
88          }
89  
90          DocumentBuilderFactory factory = getDocumentBuilderFactory();
91          builder = factory.newDocumentBuilder();
92      }
93      
94      /***
95       * Sets-up an XPath Factory, creates an XPath and compiles the XPath Expression.
96       * 
97       * @param preferences the global preferences.
98       * @param project the project specific properties;
99       * @throws XPathFactoryConfigurationException
100      * @throws XPathExpressionException
101      * @throws SAXException 
102      * @throws ParserConfigurationException 
103      */
104     public XPathSearchModule(Preferences preferences, Project project, Logger logger) throws XPathExpressionException, ParserConfigurationException, SAXException {
105         this(preferences, project, logger, true);
106 	}
107     
108     /***
109      * Execute the XPath expression.
110      * @throws XPathExpressionException 
111      * @throws IOException 
112      * @throws SAXException 
113      */
114     @Override
115 	public void execute(StatusModel status, ResultModel result, URI uri) throws XPathExpressionException {
116 
117 		if ( uri != null) {
118 			// Tell that we're loading classes and parsing, so the time it
119 			// takes to do this doesn't get confused with the time to do
120 			// the actual query and serialization.
121 			getLogger().info( "xpath-search: "+URIUtils.toString(uri));
122 
123             InputSource in = new InputSource( uri.toString());
124 
125             DefaultErrorHandler errorHandler = new DefaultErrorHandler(null);
126             builder.setErrorHandler(errorHandler);
127             builder.setEntityResolver(getCatalogResolver());
128 
129             Document document = null;
130 
131             try {
132                 document = builder.parse( in);
133                 
134             } catch ( SAXException e) {
135                 if ( e instanceof SAXParseException) {
136                     try {
137                         errorHandler.fatalError( (SAXParseException)e);
138                     } catch ( Exception x) {}
139                 }
140             } catch ( IOException e) {
141                 errorHandler.fatalError(e);
142             }
143             
144             if ( errorHandler.getProblems().size() > 0) {
145                 ArrayList<Problem> list = errorHandler.getProblems();
146 
147                 for ( Problem problem : list) {
148                     if ( problem instanceof Warning) {
149                         logWarning(uri, (SAXParseException)problem.getException());
150 
151                         if (result != null) {
152                             result.addWarning( uri, (SAXParseException)problem.getException());
153                         }
154                     } else if ( problem instanceof Error) {
155                         logError(uri, (SAXParseException)problem.getException());
156                         
157                         if (result != null) {
158                             result.addError( uri, (SAXParseException)problem.getException());
159                         }
160                     } else if ( problem instanceof Fatal) {
161                         logFatal(uri, problem.getException());
162 
163                         if (result != null) {
164                             Exception exception = problem.getException();
165                             if ( exception instanceof IOException) {
166                                 result.addFatal( uri, (IOException)problem.getException());
167                             } else {
168                                 result.addFatal( uri, (SAXParseException)problem.getException());
169                             }
170                         }
171                     }
172                 }
173             } else {
174 			
175                 QName returnType = null;
176                 
177                 String type = getProject().getXPath().getReturnType();
178 
179                 if ( "BOOLEAN".equals( type)) {
180                     returnType = XPathConstants.BOOLEAN;
181                 } else if ( "NODE".equals( type)) {
182                     returnType = XPathConstants.NODE;
183                 } else if ( "NUMBER".equals( type)) {
184                     returnType = XPathConstants.NUMBER;
185                 } else if ( "STRING".equals( type)) {
186                     returnType = XPathConstants.STRING;
187                 } else {
188                     returnType = XPathConstants.NODESET;
189                 }
190                 
191 				// Now evaluate the expression on the document to get String result
192 				Object node = expression.evaluate( document, returnType);
193                 
194 				ArrayList<Object> list = null;
195 
196 				if (node instanceof NodeList && returnType == XPathConstants.NODESET) {
197 					list = new ArrayList<Object>( ((NodeList)node).getLength());
198 
199                     for (int i = 0; i < ((NodeList)node).getLength(); i++) {
200 						list.add( ((NodeList)node).item( i));
201 					}
202 				} else if (node instanceof ArrayList) {
203 					list = new ArrayList<Object>();
204 
205                     for ( Object n : (ArrayList)node) {
206                         list.add( n);
207                     }
208                 } else if (node instanceof String || node instanceof Number || node instanceof Boolean || node instanceof Node) {
209                     list = new ArrayList<Object>();
210                     list.add( node);
211 				} else if (node != null) {
212                     getLogger().error("Unknown result type:\n"+node.getClass());
213                 }
214 
215                 if (list != null) {
216     				for ( int i = 0; i < list.size(); i++) {
217     					Object object = list.get( i);
218                         
219                         if (result != null && object != null) {
220                             result.addValue( uri, object);
221                         }
222     					
223     					// TODO: Make sure the Namespace and Document nodes are handled!!!
224     					if ( object instanceof Element) {
225                             getLogger().info( "\t[element] "+((Element)object).getTagName());
226     					} else if ( object instanceof Attr) {
227                             getLogger().info( "\t[attribute] "+((Attr)object).getName()+"=\""+((Attr)object).getNodeValue()+"\"");
228     					} else if ( object instanceof Text) {
229                             getLogger().info( "\t[text] "+((Text)object).getNodeValue());
230     					} else if ( object instanceof Comment) {
231                             getLogger().info( "\t[comment] "+((Node)object).getNodeValue());
232     					} else if ( object instanceof ProcessingInstruction) {
233                             getLogger().info( "\t[processing-instruction] "+((Node)object).getNodeValue());
234     					} else if ( object instanceof Boolean) {
235                             getLogger().info( "\t[boolean] "+object.toString());
236     					} else if ( object instanceof String) {
237                             getLogger().info( "\t[string] "+(String)object);
238     					} else if ( object instanceof Number) {
239                             getLogger().info( "\t[number] "+((Number)object).toString());
240     					} else if (object != null) {
241                             getLogger().error( "Unknown node:\n"+object.getClass());
242     					}
243     				}
244                 }
245             }
246 		}
247 	}
248 }