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