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 }