package org.epics.archiverappliance.config; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.util.HashMap; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; import javax.servlet.ServletContext; import org.apache.log4j.Logger; import org.epics.archiverappliance.config.exception.AlreadyRegisteredException; import org.epics.archiverappliance.config.exception.ConfigException; import org.epics.archiverappliance.config.persistence.InMemoryPersistence; import org.epics.archiverappliance.engine.pv.EngineContext; import org.epics.archiverappliance.etl.common.PBThreeTierETLPVLookup; import org.epics.archiverappliance.mgmt.MgmtRuntimeState; public class ConfigServiceForTests extends DefaultConfigService { private static Logger logger = Logger.getLogger(ConfigServiceForTests.class.getName()); private static Logger configlogger = Logger.getLogger("config." + ConfigServiceForTests.class.getName()); private File webInfClassesFolder; public static final String TESTAPPLIANCE0 = "appliance0"; private boolean isUnitTests = false; protected static final String DEFAULT_PB_SHORT_TERM_TEST_DATA_FOLDER = getDefaultShortTermFolder(); /** * A folder which is used to store the data for the unit tests... */ protected static final String DEFAULT_PB_TEST_DATA_FOLDER = getDefaultPBTestFolder(); /** * Tomcat is launched listening to this port when running the unit tests */ public static final int RETRIEVAL_TEST_PORT = 17665; /** * All unit test PV names are expected to begin with this. * This name is supposed to be something that we will not encounter in the field. */ public static final String ARCH_UNIT_TEST_PVNAME_PREFIX = "--ArchUnitTest"; String rootFolder = ConfigServiceForTests.DEFAULT_PB_TEST_DATA_FOLDER; static HashMap<String, ArchDBRTypes> samplePV2DBRtypemap = new HashMap<String, ArchDBRTypes>(); static { for(ArchDBRTypes type : ArchDBRTypes.values()) { samplePV2DBRtypemap.put(ConfigServiceForTests.ARCH_UNIT_TEST_PVNAME_PREFIX + (type.isWaveForm() ? "V_" : "S_") + type.getPrimitiveName(), type); } } public ConfigServiceForTests() throws ConfigException { super(); } public ConfigServiceForTests(File WebInfClassesFolder) throws ConfigException { this(WebInfClassesFolder, -1); } public ConfigServiceForTests(File WebInfClassesFolder, int jcaCommandThreadCount) throws ConfigException { this.webInfClassesFolder = WebInfClassesFolder; configlogger.info("The WEB-INF/classes folder is " + this.webInfClassesFolder.getAbsolutePath()); appliances = new HashMap<String, ApplianceInfo>(); pv2appliancemapping = new ConcurrentHashMap<String, ApplianceInfo>(); namedFlags = new ConcurrentHashMap<String, Boolean>(); typeInfos = new ConcurrentHashMap<String, PVTypeInfo>(); archivePVRequests = new ConcurrentHashMap<String, UserSpecifiedSamplingParams>(); aliasNamesToRealNames = new ConcurrentHashMap<String, String>(); channelArchiverDataServers = new ConcurrentHashMap<String, String>(); pvsForThisAppliance = new ConcurrentSkipListSet<String>(); pausedPVsForThisAppliance = new ConcurrentSkipListSet<String>(); pv2ChannelArchiverDataServer = new ConcurrentHashMap<String, List<ChannelArchiverDataServerPVInfo>>(); myApplianceInfo = new ApplianceInfo(TESTAPPLIANCE0, "http://localhost:17665/mgmt/bpl", "http://localhost:17665/engine/bpl", "http://localhost:17665/retrieval/bpl", "http://localhost:17665/etl/bpl", "localhost:16670", "http://localhost:17665/retrieval" ); appliances.put(TESTAPPLIANCE0, myApplianceInfo); appliancesInCluster.add(TESTAPPLIANCE0); try(InputStream is = this.getClass().getClassLoader().getResourceAsStream(DEFAULT_ARCHAPPL_PROPERTIES_FILENAME)) { archapplproperties.load(is); configlogger.info("Done loading installation specific properties file " + this.getClass().getClassLoader().getResource(DEFAULT_ARCHAPPL_PROPERTIES_FILENAME).toString()); } catch(Exception ex) { throw new ConfigException("Exception loading installation specific properties file " + DEFAULT_ARCHAPPL_PROPERTIES_FILENAME + " from classpath", ex); } if(jcaCommandThreadCount >= 1) { logger.warn("Overriding JCA command thread count to " + jcaCommandThreadCount); archapplproperties.put("org.epics.archiverappliance.engine.epics.commandThreadCount", Integer.toString(jcaCommandThreadCount)); } pvName2KeyConverter = new ConvertPVNameToKey(); pvName2KeyConverter.initialize(this); persistanceLayer = new InMemoryPersistence(); this.engineContext=new EngineContext(this); this.engineContext.setDisconnectCheckTimeoutInMinutesForTestingPurposesOnly(1); this.etlPVLookup = new PBThreeTierETLPVLookup(this); this.retrievalState = new SampleRetrievalState(this); this.mgmtRuntime = new MgmtRuntimeState(this); startupExecutor = Executors.newScheduledThreadPool(1, new ThreadFactory() { @Override public Thread newThread(Runnable r) { Thread t = new Thread(r); t.setName("Startup executor"); return t; } }); startupState = STARTUP_SEQUENCE.STARTUP_COMPLETE; this.addShutdownHook(new Runnable() { @Override public void run() { startupExecutor.shutdown(); } }); } @Override public void initialize(ServletContext sce) throws ConfigException { super.initialize(sce); this.retrievalState = new SampleRetrievalState(this); if(this.engineContext != null) { this.engineContext.setDisconnectCheckTimeoutInMinutesForTestingPurposesOnly(1); } } @Override public ApplianceInfo getApplianceForPV(String pvName) { ApplianceInfo applianceInfo = super.getApplianceForPV(pvName); // We should do the following code only for unit tests (and not for the real config service). if(applianceInfo == null && isUnitTests && pvName.startsWith(ConfigServiceForTests.ARCH_UNIT_TEST_PVNAME_PREFIX)) { logger.debug("Setting appliance for unit test pv " + pvName + " to self in unit tests mode."); applianceInfo = myApplianceInfo; } return applianceInfo; } @Override public void registerPVToAppliance(String pvName, ApplianceInfo applianceInfo) throws AlreadyRegisteredException { super.registerPVToAppliance(pvName, applianceInfo); if(applianceInfo.getIdentity().equals(myApplianceInfo.getIdentity())) { logger.debug("Adding pv " + pvName + " to this appliance's pvs and to ETL"); this.pvsForThisAppliance.add(pvName); if(this.getETLLookup() != null) { this.getETLLookup().addETLJobsForUnitTests(pvName, this.getTypeInfoForPV(pvName)); } } } @Override public InputStream getPolicyText() throws IOException { if (webInfClassesFolder != null) { String policiesPyPath = this.webInfClassesFolder.getAbsolutePath() + File.separator + "policies.py"; return new FileInputStream(new File(policiesPyPath)); } return super.getPolicyText(); } @Override public PVTypeInfo getTypeInfoForPV(String pvName) { PVTypeInfo ret = super.getTypeInfoForPV(pvName); if(ret != null) return ret; // For the unit tests, we have a naming convention that identifies the DBR type etc based on the name of the PV... if(pvName.startsWith(ConfigServiceForTests.ARCH_UNIT_TEST_PVNAME_PREFIX)) { pvName = PVNames.stripFieldNameFromPVName(pvName); logger.info("Unit test typeinfo for pv " + pvName); ArchDBRTypes namingConventionType = samplePV2DBRtypemap.get(pvName); if(namingConventionType == null) { logger.warn(pvName + " does not follow the testing convention. Defaulting the dbrtype to a scalar double."); namingConventionType = ArchDBRTypes.DBR_SCALAR_DOUBLE; } PVTypeInfo typeInfo = new PVTypeInfo(pvName, namingConventionType, !namingConventionType.isWaveForm(), 1); typeInfo.setUpperDisplayLimit(new Double(1.0)); typeInfo.setLowerDisplayLimit(new Double(-1.0)); typeInfo.setHasReducedDataSet(true); typeInfo.setComputedEventRate(1.0f); typeInfo.setComputedStorageRate(12.0f); typeInfo.setUserSpecifiedEventRate(1.0f); typeInfo.setApplianceIdentity(this.myIdentity); typeInfo.addArchiveField("HIHI"); typeInfo.addArchiveField("LOLO"); return typeInfo; } return null; } /** * This should only be called in the unit tests.... * @param rootFolder */ public void setPBRootFolder(String rootFolder) { this.rootFolder = rootFolder; } /** * Get the root folder for the PB storage plugin * @return */ public String getPBRootFolder() { return rootFolder; } public static String getDefaultPBTestFolder() { String defaultFolder = System.getenv("ARCHAPPL_MEDIUM_TERM_FOLDER"); if(defaultFolder != null) { return defaultFolder; } if(File.separatorChar == '\\') { return "c://temp"; } else { return "/scratch/LargeDisk/ArchiverStore"; } } public String getStandardShortTermFolder() { return getDefaultShortTermFolder(); } public String getStandardMediumTermFolder() { return getDefaultPBTestFolder(); } public static String getDefaultShortTermFolder() { String defaultSTFolder = System.getenv("ARCHAPPL_SHORT_TERM_FOLDER"); if(defaultSTFolder != null) { return defaultSTFolder; } if(File.separatorChar == '\\') { return "c://temp"; } else { return "/dev/shm/test"; } } @Override public String getWebInfFolder() { if(this.webInfClassesFolder != null) { return this.webInfClassesFolder.getAbsolutePath(); } return super.getWebInfFolder(); } @Override public int getInitialDelayBeforeStartingArchiveRequestWorkflow() { // Of course, for testing, we kick off the archive PV workflow right away. return 10; } }