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$ - $Date$
29 */
30public class FileEntry extends AbstractFileSystemEntry {
31
32    private static final byte[] EMPTY = new byte[0];
33
34    private byte[] bytes = EMPTY;
35    private ByteArrayOutputStream out;
36
37    /**
38     * Construct a new instance without setting its path
39     */
40    public FileEntry() {
41    }
42
43    /**
44     * Construct a new instance with the specified value for its path
45     *
46     * @param path - the value for path
47     */
48    public FileEntry(String path) {
49        super(path);
50    }
51
52    /**
53     * Construct a new instance with the specified path and file contents
54     *
55     * @param path     - the value for path
56     * @param contents - the contents of the file, as a String
57     */
58    public FileEntry(String path, String contents) {
59        super(path);
60        setContents(contents);
61    }
62
63    /**
64     * Return false to indicate that this entry represents a file
65     *
66     * @return false
67     */
68    public boolean isDirectory() {
69        return false;
70    }
71
72    /**
73     * Return the size of this file
74     *
75     * @return the file size in bytes
76     */
77    public long getSize() {
78        return getCurrentBytes().length;
79    }
80
81    /**
82     * Set the contents of the file represented by this entry
83     *
84     * @param contents - the String whose bytes are used as the contents
85     */
86    public void setContents(String contents) {
87        byte[] newBytes = (contents != null) ? contents.getBytes() : EMPTY;
88        setContentsInternal(newBytes);
89    }
90
91    /**
92     * Set the contents of the file represented by this entry
93     *
94     * @param contents - the byte[] used as the contents
95     */
96    public void setContents(byte[] contents) {
97        // Copy the bytes[] to guard against subsequent modification of the source array
98        byte[] newBytes = EMPTY;
99        if (contents != null) {
100            newBytes = new byte[contents.length];
101            System.arraycopy(contents, 0, newBytes, 0, contents.length);
102        }
103        setContentsInternal(newBytes);
104    }
105
106    /**
107     * Create and return an InputStream for reading the contents of the file represented by this entry
108     *
109     * @return an InputStream
110     */
111    public InputStream createInputStream() {
112        return new ByteArrayInputStream(getCurrentBytes());
113    }
114
115    /**
116     * Create and return an OutputStream for writing the contents of the file represented by this entry
117     *
118     * @param append - true if the OutputStream should append to any existing contents false if
119     *               any existing contents should be overwritten
120     * @return an OutputStream
121     * @throws FileSystemException - if an error occurs creating or initializing the OutputStream
122     */
123    public OutputStream createOutputStream(boolean append) {
124        // If appending and we already have an OutputStream, then continue to use it
125        if (append && out != null) {
126            return out;
127        }
128
129        out = new ByteArrayOutputStream();
130        byte[] initialContents = (append) ? bytes : EMPTY;
131        try {
132            out.write(initialContents);
133        }
134        catch (IOException e) {
135            throw new FileSystemException(getPath(), null, e);
136        }
137        return out;
138    }
139
140    /**
141     * Return a new FileSystemEntry that is a clone of this object, except having the specified path
142     *
143     * @param path - the new path value for the cloned file system entry
144     * @return a new FileSystemEntry that has all the same values as this object except for its path
145     */
146    public FileSystemEntry cloneWithNewPath(String path) {
147        FileEntry clone = new FileEntry(path);
148        clone.setLastModified(getLastModified());
149        clone.setOwner(getOwner());
150        clone.setGroup(getGroup());
151        clone.setPermissions(getPermissions());
152        clone.setContents(getCurrentBytes());
153        return clone;
154    }
155
156    //-------------------------------------------------------------------------
157    // Internal Helper Methods
158    //-------------------------------------------------------------------------
159
160    /**
161     * @return the current contents of this file entry as a byte[]
162     */
163    private byte[] getCurrentBytes() {
164        return (out != null) ? out.toByteArray() : bytes;
165    }
166
167    /**
168     * Set the contents of the file represented by this entry
169     *
170     * @param contents - the byte[] used as the contents
171     */
172    private void setContentsInternal(byte[] contents) {
173        this.bytes = contents;
174
175        // Get rid of any OutputStream
176        this.out = null;
177    }
178
179    /**
180     * @see java.lang.Object#toString()
181     */
182    public String toString() {
183        return "File['" + getPath() + "' size=" + getSize() + " lastModified=" + getLastModified() + " owner="
184                + getOwner() + " group=" + getGroup() + " permissions=" + getPermissions() + "]";
185    }
186
187}
188