package edu.sc.seis.sod.source.network;
import java.util.ArrayList;
import java.util.List;
import org.omg.CORBA.BAD_PARAM;
import org.w3c.dom.Element;
import edu.iris.Fissures.IfNetwork.Channel;
import edu.iris.Fissures.IfNetwork.ChannelNotFound;
import edu.iris.Fissures.IfNetwork.Instrumentation;
import edu.iris.Fissures.IfNetwork.NetworkAccess;
import edu.iris.Fissures.IfNetwork.NetworkId;
import edu.iris.Fissures.IfNetwork.NetworkNotFound;
import edu.iris.Fissures.IfNetwork.Sensitivity;
import edu.iris.Fissures.IfNetwork.VirtualNetworkHelper;
import edu.iris.Fissures.model.MicroSecondDate;
import edu.iris.Fissures.model.QuantityImpl;
import edu.iris.Fissures.network.ChannelIdUtil;
import edu.iris.Fissures.network.ChannelImpl;
import edu.iris.Fissures.network.NetworkAttrImpl;
import edu.iris.Fissures.network.NetworkIdUtil;
import edu.iris.Fissures.network.StationIdUtil;
import edu.iris.Fissures.network.StationImpl;
import edu.sc.seis.fissuresUtil.cache.CacheNetworkAccess;
import edu.sc.seis.fissuresUtil.cache.ProxyNetworkDC;
import edu.sc.seis.fissuresUtil.cache.VestingNetworkDC;
import edu.sc.seis.fissuresUtil.sac.InvalidResponse;
import edu.sc.seis.sod.SodUtil;
import edu.sc.seis.sod.Start;
public class NetworkFinder extends AbstractNetworkSource {
public NetworkFinder(String dns, String name, int retries) {
super(name, retries);
this.dns = dns;
}
public NetworkFinder(Element config) throws Exception {
super(config);
dns = SodUtil.loadText(config, "dns", "edu/iris/dmc");
if (getDNS().equals("edu/iris/dmc")) {
System.err.println("WARNING: DHI servers will be turned off June 2013, switch to <fdsnStation>");
}
}
public synchronized ProxyNetworkDC getNetworkDC() {
if (netDC == null) {
netDC = new VestingNetworkDC(getDNS(),
getName(),
getFissuresNamingService(),
Start.createRetryStrategy(getRetries()));
}
return netDC;
}
public CacheNetworkAccess getNetwork(NetworkAttrImpl attr) {
return getNetwork(attr.getId());
}
public CacheNetworkAccess getNetwork(NetworkId netId) {
CacheNetworkAccess net = checkCache(netId);
if (net == null) {
if (netId.network_code.startsWith("_")) {
// virtual network?
try {
List<CacheNetworkAccess> byName = getNetworkByName(netId.network_code);
if (byName.size() != 0) {
byNameCache.add(byName.get(0));
return byName.get(0);
}
throw new RuntimeException("Can't get network by name: "+netId.network_code);
} catch(NetworkNotFound e) {
throw new RuntimeException("Can't get network from cache or by name: "+netId.network_code);
}
}
throw new RuntimeException("can't find net, should neven happen: "+NetworkIdUtil.toString(netId));
}
return net;
}
public List<CacheNetworkAccess> getNetworkByName(String name) throws NetworkNotFound {
List<CacheNetworkAccess> out = new ArrayList<CacheNetworkAccess>();
NetworkAccess[] array = getNetworkDC().a_finder().retrieve_by_name(name);
for (int i = 0; i < array.length; i++) {
out.add(new CacheNetworkAccess(array[i]));
}
return out;
}
@Override
public synchronized List<? extends NetworkAttrImpl> getNetworks() {
if (recentNetworksCache == null) {
getNetworksInternal();
}
List<NetworkAttrImpl> out = new ArrayList<NetworkAttrImpl>();
for (CacheNetworkAccess netAccess : recentNetworksCache) {
out.add(netAccess.get_attributes());
}
return out;
}
public synchronized List<CacheNetworkAccess> getNetworksInternal() {
List<String> constrainingCodes = constraints.getConstrainingNetworkCodes();
ProxyNetworkDC netDC = getNetworkDC();
// purge cache before loading from server
netDC.reset();
ArrayList<CacheNetworkAccess> goodNets = new ArrayList<CacheNetworkAccess>();
if (constrainingCodes.size() > 0) {
edu.iris.Fissures.IfNetwork.NetworkFinder netFinder = netDC.a_finder();
for (String conCode : constrainingCodes) {
CacheNetworkAccess[] found = null;
// this is a bit of a hack as names could be one or two
// characters, but works with _US-TA style
// virtual networks at the DMC
try {
if (conCode.length() > 2) {
found = (CacheNetworkAccess[])netFinder.retrieve_by_name(conCode);
} else {
found = (CacheNetworkAccess[])netFinder.retrieve_by_code(conCode);
}
} catch(NetworkNotFound e) {
// this probably indicates a bad conf file, warn and exit
Start.informUserOfBadNetworkAndExit(conCode, e);
}
for (int j = 0; j < found.length; j++) {
goodNets.add(found[j]);
}
}
} else {
NetworkAccess[] tmpNets = netDC.a_finder().retrieve_all();
for (int i = 0; i < tmpNets.length; i++) {
try {
VirtualNetworkHelper.narrow(tmpNets[i]);
// Ignore any virtual nets returned here
logger.debug("ignoring virtual network " + tmpNets[i].get_attributes().get_code());
continue;
} catch(BAD_PARAM bp) {
// Must be a concrete, keep it
goodNets.add((CacheNetworkAccess)tmpNets[i]);
}
}
}
this.recentNetworksCache = goodNets;
return goodNets;
}
@Override
public List<StationImpl> getStations(NetworkAttrImpl netId) {
CacheNetworkAccess net = getNetwork(netId);
StationImpl[] stations = StationImpl.implize(net.retrieve_stations());
List<StationImpl> out = new ArrayList<StationImpl>(stations.length);
for (int i = 0; i < stations.length; i++) {
out.add(stations[i]);
}
return out;
}
@Override
public List<ChannelImpl> getChannels(StationImpl station) {
if (station == null) {throw new NullPointerException("station cannot be null");}
CacheNetworkAccess net = getNetwork(station.getNetworkAttrImpl());
Channel[] tmpChannels = net.retrieve_for_station(station.get_id());
return checkStationTimeOverlap(station, tmpChannels);
}
@Override
public Instrumentation getInstrumentation(ChannelImpl chan) throws ChannelNotFound, InvalidResponse {
return getNetwork(chan.getId().network_id).retrieve_instrumentation(chan.getId(), chan.getId().begin_time);
}
@Override
public QuantityImpl getSensitivity(ChannelImpl chan) throws ChannelNotFound, InvalidResponse {
CacheNetworkAccess cna = getNetwork(chan.getId().network_id);
Sensitivity s = cna.retrieve_sensitivity(chan.getId(), chan.getId().begin_time);
return new QuantityImpl(s.sensitivity_factor, cna.retrieve_initial_units(chan.getId(), chan.getId().begin_time));
}
/**
* returns the DNSName of the server.
* The context under which the objectName is registered in the CORBA naming service.
*
*
* @return a <code>String</code> value
*/
public String getDNS() {
return dns;
}
protected List<ChannelImpl> checkStationTimeOverlap(StationImpl station, Channel[] inChannels) {
MicroSecondDate stationBegin = new MicroSecondDate(station.getBeginTime());
// dmc network server ignores date in station id in
// retrieve_for_station, so all channels for station code are
// returned. This checks to make sure the station is the same.
// ProxyNetworkAccess already interns stations in channels
// so as long as station begin times are the same, they are
// equal...we hope
ArrayList<ChannelImpl> chansAtStation = new ArrayList<ChannelImpl>();
for (int i = 0; i < inChannels.length; i++) {
if (new MicroSecondDate(inChannels[i].getSite().getStation().getBeginTime()).equals(stationBegin)) {
chansAtStation.add((ChannelImpl)inChannels[i]);
} else {
logger.info("Channel " + ChannelIdUtil.toString(inChannels[i].get_id())
+ " has a station that is not the same as the requested station: req="
+ StationIdUtil.toString(station.get_id()) + " chan sta="
+ StationIdUtil.toString(inChannels[i].getSite().getStation()) + " "
+ inChannels[i].getSite().getStation().getBeginTime().date_time + " != "
+ station.getBeginTime().date_time);
}
}
return chansAtStation;
}
protected CacheNetworkAccess checkCache(NetworkId netId) {
if (recentNetworksCache == null) {
getNetworksInternal();
}
for (CacheNetworkAccess net : recentNetworksCache) {
if (NetworkIdUtil.areEqual(netId, net.get_attributes().getId())) {
return net;
}
}
for (CacheNetworkAccess net : byNameCache) {
if (NetworkIdUtil.areEqual(netId, net.get_attributes().getId())) {
return net;
}
}
return null;
}
public void reset() {
recentNetworksCache = null;
byNameCache.clear();
}
protected String dns;
protected List<CacheNetworkAccess> recentNetworksCache = null;
protected List<CacheNetworkAccess> byNameCache = new ArrayList<CacheNetworkAccess>();
protected VestingNetworkDC netDC;
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(NetworkFinder.class);
}// NetworkFinder