org.ambraproject.action.debug.DebugInfoAction.java Source code

Java tutorial

Introduction

Here is the source code for org.ambraproject.action.debug.DebugInfoAction.java

Source

/*
 * $HeadURL$
 * $Id$
 * Copyright (c) 2006-2012 by Public Library of Science http://plos.org http://ambraproject.org
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.ambraproject.action.debug;

import org.ambraproject.action.InternalIpAction;
import org.ambraproject.filestore.FileStoreService;
import org.ambraproject.web.SessionCounter;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.io.IOUtils;
import org.apache.struts2.ServletActionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.ambraproject.configuration.ConfigurationStore;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * Action class that gathers a bunch of debugging information about a running
 * ambra instance.
 */
public class DebugInfoAction extends InternalIpAction {

    private static final Logger log = LoggerFactory.getLogger(DebugInfoAction.class);

    private Date timestamp;

    private String host;

    private String hostIp;

    private String buildInfo;

    private double jvmFreeMemory;

    private double jvmTotalMemory;

    private double jvmMaxMemory;

    private String tomcatVersion;

    private int sessionCount;

    private String configuration;

    private String dbUrl;

    private String dbUser;

    private String solrUrl;

    private String filestore;

    private String cmdLine;

    @Override
    public String execute() throws Exception {
        if (!checkAccess()) {
            return ERROR;
        }
        timestamp = new Date(System.currentTimeMillis());
        Runtime rt = Runtime.getRuntime();
        jvmFreeMemory = (double) rt.freeMemory() / (1024.0 * 1024.0);
        jvmTotalMemory = (double) rt.totalMemory() / (1024.0 * 1024.0);
        jvmMaxMemory = (double) rt.maxMemory() / (1024.0 * 1024.0);
        HttpServletRequest req = ServletActionContext.getRequest();
        tomcatVersion = ServletActionContext.getServletContext().getServerInfo();
        sessionCount = SessionCounter.getSessionCount();
        host = req.getLocalName();
        hostIp = req.getLocalAddr();
        buildInfo = generateBuildInfo();

        // The easiest way I found to get the URL and username for the DB.
        // It's not that easy and involves opening a connection...
        Context initialContext = new InitialContext();
        Context context = (Context) initialContext.lookup("java:comp/env");
        DataSource ds = (DataSource) context.lookup("jdbc/AmbraDS");
        Connection conn = null;
        try {
            conn = ds.getConnection();
            DatabaseMetaData metadata = conn.getMetaData();
            dbUrl = metadata.getURL();
            dbUser = metadata.getUserName();
        } finally {
            conn.close();
        }

        Configuration config = ConfigurationStore.getInstance().getConfiguration();
        FileStoreService filestoreService = (FileStoreService) context.lookup("ambra/FileStore");
        filestore = filestoreService.toString();
        solrUrl = (String) config.getProperty("ambra.services.search.server.url");
        configuration = dumpConfig(config);
        cmdLine = IOUtils.toString(new FileInputStream("/proc/self/cmdline"));

        return SUCCESS;
    }

    /**
     * Reads a file from the ambra-base .jar in the classpath.
     *
     * @param path filepath, relative to the jar
     * @return contents of the file, or null if it was not found
     * @throws IOException
     */
    private String readFileFromAmbraJar(String path) throws IOException {

        // Scan through all such files in the classpath, and pull out the one
        // associated with the ambra-base .jar.
        URL url = null;
        for (Enumeration<URL> manifests = Thread.currentThread().getContextClassLoader()
                .getResources(path); manifests.hasMoreElements();) {
            url = manifests.nextElement();
            if (url.getFile().contains("/ambra-base-")) {
                break;
            }
        }
        InputStream is = url.openStream();
        String result = null;
        try {
            result = IOUtils.toString(is);
        } finally {
            is.close();
        }
        return result;
    }

    private static final Pattern YEAR_PATTERN = Pattern.compile("#.+20\\d{2}$");

    /**
     * Generates an informative message describing who built the application and when.
     */
    private String generateBuildInfo() throws IOException {
        String manifest = readFileFromAmbraJar("META-INF/MANIFEST.MF");
        String builder = null;
        if (manifest != null) {
            for (String line : manifest.split("\n")) {
                if (line != null && line.startsWith("Built-By:")) {
                    builder = line.substring("Built-By:".length()).trim();
                    break;
                }
            }
        }
        String properties = readFileFromAmbraJar("META-INF/maven/org.ambraproject/ambra-base/pom.properties");
        String buildDate = null;
        String version = null;
        if (properties != null) {
            for (String line : properties.split("\n")) {

                // Currently maven puts the build date on the second line, prepended
                // with a #.  Look for anything that vaguely resembles a date.
                Matcher match = YEAR_PATTERN.matcher(line);
                if (match.matches()) {
                    buildDate = line.substring(1).trim();
                } else {
                    if (line != null && line.startsWith("version=")) {
                        version = line.substring("version=".length()).trim();
                    }
                }
            }
        }
        builder = builder == null ? "" : "by " + builder;
        buildDate = buildDate == null ? "" : "on " + buildDate;
        version = version == null ? "" : String.format("(%s)", version);
        return String.format("Built %s %s %s", builder, buildDate, version);
    }

    /**
     * Returns a string with information about many of the ambra.* properties
     * in a Configuration.  Intended to be informational-only, not exhaustive.
     */
    private String dumpConfig(Configuration config) {
        StringBuilder result = new StringBuilder();
        Iterator iter = config.getKeys();
        while (iter.hasNext()) {
            String key = (String) iter.next();

            // Don't display the virtual journal stuff; it's long and not particularly useful.
            if (key.startsWith("ambra.") && !key.startsWith("ambra.virtualJournals.")) {
                Object value = config.getProperty(key);

                // Attempt to dereference other properties referred to by "${foo}" notation.
                if (value instanceof String) {
                    String valueStr = (String) value;
                    if (valueStr.startsWith("${")) {
                        String refKey = valueStr.substring(2, valueStr.length() - 1);
                        Object refValue = config.getProperty(refKey);
                        if (refValue != null) {
                            value = String.format("%s -> %s", valueStr, refValue);
                        }
                    }
                }
                result.append(key).append(": ").append(value).append('\n');
            }
        }
        return result.toString();
    }

    public Date getTimestamp() {
        return timestamp;
    }

    public String getHost() {
        return host;
    }

    public String getHostIp() {
        return hostIp;
    }

    public String getBuildInfo() {
        return buildInfo;
    }

    public double getJvmFreeMemory() {
        return jvmFreeMemory;
    }

    public double getJvmTotalMemory() {
        return jvmTotalMemory;
    }

    public double getJvmMaxMemory() {
        return jvmMaxMemory;
    }

    public String getTomcatVersion() {
        return tomcatVersion;
    }

    public int getSessionCount() {
        return sessionCount;
    }

    public String getConfiguration() {
        return configuration;
    }

    public String getDbUrl() {
        return dbUrl;
    }

    public String getDbUser() {
        return dbUser;
    }

    public String getSolrUrl() {
        return solrUrl;
    }

    public String getFilestore() {
        return filestore;
    }

    public String getCmdLine() {
        return cmdLine;
    }
}