blob: 63c8cca9be48bdd15997ec4fae6a515979ee9341 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.airavata.mft.transport.odata;
import org.apache.airavata.mft.common.AuthToken;
import org.apache.airavata.mft.core.DirectoryResourceMetadata;
import org.apache.airavata.mft.core.FileResourceMetadata;
import org.apache.airavata.mft.core.api.MetadataCollector;
import org.apache.airavata.mft.credential.stubs.odata.ODataSecret;
import org.apache.airavata.mft.credential.stubs.odata.ODataSecretGetRequest;
import org.apache.airavata.mft.resource.client.ResourceServiceClient;
import org.apache.airavata.mft.resource.client.ResourceServiceClientBuilder;
import org.apache.airavata.mft.resource.stubs.common.GenericResource;
import org.apache.airavata.mft.resource.stubs.common.GenericResourceGetRequest;
import org.apache.airavata.mft.resource.stubs.odata.storage.ODataStorage;
import org.apache.airavata.mft.secret.client.SecretServiceClient;
import org.apache.airavata.mft.secret.client.SecretServiceClientBuilder;
import org.apache.http.HttpEntity;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import java.io.StringReader;
import java.time.Instant;
import java.util.Optional;
public class ODataMetadataCollector implements MetadataCollector {
private static final Logger logger = LoggerFactory.getLogger(ODataMetadataCollector.class);
private String resourceServiceHost;
private int resourceServicePort;
private String secretServiceHost;
private int secretServicePort;
@Override
public void init(String resourceServiceHost, int resourceServicePort, String secretServiceHost, int secretServicePort) {
this.resourceServiceHost = resourceServiceHost;
this.resourceServicePort = resourceServicePort;
this.secretServiceHost = secretServiceHost;
this.secretServicePort = secretServicePort;
}
private CloseableHttpClient getHttpClient(ODataSecret oDataSecret) {
CredentialsProvider provider = new BasicCredentialsProvider();
UsernamePasswordCredentials credentials
= new UsernamePasswordCredentials(oDataSecret.getUserName(), oDataSecret.getPassword());
provider.setCredentials(AuthScope.ANY, credentials);
return HttpClientBuilder.create().setDefaultCredentialsProvider(provider).build();
}
@Override
public FileResourceMetadata getFileResourceMetadata(AuthToken authZToken, String resourceId, String credentialToken) throws Exception {
return findFileResourceMetadata(authZToken, resourceId, credentialToken)
.orElseThrow(() -> new Exception("Could not find a file resource entry for resource id " + resourceId));
}
@Override
public FileResourceMetadata getFileResourceMetadata(AuthToken authZToken, String parentResourceId, String resourcePath, String credentialToken) throws Exception {
throw new UnsupportedOperationException("OData does not have hierarchical structures");
}
@Override
public DirectoryResourceMetadata getDirectoryResourceMetadata(AuthToken authZToken, String resourceId, String credentialToken) throws Exception {
throw new UnsupportedOperationException("OData does not have directory structures");
}
@Override
public DirectoryResourceMetadata getDirectoryResourceMetadata(AuthToken authZToken, String parentResourceId, String resourcePath, String credentialToken) throws Exception {
throw new UnsupportedOperationException("OData does not have directory structures");
}
@Override
public Boolean isAvailable(AuthToken authZToken, String resourceId, String credentialToken) throws Exception {
return findFileResourceMetadata(authZToken, resourceId, credentialToken).isPresent();
}
@Override
public Boolean isAvailable(AuthToken authToken, String parentResourceId, String resourcePath, String credentialToken) throws Exception {
throw new UnsupportedOperationException("OData does not have directory structures");
}
private Optional<FileResourceMetadata> findFileResourceMetadata(AuthToken authZToken, String resourceId, String credentialToken) throws Exception {
ResourceServiceClient resourceClient = ResourceServiceClientBuilder.buildClient(resourceServiceHost, resourceServicePort);
GenericResource resource = resourceClient.get().getGenericResource(GenericResourceGetRequest.newBuilder().setResourceId(resourceId).build());
if (resource.getStorageCase() != GenericResource.StorageCase.ODATASTORAGE) {
logger.error("Invalid storage type {} specified for resource {}", resource.getStorageCase(), resourceId);
throw new Exception("Invalid storage type specified for resource " + resourceId);
}
ODataStorage odataStorage = resource.getOdataStorage();
SecretServiceClient secretClient = SecretServiceClientBuilder.buildClient(secretServiceHost, secretServicePort);
ODataSecret oDataSecret = secretClient.odata().getODataSecret(
ODataSecretGetRequest.newBuilder().setSecretId(credentialToken).build());
try (CloseableHttpClient httpClient = getHttpClient(oDataSecret)) {
HttpGet httpGet = new HttpGet(odataStorage.getBaseUrl() +
"/Products('" + resource.getFile().getResourcePath() +"')");
try (CloseableHttpResponse response = httpClient.execute(httpGet)) {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != 200) {
logger.error("Failed while invoking get product information endpoint. Got code {}", statusCode);
throw new Exception("Failed while invoking get product information endpoint. Got code " + statusCode);
}
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity, "UTF-8");
return parseXML(responseString);
}
}
}
private Optional<FileResourceMetadata> parseXML(String xmlBody) {
try {
DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder dBuilder = dbFactory.newDocumentBuilder();
Document doc = dBuilder.parse(new InputSource(new StringReader(xmlBody)));
doc.getDocumentElement().normalize();
System.out.print("Root element: ");
System.out.println(doc.getDocumentElement().getNodeName());
NodeList properties = doc.getElementsByTagName("m:properties");
if (properties.getLength() == 1) {
FileResourceMetadata.Builder builder = FileResourceMetadata.Builder.newBuilder();
Node propertyNode = properties.item(0);
NodeList childNodes = propertyNode.getChildNodes();
for (int i = 0; i < childNodes.getLength(); i++) {
Node item = childNodes.item(i);
switch (item.getNodeName()) {
case "d:ContentLength":
builder.withResourceSize(Long.parseLong(item.getTextContent()));
break;
case "d:CreationDate":
builder.withCreatedTime(Instant.parse(item.getTextContent() + "Z").toEpochMilli());
break;
case "d:ModificationDate":
builder.withUpdateTime(Instant.parse(item.getTextContent() + "Z").toEpochMilli());
break;
case "d:Name":
builder.withFriendlyName(item.getTextContent());
break;
case "d:Id":
builder.withResourcePath(item.getTextContent());
break;
case "d:Checksum":
NodeList checksumNodes = item.getChildNodes();
for (int j = 0; j < checksumNodes.getLength(); j++) {
Node item1 = checksumNodes.item(j);
if (item1.getNodeName().equals("d:Value")) {
builder.withMd5sum(item1.getTextContent());
}
}
break;
}
}
return Optional.of(builder.build());
}
} catch (Exception e) {
logger.warn("Failed while parsing provided XML body", e);
}
return Optional.empty();
}
}