package org.dcache.srm.handler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URI;
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.SRMUser;
import org.dcache.srm.request.LsRequest;
import org.dcache.srm.scheduler.IllegalStateTransition;
import org.dcache.srm.util.Configuration;
import org.dcache.srm.util.JDC;
import org.dcache.srm.v2_2.SrmLsRequest;
import org.dcache.srm.v2_2.SrmLsResponse;
import org.dcache.srm.v2_2.TReturnStatus;
import org.dcache.srm.v2_2.TStatusCode;
import static com.google.common.base.Preconditions.checkNotNull;
public class SrmLs
{
private static final Logger LOGGER =
LoggerFactory.getLogger(SrmLs.class);
private final int maxNumOfLevels;
private final Configuration configuration;
private final SrmLsRequest request;
private SrmLsResponse response;
private final SRMUser user;
private final SRM srm;
private final String clientHost;
private final int max_results_num;
public SrmLs(SRMUser user,
SrmLsRequest request,
AbstractStorageElement storage,
SRM srm,
String clientHost)
{
this.request = checkNotNull(request);
this.user = checkNotNull(user);
this.max_results_num = srm.getConfiguration().getMaxNumberOfLsEntries();
this.maxNumOfLevels = srm.getConfiguration().getMaxNumberOfLsLevels();
this.clientHost = clientHost;
this.configuration = srm.getConfiguration();
this.srm = checkNotNull(srm);
}
public SrmLsResponse getResponse()
{
if (response == null) {
try {
response = srmLs();
} catch (SRMInvalidRequestException e) {
response = getFailedResponse(e.getMessage(), TStatusCode.SRM_INVALID_REQUEST);
} catch (SRMInternalErrorException e) {
LOGGER.error(e.getMessage());
response = getFailedResponse(e.getMessage(), TStatusCode.SRM_INTERNAL_ERROR);
}
}
return response;
}
private SrmLsResponse srmLs() throws SRMInvalidRequestException, SRMInternalErrorException
{
int numOfLevels = Math.min(getNumOfLevels(request), maxNumOfLevels);
int offset = getOffset(request);
int count = getCount(request);
boolean longFormat = getFullDetailedList(request);
URI[] surls = getSurls(request);
LsRequest r = new LsRequest(user,
surls,
TimeUnit.HOURS.toMillis(1),
configuration.getLsMaxPollPeriod(),
clientHost,
count,
offset,
numOfLevels,
longFormat,
max_results_num);
try (JDC ignored = r.applyJdc()) {
srm.schedule(r);
return r.getSrmLsResponse(configuration.getLsSwitchToAsynchronousModeDelay());
} catch (InterruptedException e) {
throw new SRMInternalErrorException("Operation interrupted", e);
} catch (IllegalStateTransition e) {
throw new SRMInternalErrorException("Scheduling failure", e);
}
}
private static URI[] getSurls(SrmLsRequest request) throws SRMInvalidRequestException
{
if (request.getArrayOfSURLs() == null ||
request.getArrayOfSURLs().getUrlArray() == null ||
request.getArrayOfSURLs().getUrlArray().length == 0) {
throw new SRMInvalidRequestException("empty list of paths");
}
org.apache.axis.types.URI[] urls = request.getArrayOfSURLs().getUrlArray();
URI[] surls = new URI[urls.length];
for (int i = 0 ; i < urls.length; i++) {
surls[i] = URI.create(urls[i].toString());
}
return surls;
}
private static boolean getFullDetailedList(SrmLsRequest request)
{
return (request.getFullDetailedList() != null) && request.getFullDetailedList();
}
private static int getCount(SrmLsRequest request) throws SRMInvalidRequestException
{
int count = request.getCount() != null ? request.getCount() : Integer.MAX_VALUE;
if (count < 0) {
throw new SRMInvalidRequestException("count value less than 0, disallowed");
}
return count;
}
private static int getOffset(SrmLsRequest request) throws SRMInvalidRequestException
{
int offset = request.getOffset() != null ? request.getOffset() : 0;
if (offset < 0) {
throw new SRMInvalidRequestException("offset value less than 0, disallowed ");
}
return offset;
}
private static int getNumOfLevels(SrmLsRequest request) throws SRMInvalidRequestException
{
// The SRM specification is not clear, but
// probably intends that zero (0) means "no
// recursion", one (1) means "current
// directory plus one (1) level down, et
// cetera.
if (request.getAllLevelRecursive() != null && request.getAllLevelRecursive()) {
return Integer.MAX_VALUE;
}
if (request.getNumOfLevels() != null) {
int numOfLevels = request.getNumOfLevels();
// The spec doesn't say what to do in case of negative
// values, so filter 'em out...
if (numOfLevels < 0) {
throw new SRMInvalidRequestException("Recursion depth must be non-negative: " + numOfLevels);
}
return numOfLevels;
}
return 1;
}
public static final SrmLsResponse getFailedResponse(String error)
{
return getFailedResponse(error, TStatusCode.SRM_FAILURE);
}
public static final SrmLsResponse getFailedResponse(String error,
TStatusCode statusCode)
{
SrmLsResponse response = new SrmLsResponse();
response.setReturnStatus(new TReturnStatus(statusCode, error));
return response;
}
}