/******************************************************************************* * Copyright (c) 2011 The Board of Trustees of the Leland Stanford Junior University * as Operator of the SLAC National Accelerator Laboratory. * Copyright (c) 2011 Brookhaven National Laboratory. * EPICS archiver appliance is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. *******************************************************************************/ package org.epics.archiverappliance.mgmt.bpl.reports; import java.io.IOException; import java.io.PrintWriter; import java.net.URLEncoder; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.log4j.Logger; import org.epics.archiverappliance.common.BPLAction; import org.epics.archiverappliance.common.TimeUtils; import org.epics.archiverappliance.config.ApplianceInfo; import org.epics.archiverappliance.config.ChannelArchiverDataServerPVInfo; import org.epics.archiverappliance.config.ConfigService; import org.epics.archiverappliance.config.PVNames; import org.epics.archiverappliance.config.PVTypeInfo; import org.epics.archiverappliance.utils.ui.GetUrlContent; import org.epics.archiverappliance.utils.ui.MimeTypeConstants; import org.json.simple.JSONArray; import org.json.simple.JSONValue; /** * Detailed statistics for a PV. * * @epics.BPLAction - Get a lot of detailed statistics for a PV. The returned JSON is very UI friendly; but should be usable in a scripting environment. * @epics.BPLActionParam pv - The name of the pv. * @epics.BPLActionEnd * * @author mshankar * */ public class PVDetails implements BPLAction { private static final Logger logger = Logger.getLogger(PVDetails.class); // JSON Array etc are not generic savvy so we get generics errors when we do // fancy stuff like so. @Override public void execute(HttpServletRequest req, HttpServletResponse resp, ConfigService configService) throws IOException { String pvNameFromRequest = req.getParameter("pv"); String pvName = PVNames.stripFieldNameFromPVName(pvNameFromRequest); // Get rid of the V4 prefix pvName = PVNames.stripPrefixFromName(pvName); ApplianceInfo info = null; PVTypeInfo typeInfoForNameFromRequest = configService.getTypeInfoForPV(pvNameFromRequest); if(typeInfoForNameFromRequest != null) { logger.debug("Was able to find a PVTypeInfo for the name as specified in the request " + pvNameFromRequest); pvName = pvNameFromRequest; info = configService.getApplianceForPV(pvName); } else { String realName = configService.getRealNameForAlias(pvName); if(realName != null) pvName = realName; logger.debug("Found an alias; using that instead " + pvName); info = configService.getApplianceForPV(pvName); } logger.info("Getting the detailed status for PV " + pvName); resp.setContentType(MimeTypeConstants.APPLICATION_JSON); if(info == null) { pvName = pvNameFromRequest; info = configService.getApplianceForPV(pvName); if(info == null) { resp.sendError(HttpServletResponse.SC_NOT_FOUND, "Cannot find the appliance archiving " + pvNameFromRequest); return; } } String pvDetailsURLSnippet = "/getPVDetails?pv=" + URLEncoder.encode(pvName, "UTF-8"); try (PrintWriter out = resp.getWriter()) { LinkedList<Map<String, String>> result = new LinkedList<Map<String, String>>(); addDetailedStatus(result, "PV Name", pvNameFromRequest); if(!pvName.equals(pvNameFromRequest)) { addDetailedStatus(result, "Alias for ", pvName); } addDetailedStatus(result, "Instance archiving PV", info.getIdentity()); PVTypeInfo typeInfo = configService.getTypeInfoForPV(pvName); if(typeInfo != null) { addDetailedStatus(result, "Archival params creation time:", TimeUtils.convertToHumanReadableString(typeInfo.getCreationTime())); addDetailedStatus(result, "Archival params modification time:", TimeUtils.convertToHumanReadableString(typeInfo.getModificationTime())); addDetailedStatus(result, "Archiver DBR type (from typeinfo):", typeInfo.getDBRType().toString()); addDetailedStatus(result, "Is this a scalar:", typeInfo.isScalar() ? "Yes" : "No"); addDetailedStatus(result, "Number of elements:", Integer.toString(typeInfo.getElementCount())); addDetailedStatus(result, "Precision:", Double.toString(typeInfo.getPrecision())); addDetailedStatus(result, "Units:", typeInfo.getUnits()); addDetailedStatus(result, "Is this PV paused:", typeInfo.isPaused() ? "Yes" : "No"); addDetailedStatus(result, "Sampling method:", typeInfo.getSamplingMethod().toString()); addDetailedStatus(result, "Sampling period:", Float.toString(typeInfo.getSamplingPeriod())); addDetailedStatus(result, "Are we using PVAccess?", typeInfo.isUsePVAccess() ? "Yes" : "No"); for(String extraFieldName : configService.getExtraFields()) { String extraValue = typeInfo.getExtraFields().get(extraFieldName); if(extraValue != null) { if(extraFieldName.equals("SCAN")){ try { addDetailedStatus(result, "Extra info - " + extraFieldName + ":", changeSCANValueFromEnumToString(extraValue)); } catch(Exception ex) { addDetailedStatus(result, "Extra info - " + extraFieldName + ":", extraValue); } }else{ addDetailedStatus(result, "Extra info - " + extraFieldName + ":", extraValue); } } } String[] archiveFields = typeInfo.getArchiveFields(); if(archiveFields != null && archiveFields.length > 0) { String archiveFieldsStr = typeInfo.obtainArchiveFieldsAsString(); addDetailedStatus(result, "Archive Fields", archiveFieldsStr); } List<ChannelArchiverDataServerPVInfo> serverInfos = configService.getChannelArchiverDataServers(pvName); if(serverInfos != null && !serverInfos.isEmpty()) { for(ChannelArchiverDataServerPVInfo serverInfo : serverInfos) { addDetailedStatus(result, "External server:", serverInfo.getServerInfo().getServerURL() + "/" + serverInfo.getServerInfo().getIndex()); } } } else{ logger.warn("No PVTypeInfo for pv " + pvName); } JSONArray engineStatusVars = GetUrlContent.getURLContentAsJSONArray(info.getEngineURL() + pvDetailsURLSnippet ); if(engineStatusVars == null) { logger.warn("No status vars from engine using URL " + info.getEngineURL() + pvDetailsURLSnippet); } else { GetUrlContent.combineJSONArrays(result, engineStatusVars); } if(typeInfo.isPaused()) { logger.debug("Skipping getting pv details from ETL for paused PV " + pvName); } else { JSONArray etlStatusVars = GetUrlContent.getURLContentAsJSONArray(info.getEtlURL() + pvDetailsURLSnippet ); if(etlStatusVars == null) { logger.warn("No status vars from ETL using URL " + info.getEtlURL() + pvDetailsURLSnippet); } else { GetUrlContent.combineJSONArrays(result, etlStatusVars); } } out.println(JSONValue.toJSONString(result)); } } private static void addDetailedStatus( LinkedList<Map<String, String>> statuses, String name, String value) { Map<String, String> obj = new LinkedHashMap<String, String>(); obj.put("name", name); obj.put("value", value); obj.put("source", "mgmt"); statuses.add(obj); } private String changeSCANValueFromEnumToString(String enumValueStr) { /* * choice(menuScanPassive,"Passive") choice(menuScanEvent,"Event") * choice(menuScanI_O_Intr,"I/O Intr") * choice(menuScan10_second,"10 second") * choice(menuScan5_second,"5 second") * choice(menuScan2_second,"2 second") * choice(menuScan1_second,"1 second") * choice(menuScan_5_second,".5 second") * choice(menuScan_2_second,".2 second") * choice(menuScan_1_second,".1 second") */ String changedValue = ""; String enumValueIntStr = "" + (int) (Double.parseDouble(enumValueStr)); switch (enumValueIntStr) { case "0": { changedValue = "Passive"; break; } case "1": { changedValue = "Event"; break; } case "2": { changedValue = "I/O Intr"; break; } case "3": { changedValue = "10 second"; break; } case "4": { changedValue = "5 second"; break; } case "5": { changedValue = "2 second"; break; } case "6": { changedValue = "1 second"; break; } case "7": { changedValue = ".5 second"; break; } case "8": { changedValue = ".2 second"; break; } case "9": { changedValue = ".1 second"; break; } default: { changedValue = "unknown"; } } return changedValue; } }