/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.security.file; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Properties; import java.util.logging.Logger; import org.geoserver.platform.resource.Resource; import org.geoserver.platform.resource.Resources; import org.geoserver.security.impl.Util; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; /** * A simple class to support file based stores. * Simulates a write lock by creating/removing a * physical file on the file system * * @author Christian * */ public class LockFile { protected long lockFileLastModified; protected Resource lockFileTarget,lockFile; static Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geoserver.security.xml"); public LockFile(Resource file) throws IOException{ lockFileTarget = file; if (!Resources.exists(file)) { throw new IOException("Cannot lock a not existing file: " + file.path()); } lockFile = file.parent().get(lockFileTarget.name() + ".lock"); Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() { // remove on shutdown @Override public void run() { lockFile.delete(); } })); } /** * return true if a write lock is hold by this file watcher * * * @throws IOException */ public boolean hasWriteLock() throws IOException{ return Resources.exists(lockFile) && lockFile.lastmodified() == lockFileLastModified; } /** * return true if a write lock is hold by another file watcher * * * @throws IOException */ public boolean hasForeignWriteLock() throws IOException{ return Resources.exists(lockFile) && lockFile.lastmodified() != lockFileLastModified; } /** * remove the lockfile * */ public void writeUnLock() { if (Resources.exists(lockFile)) { if (lockFile.lastmodified() == lockFileLastModified) { lockFileLastModified=0; lockFile.delete(); } else { LOGGER.warning("Tried to unlock foreign lock: " + lockFile.path()); } } else { LOGGER.warning("Tried to unlock not exisiting lock: " + lockFile.path()); } } /** * Try to get a lock * * @throws IOException */ public void writeLock() throws IOException{ if (hasWriteLock()) return; // already locked if (Resources.exists(lockFile)) { LOGGER.warning("Cannot obtain lock: " + lockFile.path()); Properties props = new Properties(); try (InputStream in = lockFile.in()) { props.load(in); } throw new IOException(Util.convertPropsToString(props,"Already locked" )); } else { // success writeLockFileContent(lockFile); lockFileLastModified = lockFile.lastmodified(); LOGGER.info("Successful lock: " + lockFile.path()); } } /** * Write some info into the lock file * hostname, ip, user and lock file path * * @param lockFile * @throws IOException */ protected void writeLockFileContent(Resource lockFile) throws IOException { Properties props = new Properties(); try (OutputStream out = lockFile.out()) { props.store(out, "Locking info"); String hostname="UNKNOWN"; String ip ="UNKNOWN"; // find some network info try { hostname = InetAddress.getLocalHost().getHostName(); InetAddress addrs[] = InetAddress.getAllByName(hostname); for (InetAddress addr: addrs) { if (!addr.isLoopbackAddress() && addr.isSiteLocalAddress()) ip = addr.getHostAddress(); } } catch (UnknownHostException ex) { } props.put("hostname", hostname); props.put("ip", ip); props.put("location", lockFile.path()); Authentication auth = SecurityContextHolder.getContext().getAuthentication(); props.put("principal", auth==null ? "UNKNOWN" :auth.getName()); props.store(out, "Locking info"); } } }