193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair/*
293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Copyright 2007 the original author or authors.
393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Licensed under the Apache License, Version 2.0 (the "License");
593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * you may not use this file except in compliance with the License.
693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * You may obtain a copy of the License at
793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *      http://www.apache.org/licenses/LICENSE-2.0
993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
1093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Unless required by applicable law or agreed to in writing, software
1193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * distributed under the License is distributed on an "AS IS" BASIS,
1293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * See the License for the specific language governing permissions and
1493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * limitations under the License.
1593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */
1693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairpackage org.mockftpserver.core.command;
1793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
18848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismairimport org.mockftpserver.core.session.Session;
19848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismairimport org.mockftpserver.core.util.Assert;
20848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismairimport org.mockftpserver.core.util.AssertFailedException;
21848932d9e7c6953b3c345c9aa6b0b6c3cfe20d79chrismair
2293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport java.util.ArrayList;
2393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport java.util.Iterator;
2493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport java.util.List;
2593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairimport java.util.ResourceBundle;
2693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
2793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair/**
2893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * Composite CommandHandler that manages an internal list of CommandHandlers to which it delegates.
2993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * The internal CommandHandlers are maintained in an ordered list. Starting with the first
3093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * CommandHandler in the list, each invocation of this composite handler will invoke (delegate to)
3193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * the current internal CommandHander. Then it moves on the next CommandHandler in the internal list.
3293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * <p>
3393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * The following example replaces the CWD CommandHandler with a <code>SimpleCompositeCommandHandler</code>.
3493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * The first invocation of the CWD command will fail (reply code 500). The seconds will succeed.
3593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * <pre><code>
3693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
3793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * StubFtpServer stubFtpServer = new StubFtpServer();
3893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
3993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * CommandHandler commandHandler1 = new StaticReplyCommandHandler(500);
4093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * CommandHandler commandHandler2 = new CwdCommandHandler();
4193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
4293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * SimpleCompositeCommandHandler simpleCompositeCommandHandler = new SimpleCompositeCommandHandler();
4393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * simpleCompositeCommandHandler.addCommandHandler(commandHandler1);
4493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * simpleCompositeCommandHandler.addCommandHandler(commandHandler2);
4593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
4693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * stubFtpServer.setCommandHandler("CWD", simpleCompositeCommandHandler);
4793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * </code></pre>
4893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
494ca3386623ce60063f27955ad1b2b1b6cbba8b09chrismair * @version $Revision$ - $Date$
5093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair *
5193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair * @author Chris Mair
5293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair */
5393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismairpublic final class SimpleCompositeCommandHandler implements CommandHandler, ReplyTextBundleAware {
5493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
5593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    private List commandHandlers = new ArrayList();
5693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    private int invocationIndex = 0;
5793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
5893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    /**
5993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * Add a CommandHandler to the internal list of handlers.
6093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     *
6193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @param commandHandler - the CommandHandler
6293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     *
6393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @throws AssertFailedException - if the commandHandler is null
6493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     */
6593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    public void addCommandHandler(CommandHandler commandHandler) {
6693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.notNull(commandHandler, "commandHandler");
6793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        commandHandlers.add(commandHandler);
6893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    }
6993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
7093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    /**
7193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * Set the List of CommandHandlers to which to delegate. This replaces any CommandHandlers that
7293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * have been defined previously.
7393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @param commandHandlers - the complete List of CommandHandlers to which invocations are delegated
7493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     */
7593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    public void setCommandHandlers(List commandHandlers) {
7693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.notNull(commandHandlers, "commandHandlers");
7793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        this.commandHandlers = new ArrayList(commandHandlers);
7893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    }
7993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
8093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    /**
8193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * Return the CommandHandler corresponding to the specified invocation index. In other words, return
8293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * the CommandHandler instance to which the Nth {@link #handleCommand(Command, Session)} has been or will
8393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * be delegated (where N=index).
8493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @param index - the index of the desired invocation (zero-based).
8593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @return the CommandHandler
8693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     *
8793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @throws AssertFailedException - if no CommandHandler is defined for the index or the index is not valid
8893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     */
8993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    public CommandHandler getCommandHandler(int index) {
9093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.isTrue(index < commandHandlers.size(), "No CommandHandler defined for index " + index);
9193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.isTrue(index >= 0, "The index cannot be less than zero: " + index);
9293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        return (CommandHandler) commandHandlers.get(index);
9393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    }
9493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
9593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    /**
9693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @see org.mockftpserver.core.command.CommandHandler#handleCommand(org.mockftpserver.core.command.Command, org.mockftpserver.core.session.Session)
9793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     */
9893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    public void handleCommand(Command command, Session session) throws Exception {
9993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.notNull(command, "command");
10093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.notNull(session, "session");
10193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        Assert.isTrue(commandHandlers.size() > invocationIndex, "No CommandHandler defined for invocation #" + invocationIndex);
10293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
10393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        CommandHandler commandHandler = (CommandHandler) commandHandlers.get(invocationIndex);
10493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        invocationIndex++;
10593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        commandHandler.handleCommand(command, session);
10693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    }
10793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
10893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    /**
10993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * Returns null. This is a composite, and has no reply text bundle.
11093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     *
11193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @see org.mockftpserver.core.command.ReplyTextBundleAware#getReplyTextBundle()
11293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     */
11393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    public ResourceBundle getReplyTextBundle() {
11493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        return null;
11593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    }
11693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
11793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    /**
11893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * Call <code>setReplyTextBundle()</code> on each of the command handlers within the internal list.
11993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     *
12093102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     * @see org.mockftpserver.core.command.ReplyTextBundleAware#setReplyTextBundle(java.util.ResourceBundle)
12193102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair     */
12293102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    public void setReplyTextBundle(ResourceBundle replyTextBundle) {
12393102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        for (Iterator iter = commandHandlers.iterator(); iter.hasNext();) {
12493102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair            CommandHandler commandHandler = (CommandHandler) iter.next();
12593102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair            ReplyTextBundleUtil.setReplyTextBundleIfAppropriate(commandHandler, replyTextBundle);
12693102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair        }
12793102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair    }
12893102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair
12993102446a7b7c3d17888064b4e2e4e5cb534e6d0chrismair}
130