View Javadoc

1   /****************************************************************
2    * Licensed to the Apache Software Foundation (ASF) under one   *
3    * or more contributor license agreements.  See the NOTICE file *
4    * distributed with this work for additional information        *
5    * regarding copyright ownership.  The ASF licenses this file   *
6    * to you under the Apache License, Version 2.0 (the            *
7    * "License"); you may not use this file except in compliance   *
8    * with the License.  You may obtain a copy of the License at   *
9    *                                                              *
10   *   http://www.apache.org/licenses/LICENSE-2.0                 *
11   *                                                              *
12   * Unless required by applicable law or agreed to in writing,   *
13   * software distributed under the License is distributed on an  *
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
15   * KIND, either express or implied.  See the License for the    *
16   * specific language governing permissions and limitations      *
17   * under the License.                                           *
18   ****************************************************************/
19  
20  package org.apache.jsieve;
21  
22  import java.util.ArrayList;
23  import java.util.Iterator;
24  import java.util.List;
25  
26  import org.apache.jsieve.exception.SieveException;
27  import org.apache.jsieve.mail.MailAdapter;
28  import org.apache.jsieve.parser.generated.ASTargument;
29  import org.apache.jsieve.parser.generated.ASTarguments;
30  import org.apache.jsieve.parser.generated.ASTblock;
31  import org.apache.jsieve.parser.generated.ASTcommand;
32  import org.apache.jsieve.parser.generated.ASTcommands;
33  import org.apache.jsieve.parser.generated.ASTstart;
34  import org.apache.jsieve.parser.generated.ASTstring;
35  import org.apache.jsieve.parser.generated.ASTstring_list;
36  import org.apache.jsieve.parser.generated.ASTtest;
37  import org.apache.jsieve.parser.generated.ASTtest_list;
38  import org.apache.jsieve.parser.generated.SieveParserVisitor;
39  import org.apache.jsieve.parser.generated.SimpleNode;
40  
41  /**
42   * <p>
43   * Class SieveParserVisitorImpl defines the behaviour for each visited node in
44   * the Sieve grammar. Each method corresponds to a node type and is invoked when
45   * a node of that type is evaluated.
46   * </p>
47   * 
48   * <p>
49   * In essence, this class translates between the nodes operated on by the JavaCC
50   * generated classes and the Sieve classes operated upon by the Commands, Tests
51   * and Comparators. A visit to the start node, ASTstart, triggers evaluation of
52   * all of its descendants.
53   * </p>
54   * 
55   * <p>
56   * See https://javacc.dev.java.net/doc/JJTree.html for indepth information about
57   * Visitor support.
58   * </p>
59   * 
60   * <p>
61   * <strong>Note</strong> that this class is not thread safe. It's use should be
62   * restricted to a single thread for the duration of a visit.
63   * </p>
64   */
65  public class SieveParserVisitorImpl implements SieveParserVisitor {
66      private final SieveContext context;
67  
68      /**
69       * Constructor for NodeVisitor.
70       */
71      public SieveParserVisitorImpl(final SieveContext context) {
72          super();
73          this.context = context;
74      }
75  
76      /**
77       * Method visitChildren adds the children of the node to the passed List.
78       * 
79       * @param node
80       * @param data -
81       *            Assumes a List
82       * @return Object - A List
83       * @throws SieveException
84       */
85      protected Object visitChildren(SimpleNode node, Object data)
86              throws SieveException {
87          List children = new ArrayList(node.jjtGetNumChildren());
88          node.childrenAccept(this, children);
89          ((List) data).addAll(children);
90          return data;
91      }
92  
93      /**
94       * @see SieveParserVisitor#visit(ASTargument, Object)
95       */
96      public Object visit(ASTargument node, Object data) throws SieveException {
97          List children = new ArrayList(node.jjtGetNumChildren());
98          Argument argument = null;
99  
100         if (null != node.getValue()) {
101             argument = (Argument) node.getValue();
102         } else {
103             argument = new StringListArgument(((List) node.childrenAccept(this,
104                     children)));
105         }
106         ((List) data).add(argument);
107 
108         return data;
109     }
110 
111     /**
112      * @see SieveParserVisitor#visit(ASTarguments, Object)
113      */
114     public Object visit(ASTarguments node, Object data) throws SieveException {
115         List children = new ArrayList(node.jjtGetNumChildren());
116         children = ((List) node.childrenAccept(this, children));
117 
118         // Extract Tests and TestList from the children
119         Iterator childrenIter = children.iterator();
120         TestList testList = null;
121         List argList = new ArrayList(children.size());
122         while (childrenIter.hasNext()) {
123             Object next = childrenIter.next();
124             if (next instanceof Test)
125                 testList = new TestList((Test) next);
126             else if (next instanceof TestList)
127                 testList = (TestList) next;
128             else
129                 argList.add(next);
130         }
131 
132         Arguments arguments = new Arguments(argList, testList);
133         ((List) data).add(arguments);
134         return data;
135     }
136 
137     /**
138      * @see SieveParserVisitor#visit(ASTblock, Object)
139      */
140     public Object visit(ASTblock node, Object data) throws SieveException {
141         // if (node.jjtGetNumChildren() != 1)
142         // throw new ParseException("Expecting exactly one 1 child");
143         List children = new ArrayList(node.jjtGetNumChildren());
144         Commands commands = (Commands) ((List) node.childrenAccept(this,
145                 children)).get(0);
146         Block block = new Block(commands);
147         ((List) data).add(block);
148         return data;
149     }
150 
151     /**
152      * @see SieveParserVisitor#visit(ASTcommand, Object)
153      */
154     public Object visit(ASTcommand node, Object data) throws SieveException {
155         List children = new ArrayList(node.jjtGetNumChildren());
156         children = ((List) node.childrenAccept(this, children));
157 
158         // Extract the Arguments and Block from the children
159         Iterator childrenIter = children.iterator();
160         Arguments arguments = null;
161         Block block = null;
162         while (childrenIter.hasNext()) {
163             Object next = childrenIter.next();
164             if (next instanceof Arguments)
165                 arguments = (Arguments) next;
166             else if (next instanceof Block)
167                 block = (Block) next;
168         }
169 
170         context.setCoordinate(node.getCoordinate());
171         final ScriptCoordinate coordinate = context.getCoordinate();
172         Command command = new Command(node.getName(), arguments, block,
173                 coordinate);
174         ((List) data).add(command);
175         return data;
176     }
177 
178     /**
179      * @see SieveParserVisitor#visit(ASTcommands, Object)
180      */
181     public Object visit(ASTcommands node, Object data) throws SieveException {
182         List children = new ArrayList(node.jjtGetNumChildren());
183         Commands commands = new Commands(((List) node.childrenAccept(this,
184                 children)));
185         ((List) data).add(commands);
186         return data;
187     }
188 
189     /**
190      * @see SieveParserVisitor#visit(ASTstart, Object)
191      */
192     public Object visit(ASTstart node, Object data) throws SieveException {
193         // The data object must be the MailAdapter to process
194         if (!(data instanceof MailAdapter))
195             throw new SieveException("Expecting an instance of "
196                     + MailAdapter.class.getName()
197                     + " as data, received an instance of "
198                     + (data == null ? "<null>" : data.getClass().getName())
199                     + ".");
200 
201         // Start is an implicit Block
202         // There will be one child, an instance of Commands
203         List children = new ArrayList(node.jjtGetNumChildren());
204         Commands commands = (Commands) ((List) node.childrenAccept(this,
205                 children)).get(0);
206         Block block = new Block(commands);
207         context.setCoordinate(node.getCoordinate());
208         // Answer the result of executing the Block
209         return block.execute((MailAdapter) data, context);
210     }
211 
212     /**
213      * @see SieveParserVisitor#visit(ASTstring_list, Object)
214      */
215     public Object visit(ASTstring_list node, Object data) throws SieveException {
216         return visitChildren(node, data);
217     }
218 
219     /**
220      * @see SieveParserVisitor#visit(ASTstring, Object)
221      */
222     public Object visit(ASTstring node, Object data) {
223         // Strings are always surround by double-quotes
224         final String value = (String) node.getValue();
225         // A String is terminal, add it
226         ((List) data).add(value);
227         return data;
228     }
229 
230     /**
231      * @see SieveParserVisitor#visit(ASTtest_list, Object)
232      */
233     public Object visit(ASTtest_list node, Object data) throws SieveException {
234         // return visitChildren(node, data);
235         List children = new ArrayList(node.jjtGetNumChildren());
236         TestList testList = new TestList(((List) node.childrenAccept(this,
237                 children)));
238         ((List) data).add(testList);
239         return data;
240     }
241 
242     /**
243      * @see SieveParserVisitor#visit(ASTtest, Object)
244      */
245     public Object visit(ASTtest node, Object data) throws SieveException {
246         List children = new ArrayList(node.jjtGetNumChildren());
247         children = ((List) node.childrenAccept(this, children));
248 
249         // Extract the Arguments from the children
250         Iterator childrenIter = children.iterator();
251         Arguments arguments = null;
252         while (childrenIter.hasNext()) {
253             Object next = childrenIter.next();
254             if (next instanceof Arguments)
255                 arguments = (Arguments) next;
256         }
257 
258         context.setCoordinate(node.getCoordinate());
259         Test test = new Test(node.getName(), arguments);
260         ((List) data).add(test);
261         return data;
262     }
263 
264     /**
265      * @see SieveParserVisitor#visit(SimpleNode, Object)
266      */
267     public Object visit(SimpleNode node, Object data) throws SieveException {
268         return visitChildren(node, data);
269     }
270 
271 }