KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > innig > macker > rule > RuleSetBuilder


1 /*______________________________________________________________________________
2  *
3  * Macker http://innig.net/macker/
4  *
5  * Copyright 2002-2003 Paul Cantrell
6  *
7  * This program is free software; you can redistribute it and/or modify it under
8  * the terms of the GNU General Public License version 2, as published by the
9  * Free Software Foundation. See the file LICENSE.html for more information.
10  *
11  * This program is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY, including the implied warranty of MERCHANTABILITY or FITNESS
13  * FOR A PARTICULAR PURPOSE. See the license for more details.
14  *
15  * You should have received a copy of the GNU General Public License along with
16  * this program; if not, write to the Free Software Foundation, Inc. / 59 Temple
17  * Place, Suite 330 / Boston, MA 02111-1307 / USA.
18  *______________________________________________________________________________
19  */

20  
21 package net.innig.macker.rule;
22
23 import net.innig.macker.rule.filter.*;
24
25 import java.io.*;
26 import java.util.*;
27
28 import net.innig.util.EnumeratedType;
29 import net.innig.util.OrderedType;
30 import net.innig.io.NullOutputStream;
31
32 import org.jdom.*;
33 import org.jdom.input.SAXBuilder;
34 import org.jdom.output.XMLOutputter;
35
36 public class RuleSetBuilder
37     {
38     public RuleSetBuilder()
39         {
40         saxBuilder = new SAXBuilder(false);
41         saxBuilderVerify = new SAXBuilder(true);
42         xmlOut = new XMLOutputter();
43         
44         //! hack to get around bogus messages generated by Ant's classloader
45
PrintStream realErr = System.err;
46         try {
47             System.setErr(new PrintStream(new NullOutputStream()));
48             dtdUrlS = getClass().getClassLoader()
49                                 .getResource("net/innig/macker/macker.dtd")
50                                 .toExternalForm();
51             }
52         finally
53             { System.setErr(realErr); }
54         }
55         
56     public Collection/*<RuleSet>*/ build(InputStream is)
57         throws RulesException
58         {
59         try { return build(saxBuilder.build(is)); }
60         catch(JDOMException jdome)
61             { throw new RulesDocumentException(jdome); }
62         catch(IOException ioe)
63             { throw new RulesDocumentException(ioe); }
64         }
65
66     public Collection/*<RuleSet>*/ build(Reader reader)
67         throws RulesException
68         {
69         try { return build(saxBuilder.build(reader)); }
70         catch(JDOMException jdome)
71             { throw new RulesDocumentException(jdome); }
72         catch(IOException ioe)
73             { throw new RulesDocumentException(ioe); }
74         }
75
76     public Collection/*<RuleSet>*/ build(File file)
77         throws RulesException
78         {
79         try { return build(saxBuilder.build(file)); }
80         catch(JDOMException jdome)
81             { throw new RulesDocumentException(jdome); }
82         catch(IOException ioe)
83             { throw new RulesDocumentException(ioe); }
84         }
85
86     public Collection/*<RuleSet>*/ build(String JavaDoc fileName)
87         throws RulesException
88         {
89         try { return build(saxBuilder.build(fileName)); }
90         catch(JDOMException jdome)
91             { throw new RulesDocumentException(jdome); }
92         catch(IOException ioe)
93             { throw new RulesDocumentException(ioe); }
94         }
95
96     public Collection/*<RuleSet>*/ build(Document doc)
97         throws RulesException
98         {
99         validateAgainstDTD(doc);
100         return build(doc.getRootElement());
101         }
102     
103     public Collection/*<RuleSet>*/ build(Element elem)
104         throws RulesException
105         {
106         Collection ruleSets = new ArrayList();
107         for(Iterator rsIter = elem.getChildren("ruleset").iterator(); rsIter.hasNext(); )
108             ruleSets.add(buildRuleSet((Element) rsIter.next(), RuleSet.getMackerDefaults()));
109         return ruleSets;
110         }
111
112     private void validateAgainstDTD(Document doc)
113         throws RulesDocumentException
114         {
115         doc.setDocType(new DocType("macker", dtdUrlS));
116
117         StringWriter out = new StringWriter();
118         try { xmlOut.output(doc, out); }
119         catch(IOException ioe)
120             {
121             ioe.printStackTrace();
122             throw new RuntimeException JavaDoc("Unexpected output exception: " + ioe);
123             }
124         Reader in = new StringReader(out.toString());
125         try { saxBuilderVerify.build(in); }
126         catch(JDOMException jdome)
127             { throw new RulesDocumentException(jdome); }
128         catch(IOException ioe)
129             { throw new RulesDocumentException(ioe); }
130         }
131
132     public RuleSet buildRuleSet(Element ruleSetElem, RuleSet parent)
133         throws RulesException
134         {
135         RuleSet ruleSet = new RuleSet(parent);
136         
137         String JavaDoc name = ruleSetElem.getAttributeValue("name");
138         if(name != null)
139             ruleSet.setName(name);
140         
141         buildSeverity(ruleSet, ruleSetElem);
142         
143         for(Iterator patIter = ruleSetElem.getChildren().iterator(); patIter.hasNext(); )
144             {
145             Element subElem = (Element) patIter.next();
146             String JavaDoc subElemName = subElem.getName();
147             if(subElemName.equals("pattern"))
148                 {
149                 String JavaDoc patternName = subElem.getAttributeValue("name");
150                 if(ruleSet.declaresPattern(patternName))
151                     throw new RulesDocumentException(
152                         subElem,
153                         "Pattern named \"" + patternName + "\" is already defined in this context");
154
155                 ruleSet.setPattern(patternName, buildPattern(subElem, ruleSet));
156                 }
157             else if(subElemName.equals("subset"))
158                 {
159                 if(ruleSet.getSubsetPattern() != null)
160                     throw new RulesDocumentException(
161                         subElem,
162                         "<ruleset> may only contain a single <subset> element");
163                 ruleSet.setSubsetPattern(buildPattern(subElem, ruleSet));
164                 }
165             else if(subElemName.equals("access-rule"))
166                 ruleSet.addRule(buildAccessRule(subElem, ruleSet));
167             else if(subElemName.equals("var"))
168                 ruleSet.addRule(buildVariable(subElem, ruleSet));
169             else if(subElemName.equals("foreach"))
170                 ruleSet.addRule(buildForEach(subElem, ruleSet));
171             else if(subElemName.equals("ruleset"))
172                 ruleSet.addRule(buildRuleSet(subElem, ruleSet));
173             else if(subElemName.equals("message"))
174                 ruleSet.addRule(buildMessage(subElem, ruleSet));
175             }
176         
177         return ruleSet;
178         }
179
180     public Pattern buildPattern(Element patternElem, RuleSet ruleSet)
181         throws RulesException
182         { return buildPattern(patternElem, ruleSet, true, null); }
183     
184     public Pattern buildPattern(
185             Element patternElem,
186             RuleSet ruleSet,
187             boolean isTopElem,
188             Pattern nextPat)
189         throws RulesException
190         {
191         // handle options
192

193         String JavaDoc otherPatName = patternElem.getAttributeValue("pattern");
194         String JavaDoc className = getClassNameAttributeValue(patternElem);
195         String JavaDoc filterName = patternElem.getAttributeValue("filter");
196
197         CompositePatternType patType;
198         if(patternElem.getName().equals("include"))
199             patType = CompositePatternType.INCLUDE;
200         else if(patternElem.getName().equals("exclude"))
201             patType = (filterName == null)
202                 ? CompositePatternType.EXCLUDE
203                 : CompositePatternType.INCLUDE;
204         else if(isTopElem)
205             patType = CompositePatternType.INCLUDE;
206         else
207             throw new RulesDocumentException(
208                 patternElem,
209                 "Invalid element <" + patternElem.getName() + "> --"
210                 + " expected <include> or <exclude>");
211         
212         if(otherPatName != null && className != null)
213             throw new RulesDocumentException(
214                 patternElem,
215                 "patterns cannot have both a \"pattern\" and a \"class\" attribute");
216         
217         // do the head thing
218

219         Pattern head = null;
220         if(className != null)
221             head = new RegexPattern(className);
222         else if(otherPatName != null)
223             {
224             head = ruleSet.getPattern(otherPatName);
225             if(head == null)
226                 throw new UndeclaredPatternException(otherPatName);
227             }
228         
229         // build up children
230

231         Pattern childrenPat = null;
232         List children = new ArrayList(patternElem.getChildren()); //! workaround for bug in JUnit
233
//List children = patternElem.getChildren(); // this should work instead when JUnit bug is fixed
234
for(ListIterator childIter = children.listIterator(children.size()); childIter.hasPrevious(); )
235             {
236             Element subElem = (Element) childIter.previous();
237             if(subElem.getName().equals("message"))
238                 continue;
239             
240             childrenPat = buildPattern(subElem, ruleSet, false, childrenPat);
241             }
242         
243         // wrap head in a filter if necessary
244

245         if(filterName != null)
246             {
247             Map options = new HashMap();
248             for(Iterator i = patternElem.getAttributes().iterator(); i.hasNext(); )
249                 {
250                 Attribute attr = (Attribute) i.next();
251                 options.put(attr.getName(), attr.getValue());
252                 }
253             options.remove("name");
254             options.remove("pattern");
255             options.remove("class");
256             options.remove("regex");
257             
258             Filter filter = FilterFinder.findFilter(filterName);
259             head = filter.createPattern(
260                 ruleSet,
261                 (head == null)
262                     ? Collections.EMPTY_LIST
263                     : Collections.singletonList(head),
264                 options);
265                 
266             if(patternElem.getName().equals("exclude"))
267                 head = CompositePattern.create(CompositePatternType.EXCLUDE, head, null, null);
268             }
269         
270         // pull together composite
271

272         return CompositePattern.create(patType, head, childrenPat, nextPat);
273         }
274     
275     public Variable buildVariable(Element forEachElem, RuleSet parent)
276         throws RulesException
277         {
278         String JavaDoc varName = forEachElem.getAttributeValue("name");
279         if(varName == null)
280             throw new RulesDocumentException(
281                 forEachElem,
282                 "<var> is missing the \"name\" attribute");
283         
284         String JavaDoc value = forEachElem.getAttributeValue("value");
285         if(value == null)
286             throw new RulesDocumentException(
287                 forEachElem,
288                 "<var> is missing the \"value\" attribute");
289         
290         return new Variable(parent, varName, value);
291         }
292     
293     public Message buildMessage(Element messageElem, RuleSet parent)
294         throws RulesException
295         {
296         Message message = new Message(parent, messageElem.getText());
297         buildSeverity(message, messageElem);
298         return message;
299         }
300     
301     public ForEach buildForEach(Element forEachElem, RuleSet parent)
302         throws RulesException
303         {
304         String JavaDoc varName = forEachElem.getAttributeValue("var");
305         if(varName == null)
306             throw new RulesDocumentException(
307                 forEachElem,
308                 "<foreach> is missing the \"var\" attribute");
309         
310         String JavaDoc className = getClassNameAttributeValue(forEachElem);
311         if(className == null)
312             throw new RulesDocumentException(
313                 forEachElem,
314                 "<foreach> is missing the \"class\" attribute");
315         
316         ForEach forEach = new ForEach(parent);
317         forEach.setVariableName(varName);
318         forEach.setRegex(className);
319         forEach.setRuleSet(buildRuleSet(forEachElem, parent));
320         return forEach;
321         }
322     
323     public AccessRule buildAccessRule(Element ruleElem, RuleSet ruleSet)
324         throws RulesException
325         {
326         AccessRule prevRule = null, topRule = null;
327         for(Iterator childIter = ruleElem.getChildren().iterator(); childIter.hasNext(); )
328             {
329             Element subElem = (Element) childIter.next();
330             AccessRule accRule = new AccessRule(ruleSet);
331             
332             if(subElem.getName().equals("allow"))
333                 accRule.setType(AccessRuleType.ALLOW);
334             else if(subElem.getName().equals("deny"))
335                 accRule.setType(AccessRuleType.DENY);
336             else if(subElem.getName().equals("from")
337                  || subElem.getName().equals("to")
338                  || subElem.getName().equals("message"))
339                 continue;
340             else
341                 throw new RulesDocumentException(
342                     subElem,
343                     "Invalid element <" + subElem.getName() + "> --"
344                     + " expected an access rule (<deny> or <allow>)");
345             
346             Element fromElem = subElem.getChild("from");
347             if(fromElem != null)
348                 accRule.setFrom(buildPattern(fromElem, ruleSet));
349             
350             Element toElem = subElem.getChild("to");
351             if(toElem != null)
352                 accRule.setTo(buildPattern(toElem, ruleSet));
353
354             if(!subElem.getChildren().isEmpty())
355                 accRule.setChild(buildAccessRule(subElem, ruleSet));
356             
357             if(topRule == null)
358                 topRule = accRule;
359             else
360                 prevRule.setNext(accRule);
361             prevRule = accRule;
362             }
363         if(topRule != null)
364             {
365             topRule.setMessage(ruleElem.getChildText("message"));
366             buildSeverity(topRule, ruleElem);
367             }
368         return topRule;
369         }
370
371     public void buildSeverity(Rule rule, Element elem)
372         throws RulesDocumentException
373         {
374         String JavaDoc severityS = elem.getAttributeValue("severity");
375         if(severityS != null && !"".equals(severityS))
376             {
377             RuleSeverity severity;
378             try { severity = RuleSeverity.fromName(severityS); }
379             catch(IllegalArgumentException JavaDoc iae)
380                 { throw new RulesDocumentException(elem, iae.getMessage()); }
381             rule.setSeverity(severity);
382             }
383         }
384     
385     private String JavaDoc getClassNameAttributeValue(Element elem)
386         {
387         String JavaDoc value = elem.getAttributeValue("class");
388         if(value == null)
389             {
390             value = elem.getAttributeValue("regex");
391             if(value != null)
392                 System.err.println("WARNING: The \"regex\" attribute is deprecated, and will be removed in v1.0. Use \"class\" instead");
393             }
394         return value;
395         }
396     
397     private SAXBuilder saxBuilder, saxBuilderVerify;
398     private XMLOutputter xmlOut;
399     private String JavaDoc dtdUrlS;
400     }
401
402
403
404
Popular Tags