CodeStore.java revision 953:221a84ef44c0
1/* 2 * Copyright (c) 2010, 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 26package jdk.nashorn.internal.runtime; 27 28import java.io.BufferedInputStream; 29import java.io.BufferedOutputStream; 30import java.io.File; 31import java.io.FileInputStream; 32import java.io.FileOutputStream; 33import java.io.IOException; 34import java.io.ObjectInputStream; 35import java.io.ObjectOutputStream; 36import java.io.Serializable; 37import java.security.AccessController; 38import java.security.PrivilegedActionException; 39import java.security.PrivilegedExceptionAction; 40import java.util.Map; 41 42/** 43 * A code cache for persistent caching of compiled scripts. 44 */ 45final class CodeStore { 46 47 private final File dir; 48 private final int minSize; 49 50 // Default minimum size for storing a compiled script class 51 private final static int DEFAULT_MIN_SIZE = 1000; 52 53 /** 54 * Constructor 55 * @param path directory to store code in 56 * @throws IOException 57 */ 58 public CodeStore(final String path) throws IOException { 59 this(path, DEFAULT_MIN_SIZE); 60 } 61 62 /** 63 * Constructor 64 * @param path directory to store code in 65 * @param minSize minimum file size for caching scripts 66 * @throws IOException 67 */ 68 public CodeStore(final String path, final int minSize) throws IOException { 69 this.dir = checkDirectory(path); 70 this.minSize = minSize; 71 } 72 73 private static File checkDirectory(final String path) throws IOException { 74 try { 75 return AccessController.doPrivileged(new PrivilegedExceptionAction<File>() { 76 @Override 77 public File run() throws IOException { 78 final File dir = new File(path).getAbsoluteFile(); 79 if (!dir.exists() && !dir.mkdirs()) { 80 throw new IOException("Could not create directory: " + dir); 81 } else if (!dir.isDirectory()) { 82 throw new IOException("Not a directory: " + dir); 83 } else if (!dir.canRead() || !dir.canWrite()) { 84 throw new IOException("Directory not readable or writable: " + dir); 85 } 86 return dir; 87 } 88 }); 89 } catch (final PrivilegedActionException e) { 90 throw (IOException) e.getException(); 91 } 92 } 93 94 /** 95 * Return a compiled script from the cache, or null if it isn't found. 96 * 97 * @param source the source 98 * @return the compiled script or null 99 * @throws IOException 100 * @throws ClassNotFoundException 101 */ 102 public CompiledScript getScript(final Source source) throws IOException, ClassNotFoundException { 103 if (source.getLength() < minSize) { 104 return null; 105 } 106 107 final File file = new File(dir, source.getDigest()); 108 109 try { 110 return AccessController.doPrivileged(new PrivilegedExceptionAction<CompiledScript>() { 111 @Override 112 public CompiledScript run() throws IOException, ClassNotFoundException { 113 if (!file.exists()) { 114 return null; 115 } 116 try (ObjectInputStream in = new ObjectInputStream(new BufferedInputStream(new FileInputStream(file)))) { 117 final CompiledScript compiledScript = (CompiledScript) in.readObject(); 118 compiledScript.setSource(source); 119 return compiledScript; 120 } 121 } 122 }); 123 } catch (final PrivilegedActionException e) { 124 final Exception ex = e.getException(); 125 if (ex instanceof IOException) { 126 throw (IOException) ex; 127 } else if (ex instanceof ClassNotFoundException) { 128 throw (ClassNotFoundException) ex; 129 } 130 throw (new RuntimeException(ex)); 131 } 132 } 133 134 /** 135 * Store a compiled script in the cache. 136 * 137 * @param source the source 138 * @param mainClassName the main class name 139 * @param classBytes a map of class bytes 140 * @param constants the constants array 141 * @throws IOException 142 */ 143 public void putScript(final Source source, final String mainClassName, final Map<String, byte[]> classBytes, final Object[] constants) 144 throws IOException { 145 if (source.getLength() < minSize) { 146 return; 147 } 148 for (final Object constant : constants) { 149 // Make sure all constant data is serializable 150 if (! (constant instanceof Serializable)) { 151 return; 152 } 153 } 154 155 final File file = new File(dir, source.getDigest()); 156 final CompiledScript script = new CompiledScript(source, mainClassName, classBytes, constants); 157 158 try { 159 AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() { 160 @Override 161 public Void run() throws IOException { 162 try (ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(file)))) { 163 out.writeObject(script); 164 } 165 return null; 166 } 167 }); 168 } catch (final PrivilegedActionException e) { 169 throw (IOException) e.getException(); 170 } 171 } 172} 173 174