/* | 
|
 * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved. | 
|
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|
 * | 
|
 * This code is free software; you can redistribute it and/or modify it | 
|
 * under the terms of the GNU General Public License version 2 only, as | 
|
 * published by the Free Software Foundation.  Oracle designates this | 
|
 * particular file as subject to the "Classpath" exception as provided | 
|
 * by Oracle in the LICENSE file that accompanied this code. | 
|
 * | 
|
 * This code is distributed in the hope that it will be useful, but WITHOUT | 
|
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|
 * version 2 for more details (a copy is included in the LICENSE file that | 
|
 * accompanied this code). | 
|
 * | 
|
 * You should have received a copy of the GNU General Public License version | 
|
 * 2 along with this work; if not, write to the Free Software Foundation, | 
|
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|
 * | 
|
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|
 * or visit www.oracle.com if you need additional information or have any | 
|
 * questions. | 
|
*/  | 
|
package sun.jvmstat.perfdata.monitor.protocol.local;  | 
|
import java.io.File;  | 
|
import java.io.FilenameFilter;  | 
|
/** | 
|
 * Class to provide translations from the local Vm Identifier | 
|
 * name space into the file system name space and vice-versa. | 
|
 * <p> | 
|
 * Provides a factory for creating a File object to the backing | 
|
 * store file for instrumentation shared memory region for a JVM | 
|
 * identified by its Local Java Virtual Machine Identifier, or | 
|
 * <em>lvmid</em>. | 
|
 * | 
|
 * @author Brian Doherty | 
|
 * @since 1.5 | 
|
 * @see java.io.File | 
|
*/  | 
|
public class PerfDataFile { | 
|
    private PerfDataFile() { }; | 
|
    /** | 
|
     * The name of the of the system dependent temporary directory | 
|
*/  | 
|
public static final String tmpDirName;  | 
|
    /** | 
|
     * The file name prefix for PerfData shared memory files. | 
|
     * <p> | 
|
     * This prefix must be kept in sync with the prefix used by the JVM. | 
|
*/  | 
|
public static final String dirNamePrefix = "hsperfdata_";  | 
|
    /** | 
|
     * The directory name pattern for the user directories. | 
|
*/  | 
|
public static final String userDirNamePattern = "hsperfdata_\\S*";  | 
|
    /** | 
|
     * The file name pattern for PerfData shared memory files. | 
|
     * <p> | 
|
     * This pattern must be kept in synch with the file name pattern | 
|
     * used by the 1.4.2 and later HotSpot JVM. | 
|
*/  | 
|
public static final String fileNamePattern = "^[0-9]+$";  | 
|
    /** | 
|
     * The file name pattern for 1.4.1 PerfData shared memory files. | 
|
     * <p> | 
|
     * This pattern must be kept in synch with the file name pattern | 
|
     * used by the 1.4.1 HotSpot JVM. | 
|
*/  | 
|
public static final String tmpFileNamePattern =  | 
|
            "^hsperfdata_[0-9]+(_[1-2]+)?$"; | 
|
    /** | 
|
     * Get a File object for the instrumentation backing store file | 
|
     * for the JVM identified by the given local Vm Identifier. | 
|
     * <p> | 
|
     * This method looks for the most up to date backing store file for | 
|
     * the given <tt>lvmid</tt>. It will search all the user specific | 
|
     * directories in the temporary directory for the host operating | 
|
     * system, which may be influenced by platform specific environment | 
|
     * variables. | 
|
     * | 
|
     * @param lvmid  the local Java Virtual Machine Identifier for the target | 
|
     * @return File - a File object to the backing store file for the named | 
|
     *                shared memory region of the target JVM. | 
|
     * @see java.io.File | 
|
     * @see #getTempDirectory() | 
|
*/  | 
|
public static File getFile(int lvmid) {  | 
|
if (lvmid == 0) {  | 
|
            /* | 
|
             * lvmid == 0 is used to indicate the current Java Virtual Machine. | 
|
             * If the SDK provided an API to get a unique Java Virtual Machine | 
|
             * identifier, then a filename could be constructed with that | 
|
             * identifier. In absence of such an api, return null. | 
|
*/  | 
|
return null;  | 
|
}  | 
|
        /* | 
|
         * iterate over all files in all directories in tmpDirName that | 
|
         * match the file name patterns. | 
|
*/  | 
|
File tmpDir = new File(tmpDirName);  | 
|
String[] files = tmpDir.list(new FilenameFilter() {  | 
|
public boolean accept(File dir, String name) {  | 
|
if (!name.startsWith(dirNamePrefix)) {  | 
|
return false;  | 
|
}  | 
|
File candidate = new File(dir, name);  | 
|
return ((candidate.isDirectory() || candidate.isFile())  | 
|
&& candidate.canRead());  | 
|
}  | 
|
});  | 
|
long newestTime = 0;  | 
|
File newest = null;  | 
|
for (int i = 0; i < files.length; i++) {  | 
|
File f = new File(tmpDirName + files[i]);  | 
|
File candidate = null;  | 
|
if (f.exists() && f.isDirectory()) {  | 
|
                /* | 
|
                 * found a directory matching the name patterns. This | 
|
                 * is a 1.4.2 hsperfdata_<user> directory. Check for | 
|
                 * file named <lvmid> in that directory | 
|
*/  | 
|
String name = Integer.toString(lvmid);  | 
|
candidate = new File(f.getName(), name);  | 
|
} else if (f.exists() && f.isFile()) {  | 
|
                /* | 
|
                 * found a file matching the name patterns. This | 
|
                 * is a 1.4.1 hsperfdata_<lvmid> file. | 
|
*/  | 
|
candidate = f;  | 
|
            } else { | 
|
                // unexpected - let conditional below filter this one out | 
|
candidate = f;  | 
|
}  | 
|
if (candidate.exists() && candidate.isFile()  | 
|
&& candidate.canRead()) {  | 
|
long modTime = candidate.lastModified();  | 
|
if (modTime >= newestTime) {  | 
|
newestTime = modTime;  | 
|
newest = candidate;  | 
|
}  | 
|
}  | 
|
}  | 
|
return newest;  | 
|
}  | 
|
    /** | 
|
     * Return the File object for the backing store file for the specified Java | 
|
     * Virtual Machine. | 
|
     * <p> | 
|
     * This method looks for the most up to date backing store file for | 
|
     * the JVM identified by the given user name and lvmid. The directory | 
|
     * searched is the temporary directory for the host operating system, | 
|
     * which may be influenced by environment variables. | 
|
     * | 
|
     * @param user   the user name | 
|
     * @param lvmid  the local Java Virtual Machine Identifier for the target | 
|
     * @return File - a File object to the backing store file for the named | 
|
     *                shared memory region of the target JVM. | 
|
     * @see java.io.File | 
|
     * @see #getTempDirectory() | 
|
*/  | 
|
public static File getFile(String user, int lvmid) {  | 
|
if (lvmid == 0) {  | 
|
            /* | 
|
             * lvmid == 0 is used to indicate the current Java Virtual Machine. | 
|
             * If the SDK provided an API to get a unique Java Virtual Machine | 
|
             * identifier, then a filename could be constructed with that | 
|
             * identifier. In absence of such an api, return null. | 
|
*/  | 
|
return null;  | 
|
}  | 
|
        // first try for 1.4.2 and later JVMs | 
|
String basename = getTempDirectory(user) + Integer.toString(lvmid);  | 
|
File f = new File(basename);  | 
|
if (f.exists() && f.isFile() && f.canRead()) {  | 
|
return f;  | 
|
}  | 
|
        // No hit on 1.4.2 JVMs, try 1.4.1 files | 
|
long newestTime = 0;  | 
|
File newest = null;  | 
|
for (int i = 0; i < 2; i++) {  | 
|
if (i == 0) {  | 
|
basename = getTempDirectory() + Integer.toString(lvmid);  | 
|
            } else { | 
|
basename = getTempDirectory() + Integer.toString(lvmid)  | 
|
+ Integer.toString(i);  | 
|
}  | 
|
f = new File(basename);  | 
|
if (f.exists() && f.isFile() && f.canRead()) {  | 
|
long modTime = f.lastModified();  | 
|
if (modTime >= newestTime) {  | 
|
newestTime = modTime;  | 
|
newest = f;  | 
|
}  | 
|
}  | 
|
}  | 
|
return newest;  | 
|
}  | 
|
    /** | 
|
     * Method to extract a local Java Virtual Machine Identifier from the | 
|
     * file name of the given File object. | 
|
     * | 
|
     * @param file A File object representing the name of a | 
|
     *             shared memory region for a target JVM | 
|
     * @return int - the local Java Virtual Machine Identifier for the target | 
|
     *               associated with the file | 
|
     * @throws java.lang.IllegalArgumentException Thrown if the file name | 
|
     *               does not conform to the expected pattern | 
|
*/  | 
|
public static int getLocalVmId(File file) {  | 
|
        try { | 
|
            // try 1.4.2 and later format first | 
|
return Integer.parseInt(file.getName());  | 
|
} catch (NumberFormatException e) { }  | 
|
        // now try the 1.4.1 format | 
|
String name = file.getName();  | 
|
if (name.startsWith(dirNamePrefix)) {  | 
|
int first = name.indexOf('_');  | 
|
int last = name.lastIndexOf('_');  | 
|
            try { | 
|
if (first == last) {  | 
|
return Integer.parseInt(name.substring(first + 1));  | 
|
                } else { | 
|
return Integer.parseInt(name.substring(first + 1, last));  | 
|
}  | 
|
} catch (NumberFormatException e) { }  | 
|
}  | 
|
throw new IllegalArgumentException("file name does not match pattern");  | 
|
}  | 
|
    /** | 
|
     * Return the name of the temporary directory being searched for | 
|
     * HotSpot PerfData backing store files. | 
|
     * <p> | 
|
     * This method generally returns the value of the java.io.tmpdir | 
|
     * property. However, on some platforms it may return a different | 
|
     * directory, as the JVM implementation may store the PerfData backing | 
|
     * store files in a different directory for performance reasons. | 
|
     * | 
|
     * @return String - the name of the temporary directory. | 
|
*/  | 
|
public static String getTempDirectory() {  | 
|
return tmpDirName;  | 
|
}  | 
|
    /** | 
|
     * Return the name of the temporary directory to be searched | 
|
     * for HotSpot PerfData backing store files for a given user. | 
|
     * <p> | 
|
     * This method generally returns the name of a subdirectory of | 
|
     * the directory indicated in the java.io.tmpdir property. However, | 
|
     * on some platforms it may return a different directory, as the | 
|
     * JVM implementation may store the PerfData backing store files | 
|
     * in a different directory for performance reasons. | 
|
     * | 
|
     * @return String - the name of the temporary directory. | 
|
*/  | 
|
public static String getTempDirectory(String user) {  | 
|
return tmpDirName + dirNamePrefix + user + File.separator;  | 
|
}  | 
|
    static { | 
|
        /* | 
|
         * For this to work, the target VM and this code need to use | 
|
         * the same directory. Instead of guessing which directory the | 
|
         * VM is using, we will ask. | 
|
*/  | 
|
String tmpdir = sun.misc.VMSupport.getVMTemporaryDirectory();  | 
|
        /* | 
|
         * Assure that the string returned has a trailing File.separator | 
|
         * character. This check was added because the Linux implementation | 
|
         * changed such that the java.io.tmpdir string no longer terminates | 
|
         * with a File.separator character. | 
|
*/  | 
|
if (tmpdir.lastIndexOf(File.separator) != (tmpdir.length()-1)) {  | 
|
tmpdir = tmpdir + File.separator;  | 
|
}  | 
|
tmpDirName = tmpdir;  | 
|
}  | 
|
}  |