package org.dcache.srm.handler;
import com.google.common.base.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.dcache.srm.AbstractStorageElement;
import org.dcache.srm.SRM;
import org.dcache.srm.SRMInternalErrorException;
import org.dcache.srm.SRMInvalidRequestException;
import org.dcache.srm.SRMNotSupportedException;
import org.dcache.srm.SRMUser;
import org.dcache.srm.request.BringOnlineRequest;
import org.dcache.srm.scheduler.IllegalStateTransition;
import org.dcache.srm.util.Configuration;
import org.dcache.srm.util.JDC;
import org.dcache.srm.util.Lifetimes;
import org.dcache.srm.util.Tools;
import org.dcache.srm.v2_2.ArrayOfTExtraInfo;
import org.dcache.srm.v2_2.SrmBringOnlineRequest;
import org.dcache.srm.v2_2.SrmBringOnlineResponse;
import org.dcache.srm.v2_2.TExtraInfo;
import org.dcache.srm.v2_2.TGetFileRequest;
import org.dcache.srm.v2_2.TReturnStatus;
import org.dcache.srm.v2_2.TStatusCode;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Predicates.in;
import static com.google.common.collect.Iterables.any;
import static java.util.Arrays.asList;
public class SrmBringOnline
{
private static final Logger LOGGER =
LoggerFactory.getLogger(SrmBringOnline.class);
private final SrmBringOnlineRequest request;
private final AbstractStorageElement storage;
private SrmBringOnlineResponse response;
private final SRMUser user;
private final SRM srm;
private final Configuration configuration;
private final String clientHost;
public SrmBringOnline(SRMUser user,
SrmBringOnlineRequest request,
AbstractStorageElement storage,
SRM srm,
String clientHost)
{
this.srm = checkNotNull(srm);
this.request = checkNotNull(request);
this.user = checkNotNull(user);
this.clientHost = clientHost;
this.storage = checkNotNull(storage);
this.configuration = srm.getConfiguration();
}
public SrmBringOnlineResponse getResponse()
{
if (response == null) {
try {
response = srmBringOnline();
} catch (SRMNotSupportedException e) {
response = getFailedResponse(e.getMessage(), TStatusCode.SRM_NOT_SUPPORTED);
} catch (SRMInternalErrorException e) {
LOGGER.error(e.getMessage());
response = getFailedResponse(e.getMessage(), TStatusCode.SRM_INTERNAL_ERROR);
} catch (SRMInvalidRequestException e) {
response = getFailedResponse(e.getMessage(), TStatusCode.SRM_INVALID_REQUEST);
}
}
return response;
}
private SrmBringOnlineResponse srmBringOnline()
throws SRMInvalidRequestException, SRMInternalErrorException, SRMNotSupportedException
{
String[] protocols = getProtocols(request);
String clientHost = getClientNetwork(request).or(this.clientHost);
TGetFileRequest[] fileRequests = getFileRequests(request);
URI[] surls = getSurls(fileRequests);
long requestTime = Lifetimes.calculateLifetime(request.getDesiredTotalRequestTime(), configuration.getBringOnlineLifetime());
long desiredLifetimeInSeconds = getDesiredLifetime(request, requestTime);
if (protocols != null && protocols.length > 0) {
String[] supportedProtocols = storage.supportedGetProtocols();
boolean isAnyProtocolSupported = any(asList(protocols), in(asList(supportedProtocols)));
if (!isAnyProtocolSupported) {
throw new SRMNotSupportedException("Protocol(s) not supported: " + Arrays.toString(protocols));
}
}
BringOnlineRequest r =
new BringOnlineRequest(user,
surls,
protocols,
requestTime,
desiredLifetimeInSeconds,
configuration.getBringOnlineMaxPollPeriod(),
request.getUserRequestDescription(),
clientHost);
try (JDC ignored = r.applyJdc()) {
srm.schedule(r);
return r.getSrmBringOnlineResponse(configuration.getBringOnlineSwitchToAsynchronousModeDelay());
} catch (InterruptedException e) {
throw new SRMInternalErrorException("Operation interrupted", e);
} catch (IllegalStateTransition e) {
throw new SRMInternalErrorException("Scheduling failure", e);
}
}
private static long getDesiredLifetime(SrmBringOnlineRequest request, long requestTime)
{
if (request.getDesiredLifeTime() == null
|| request.getDesiredLifeTime() == 0) {
return TimeUnit.MILLISECONDS.toSeconds(requestTime);
}
return (long) request.getDesiredLifeTime();
}
private static URI[] getSurls(TGetFileRequest[] fileRequests) throws SRMInvalidRequestException
{
URI[] surls = new URI[fileRequests.length];
for (int i = 0; i < fileRequests.length; ++i) {
TGetFileRequest fileRequest = fileRequests[i];
if (fileRequest == null) {
throw new SRMInvalidRequestException("file request #" + (i + 1) + " is null");
}
if (fileRequest.getSourceSURL() == null) {
throw new SRMInvalidRequestException("can't get surl of file request #" + (i + 1) + " null");
}
surls[i] = URI.create(fileRequest.getSourceSURL().toString());
}
return surls;
}
private static TGetFileRequest[] getFileRequests(SrmBringOnlineRequest request) throws SRMInvalidRequestException
{
TGetFileRequest[] fileRequests = null;
if (request.getArrayOfFileRequests() != null) {
fileRequests = request.getArrayOfFileRequests().getRequestArray();
}
if (fileRequests == null || fileRequests.length < 1) {
throw new SRMInvalidRequestException("request contains no file requests");
}
return fileRequests;
}
private static String[] getProtocols(SrmBringOnlineRequest request)
{
String[] protocols = null;
if (request.getTransferParameters() != null &&
request.getTransferParameters().getArrayOfTransferProtocols() != null) {
protocols = request.getTransferParameters().getArrayOfTransferProtocols().getStringArray();
}
return Tools.trimStringArray(protocols);
}
private static Optional<String> getClientNetwork(SrmBringOnlineRequest request)
{
if (request.getTransferParameters() != null &&
request.getTransferParameters().getArrayOfClientNetworks() != null) {
String[] clientNetworks =
request.getTransferParameters().getArrayOfClientNetworks().getStringArray();
if (clientNetworks != null &&
clientNetworks.length > 0 &&
clientNetworks[0] != null) {
return Optional.of(clientNetworks[0]);
}
}
return Optional.absent();
}
public static final SrmBringOnlineResponse getFailedResponse(String error)
{
return getFailedResponse(error, TStatusCode.SRM_FAILURE);
}
public static final SrmBringOnlineResponse getFailedResponse(String error, TStatusCode statusCode)
{
SrmBringOnlineResponse srmBringOnlineResponse = new SrmBringOnlineResponse();
srmBringOnlineResponse.setReturnStatus(new TReturnStatus(statusCode, error));
return srmBringOnlineResponse;
}
}