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