/*******************************************************************************
* 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.config;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import org.apache.commons.lang3.text.StrLookup;
import org.apache.commons.lang3.text.StrSubstitutor;
import org.apache.log4j.Logger;
import org.epics.archiverappliance.StoragePlugin;
import org.epics.archiverappliance.etl.ETLDest;
import org.epics.archiverappliance.etl.ETLSource;
import org.epics.archiverappliance.retrieval.channelarchiver.ChannelArchiverReadOnlyPlugin;
import org.epics.archiverappliance.utils.blackhole.BlackholeStoragePlugin;
import edu.stanford.slac.archiverappliance.PBOverHTTP.PBOverHTTPStoragePlugin;
import edu.stanford.slac.archiverappliance.PlainPB.PlainPBStoragePlugin;
/**
* Parses a URL representation of a storage plugin.
* Storage plugins can optionally implement ETLSource, ETLDest and perhaps other interfaces.
* This is one stop shopping for initializing all of these from a URL representation.
* For example, <code>pb://localhost?name=LTS&rootFolder=${ARCHAPPL_LONG_TERM_FOLDER}&partitionGranularity=PARTITION_YEAR</code> will initialize a PlainPBStoragePlugin.
* <ol>
* <li>The <code>pb</code> prefix initializes {@link edu.stanford.slac.archiverappliance.PlainPB.PlainPBStoragePlugin PlainPBStoragePlugin}.</li>
* <li>The <code>pbraw</code> prefix initializes {@link edu.stanford.slac.archiverappliance.PBOverHTTP.PBOverHTTPStoragePlugin PBOverHTTPStoragePlugin}.</li>
* <li>The <code>blackhole</code> prefix initializes {@link org.epics.archiverappliance.utils.blackhole.BlackholeStoragePlugin BlackholeStoragePlugin}.</li>
* <li>The <code>rtree</code> prefix initializes {@link org.epics.archiverappliance.retrieval.channelarchiver.ChannelArchiverReadOnlyPlugin ChannelArchiverReadOnlyPlugin}.</li>
* </ol>
* @author mshankar
*
*/
public class StoragePluginURLParser {
private static Logger logger = Logger.getLogger(StoragePluginURLParser.class.getName());
public static StoragePlugin parseStoragePlugin(String srcURIStr, ConfigService configService) throws IOException {
try {
srcURIStr = expandMacros(srcURIStr);
URI srcURI = new URI(srcURIStr);
String pluginIdentifier = srcURI.getScheme();
switch(pluginIdentifier) {
case "pb" : {
return parsePlainPBStoragePlugin(srcURIStr, configService);
}
case "pbraw" : {
return parseHTTPStoragePlugin(srcURIStr, configService);
}
case "blackhole" : {
return parseBlackHolePlugin(srcURIStr, configService);
}
case "rtree" : {
return parseChannelArchiverPlugin(srcURIStr, configService);
}
default : {
logger.error("Unsupported plugin " + pluginIdentifier + ". Did you forget to register this?");
}
}
} catch(URISyntaxException ex) {
throw new IOException(ex);
}
return null;
}
public static ETLSource parseETLSource(String srcURIStr, ConfigService configService) throws IOException {
try {
srcURIStr = expandMacros(srcURIStr);
URI srcURI = new URI(srcURIStr);
String pluginIdentifier = srcURI.getScheme();
switch(pluginIdentifier) {
case "pb" : {
return parsePlainPBStoragePlugin(srcURIStr, configService);
}
case "blackhole" : {
logger.warn("The blackhole plugin cannot serve as an ETL source; so it has to be the last plugin in the list of data stores.");
return null;
}
default : {
logger.error("Unsupported plugin " + pluginIdentifier + ". Did you forget to register this?");
}
}
} catch(URISyntaxException ex) {
throw new IOException(ex);
}
return null;
}
public static ETLDest parseETLDest(String srcURIStr, ConfigService configService) throws IOException {
try {
srcURIStr = expandMacros(srcURIStr);
URI srcURI = new URI(srcURIStr);
String pluginIdentifier = srcURI.getScheme();
switch(pluginIdentifier) {
case "pb" : {
return parsePlainPBStoragePlugin(srcURIStr, configService);
}
case "blackhole" : {
return parseBlackHolePlugin(srcURIStr, configService);
}
default : {
logger.error("Unsupported plugin " + pluginIdentifier + ". Did you forget to register this?");
}
}
} catch(URISyntaxException ex) {
throw new IOException(ex);
}
return null;
}
private static PlainPBStoragePlugin parsePlainPBStoragePlugin(String srcURIStr, ConfigService configService) throws IOException {
PlainPBStoragePlugin ret = new PlainPBStoragePlugin();
ret.initialize(expandMacros(srcURIStr), configService);
return ret;
}
private static PBOverHTTPStoragePlugin parseHTTPStoragePlugin(String srcURIStr, ConfigService configService) throws IOException {
PBOverHTTPStoragePlugin ret = new PBOverHTTPStoragePlugin();
ret.initialize(srcURIStr, configService);
return ret;
}
private static BlackholeStoragePlugin parseBlackHolePlugin(String srcURIStr, ConfigService configService) throws IOException {
BlackholeStoragePlugin ret = new BlackholeStoragePlugin();
ret.initialize(srcURIStr, configService);
return ret;
}
private static ChannelArchiverReadOnlyPlugin parseChannelArchiverPlugin(String srcURIStr, ConfigService configService) throws IOException {
ChannelArchiverReadOnlyPlugin ret = new ChannelArchiverReadOnlyPlugin();
ret.initialize(srcURIStr, configService);
return ret;
}
/**
* Expands macros in the plugin definition strings.
* Checks java.system.properties first (passed in with a -D to the JVM)
* Then checks the environment (for example, using export in Linux).
* If we are not able to match in either place, we return as is.
*
* For example, if we did <code>export ARCHAPPL_SHORT_TERM_FOLDER=/dev/test</code>, and then used <code>pbraw://${ARCHAPPL_SHORT_TERM_FOLDER}<code> in the policy datastore definition,
* these would be expanded into <code>pbraw:///dev/test<code></code>
* @param srcURIStr
* @return
*/
private static String expandMacros(String srcURIStr) {
StrSubstitutor sub = new StrSubstitutor(new StrLookup<String>() {
@Override
public String lookup(String name) {
String valueFromProps = System.getProperty(name);
if(valueFromProps != null) {
if(logger.isDebugEnabled()) logger.debug("Resolving " + name + " from system properties into " + valueFromProps);
return valueFromProps;
}
String valueFromEnvironment = System.getenv(name);
if(valueFromEnvironment != null) {
if(logger.isDebugEnabled()) logger.debug("Resolving " + name + " from system environment into " + valueFromEnvironment);
return valueFromEnvironment;
}
logger.error("Unable to find " + name + " in either the java system properties or the system environment. Returning as is without expanding");
return name;
}
});
return sub.replace(srcURIStr);
}
}