001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.vfs2.provider.ram;
018
019import java.io.ByteArrayInputStream;
020import java.io.IOException;
021import java.io.InputStream;
022import java.io.OutputStream;
023
024import org.apache.commons.vfs2.FileObject;
025import org.apache.commons.vfs2.FileSystemException;
026import org.apache.commons.vfs2.FileSystemOptions;
027import org.apache.commons.vfs2.FileType;
028import org.apache.commons.vfs2.RandomAccessContent;
029import org.apache.commons.vfs2.provider.AbstractFileName;
030import org.apache.commons.vfs2.provider.AbstractFileObject;
031import org.apache.commons.vfs2.util.FileObjectUtils;
032import org.apache.commons.vfs2.util.RandomAccessMode;
033
034/**
035 * A RAM File contains a single RAM FileData instance, it provides methods to access the data by implementing FileObject
036 * interface.
037 */
038public class RamFileObject extends AbstractFileObject<RamFileSystem> {
039    /**
040     * RAM File Object Data.
041     */
042    private RamFileData data;
043
044    /**
045     * @param name The name of the file.
046     * @param fs The FileSystem.
047     */
048    protected RamFileObject(final AbstractFileName name, final RamFileSystem fs) {
049        super(name, fs);
050        this.getAbstractFileSystem().attach(this);
051    }
052
053    private void save() throws FileSystemException {
054        this.getAbstractFileSystem().save(this);
055    }
056
057    /*
058     * (non-Javadoc)
059     *
060     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetType()
061     */
062    @Override
063    protected FileType doGetType() throws Exception {
064        return data.getType();
065    }
066
067    /*
068     * (non-Javadoc)
069     *
070     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doListChildren()
071     */
072    @Override
073    protected String[] doListChildren() throws Exception {
074        return this.getAbstractFileSystem().listChildren(this.getName());
075    }
076
077    /*
078     * (non-Javadoc)
079     *
080     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetContentSize()
081     */
082    @Override
083    protected long doGetContentSize() throws Exception {
084        return this.size();
085    }
086
087    /*
088     * (non-Javadoc)
089     *
090     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetInputStream()
091     */
092    @Override
093    protected InputStream doGetInputStream() throws Exception {
094        // VFS-210: ram allows to gather an input stream even from a directory. So we need to check the type anyway.
095        if (!getType().hasContent()) {
096            throw new FileSystemException("vfs.provider/read-not-file.error", getName());
097        }
098
099        return new ByteArrayInputStream(this.data.getContent());
100    }
101
102    /*
103     * (non-Javadoc)
104     *
105     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetOutputStream(boolean)
106     */
107    @Override
108    protected OutputStream doGetOutputStream(final boolean bAppend) throws Exception {
109        if (!bAppend) {
110            this.data.setContent(RamFileData.EMPTY);
111        }
112        return new RamFileOutputStream(this);
113    }
114
115    /*
116     * (non-Javadoc)
117     *
118     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doDelete()
119     */
120    @Override
121    protected void doDelete() throws Exception {
122
123        if (this.isContentOpen()) {
124            throw new FileSystemException(this.getName() + " cannot be deleted while the file is openg");
125        }
126        getAbstractFileSystem().delete(this);
127    }
128
129    /*
130     * (non-Javadoc)
131     *
132     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetLastModifiedTime()
133     */
134    @Override
135    protected long doGetLastModifiedTime() throws Exception {
136        return data.getLastModified();
137    }
138
139    /*
140     * (non-Javadoc)
141     *
142     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doSetLastModifiedTime(long)
143     */
144    /** @since 2.0 */
145    @Override
146    protected boolean doSetLastModifiedTime(final long modtime) throws Exception {
147        data.setLastModified(modtime);
148        return true;
149    }
150
151    /*
152     * (non-Javadoc)
153     *
154     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doCreateFolder()
155     */
156    @Override
157    protected void doCreateFolder() throws Exception {
158        this.injectType(FileType.FOLDER);
159        this.save();
160    }
161
162    /*
163     * (non-Javadoc)
164     *
165     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doRename(org.apache.commons.vfs2.FileObject)
166     */
167    @Override
168    protected void doRename(final FileObject newFile) throws Exception {
169        final RamFileObject newRamFileObject = (RamFileObject) FileObjectUtils.getAbstractFileObject(newFile);
170        getAbstractFileSystem().rename(this, newRamFileObject);
171    }
172
173    /*
174     * (non-Javadoc)
175     *
176     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doGetRandomAccessContent(
177     * org.apache.commons.vfs2.util.RandomAccessMode)
178     */
179    @Override
180    protected RandomAccessContent doGetRandomAccessContent(final RandomAccessMode mode) throws Exception {
181        return new RamFileRandomAccessContent(this, mode);
182    }
183
184    /*
185     * (non-Javadoc)
186     *
187     * @see org.apache.commons.vfs2.provider.AbstractFileObject#doAttach()
188     */
189    @Override
190    protected void doAttach() throws Exception {
191        this.getAbstractFileSystem().attach(this);
192    }
193
194    /**
195     * @return Returns the data.
196     */
197    RamFileData getData() {
198        return data;
199    }
200
201    /**
202     * @param data The data to set.
203     */
204    void setData(final RamFileData data) {
205        this.data = data;
206    }
207
208    /*
209     * (non-Javadoc)
210     *
211     * @see org.apache.commons.vfs2.provider.AbstractFileObject#injectType(org.apache.commons.vfs2.FileType)
212     */
213    @Override
214    protected void injectType(final FileType fileType) {
215        this.data.setType(fileType);
216        super.injectType(fileType);
217    }
218
219    /*
220     * (non-Javadoc)
221     *
222     * @see org.apache.commons.vfs2.provider.AbstractFileObject#endOutput()
223     */
224    @Override
225    protected void endOutput() throws Exception {
226        super.endOutput();
227        this.save();
228    }
229
230    /**
231     * @return Returns the size of the {@link RamFileData}.
232     */
233    int size() {
234        return data == null ? 0 : data.size();
235    }
236
237    /**
238     * @param newSize
239     * @throws IOException if the new size exceeds the limit
240     */
241    synchronized void resize(final long newSize) throws IOException {
242        final RamFileSystem afs = getAbstractFileSystem();
243        final FileSystemOptions afsOptions = afs.getFileSystemOptions();
244        if (afsOptions != null) {
245            final long maxSize = RamFileSystemConfigBuilder.getInstance().getLongMaxSize(afsOptions);
246            if (afs.size() + newSize - this.size() > maxSize) {
247                throw new IOException("FileSystem capacity (" + maxSize + ") exceeded.");
248            }
249        }
250        this.data.resize(newSize);
251    }
252
253}