PortFile.java revision 2593:035b01d356ee
1/* 2 * Copyright (c) 2012, 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 com.sun.tools.sjavac.server; 27 28import java.io.File; 29import java.io.FileNotFoundException; 30import java.io.IOException; 31import java.io.RandomAccessFile; 32import java.nio.channels.ClosedChannelException; 33import java.nio.channels.FileChannel; 34import java.nio.channels.FileLock; 35import java.nio.channels.FileLockInterruptionException; 36import com.sun.tools.javac.util.Assert; 37import com.sun.tools.sjavac.Log; 38 39/** 40 * The PortFile class mediates access to a short binary file containing the tcp/ip port (for the localhost) 41 * and a cookie necessary for the server answering on that port. The file can be locked using file system 42 * primitives to avoid race conditions when several javac clients are started at the same. Note that file 43 * system locking is not always supported on a all operating systems and/or file systems. 44 * 45 * <p><b>This is NOT part of any supported API. 46 * If you write code that depends on this, you do so at your own risk. 47 * This code and its internal interfaces are subject to change or 48 * deletion without notice.</b> 49 */ 50public class PortFile { 51 52 // Port file format: 53 // byte ordering: high byte first = big endian 54 // Magic nr, 4 byte int, first in file. 55 private final static int magicNr = 0x1174; 56 // Followed by a 4 byte int, with the port nr. 57 // Followed by a 8 byte long, with cookie nr. 58 59 private String filename; 60 private File file; 61 private File stopFile; 62 private RandomAccessFile rwfile; 63 private FileChannel channel; 64 private FileLock lock; 65 66 private boolean containsPortInfo; 67 private int serverPort; 68 private long serverCookie; 69 private int myServerPort; 70 private long myServerCookie; 71 72 /** 73 * Create a new portfile. 74 * @param filename is the path to the file. 75 */ 76 public PortFile(String fn) throws FileNotFoundException { 77 filename = fn; 78 file = new File(filename); 79 stopFile = new File(filename+".stop"); 80 rwfile = new RandomAccessFile(file, "rw"); 81 // The rwfile should only be readable by the owner of the process 82 // and no other! How do we do that on a RandomAccessFile? 83 channel = rwfile.getChannel(); 84 containsPortInfo = false; 85 lock = null; 86 } 87 88 /** 89 * Lock the port file. 90 */ 91 public void lock() throws IOException { 92 lock = channel.lock(); 93 } 94 95 /** 96 * Read the values from the port file in the file system. 97 * Expects the port file to be locked. 98 */ 99 public void getValues() { 100 containsPortInfo = false; 101 if (lock == null) { 102 // Not locked, remain ignorant about port file contents. 103 return; 104 } 105 try { 106 if (rwfile.length()>0) { 107 rwfile.seek(0); 108 int nr = rwfile.readInt(); 109 serverPort = rwfile.readInt(); 110 serverCookie = rwfile.readLong(); 111 112 if (nr == magicNr) { 113 containsPortInfo = true; 114 } else { 115 containsPortInfo = false; 116 } 117 } 118 } catch (IOException e) { 119 containsPortInfo = false; 120 } 121 } 122 123 /** 124 * Did the locking and getValues succeed? 125 */ 126 public boolean containsPortInfo() { 127 return containsPortInfo; 128 } 129 130 /** 131 * If so, then we can acquire the tcp/ip port on localhost. 132 */ 133 public int getPort() { 134 Assert.check(containsPortInfo); 135 return serverPort; 136 } 137 138 /** 139 * If so, then we can acquire the server cookie. 140 */ 141 public long getCookie() { 142 Assert.check(containsPortInfo); 143 return serverCookie; 144 } 145 146 /** 147 * Store the values into the locked port file. 148 */ 149 public void setValues(int port, long cookie) throws IOException { 150 Assert.check(lock != null); 151 rwfile.seek(0); 152 // Write the magic nr that identifes a port file. 153 rwfile.writeInt(magicNr); 154 rwfile.writeInt(port); 155 rwfile.writeLong(cookie); 156 myServerPort = port; 157 myServerCookie = cookie; 158 } 159 160 /** 161 * Delete the port file. 162 */ 163 public void delete() throws IOException { 164 // Access to file must be closed before deleting. 165 rwfile.close(); 166 // Now delete. 167 file.delete(); 168 } 169 170 /** 171 * Is the port file still there? 172 */ 173 public boolean exists() throws IOException { 174 return file.exists(); 175 } 176 177 /** 178 * Is a stop file there? 179 */ 180 public boolean markedForStop() throws IOException { 181 if (stopFile.exists()) { 182 try { 183 stopFile.delete(); 184 } catch (Exception e) 185 {} 186 return true; 187 } 188 return false; 189 } 190 191 /** 192 * Unlock the port file. 193 */ 194 public void unlock() throws IOException { 195 Assert.check(lock != null); 196 lock.release(); 197 lock = null; 198 } 199 200 /** 201 * Wait for the port file to contain values that look valid. 202 * Return true, if a-ok, false if the valid values did not materialize within 5 seconds. 203 */ 204 public synchronized boolean waitForValidValues() throws IOException, FileNotFoundException { 205 for (int tries = 0; tries < 50; tries++) { 206 lock(); 207 getValues(); 208 unlock(); 209 if (containsPortInfo) { 210 Log.debug("Found valid values in port file after waiting "+(tries*100)+"ms"); 211 return true; 212 } 213 try { 214 Thread.sleep(100); 215 } catch (InterruptedException e) 216 {} 217 } 218 Log.debug("Gave up waiting for valid values in port file"); 219 return false; 220 } 221 222 /** 223 * Check if the portfile still contains my values, assuming that I am the server. 224 */ 225 public synchronized boolean stillMyValues() throws IOException, FileNotFoundException { 226 for (;;) { 227 try { 228 lock(); 229 getValues(); 230 unlock(); 231 if (containsPortInfo) { 232 if (serverPort == myServerPort && 233 serverCookie == myServerCookie) { 234 // Everything is ok. 235 return true; 236 } 237 // Someone has overwritten the port file. 238 // Probably another javac server, lets quit. 239 return false; 240 } 241 // Something else is wrong with the portfile. Lets quit. 242 return false; 243 } catch (FileLockInterruptionException e) { 244 continue; 245 } 246 catch (ClosedChannelException e) { 247 // The channel has been closed since sjavac is exiting. 248 return false; 249 } 250 } 251 } 252 253 /** 254 * Return the name of the port file. 255 */ 256 public String getFilename() { 257 return filename; 258 } 259} 260