package org.epics.archiverappliance.config; import java.util.regex.Pattern; import org.apache.log4j.Logger; /** * Utility class for dealing with various aspects of EPICS PV names * @author mshankar * */ public class PVNames { private static Logger logger = Logger.getLogger(PVNames.class.getName()); /** * When you intend to connect to the PV's using PVAccess, use this string as a prefix in the UI/archivePV BPL. For example, pva://double01 * This syntax should be consistent with CSS. */ public static final String V4_PREFIX = "pva://"; /** * Remove the .VAL, .HIHI etc portion of a pvName and return the plain pvName * @param pvName The name of PV. * @return String The plain pvName */ public static String stripFieldNameFromPVName(String pvName) { if(pvName == null || pvName.equals("")) { return pvName; } return pvName.split("\\.")[0]; } /** * Remove the .VAL, .HIHI etc portion of an array of pvNames and return an array of plain pvNames * @param pvNames The name of PVs. * @return String An array of plain pvNames */ public static String[] stripFieldNameFromPVNames(String[] pvNames) { if(pvNames == null || pvNames.length == 0) return pvNames; String[] ret = new String[pvNames.length]; for(int i = 0; i < pvNames.length; i++) { ret[i] = stripFieldNameFromPVName(pvNames[i]); } return ret; } public static String getFieldName(String pvName) { if(pvName == null || pvName.equals("") || !pvName.contains(".")) { return ""; } String[] parts = pvName.split("\\."); if(parts.length != 2) { logger.error("Invalid PV name " + pvName); return ""; } return parts[1]; } /** * Remove .VAL from pv names if present. * Returned value is something that can be used to lookup for PVTypeInfo * @param pvName The name of PVs. * @return String normalizePVName */ public static String normalizePVName(String pvName) { if(pvName == null || pvName.equals("")) { return pvName; } String[] parts = pvName.split("\\."); if(parts.length == 1) { return pvName; } else if (parts.length == 2) { String fieldName = parts[1]; if(fieldName != null && !fieldName.equals("") && fieldName.equals("VAL")) { return parts[0]; } else { return pvName; } } else { logger.error("Invalid PV name " + pvName); return ""; } } /** * Gives you something you can use with caget to get the field associated with a PV even if you have a field already. * normalizePVNameWithField("ABC", "NAME") gives "ABC.NAME" * normalizePVNameWithField("ABC.HIHI", "NAME") gives "ABC.NAME" * @param pvName The name of PV. * @param fieldName   * @return String normalizePVNameWithField */ public static String normalizePVNameWithField(String pvName, String fieldName) { if(pvName == null || pvName.equals("")) { return pvName; } String[] parts = pvName.split("\\."); if(parts.length == 1) { return pvName + "." + fieldName; } else if (parts.length == 2) { return parts[0] + "." + fieldName; } else { logger.error("Invalid PV name " + pvName); return ""; } } /** * Is this a field? * @param pvName The name of PV. * @return boolean True or False */ public static boolean isField(String pvName) { if(pvName == null || pvName.equals("")) { return false; } String[] parts = pvName.split("\\."); if(parts.length == 1) { return false; } else if (parts.length == 2) { String fieldName = parts[1]; if(fieldName == null || fieldName.equals("")) { return false; } else { if(fieldName.equals("VAL")) { return false; } else { return true; } } } else { logger.error("Invalid PV name " + pvName); return false; } } /** * Transfer any fields from the source name to the dest name * Transferring ABC:123 onto DEF:456 should give DEF:456 * Transferring ABC:123.DESC onto DEF:456 should give DEF:456.DESC * @param srcName The source name * @param destName The destination name * @return String transferField */ public static String transferField(String srcName, String destName) { if(isField(srcName)) { return normalizePVNameWithField(destName, getFieldName(srcName)); } else { return destName; } } /** * A standard process for dealing with aliases, standard fields and the like. * @param pvName The name of PV. * @param configService ConfigService * @return PVTypeInfo   */ public static PVTypeInfo determineAppropriatePVTypeInfo(String pvName, ConfigService configService) { // First check for the pvName as is PVTypeInfo typeInfo = configService.getTypeInfoForPV(pvName); if(typeInfo != null) { logger.debug("Found typeinfo for pvName " + pvName); return typeInfo; } String pvNameAlone = PVNames.stripFieldNameFromPVName(pvName); String fieldName= PVNames.getFieldName(pvName); // Check for aliases. String realName = configService.getRealNameForAlias(pvNameAlone); if(realName != null) { pvName = realName + (fieldName == null || fieldName.equals("") ? "" : ("." + fieldName)); pvNameAlone = realName; typeInfo = configService.getTypeInfoForPV(pvName); if(typeInfo != null) { logger.debug("Found typeinfo for " + pvName + " as alias " + realName); return typeInfo; } } // Check for fields archived as part of PV. if(fieldName != null && !fieldName.equals("")) { typeInfo = configService.getTypeInfoForPV(pvNameAlone); if(typeInfo != null && typeInfo.checkIfFieldAlreadySepcified(fieldName)) { logger.debug("Found typeinfo for " + pvName + " for field " + fieldName); return typeInfo; } } logger.debug("Did not find typeinfo for pvName " + pvName); return null; } /** * A standard process for dealing with aliases, standard fields and the like; should be similar to determineAppropriatePVTypeInfo * @param pvName The name of PV. * @param configService ConfigService * @return ApplianceInfo   */ public static ApplianceInfo determineAppropriateApplianceInfo(String pvName, ConfigService configService) { // First check for the pvName as is ApplianceInfo info = configService.getApplianceForPV(pvName); if(info != null) { logger.debug("Found appliance info for pvName " + pvName); return info; } String pvNameAlone = PVNames.stripFieldNameFromPVName(pvName); String fieldName= PVNames.getFieldName(pvName); // Check for aliases. String realName = configService.getRealNameForAlias(pvNameAlone); if(realName != null) { pvName = realName + (fieldName == null || fieldName.equals("") ? "" : ("." + fieldName)); pvNameAlone = realName; info = configService.getApplianceForPV(pvName); if(info != null) { logger.debug("Found appliance info for " + pvName + " as alias " + realName); return info; } } // Check for fields archived as part of PV. if(fieldName != null && !fieldName.equals("")) { info = configService.getApplianceForPV(pvNameAlone); if(info != null) { logger.debug("Found appliance info for " + pvName + " for field " + fieldName); return info; } } logger.debug("Did not find appliance info for pvName " + pvName); return null; } private static Pattern validPVName = Pattern.compile("[a-zA-Z0-9\\_\\-\\+\\:\\[\\]\\<\\>\\;\\.\\/\\,\\#\\{\\}]+"); /** * Check to see if the pvName has valid characters. * For certain characters, EPICS will not throw exceptions but generate spurious traffic which is hard to detect. * From the App dev Guide at http://www.aps.anl.gov/epics/base/R3-14/12-docs/AppDevGuide/node7.html#SECTION007140000000000000000 * Valid characters are a-z A-Z 0-9 _ - + : [ ] < > ; * We add the '.' character for suporting fieldnames as well. * And we add the '/' character because some folks at FACET use this. * And we add the ',' character because some folks at LBL use this. * And we add the '#' character because some folks at FRIB use this. * And we add the '{' and the '}' character because some folks at BNL use this. * @param pvName The name of PV. * @return boolean True or False */ public static boolean isValidPVName(String pvName) { if(pvName == null || pvName.isEmpty()) return false; return validPVName.matcher(pvName).matches(); } /** * Does this pvName imply a connection using PVAccess? * @param pvName The name of PV. * @return boolean True or False */ public static boolean isEPICSV4PVName(String pvName) { if(pvName == null || pvName.isEmpty()) return false; return pvName.startsWith(V4_PREFIX); } /** * Remove the pva:// prefix from the PV name if present. * @param pvName The name of PV. * @return String   */ public static String stripPrefixFromName(String pvName) { if(pvName == null || pvName.isEmpty()) return pvName; if(pvName.startsWith(V4_PREFIX)) { return pvName.replace(V4_PREFIX, ""); } return pvName; } }