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