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 }