153295844df24dff0a1f59e1104795e640b54c2efchrismair/*
253295844df24dff0a1f59e1104795e640b54c2efchrismair * Copyright 2007 the original author or authors.
353295844df24dff0a1f59e1104795e640b54c2efchrismair *
453295844df24dff0a1f59e1104795e640b54c2efchrismair * Licensed under the Apache License, Version 2.0 (the "License");
553295844df24dff0a1f59e1104795e640b54c2efchrismair * you may not use this file except in compliance with the License.
653295844df24dff0a1f59e1104795e640b54c2efchrismair * You may obtain a copy of the License at
753295844df24dff0a1f59e1104795e640b54c2efchrismair *
853295844df24dff0a1f59e1104795e640b54c2efchrismair *      http://www.apache.org/licenses/LICENSE-2.0
953295844df24dff0a1f59e1104795e640b54c2efchrismair *
1053295844df24dff0a1f59e1104795e640b54c2efchrismair * Unless required by applicable law or agreed to in writing, software
1153295844df24dff0a1f59e1104795e640b54c2efchrismair * distributed under the License is distributed on an "AS IS" BASIS,
1253295844df24dff0a1f59e1104795e640b54c2efchrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1353295844df24dff0a1f59e1104795e640b54c2efchrismair * See the License for the specific language governing permissions and
1453295844df24dff0a1f59e1104795e640b54c2efchrismair * limitations under the License.
1553295844df24dff0a1f59e1104795e640b54c2efchrismair */
1653295844df24dff0a1f59e1104795e640b54c2efchrismairpackage org.mockftpserver.stub.command;
1753295844df24dff0a1f59e1104795e640b54c2efchrismair
1853295844df24dff0a1f59e1104795e640b54c2efchrismairimport java.io.IOException;
1953295844df24dff0a1f59e1104795e640b54c2efchrismairimport java.io.InputStream;
2053295844df24dff0a1f59e1104795e640b54c2efchrismair
2153295844df24dff0a1f59e1104795e640b54c2efchrismair
2253295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.apache.log4j.Logger;
2353295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.MockFtpServerException;
2453295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.command.Command;
2553295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.command.CommandHandler;
2653295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.command.InvocationRecord;
2753295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.session.Session;
2853295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.util.Assert;
2953295844df24dff0a1f59e1104795e640b54c2efchrismairimport org.mockftpserver.core.util.AssertFailedException;
3053295844df24dff0a1f59e1104795e640b54c2efchrismair
3153295844df24dff0a1f59e1104795e640b54c2efchrismair/**
3253295844df24dff0a1f59e1104795e640b54c2efchrismair * CommandHandler for the RETR command. Returns the contents of the specified file on the
3353295844df24dff0a1f59e1104795e640b54c2efchrismair * data connection, along with two replies on the control connection: a reply code of 150 and
3453295844df24dff0a1f59e1104795e640b54c2efchrismair * another of 226.
3553295844df24dff0a1f59e1104795e640b54c2efchrismair * <p>
3653295844df24dff0a1f59e1104795e640b54c2efchrismair * The <code>file</code> property specifies the pathname for the file whose contents should
3753295844df24dff0a1f59e1104795e640b54c2efchrismair * be returned from this command. The file path is relative to the CLASSPATH (using the
3853295844df24dff0a1f59e1104795e640b54c2efchrismair * ClassLoader for this class).
3953295844df24dff0a1f59e1104795e640b54c2efchrismair * <p>
4053295844df24dff0a1f59e1104795e640b54c2efchrismair * An exception is thrown if the <code>file</code> property has not been set or if the specified
4153295844df24dff0a1f59e1104795e640b54c2efchrismair * file does not exist or cannot be read.
4253295844df24dff0a1f59e1104795e640b54c2efchrismair * <p>
4353295844df24dff0a1f59e1104795e640b54c2efchrismair * Each invocation record stored by this CommandHandler includes the following data element key/values:
4453295844df24dff0a1f59e1104795e640b54c2efchrismair * <ul>
4553295844df24dff0a1f59e1104795e640b54c2efchrismair *    <li>{@link #PATHNAME_KEY} ("pathname") - the pathname of the file submitted on the invocation (the first command parameter)
4653295844df24dff0a1f59e1104795e640b54c2efchrismair * </ul>
4753295844df24dff0a1f59e1104795e640b54c2efchrismair *
4853295844df24dff0a1f59e1104795e640b54c2efchrismair * @version $Revision$ - $Date$
4953295844df24dff0a1f59e1104795e640b54c2efchrismair *
5053295844df24dff0a1f59e1104795e640b54c2efchrismair * @author Chris Mair
5153295844df24dff0a1f59e1104795e640b54c2efchrismair */
5253295844df24dff0a1f59e1104795e640b54c2efchrismairpublic final class FileRetrCommandHandler extends AbstractStubDataCommandHandler implements CommandHandler {
5353295844df24dff0a1f59e1104795e640b54c2efchrismair
5453295844df24dff0a1f59e1104795e640b54c2efchrismair    public static final String PATHNAME_KEY = "pathname";
5553295844df24dff0a1f59e1104795e640b54c2efchrismair    static final int BUFFER_SIZE = 512;     // package-private for testing
5653295844df24dff0a1f59e1104795e640b54c2efchrismair    private static final Logger LOG = Logger.getLogger(FileRetrCommandHandler.class);
5753295844df24dff0a1f59e1104795e640b54c2efchrismair
5853295844df24dff0a1f59e1104795e640b54c2efchrismair    private String file;
5953295844df24dff0a1f59e1104795e640b54c2efchrismair
6053295844df24dff0a1f59e1104795e640b54c2efchrismair    /**
6153295844df24dff0a1f59e1104795e640b54c2efchrismair     * Create new uninitialized instance
6253295844df24dff0a1f59e1104795e640b54c2efchrismair     */
6353295844df24dff0a1f59e1104795e640b54c2efchrismair    public FileRetrCommandHandler() {
6453295844df24dff0a1f59e1104795e640b54c2efchrismair    }
6553295844df24dff0a1f59e1104795e640b54c2efchrismair
6653295844df24dff0a1f59e1104795e640b54c2efchrismair    /**
6753295844df24dff0a1f59e1104795e640b54c2efchrismair     * Create new instance using the specified file pathname
6853295844df24dff0a1f59e1104795e640b54c2efchrismair     * @param file - the path to the file
6953295844df24dff0a1f59e1104795e640b54c2efchrismair     * @throws AssertFailedException - if the file is null
7053295844df24dff0a1f59e1104795e640b54c2efchrismair     */
7153295844df24dff0a1f59e1104795e640b54c2efchrismair    public FileRetrCommandHandler(String file) {
7253295844df24dff0a1f59e1104795e640b54c2efchrismair        setFile(file);
7353295844df24dff0a1f59e1104795e640b54c2efchrismair    }
7453295844df24dff0a1f59e1104795e640b54c2efchrismair
7553295844df24dff0a1f59e1104795e640b54c2efchrismair    /**
7653295844df24dff0a1f59e1104795e640b54c2efchrismair     * @see org.mockftpserver.stub.command.AbstractStubDataCommandHandler#beforeProcessData(org.mockftpserver.core.command.Command, org.mockftpserver.core.session.Session, org.mockftpserver.core.command.InvocationRecord)
7753295844df24dff0a1f59e1104795e640b54c2efchrismair     */
7853295844df24dff0a1f59e1104795e640b54c2efchrismair    protected void beforeProcessData(Command command, Session session, InvocationRecord invocationRecord) throws Exception {
7953295844df24dff0a1f59e1104795e640b54c2efchrismair        Assert.notNull(file, "file");
8053295844df24dff0a1f59e1104795e640b54c2efchrismair        invocationRecord.set(PATHNAME_KEY, command.getRequiredString(0));
8153295844df24dff0a1f59e1104795e640b54c2efchrismair    }
8253295844df24dff0a1f59e1104795e640b54c2efchrismair
8353295844df24dff0a1f59e1104795e640b54c2efchrismair    /**
8453295844df24dff0a1f59e1104795e640b54c2efchrismair     * @see org.mockftpserver.stub.command.AbstractStubDataCommandHandler#processData(org.mockftpserver.core.command.Command, org.mockftpserver.core.session.Session, org.mockftpserver.core.command.InvocationRecord)
8553295844df24dff0a1f59e1104795e640b54c2efchrismair     */
8653295844df24dff0a1f59e1104795e640b54c2efchrismair    protected void processData(Command command, Session session, InvocationRecord invocationRecord) {
8753295844df24dff0a1f59e1104795e640b54c2efchrismair        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(file);
8853295844df24dff0a1f59e1104795e640b54c2efchrismair        Assert.notNull(inputStream, "InputStream for [" + file + "]");
8953295844df24dff0a1f59e1104795e640b54c2efchrismair        byte[] buffer = new byte[BUFFER_SIZE];
9053295844df24dff0a1f59e1104795e640b54c2efchrismair        try {
9153295844df24dff0a1f59e1104795e640b54c2efchrismair            int numBytes = 0;
9253295844df24dff0a1f59e1104795e640b54c2efchrismair            while ((numBytes = inputStream.read(buffer)) != -1) {
9353295844df24dff0a1f59e1104795e640b54c2efchrismair                LOG.trace("Sending " + numBytes + " bytes...");
9453295844df24dff0a1f59e1104795e640b54c2efchrismair                session.sendData(buffer, numBytes);
9553295844df24dff0a1f59e1104795e640b54c2efchrismair            }
9653295844df24dff0a1f59e1104795e640b54c2efchrismair        }
9753295844df24dff0a1f59e1104795e640b54c2efchrismair        catch(IOException e) {
9853295844df24dff0a1f59e1104795e640b54c2efchrismair            throw new MockFtpServerException(e);
9953295844df24dff0a1f59e1104795e640b54c2efchrismair        }
10053295844df24dff0a1f59e1104795e640b54c2efchrismair    }
10153295844df24dff0a1f59e1104795e640b54c2efchrismair
10253295844df24dff0a1f59e1104795e640b54c2efchrismair    /**
10353295844df24dff0a1f59e1104795e640b54c2efchrismair     * Set the path of the file whose contents should be returned when this command is
10453295844df24dff0a1f59e1104795e640b54c2efchrismair     * invoked. The path is relative to the CLASSPATH.
10553295844df24dff0a1f59e1104795e640b54c2efchrismair     * @param file - the path to the file
10653295844df24dff0a1f59e1104795e640b54c2efchrismair     * @throws AssertFailedException - if the file is null
10753295844df24dff0a1f59e1104795e640b54c2efchrismair     */
10853295844df24dff0a1f59e1104795e640b54c2efchrismair    public void setFile(String file) {
10953295844df24dff0a1f59e1104795e640b54c2efchrismair        Assert.notNull(file, "file");
11053295844df24dff0a1f59e1104795e640b54c2efchrismair        this.file = file;
11153295844df24dff0a1f59e1104795e640b54c2efchrismair    }
11253295844df24dff0a1f59e1104795e640b54c2efchrismair
11353295844df24dff0a1f59e1104795e640b54c2efchrismair}
114