1a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair/*
2a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * Copyright 2008 the original author or authors.
3a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair *
4a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * Licensed under the Apache License, Version 2.0 (the "License");
5a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * you may not use this file except in compliance with the License.
6a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * You may obtain a copy of the License at
7a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair *
8a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair *      http://www.apache.org/licenses/LICENSE-2.0
9a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair *
10a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * Unless required by applicable law or agreed to in writing, software
11a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * distributed under the License is distributed on an "AS IS" BASIS,
12a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * See the License for the specific language governing permissions and
14a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * limitations under the License.
15a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair */
16a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairpackage org.mockftpserver.fake.filesystem;
17a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
18a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairimport java.io.ByteArrayInputStream;
19a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairimport java.io.ByteArrayOutputStream;
20a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairimport java.io.IOException;
21a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairimport java.io.InputStream;
22a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairimport java.io.OutputStream;
23a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
24a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair/**
25a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * File system entry representing a file
26a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair *
27a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * @author Chris Mair
28a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair * @version $Revision$ - $Date$
29a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair */
30a0ad464efff5f5e2d2523a3522cce6823ce05858chrismairpublic class FileEntry extends AbstractFileSystemEntry {
31a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
32a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    private static final byte[] EMPTY = new byte[0];
33a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
34a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    private byte[] bytes = EMPTY;
35a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    private ByteArrayOutputStream out;
36a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
37a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
38a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Construct a new instance without setting its path
39a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
40a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public FileEntry() {
41a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
42a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
43a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
44a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Construct a new instance with the specified value for its path
45a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
46a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param path - the value for path
47a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
48a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public FileEntry(String path) {
49a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        super(path);
50a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
51a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
52a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
53a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Construct a new instance with the specified path and file contents
54a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
55a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param path     - the value for path
56a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param contents - the contents of the file, as a String
57a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
58a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public FileEntry(String path, String contents) {
59a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        super(path);
60a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        setContents(contents);
61a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
62a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
63a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
64a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Return false to indicate that this entry represents a file
65a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
66a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @return false
67a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
68a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public boolean isDirectory() {
69a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return false;
70a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
71a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
72a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
73a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Return the size of this file
74a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
75a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @return the file size in bytes
76a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
77a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public long getSize() {
78a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return getCurrentBytes().length;
79a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
80a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
81a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
82a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Set the contents of the file represented by this entry
83a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
84a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param contents - the String whose bytes are used as the contents
85a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
86a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public void setContents(String contents) {
87a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        byte[] newBytes = (contents != null) ? contents.getBytes() : EMPTY;
88a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        setContentsInternal(newBytes);
89a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
90a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
91a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
92a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Set the contents of the file represented by this entry
93a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
94a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param contents - the byte[] used as the contents
95a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
96a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public void setContents(byte[] contents) {
97a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        // Copy the bytes[] to guard against subsequent modification of the source array
98a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        byte[] newBytes = (contents != null) ? new String(contents).getBytes() : EMPTY;
99a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        setContentsInternal(newBytes);
100a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
101a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
102a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
103a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Create and return an InputStream for reading the contents of the file represented by this entry
104a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
105a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @return an InputStream
106a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
107a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public InputStream createInputStream() {
108a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return new ByteArrayInputStream(getCurrentBytes());
109a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
110a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
111a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
112a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Create and return an OutputStream for writing the contents of the file represented by this entry
113a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
114a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param append - true if the OutputStream should append to any existing contents false if
115a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *               any existing contents should be overwritten
116a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @return an OutputStream
117a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @throws FileSystemException - if an error occurs creating or initializing the OutputStream
118a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
119a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public OutputStream createOutputStream(boolean append) {
120a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        // If appending and we already have an OutputStream, then continue to use it
121a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        if (append && out != null) {
122a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair            return out;
123a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        }
124a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
125a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        out = new ByteArrayOutputStream();
126a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        byte[] initialContents = (append) ? bytes : EMPTY;
127a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        try {
128a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair            out.write(initialContents);
129a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        }
130a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        catch (IOException e) {
131a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair            throw new FileSystemException(getPath(), null, e);
132a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        }
133a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return out;
134a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
135a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
136a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
137a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Return a new FileSystemEntry that is a clone of this object, except having the specified path
138a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
139a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param path - the new path value for the cloned file system entry
140a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @return a new FileSystemEntry that has all the same values as this object except for its path
141a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
142a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public FileSystemEntry cloneWithNewPath(String path) {
143a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        FileEntry clone = new FileEntry(path);
144a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        clone.setLastModified(getLastModified());
145a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        clone.setOwner(getOwner());
146a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        clone.setGroup(getGroup());
147a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        clone.setPermissions(getPermissions());
148a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        clone.setContents(bytes);
149a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return clone;
150a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
151a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
152a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    //-------------------------------------------------------------------------
153a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    // Internal Helper Methods
154a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    //-------------------------------------------------------------------------
155a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
156a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
157a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @return the current contents of this file entry as a byte[]
158a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
159a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    private byte[] getCurrentBytes() {
160a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return (out != null) ? out.toByteArray() : bytes;
161a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
162a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
163a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
164a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * Set the contents of the file represented by this entry
165a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     *
166a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @param contents - the byte[] used as the contents
167a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
168a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    private void setContentsInternal(byte[] contents) {
169a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        this.bytes = contents;
170a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
171a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        // Get rid of any OutputStream
172a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        this.out = null;
173a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
174a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
175a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    /**
176a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     * @see java.lang.Object#toString()
177a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair     */
178a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    public String toString() {
179a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair        return "File['" + getPath() + "' size=" + getSize() + " lastModified=" + getLastModified() + " owner="
180a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair                + getOwner() + " group=" + getGroup() + " permissions=" + getPermissions() + "]";
181a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair    }
182a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair
183a0ad464efff5f5e2d2523a3522cce6823ce05858chrismair}
184