001: /*
002:
003: Derby - Class org.apache.derby.impl.io.InputStreamFile
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to you under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.impl.io;
023:
024: import org.apache.derby.io.StorageFactory;
025: import org.apache.derby.io.StorageFile;
026: import org.apache.derby.io.StorageRandomAccessFile;
027:
028: import org.apache.derby.iapi.services.sanity.SanityManager;
029:
030: import java.io.File;
031: import java.io.InputStream;
032: import java.io.OutputStream;
033: import java.io.IOException;
034: import java.io.FileNotFoundException;
035: import java.net.MalformedURLException;
036: import java.net.URL;
037:
038: /**
039: * This class provides the base for read-only stream implementations of the StorageFile interface. It is used with the
040: * classpath, jar, http, and https subsubprotocols
041: */
042: abstract class InputStreamFile implements StorageFile {
043:
044: final String path;
045: final int nameStart; // getName() = path.substring( nameStart)
046: final BaseStorageFactory storageFactory;
047:
048: InputStreamFile(BaseStorageFactory storageFactory, String path) {
049: this .storageFactory = storageFactory;
050: if (path == null || path.length() == 0) {
051: this .path = storageFactory.dataDirectory;
052: nameStart = -1;
053: } else {
054: StringBuffer sb = new StringBuffer(
055: storageFactory.separatedDataDirectory);
056: if (File.separatorChar != '/')
057: sb.append(path.replace(File.separatorChar, '/'));
058: else
059: sb.append(path);
060: this .path = sb.toString();
061: nameStart = this .path.lastIndexOf('/') + 1;
062: }
063: }
064:
065: InputStreamFile(BaseStorageFactory storageFactory, String parent,
066: String name) {
067: this .storageFactory = storageFactory;
068: StringBuffer sb = new StringBuffer(
069: storageFactory.separatedDataDirectory);
070: if (File.separatorChar != '/') {
071: sb.append(parent.replace(File.separatorChar, '/'));
072: sb.append('/');
073: sb.append(name.replace(File.separatorChar, '/'));
074: } else {
075: sb.append(parent);
076: sb.append('/');
077: sb.append(name);
078: }
079: path = sb.toString();
080: nameStart = this .path.lastIndexOf('/') + 1;
081: }
082:
083: InputStreamFile(InputStreamFile dir, String name) {
084: this .storageFactory = dir.storageFactory;
085: StringBuffer sb = new StringBuffer(dir.path);
086: sb.append('/');
087: if (File.separatorChar != '/')
088: sb.append(name.replace(File.separatorChar, '/'));
089: else
090: sb.append(name);
091: path = sb.toString();
092: nameStart = this .path.lastIndexOf('/') + 1;
093: }
094:
095: InputStreamFile(BaseStorageFactory storageFactory, String child,
096: int pathLen) {
097: this .storageFactory = storageFactory;
098: path = child.substring(0, pathLen);
099: nameStart = this .path.lastIndexOf('/') + 1;
100: }
101:
102: public boolean equals(Object other) {
103: if (other == null || !getClass().equals(other.getClass()))
104: return false;
105: InputStreamFile otherFile = (InputStreamFile) other;
106: return path.equals(otherFile.path);
107: }
108:
109: public int hashCode() {
110: return path.hashCode();
111: }
112:
113: /**
114: * Get the names of all files and sub-directories in the directory named by this path name.
115: *
116: * @return An array of the names of the files and directories in this
117: * directory denoted by this abstract pathname. The returned array will have length 0
118: * if this directory is empty. Returns null if this StorageFile is not a directory, or
119: * if an I/O error occurs.
120: */
121: public String[] list() {
122: return null;
123: }
124:
125: /**
126: * Determine whether the named file is writable.
127: *
128: * @return <b>true</b> if the file exists and is writable, <b>false</b> if not.
129: */
130: public boolean canWrite() {
131: return false;
132: }
133:
134: /**
135: * Tests whether the named file exists.
136: *
137: * @return <b>true</b> if the named file exists, <b>false</b> if not.
138: */
139: public abstract boolean exists();
140:
141: /**
142: * Tests whether the named file is a directory, or not. This is only called in writable storage factories.
143: *
144: * @return <b>true</b> if named file exists and is a directory, <b>false</b> if not.
145: * The return value is undefined if the storage is read-only.
146: */
147: public boolean isDirectory() {
148: return false;
149: }
150:
151: /**
152: * Deletes the named file or empty directory. This method does not delete non-empty directories.
153: *
154: * @return <b>true</b> if the named file or directory is successfully deleted, <b>false</b> if not
155: */
156: public boolean delete() {
157: return false;
158: }
159:
160: /**
161: * Deletes the named file and, if it is a directory, all the files and directories it contains.
162: *
163: * @return <b>true</b> if the named file or directory is successfully deleted, <b>false</b> if not
164: */
165: public boolean deleteAll() {
166: return false;
167: }
168:
169: /**
170: * Converts this StorageFile into a pathname string. The character returned by StorageFactory.getSeparator()
171: * is used to separate the directory and file names in the sequence.
172: *
173: *<p>
174: *<b>The returned path may include the database directory. Therefore it cannot be directly used to make an StorageFile
175: * equivalent to this one.</b>
176: *
177: * @return The pathname as a string.
178: *
179: * @see StorageFactory#getSeparator
180: */
181: public String getPath() {
182: if (File.separatorChar != '/')
183: return path.replace('/', File.separatorChar);
184: return path;
185: } // end of getPath
186:
187: public String getCanonicalPath() throws IOException {
188: return storageFactory.getCanonicalName() + "/" + path;
189: }
190:
191: /**
192: * @return The last segment in the path name, "" if the path name sequence is empty.
193: */
194: public String getName() {
195: return (nameStart < 0) ? "" : path.substring(nameStart);
196: }
197:
198: /**
199: * If the named file does not already exist then create it as an empty normal file.
200: *
201: * The implementation
202: * must synchronize with other threads accessing the same file (in the same or a different process).
203: * If two threads both attempt to create a file with the same name
204: * at the same time then at most one should succeed.
205: *
206: * @return <b>true</b> if this thread's invocation of createNewFile successfully created the named file;
207: * <b>false</b> if not, i.e. <b>false</b> if the named file already exists or if another concurrent thread created it.
208: *
209: * @exception IOException - If the directory does not exist or some other I/O error occurred
210: */
211: public boolean createNewFile() throws IOException {
212: throw new IOException(
213: "createNewFile called in a read-only file system.");
214: }
215:
216: /**
217: * Rename the file denoted by this name. Note that StorageFile objects are immutable. This method
218: * renames the underlying file, it does not change this StorageFile object. The StorageFile object denotes the
219: * same name as before, however the exists() method will return false after the renameTo method
220: * executes successfully.
221: *
222: *<p>It is not specified whether this method will succeed if a file already exists under the new name.
223: *
224: * @param newName the new name.
225: *
226: * @return <b>true</b> if the rename succeeded, <b>false</b> if not.
227: */
228: public boolean renameTo(StorageFile newName) {
229: return false;
230: }
231:
232: /**
233: * Creates the named directory.
234: *
235: * @return <b>true</b> if the directory was created; <b>false</b> if not.
236: */
237: public boolean mkdir() {
238: return false;
239: }
240:
241: /**
242: * Creates the named directory, and all nonexistent parent directories.
243: *
244: * @return <b>true</b> if the directory was created, <b>false</b> if not
245: */
246: public boolean mkdirs() {
247: return false;
248: }
249:
250: /**
251: * Returns the length of the named file if it is not a directory. The return value is not specified
252: * if the file is a directory.
253: *
254: * @return The length, in bytes, of the named file if it exists and is not a directory,
255: * 0 if the file does not exist, or any value if the named file is a directory.
256: */
257: public long length() {
258: try {
259: InputStream is = getInputStream();
260: if (is == null)
261: return 0;
262: long len = is.available();
263: is.close();
264: return len;
265: } catch (IOException e) {
266: return 0;
267: }
268: } // end of length
269:
270: /**
271: * Get the name of the parent directory if this name includes a parent.
272: *
273: * @return An StorageFile denoting the parent directory of this StorageFile, if it has a parent, null if
274: * it does not have a parent.
275: */
276: public StorageFile getParentDir() {
277: if (path.length() <= storageFactory.separatedDataDirectory
278: .length())
279: return null;
280: return getParentDir(path.lastIndexOf('/'));
281: }
282:
283: /**
284: * Get the parent of this file.
285: *
286: * @param pathLen the length of the parent's path name.
287: */
288: abstract StorageFile getParentDir(int pathLen);
289:
290: /**
291: * Make the named file or directory read-only. This interface does not specify whether this
292: * also makes the file undeletable.
293: *
294: * @return <b>true</b> if the named file or directory was made read-only, or it already was read-only;
295: * <b>false</b> if not.
296: */
297: public boolean setReadOnly() {
298: return true;
299: }
300:
301: /**
302: * Creates an output stream from a file name. If a normal file already exists with this name it
303: * will first be truncated to zero length.
304: *
305: * @return an output stream suitable for writing to the file.
306: *
307: * @exception FileNotFoundException if the file exists but is a directory
308: * rather than a regular file, does not exist but cannot be created, or
309: * cannot be opened for any other reason.
310: */
311: public OutputStream getOutputStream() throws FileNotFoundException {
312: throw new FileNotFoundException(
313: "Attempt to write into a read only file system.");
314: }
315:
316: /**
317: * Creates an output stream from a file name. If a normal file already exists with this name it
318: * will first be truncated to zero length.
319: *
320: * @return an output stream suitable for writing to the file.
321: *
322: * @exception FileNotFoundException if the file exists but is a directory
323: * rather than a regular file, does not exist but cannot be created, or
324: * cannot be opened for any other reason.
325: */
326: public OutputStream getOutputStream(boolean append)
327: throws FileNotFoundException {
328: throw new FileNotFoundException(
329: "Attempt to write into a read only file system.");
330: }
331:
332: /**
333: * Creates an input stream from a file name.
334: *
335: * @return an input stream suitable for reading from the file.
336: *
337: * @exception FileNotFoundException if the file is not found.
338: */
339: abstract public InputStream getInputStream()
340: throws FileNotFoundException;
341:
342: /**
343: * Get an exclusive lock with this name. This is used to ensure that two or more JVMs do not open the same database
344: * at the same time.
345: *
346: * @return EXCLUSIVE_FILE_LOCK_NOT_AVAILABLE if the lock cannot be acquired because it is already held.<br>
347: * EXCLUSIVE_FILE_LOCK if the lock was successfully acquired.<br>
348: * NO_FILE_LOCK_SUPPORT if the system does not support exclusive locks.<br>
349: */
350: public int getExclusiveFileLock() {
351: return NO_FILE_LOCK_SUPPORT;
352: }
353:
354: /**
355: * Release the resource associated with an earlier acquired exclusive lock
356: *
357: * @see #getExclusiveFileLock
358: */
359: public void releaseExclusiveFileLock() {
360: }
361:
362: /**
363: * Get a random access file.
364: *
365: * @param mode "r", "rw", "rws", or "rwd". The "rws" and "rwd" modes specify
366: * that the data is to be written to persistent store, consistent with the
367: * java.io.RandomAccessFile class ("synchronized" with the persistent
368: * storage, in the file system meaning of the word "synchronized"). However
369: * the implementation is not required to implement the "rws" or "rwd"
370: * modes. The implementation may treat "rws" and "rwd" as "rw". It is up to
371: * the user of this interface to call the StorageRandomAccessFile.sync
372: * method. However, if the "rws" or "rwd" modes are supported and the
373: * RandomAccessFile was opened in "rws" or "rwd" mode then the
374: * implementation of StorageRandomAccessFile.sync need not do anything.
375: *
376: * @return an object that can be used for random access to the file.
377: *
378: * @exception IllegalArgumentException if the mode argument is not equal to one of "r", "rw", "rws", or "rwd".
379: * @exception FileNotFoundException if the file exists but is a directory rather than a regular
380: * file, or cannot be opened or created for any other reason .
381: *
382: * @see <a href="http://java.sun.com/j2se/1.4.2/docs/api/java/io/RandomAccessFile.html">java.io.RandomAccessFile</a>
383: */
384: public StorageRandomAccessFile getRandomAccessFile(String mode)
385: throws FileNotFoundException {
386: if (SanityManager.DEBUG)
387: SanityManager.NOTREACHED();
388: return null;
389: }
390:
391: /**
392: * Get the file name for diagnostic purposes. Usually the same as getPath().
393: *
394: * @return the file name
395: */
396: public String toString() {
397: return path;
398: }
399:
400: /**
401: * @see org.apache.derby.io.StorageFile#getURL()
402: */
403: public URL getURL() throws MalformedURLException {
404: throw new MalformedURLException(toString());
405: }
406: }
|