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.io.InputStream;
23  
24  import org.apache.commons.logging.Log;
25  import org.apache.jsieve.exception.SieveException;
26  import org.apache.jsieve.exception.StopException;
27  import org.apache.jsieve.mail.ActionKeep;
28  import org.apache.jsieve.mail.MailAdapter;
29  import org.apache.jsieve.parser.generated.Node;
30  import org.apache.jsieve.parser.generated.ParseException;
31  import org.apache.jsieve.parser.generated.SieveParser;
32  import org.apache.jsieve.parser.generated.SieveParserVisitor;
33  import org.apache.jsieve.parser.generated.SimpleNode;
34  
35  /**
36   * <p>
37   * SieveFactory is the primary invocation point for all Sieve
38   * operations. Theses are...
39   * <dl>
40   * <dt>parse</dt>
41   * <dd> Parse a Sieve script into a hierarchy of parsed nodes. A succesful parse
42   * means the script is lexically and gramatically valid according to RFC 3028,
43   * section 8. The result is the start node of the parsed Sieve script. The start
44   * node is resuable. Typically it is stored for reuse in all subsequent
45   * evaluations of the script. </dd>
46   * <dt>evaluate</dt>
47   * <dd> Evaluate an RFC 822 compliant mail message wrapped in a MailAdapter
48   * against the parse result referenced by the start node from the Parse
49   * operation above. As evaluation proceeds a List of Actions is added to the
50   * MailAdapter. At the end of evaluation, each Action in the List is executed in
51   * the order they were added. </dd>
52   * <dt>interpret/dt>
53   * <dd>A concatenation of parse and evaluate. Useful for testing, but generally
54   * the parse result should be stored for reuse in subsequent evaluations. </dd>
55   * </dl>
56   * </p>
57   * 
58   * 
59   */
60  public class SieveFactory {
61  
62      private final CommandManager commandManager;
63  
64      private final ComparatorManager comparatorManager;
65  
66      private final TestManager testManager;
67  
68      private final Log log;
69  
70      /**
71       * Constructor for SieveFactory.
72       */
73      public SieveFactory(final CommandManager commandManager,
74              final ComparatorManager comparatorManager,
75              final TestManager testManager, final Log log) {
76          super();
77          this.commandManager = commandManager;
78          this.comparatorManager = comparatorManager;
79          this.testManager = testManager;
80          this.log = log;
81      }
82  
83      /**
84       * Method parse parses a Sieve script into a hierarchy of parsed nodes. A
85       * successful parse means the script is lexically and grammatically valid
86       * according to RFC 3028, section 8. The result is the start node of the
87       * parsed Sieve script. The start node is reusable. Typically it is stored
88       * for reuse in subsequent evaluations of the script.
89       * 
90       * @param inputStream
91       * @return Node
92       * @throws ParseException
93       */
94      public Node parse(InputStream inputStream) throws ParseException {
95          try {
96              final SimpleNode node = new SieveParser(inputStream, "UTF-8")
97                      .start();
98              SieveValidationVisitor visitor = new SieveValidationVisitor(
99                      commandManager, testManager);
100             node.jjtAccept(visitor, null);
101             return node;
102         } catch (ParseException ex) {
103             if (log.isErrorEnabled())
104                 log.error("Parse failed. Reason: " + ex.getMessage());
105             if (log.isDebugEnabled())
106                 log.debug("Parse failed.", ex);
107             throw ex;
108         } catch (SieveException ex) {
109             if (log.isErrorEnabled())
110                 log.error("Parse failed. Reason: " + ex.getMessage());
111             if (log.isDebugEnabled())
112                 log.debug("Parse failed.", ex);
113             throw new ParseException(ex.getMessage());
114         }
115     }
116 
117     /**
118      * <p>
119      * Method evaluate evaluates an RFC 822 compliant mail message wrapped in a
120      * MailAdapter by visting each node of the parsed script beginning at the
121      * passed start node. As evaluation proceeds a List of Actions is added to
122      * the MailAdapter.
123      * <p>
124      * 
125      * <p>
126      * At the start of evaluation an 'implicitKeep' state is set. This can be
127      * cancelled by a Command during evaluation. If 'implicitKeep' is still set
128      * at the end of evaluation, a Keep Action is added to the List of Actions.
129      * Finally, each Action in the List is executed in the order they were
130      * added.
131      * </p>
132      * 
133      * @param mail
134      * @param startNode
135      * @throws SieveException
136      */
137     public void evaluate(MailAdapter mail, Node startNode)
138             throws SieveException {
139         SieveContext context = new BaseSieveContext(commandManager,
140                 comparatorManager, testManager, log);
141         SieveParserVisitor visitor = new SieveParserVisitorImpl(context);
142         try {
143             // Evaluate the Nodes
144             startNode.jjtAccept(visitor, mail);
145 
146         } catch (StopException ex) {
147             // Stop is OK
148         } catch (SieveException ex) {
149             if (log.isErrorEnabled())
150                 log.error("Evaluation failed. Reason: " + ex.getMessage());
151             if (log.isDebugEnabled())
152                 log.debug("Evaluation failed.", ex);
153             throw ex;
154         }
155 
156         // If after evaluating all of the nodes or stopping, implicitKeep is
157         // still
158         // in effect, add a Keep to the list of Actions.
159         if (context.getCommandStateManager().isImplicitKeep())
160             mail.addAction(new ActionKeep());
161 
162         // Execute the List of Actions
163         try {
164             mail.executeActions();
165         } catch (SieveException ex) {
166             if (log.isErrorEnabled())
167                 log.error("Evaluation failed. Reason: " + ex.getMessage());
168             if (log.isDebugEnabled())
169                 log.debug("Evaluation failed.", ex);
170             throw ex;
171         }
172     }
173 
174     /**
175      * Method interpret parses a Sieve script and then evaluates the result
176      * against a mail.
177      * 
178      * @param mail
179      * @param inputStream
180      * @throws ParseException
181      * @throws SieveException
182      */
183     public void interpret(MailAdapter mail, InputStream inputStream)
184             throws ParseException, SieveException {
185         evaluate(mail, parse(inputStream));
186     }
187 }