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      @SuppressWarnings("unchecked")
86      protected Object visitChildren(SimpleNode node, Object data)
87              throws SieveException {
88          List children = new ArrayList(node.jjtGetNumChildren());
89          node.childrenAccept(this, children);
90          ((List) data).addAll(children);
91          return data;
92      }
93  
94      /**
95       * @see SieveParserVisitor#visit(ASTargument, Object)
96       */
97      @SuppressWarnings("unchecked")
98      public Object visit(ASTargument node, Object data) throws SieveException {
99          List<String> children = new ArrayList<String>(node.jjtGetNumChildren());
100         Argument argument = null;
101 
102         if (null != node.getValue()) {
103             argument = (Argument) node.getValue();
104         } else {
105             argument = new StringListArgument(((List) node.childrenAccept(this,
106                     children)));
107         }
108         ((List) data).add(argument);
109 
110         return data;
111     }
112 
113     /**
114      * @see SieveParserVisitor#visit(ASTarguments, Object)
115      */
116     @SuppressWarnings("unchecked")
117     public Object visit(ASTarguments node, Object data) throws SieveException {
118         List children = new ArrayList(node.jjtGetNumChildren());
119         children = ((List) node.childrenAccept(this, children));
120 
121         // Extract Tests and TestList from the children
122         Iterator childrenIter = children.iterator();
123         TestList testList = null;
124         List<Argument> argList = new ArrayList<Argument>(children.size());
125         while (childrenIter.hasNext()) {
126             Object next = childrenIter.next();
127             if (next instanceof Test)
128                 testList = new TestList((Test) next);
129             else if (next instanceof TestList)
130                 testList = (TestList) next;
131             else if (next instanceof Argument) {
132                 argList.add((Argument)next);
133             } else {
134                 context.getLog().error("Expected an 'Argument' but was " + next);
135             }
136         }
137 
138         Arguments arguments = new Arguments(argList, testList);
139         ((List) data).add(arguments);
140         return data;
141     }
142 
143     /**
144      * @see SieveParserVisitor#visit(ASTblock, Object)
145      */
146     @SuppressWarnings("unchecked")
147     public Object visit(ASTblock node, Object data) throws SieveException {
148         // if (node.jjtGetNumChildren() != 1)
149         // throw new ParseException("Expecting exactly one 1 child");
150         List children = new ArrayList(node.jjtGetNumChildren());
151         Commands commands = (Commands) ((List) node.childrenAccept(this,
152                 children)).get(0);
153         Block block = new Block(commands);
154         ((List) data).add(block);
155         return data;
156     }
157 
158     /**
159      * @see SieveParserVisitor#visit(ASTcommand, Object)
160      */
161     @SuppressWarnings("unchecked")
162     public Object visit(ASTcommand node, Object data) throws SieveException {
163         List children = new ArrayList(node.jjtGetNumChildren());
164         children = ((List) node.childrenAccept(this, children));
165 
166         // Extract the Arguments and Block from the children
167         Iterator childrenIter = children.iterator();
168         Arguments arguments = null;
169         Block block = null;
170         while (childrenIter.hasNext()) {
171             Object next = childrenIter.next();
172             if (next instanceof Arguments)
173                 arguments = (Arguments) next;
174             else if (next instanceof Block)
175                 block = (Block) next;
176         }
177 
178         context.setCoordinate(node.getCoordinate());
179         final ScriptCoordinate coordinate = context.getCoordinate();
180         Command command = new Command(node.getName(), arguments, block,
181                 coordinate);
182         ((List) data).add(command);
183         return data;
184     }
185 
186     /**
187      * @see SieveParserVisitor#visit(ASTcommands, Object)
188      */
189     @SuppressWarnings("unchecked")
190     public Object visit(ASTcommands node, Object data) throws SieveException {
191         List<Command> children = new ArrayList<Command>(node.jjtGetNumChildren());
192         Commands commands = new Commands(((List) node.childrenAccept(this,
193                 children)));
194         ((List) data).add(commands);
195         return data;
196     }
197 
198     /**
199      * @see SieveParserVisitor#visit(ASTstart, Object)
200      */
201     public Object visit(ASTstart node, Object data) throws SieveException {
202         // The data object must be the MailAdapter to process
203         if (!(data instanceof MailAdapter))
204             throw new SieveException("Expecting an instance of "
205                     + MailAdapter.class.getName()
206                     + " as data, received an instance of "
207                     + (data == null ? "<null>" : data.getClass().getName())
208                     + ".");
209 
210         // Start is an implicit Block
211         // There will be one child, an instance of Commands
212         List children = new ArrayList(node.jjtGetNumChildren());
213         Commands commands = (Commands) ((List) node.childrenAccept(this,
214                 children)).get(0);
215         Block block = new Block(commands);
216         context.setCoordinate(node.getCoordinate());
217         // Answer the result of executing the Block
218         return block.execute((MailAdapter) data, context);
219     }
220 
221     /**
222      * @see SieveParserVisitor#visit(ASTstring_list, Object)
223      */
224     public Object visit(ASTstring_list node, Object data) throws SieveException {
225         return visitChildren(node, data);
226     }
227 
228     /**
229      * @see SieveParserVisitor#visit(ASTstring, Object)
230      */
231     @SuppressWarnings("unchecked")
232     public Object visit(ASTstring node, Object data) {
233         // Strings are always surround by double-quotes
234         final String value = (String) node.getValue();
235         // A String is terminal, add it
236         ((List) data).add(value);
237         return data;
238     }
239 
240     /**
241      * @see SieveParserVisitor#visit(ASTtest_list, Object)
242      */
243     @SuppressWarnings("unchecked")
244     public Object visit(ASTtest_list node, Object data) throws SieveException {
245         // return visitChildren(node, data);
246         List<Test> children = new ArrayList<Test>(node.jjtGetNumChildren());
247         TestList testList = new TestList(((List<Test>) node.childrenAccept(this,
248                 children)));
249         ((List) data).add(testList);
250         return data;
251     }
252 
253     /**
254      * @see SieveParserVisitor#visit(ASTtest, Object)
255      */
256     @SuppressWarnings("unchecked")
257     public Object visit(ASTtest node, Object data) throws SieveException {
258         List children = new ArrayList(node.jjtGetNumChildren());
259         children = ((List) node.childrenAccept(this, children));
260 
261         // Extract the Arguments from the children
262         Iterator childrenIter = children.iterator();
263         Arguments arguments = null;
264         while (childrenIter.hasNext()) {
265             Object next = childrenIter.next();
266             if (next instanceof Arguments)
267                 arguments = (Arguments) next;
268         }
269 
270         context.setCoordinate(node.getCoordinate());
271         Test test = new Test(node.getName(), arguments);
272         ((List) data).add(test);
273         return data;
274     }
275 
276     /**
277      * @see SieveParserVisitor#visit(SimpleNode, Object)
278      */
279     public Object visit(SimpleNode node, Object data) throws SieveException {
280         return visitChildren(node, data);
281     }
282 
283 }