001/****************************************************************
002 * Licensed to the Apache Software Foundation (ASF) under one   *
003 * or more contributor license agreements.  See the NOTICE file *
004 * distributed with this work for additional information        *
005 * regarding copyright ownership.  The ASF licenses this file   *
006 * to you under the Apache License, Version 2.0 (the            *
007 * "License"); you may not use this file except in compliance   *
008 * with the License.  You may obtain a copy of the License at   *
009 *                                                              *
010 *   http://www.apache.org/licenses/LICENSE-2.0                 *
011 *                                                              *
012 * Unless required by applicable law or agreed to in writing,   *
013 * software distributed under the License is distributed on an  *
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
015 * KIND, either express or implied.  See the License for the    *
016 * specific language governing permissions and limitations      *
017 * under the License.                                           *
018 ****************************************************************/
019
020package org.apache.james.mpt.protocol;
021
022import java.io.BufferedReader;
023import java.io.InputStream;
024import java.io.InputStreamReader;
025import java.util.ArrayList;
026import java.util.List;
027
028import org.apache.commons.io.IOUtils;
029import org.apache.james.mpt.protocol.ProtocolSession.TimerCommand;
030
031/**
032 * A builder which generates a ProtocolSession from a test file.
033 * 
034 * @author Darrell DeBoer <darrell@apache.org>
035 * 
036 * @version $Revision$
037 */
038public class FileProtocolSessionBuilder extends ProtocolSessionBuilder {
039
040    public static final String DEBUG = "DEBUG";
041    public static final String INFO = "INFO";
042    public static final String WARN = "WARN";
043    public static final String ERR = "ERR";
044
045    private static final int TIMER_COMMAND_START = TIMER.length() + 1;
046    private static final int TIMER_COMMAND_END = TIMER_COMMAND_START + 5;
047
048    /**
049     * Builds a ProtocolSession by reading lines from the test file with the
050     * supplied name.
051     * 
052     * @param fileName
053     *            The name of the protocol session file.
054     * @return The ProtocolSession
055     */
056    public ProtocolSession buildProtocolSession(String fileName) throws Exception {
057        ProtocolSession session = new ProtocolSession();
058        addTestFile(fileName, session);
059        return session;
060    }
061
062    /**
063     * Adds all protocol elements from a test file to the ProtocolSession
064     * supplied.
065     * 
066     * @param fileName
067     *            The name of the protocol session file.
068     * @param session
069     *            The ProtocolSession to add the elements to.
070     */
071    public void addTestFile(String fileName, ProtocolSession session) throws Exception {
072        // Need to find local resource.
073        InputStream is = this.getClass().getResourceAsStream(fileName);
074        if (is == null) {
075            throw new Exception("Test Resource '" + fileName + "' not found.");
076        }
077
078        try {
079            addProtocolLinesFromStream(is, session, fileName);
080        }
081        finally {
082            IOUtils.closeQuietly(is);
083        }
084    }
085
086    /**
087     * Reads ProtocolElements from the supplied InputStream and adds them to the
088     * ProtocolSession.
089     * 
090     * @param is
091     *            The input stream containing the protocol definition.
092     * @param session
093     *            The ProtocolSession to add elements to.
094     * @param fileName
095     *            The name of the source file, for error messages.
096     */
097    public void addProtocolLinesFromStream(InputStream is, ProtocolSession session, String fileName) throws Exception {
098        int sessionNumber = -1;
099        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
100        try {
101            String next;
102            int lineNumber = -1;
103            String lastClientMsg = "";
104            while ((next = reader.readLine()) != null) {
105                String location = fileName + ":" + lineNumber;
106                if (SERVER_CONTINUATION_TAG.equals(next)) {
107                    session.CONT(sessionNumber);
108                }
109                else if (next.startsWith(CLIENT_TAG)) {
110                    String clientMsg = "";
111                    if (next.length() > 3) {
112                        clientMsg = next.substring(3);
113                    }
114                    session.CL(sessionNumber, clientMsg);
115                    lastClientMsg = clientMsg;
116                }
117                else if (next.startsWith(SERVER_TAG)) {
118                    String serverMsg = "";
119                    if (next.length() > 3) {
120                        serverMsg = next.substring(3);
121                    }
122                    session.SL(sessionNumber, serverMsg, location, lastClientMsg);
123                }
124                else if (next.startsWith(WAIT)) {
125                    if (next.length() > 5) {
126                        session.WAIT(sessionNumber, Long.valueOf(next.substring(5)));
127                    } else {
128                        throw new Exception("Invalid line length on WAIT instruction : " + next);
129                    }
130                }
131                else if (next.startsWith(LOG)) {
132                    String logInstruction = next.substring(4);
133                    if (logInstruction.startsWith(DEBUG)) {
134                        session.LOG(sessionNumber, ProtocolSession.LolLevel.Debug, logInstruction.substring(6));
135                    } else if (logInstruction.startsWith(INFO)) {
136                        session.LOG(sessionNumber, ProtocolSession.LolLevel.Info, logInstruction.substring(5));
137                    } else if (logInstruction.startsWith(WARN)) {
138                        session.LOG(sessionNumber, ProtocolSession.LolLevel.Warn, logInstruction.substring(5));
139                    } else if (logInstruction.startsWith(ERR)) {
140                        session.LOG(sessionNumber, ProtocolSession.LolLevel.Err, logInstruction.substring(4));
141                    } else {
142                        throw new Exception("Unrecognized log level for " + next);
143                    }
144                }
145                else if (next.startsWith(REINIT)) {
146                    session.REINIT(sessionNumber);
147                }
148                else if (next.startsWith(OPEN_UNORDERED_BLOCK_TAG)) {
149                    List<String> unorderedLines = new ArrayList<String>(5);
150                    next = reader.readLine();
151
152                    if (next == null)
153                        throw new Exception("Readline doesn't contain any data, but must not be 'null' (linenumber="
154                                + lineNumber);
155
156                    while (!next.startsWith(CLOSE_UNORDERED_BLOCK_TAG)) {
157                        if (!next.startsWith(SERVER_TAG)) {
158                            throw new Exception("Only 'S: ' lines are permitted inside a 'SUB {' block.");
159                        }
160                        String serverMsg = next.substring(3);
161                        unorderedLines.add(serverMsg);
162                        next = reader.readLine();
163                        lineNumber++;
164
165                        if (next == null)
166                            throw new Exception(
167                                    "Readline doesn't contain any data, but must not be 'null' (linenumber="
168                                            + lineNumber);
169
170                    }
171
172                    session.SUB(sessionNumber, unorderedLines, location, lastClientMsg);
173                }
174                else if (next.startsWith(COMMENT_TAG) || next.trim().length() == 0) {
175                    // ignore these lines.
176                }
177                else if (next.startsWith(SESSION_TAG)) {
178                    String number = next.substring(SESSION_TAG.length()).trim();
179                    if (number.length() == 0) {
180                        throw new Exception("No session number specified");
181                    }
182                    sessionNumber = Integer.parseInt(number);
183                }
184                else if (next.startsWith(TIMER)) {
185                    TimerCommand timerCommand = TimerCommand.from(next.substring(TIMER_COMMAND_START, TIMER_COMMAND_END));
186                    String timerName = next.substring(TIMER_COMMAND_END + 1);
187                    session.TIMER(timerCommand, timerName);
188                }
189                else {
190                    String prefix = next;
191                    if (next.length() > 3) {
192                        prefix = next.substring(0, 3);
193                    }
194                    throw new Exception("Invalid line prefix: " + prefix);
195                }
196                lineNumber++;
197            }
198        }
199        finally {
200            IOUtils.closeQuietly(reader);
201        }
202    }
203
204}