1 /* 2 * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.jimage; 27 28 import java.io.Closeable; 29 import java.io.IOException; 30 import java.io.RandomAccessFile; 31 import java.nio.channels.FileChannel; 32 import java.lang.reflect.Constructor; 33 import java.lang.reflect.InvocationTargetException; 34 35 /** 36 * Supports reading a file from given positions (offsets) in the file. 37 */ 38 39 public abstract class PReader implements Closeable { 40 private final FileChannel fc; 41 42 protected PReader(FileChannel fc) { 43 this.fc = fc; 44 } 45 46 /** 47 * Returns the {@code FileChannel}. 48 */ 49 final FileChannel channel() { 50 return fc; 51 } 52 53 /** 54 * Closes this {@code PReader} and the underlying file. 55 */ 56 @Override 57 public final void close() throws IOException { 58 fc.close(); 59 } 60 61 /** 62 * Returns {@code true} if this {@code PReader} and the underlying file is 63 * open. 64 */ 65 public final boolean isOpen() { 66 return fc.isOpen(); 67 } 68 69 /** 70 * Returns {@code len} bytes from a given position in the file. The bytes 71 * are returned as a byte array. 72 * 73 * @throws IOException if an I/O error occurs 74 */ 75 public abstract byte[] read(int len, long position) throws IOException; 76 77 /** 78 * Opens the given file, returning a {@code PReader} to read from the file. 79 * 80 * @implNote Returns a {@code PReader} that supports concurrent pread operations 81 * if possible, otherwise a simple {@code PReader} that doesn't support 82 * concurrent operations. 83 */ 84 static PReader open(String file) throws IOException { 85 Class<?> clazz; 86 try { 87 clazz = Class.forName("jdk.internal.jimage.concurrent.ConcurrentPReader"); 88 } catch (ClassNotFoundException e) { 89 return new SimplePReader(file); 90 } 91 try { 92 Constructor<?> ctor = clazz.getConstructor(String.class); 93 return (PReader) ctor.newInstance(file); 94 } catch (InvocationTargetException e) { 95 Throwable cause = e.getCause(); 96 if (cause instanceof IOException) 97 throw (IOException) cause; 98 if (cause instanceof Error) 99 throw (Error) cause; 100 if (cause instanceof RuntimeException) 101 throw (RuntimeException) cause; 102 throw new Error(e); 103 } catch (NoSuchMethodException | IllegalAccessException | 104 InstantiationException e) { 105 throw new InternalError(e); 106 } 107 } 108 } 109 110 /** 111 * Simple PReader implementation based on {@code RandomAccessFile}. 112 * 113 * @implNote This class cannot use FileChannel read methods to do the 114 * positional reads because FileChannel is interruptible. 115 */ 116 class SimplePReader extends PReader { 117 private final RandomAccessFile raf; 118 119 private SimplePReader(RandomAccessFile raf) throws IOException { 120 super(raf.getChannel()); 121 this.raf = raf; 122 } 123 124 SimplePReader(String file) throws IOException { 125 this(new RandomAccessFile(file, "r")); 126 } 127 128 @Override 129 public byte[] read(int len, long position) throws IOException { 130 synchronized (this) { 131 byte[] bytes = new byte[len]; 132 raf.seek(position); 133 int n = raf.read(bytes); 134 if (n != len) 135 throw new InternalError("short read, not handled yet"); 136 return bytes; 137 } 138 } 139 }