Source code: org/altara/mars/engine/XmlProbeFactory.java
1 /* MARS Network Monitoring Engine
2 Copyright (C) 1999 Brian H. Trammell
3 Copyright (C) 2002 Leapfrog Research & Development, LLC
4
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, it is available at
17 http:///www.gnu.org/copyleft/gpl.html, or by writing to the
18 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA.
20 */
21
22 package org.altara.mars.engine;
23
24 import java.io.*;
25 import java.net.*;
26 import java.util.*;
27 import org.jdom.*;
28 import org.jdom.input.*;
29 import org.altara.mars.*;
30 import org.apache.oro.text.regex.*;
31
32 /** This class implements a SendExpectProbe-creating ProbeFactory
33 configured from an incoming JDOM mdef:svctype element.
34 */
35
36 public class XmlProbeFactory extends ProbeFactory {
37
38 public static final Namespace NAMESPACE =
39 Namespace.getNamespace("mdef","http://www.altara.org/mars/xmlns/def/");
40
41 private int defaultPort;
42 private List paramNames;
43 private List paramLabels;
44 private HashMap paramDefaults;
45 private Element scriptElem;
46 private SendExpectProbe prototypeProbe;
47
48 public XmlProbeFactory(String name, Element in)
49 throws InvalidDocumentException {
50 super(name);
51
52 // set the default port
53 try {
54 this.defaultPort = Integer.parseInt(
55 in.getAttributeValue("defaultPort"));
56 } catch (Exception ex) {
57 throw new InvalidDocumentException("Missing default port");
58 }
59
60 // read parameter definitions
61 paramNames = new LinkedList();
62 paramLabels = new LinkedList();
63 paramDefaults = new HashMap();
64 Iterator paramElemIter = in.getChildren("param",NAMESPACE).iterator();
65 while (paramElemIter.hasNext()) {
66 parseParam((Element)paramElemIter.next());
67 }
68
69 // read the script
70 scriptElem = in.getChild("script",NAMESPACE);
71 if (scriptElem == null)
72 throw new InvalidDocumentException("Missing script");
73
74 // parse it into an example SendExpectProbe
75 parseScript(scriptElem);
76 }
77
78 public int getDefaultPort() {
79 return defaultPort;
80 }
81
82 public Probe createProbe(Service service) {
83 SendExpectProbe out = prototypeProbe.instantiatePrototype(service);
84 return out;
85 }
86
87 public String[] getServiceParamNames() {
88 if (paramNames.size() == 0) return null;
89 return (String[])paramNames.toArray(new String[paramNames.size()]);
90 }
91
92 public String[] getServiceParamLabels() {
93 if (paramLabels.size() == 0) return null;
94 return (String[])paramLabels.toArray(new String[paramLabels.size()]);
95 }
96
97 public String getServiceParamDefault(Service service, String name) {
98 String def = (String)paramDefaults.get(name);
99 if (def.equals("%%(remote-hostname)")) {
100 def = service.getHost().getAddress().getHostName();
101 }
102 return def;
103 }
104
105 // ---------------------------------------------------------------------
106 // Script Parsing - parses XML into verified runtime script
107 // ---------------------------------------------------------------------
108
109 private void parseScript(Element in) throws InvalidDocumentException {
110 prototypeProbe = new SendExpectProbe();
111 Iterator scriptIter = in.getChildren().iterator();
112 while (scriptIter.hasNext()) {
113 Element nextLine = (Element)scriptIter.next();
114 String lineName = nextLine.getName();
115 if (lineName.equals("param")) {
116 parseParam(nextLine);
117 } else if (lineName.equals("send")) {
118 parseSend(nextLine);
119 } else if (lineName.equals("expect")) {
120 parseExpect(nextLine);
121 } else if (lineName.equals("fail")) {
122 Element nextExpect = (Element)scriptIter.next();
123 if (nextExpect == null ||
124 !nextExpect.getName().equals("expect")) {
125 throw new InvalidDocumentException("fail wasn't followed "+
126 "by expect");
127 }
128 parseFailExpect(nextLine,nextExpect);
129 } else {
130 throw new InvalidDocumentException("Unexpected line in script");
131 }
132 }
133 /*
134 // print the script out - for debugging purposes
135 System.err.println("SVCTYPE "+getName());
136 System.err.println("Default Port "+getDefaultPort());
137 System.err.println("Parameters:");
138 String[] pnStrs= getServiceParamNames();
139 String[] plStrs= getServiceParamLabels();
140 if (pnStrs == null) {
141 System.err.println("\tNo Parameters");
142 } else {
143 for (int i = 0; i < pnStrs.length; i++) {
144 System.err.println("\t"+pnStrs[i]+" ("+plStrs[i]+")");
145 }
146 }
147 System.err.println("Created prototype:\n"+prototypeProbe.dumpScript());
148 */
149 }
150
151 private void parseParam(Element in)
152 throws InvalidDocumentException {
153 String paramName = in.getAttributeValue("name");
154 if (paramName == null)
155 throw new InvalidDocumentException("Missing "+
156 "parameter name");
157 String paramLabel = in.getAttributeValue("label");
158 if (paramLabel == null)
159 throw new InvalidDocumentException("Missing "+
160 "parameter label");
161 paramNames.add(paramName);
162 paramLabels.add(paramLabel);
163 String paramDefault = in.getAttributeValue("default");
164 if (paramDefault != null) {
165 paramDefaults.put(paramName,paramDefault);
166 }
167 }
168
169 private void parseSend(Element in)
170 throws InvalidDocumentException {
171 Iterator cIter = parseContent(in).iterator();
172 while (cIter.hasNext()) prototypeProbe.send(cIter.next());
173 }
174
175 private void parseExpect(Element in)
176 throws InvalidDocumentException {
177 LinkedList content = parseContent(in);
178 if (content.size() != 1) {
179 throw new InvalidDocumentException("Expect must be either "+
180 "a single string or a regex.");
181 }
182 prototypeProbe.expect(content.get(0));
183 }
184
185 private void parseFailExpect(Element failIn, Element expectIn)
186 throws InvalidDocumentException {
187 LinkedList failContent = parseContent(failIn);
188 if (failContent.size() != 1) {
189 throw new InvalidDocumentException("Fail must be either "+
190 "a single string or a regex.");
191 }
192 LinkedList expectContent = parseContent(expectIn);
193 if (expectContent.size() != 1) {
194 throw new InvalidDocumentException("Expect must be either "+
195 "a single string or a regex.");
196 }
197 prototypeProbe.expect(expectContent.get(0),failContent.get(0));
198 }
199
200 private LinkedList parseContent(Element in)
201 throws InvalidDocumentException {
202 LinkedList out = new LinkedList();
203
204 // get the element's content list
205 Iterator contentIter = in.getContent().iterator();
206
207 while (contentIter.hasNext()) {
208 Object nextItem = contentIter.next();
209 // check for element
210 if (nextItem instanceof Element) {
211 Element nextElem = (Element)nextItem;
212 // What sort of element?
213 String nextElemName = nextElem.getName();
214 if (nextElemName.equals("regex")) {
215 // if there's a regular expression, there can be only
216 // one, and nothing else
217 String pattern = nextElem.getAttributeValue("pattern");
218 if (pattern == null)
219 throw new InvalidDocumentException("Missing regex "+
220 "pattern");
221 out.clear();
222 try {
223 out.add(recompiler.compile(pattern));
224 } catch (MalformedPatternException ex) {
225 throw new InvalidDocumentException("Couldn't compile "+
226 "regex: "+ex.getMessage());
227 }
228 break;
229 } else if (nextElemName.equals("param")) {
230 String paramName = nextElem.getAttributeValue("name");
231 if (paramName == null)
232 throw new InvalidDocumentException("Missing "+
233 "parameter name");
234 out.add(new SendExpectClient.SendParameter(
235 prototypeProbe, paramName));
236 } else if (nextElemName.equals("remote-hostname")) {
237 out.add(new SendExpectClient.SendRemoteHostname(
238 prototypeProbe));
239 } else if (nextElemName.equals("version")) {
240 out.add(Main.VERSION);
241 } else if (nextElemName.equals("space")) {
242 out.add(" ");
243 } else if (nextElemName.equals("crlf")) {
244 out.add("\n");
245 } else {
246 throw new InvalidDocumentException("Unexpected element "+
247 nextElemName+" in script line content");
248 }
249 } else if (nextItem instanceof Text) {
250 out.add(((Text)nextItem).getTextNormalize());
251 } else {
252 // Ignore anything else in script line
253 }
254 }
255 return out;
256 }
257
258 // ---------------------------------------------------------------------
259 // Autoregistration - called by Main to locate and attach mars-def file
260 // ---------------------------------------------------------------------
261
262 public static void registerAll(File homeDir)
263 throws InvalidDocumentException, IOException, JDOMException {
264 // locate a mars-def root element
265 Element root = getMarsDefRoot(homeDir);
266
267 // find all svctype children
268 Iterator svcIter = root.getChildren("svctype",NAMESPACE).iterator();
269 while (svcIter.hasNext()) {
270 // determine its name
271 Element svcElem = (Element)svcIter.next();
272 String svcName = svcElem.getAttributeValue("name");
273 if (svcName == null)
274 throw new InvalidDocumentException("Missing svctype name");
275 // create and register a new factory
276 registerFactory(new XmlProbeFactory(svcName,svcElem));
277 }
278 }
279
280 private static Element getMarsDefRoot(File homeDir)
281 throws IOException, JDOMException {
282 // look for a mars-def.xml in the home directory first
283 File homeDef = new File(homeDir,"mars-def.xml");
284 if (homeDef.exists()) {
285 Main.getMain().showStatus("Using probe definition file "+homeDef.getAbsolutePath());
286 return new SAXBuilder().build(homeDef).getRootElement();
287 }
288
289 // look for the JAR-contained mars-def.xml next
290 URL jarDef =
291 XmlProbeFactory.class
292 .getResource("mars-def.xml");
293 if (jarDef == null) throw new IOException("JAR missing mars-def.xml");
294 return new SAXBuilder().build(jarDef.openStream()).getRootElement();
295 }
296 }