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  package org.apache.jsieve.util;
20  
21  import java.io.IOException;
22  import java.io.Writer;
23  
24  /**
25   * <p>Builds sieve handlers that convert nodes to a Sieve script.</p>
26   * <h4>Usage</h4>
27   * <ul>
28   * <li>Create an instance</li>
29   * <li>Configure using setters</li>
30   * <li>{@link #build(Writer)} configured {@link SieveHandler}</li>
31   * <li>Supply handler to {@link NodeTraverser}</li>
32   * </ul>
33   * <p>
34   * Handler instances are fully configured when built. 
35   * Changes to the factory configuration will not effect 
36   * them.
37   * </p>
38   */
39  public class ToSieveHandlerFactory {
40  
41      /**
42       * Builds a configured handler.
43       * @return not null
44       * @see NodeToSieveAdapter
45       * @see NodeTraverser
46       */
47      public SieveHandler build(final Writer writer) {
48          return new ToSieveHandler(writer);
49      }
50      
51      /**
52       * Thread safe worker.
53       */
54      private static final class ToSieveHandler extends SieveHandler.Base {
55          private final Writer writer;
56          
57          private boolean commaRequiredBeforeNextTest;
58          private boolean firstTestInList;
59          private boolean commandUsedBlock;
60          private boolean commandAfterEndCommand;
61       
62          public ToSieveHandler(final Writer writer) {
63              this.writer = writer;
64              commaRequiredBeforeNextTest = false;
65              firstTestInList = false;
66              commandUsedBlock = false;
67              commandAfterEndCommand = false;
68          }
69          
70          /** @see SieveHandler#endBlock() */
71          @Override
72          public SieveHandler endBlock() throws HaltTraversalException {
73              commandUsedBlock = true;
74              return append('}');
75          }
76  
77          /** @see SieveHandler#startBlock() */
78          @Override
79          public SieveHandler startBlock() throws HaltTraversalException {
80              space();
81              return append('{');
82          }
83          
84          /** @see SieveHandler#startCommand() */
85          @Override
86          public SieveHandler startCommand(String commandName) throws HaltTraversalException {
87              commaRequiredBeforeNextTest = false;
88              if (commandAfterEndCommand) {
89                  space();
90                  commandAfterEndCommand = false;
91              }
92              return append(commandName);
93          }
94          
95          /** @see SieveHandler#endCommand() */
96          @Override
97          public SieveHandler endCommand(String commandName) throws HaltTraversalException {
98              if (!commandUsedBlock) {
99                  append(';');
100             }
101             commandAfterEndCommand = true;
102             commandUsedBlock = false;
103             return this;
104         }
105         
106         /** @see SieveHandler#argument(String) */
107         @Override
108         public SieveHandler argument(String tag) throws HaltTraversalException {
109             space();
110             append(':');
111             return append(tag);
112         }
113 
114         /**
115          * Appends white space.
116          * @throws HaltTraversalException
117          */
118         private void space() throws HaltTraversalException {
119             append(' ');
120         }
121 
122         /** @see SieveHandler#argument(int) */
123         @Override
124         public SieveHandler argument(int number) throws HaltTraversalException {
125             space();
126             return append(Integer.toString(number));
127         }
128         
129         /** @see SieveHandler#startStringListArgument() */
130         @Override
131         public SieveHandler startStringListArgument() throws HaltTraversalException {
132             space();
133             return append('[');
134         }
135         
136         /** @see SieveHandler#endStringListArgument() */
137         @Override
138         public SieveHandler endStringListArgument() throws HaltTraversalException {
139             return append(']');
140         }
141         
142         /** @see SieveHandler#listMember(String) */
143         @Override
144         public SieveHandler listMember(String string) throws HaltTraversalException {
145             append('"');
146             for (int i=0;i<string.length();i++) {
147                 char next = string.charAt(i);
148                 if (next == '"' || next == '\\' || next =='\r' || next =='\f') {
149                     append('\\');
150                 } 
151                 append(next);
152             }
153             return append('"');
154         }
155         
156         
157         /** @see SieveHandler#startTestList() */
158         @Override
159         public SieveHandler startTestList() throws HaltTraversalException {
160             firstTestInList = true;
161             commaRequiredBeforeNextTest = false;
162             return append('(');
163         }
164         
165         /** @see SieveHandler#endTestList() */
166         @Override
167         public SieveHandler endTestList() throws HaltTraversalException {
168             commaRequiredBeforeNextTest = false;
169             return append(')');
170         }
171 
172         /** @see SieveHandler#startTest(String) */
173         @Override
174         public SieveHandler startTest(String testName) throws HaltTraversalException {
175             if (commaRequiredBeforeNextTest) {
176                 append(",");
177             }
178             if (!firstTestInList) {
179                 space();
180             }
181             commaRequiredBeforeNextTest = true;
182             firstTestInList = false;
183             return append(testName);
184         }
185 
186         /**
187          * Appends the given sequence.
188          * @param character to be appended
189          * @return this
190          * @throws HaltTraversalException when character cannot be written
191          */
192         private SieveHandler append(CharSequence characterSequence) throws HaltTraversalException {
193             try {
194                 writer.append(characterSequence);
195                 return this;
196             } catch (IOException e) {
197                 throw new HaltTraversalException(e);
198             }
199         }
200         
201         /**
202          * Appends the given character.
203          * @param character to be appended
204          * @return this
205          * @throws HaltTraversalException when character cannot be written
206          */
207         private SieveHandler append(char character) throws HaltTraversalException {
208             try {
209                 writer.append(character);
210                 return this;
211             } catch (IOException e) {
212                 throw new HaltTraversalException(e);
213             }
214         }
215     }
216 }