Fetching file metadata directly through agents using a custom sync - rpc protocol with consul backend
diff --git a/admin/src/main/java/org/apache/airavata/mft/admin/models/rpc/SyncRPCRequest.java b/admin/src/main/java/org/apache/airavata/mft/admin/models/rpc/SyncRPCRequest.java
index 2c0f2ff..d7933e4 100644
--- a/admin/src/main/java/org/apache/airavata/mft/admin/models/rpc/SyncRPCRequest.java
+++ b/admin/src/main/java/org/apache/airavata/mft/admin/models/rpc/SyncRPCRequest.java
@@ -17,6 +17,7 @@
 
  package org.apache.airavata.mft.admin.models.rpc;
 
+import java.util.HashMap;
 import java.util.Map;
 
 public class SyncRPCRequest {
@@ -70,4 +71,54 @@
         this.messageId = messageId;
         return this;
     }
+
+    public static final class SyncRPCRequestBuilder {
+        private String agentId;
+        private String method;
+        private Map<String, String> parameters = new HashMap<>();
+        private String returnAddress;
+        private String messageId;
+
+        private SyncRPCRequestBuilder() {
+        }
+
+        public static SyncRPCRequestBuilder builder() {
+            return new SyncRPCRequestBuilder();
+        }
+
+        public SyncRPCRequestBuilder withAgentId(String agentId) {
+            this.agentId = agentId;
+            return this;
+        }
+
+        public SyncRPCRequestBuilder withMethod(String method) {
+            this.method = method;
+            return this;
+        }
+
+        public SyncRPCRequestBuilder withParameter(String key, String value) {
+            this.parameters.put(key, value);
+            return this;
+        }
+
+        public SyncRPCRequestBuilder withReturnAddress(String returnAddress) {
+            this.returnAddress = returnAddress;
+            return this;
+        }
+
+        public SyncRPCRequestBuilder withMessageId(String messageId) {
+            this.messageId = messageId;
+            return this;
+        }
+
+        public SyncRPCRequest build() {
+            SyncRPCRequest syncRPCRequest = new SyncRPCRequest();
+            syncRPCRequest.setAgentId(agentId);
+            syncRPCRequest.setMethod(method);
+            syncRPCRequest.setParameters(parameters);
+            syncRPCRequest.setReturnAddress(returnAddress);
+            syncRPCRequest.setMessageId(messageId);
+            return syncRPCRequest;
+        }
+    }
 }
diff --git a/agent/src/main/java/org/apache/airavata/mft/agent/AppConfig.java b/agent/src/main/java/org/apache/airavata/mft/agent/AppConfig.java
index 9d1bd65..4409232 100644
--- a/agent/src/main/java/org/apache/airavata/mft/agent/AppConfig.java
+++ b/agent/src/main/java/org/apache/airavata/mft/agent/AppConfig.java
@@ -18,6 +18,7 @@
 package org.apache.airavata.mft.agent;
 
 import org.apache.airavata.mft.admin.MFTConsulClient;
+import org.apache.airavata.mft.agent.rpc.RPCParser;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.PropertySource;
@@ -35,4 +36,9 @@
     public MFTConsulClient mftConsulClient() {
         return new MFTConsulClient(consulHost, consulPort);
     }
+
+    @Bean
+    public RPCParser rpcParser() {
+        return new RPCParser();
+    }
 }
diff --git a/agent/src/main/java/org/apache/airavata/mft/agent/MFTAgent.java b/agent/src/main/java/org/apache/airavata/mft/agent/MFTAgent.java
index 15c8442..c7bd8f7 100644
--- a/agent/src/main/java/org/apache/airavata/mft/agent/MFTAgent.java
+++ b/agent/src/main/java/org/apache/airavata/mft/agent/MFTAgent.java
@@ -30,7 +30,7 @@
 import org.apache.airavata.mft.admin.models.TransferCommand;
 import org.apache.airavata.mft.admin.models.TransferState;
 import org.apache.airavata.mft.admin.models.rpc.SyncRPCRequest;
-import org.apache.airavata.mft.admin.models.rpc.SyncRPCResponse;
+import org.apache.airavata.mft.agent.rpc.RPCParser;
 import org.apache.airavata.mft.core.ConnectorResolver;
 import org.apache.airavata.mft.core.MetadataCollectorResolver;
 import org.apache.airavata.mft.core.api.Connector;
@@ -96,6 +96,9 @@
     private ObjectMapper mapper = new ObjectMapper();
 
     @Autowired
+    private RPCParser rpcParser;
+
+    @Autowired
     private MFTConsulClient mftConsulClient;
 
     public void init() {
@@ -110,7 +113,7 @@
                 decodedValue.ifPresent(v -> {
                     try {
                         SyncRPCRequest rpcRequest = mapper.readValue(v, SyncRPCRequest.class);
-                        mftConsulClient.sendSyncRPCResponseFromAgent(rpcRequest.getReturnAddress(), processRPCRequest(rpcRequest));
+                        mftConsulClient.sendSyncRPCResponseFromAgent(rpcRequest.getReturnAddress(), rpcParser.processRPCRequest(rpcRequest));
                     } catch (Throwable e) {
                         logger.error("Error processing the RPC request {}", value.getKey(), e);
                     } finally {
@@ -124,11 +127,6 @@
         rpcMessageCache.start();
     }
 
-    private SyncRPCResponse processRPCRequest(SyncRPCRequest request) {
-        // TODO implement using the reflection
-        return null;
-    }
-
     private void acceptTransferRequests() {
 
         transferCacheListener = newValues -> {
diff --git a/agent/src/main/java/org/apache/airavata/mft/agent/rpc/RPCParser.java b/agent/src/main/java/org/apache/airavata/mft/agent/rpc/RPCParser.java
new file mode 100644
index 0000000..a915348
--- /dev/null
+++ b/agent/src/main/java/org/apache/airavata/mft/agent/rpc/RPCParser.java
@@ -0,0 +1,86 @@
+/*
+ * 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.agent.rpc;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.airavata.mft.admin.models.rpc.SyncRPCRequest;
+import org.apache.airavata.mft.admin.models.rpc.SyncRPCResponse;
+import org.apache.airavata.mft.core.FileResourceMetadata;
+import org.apache.airavata.mft.core.MetadataCollectorResolver;
+import org.apache.airavata.mft.core.api.MetadataCollector;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Optional;
+
+public class RPCParser {
+
+    private static final Logger logger = LoggerFactory.getLogger(RPCParser.class);
+
+    @org.springframework.beans.factory.annotation.Value("${resource.service.host}")
+    private String resourceServiceHost;
+
+    @org.springframework.beans.factory.annotation.Value("${resource.service.port}")
+    private int resourceServicePort;
+
+    @org.springframework.beans.factory.annotation.Value("${secret.service.host}")
+    private String secretServiceHost;
+
+    @org.springframework.beans.factory.annotation.Value("${secret.service.port}")
+    private int secretServicePort;
+
+    public String resolveRPCRequest(SyncRPCRequest request) throws Exception {
+        // TODO implement using the reflection
+        ObjectMapper mapper = new ObjectMapper();
+
+        switch (request.getMethod()) {
+            case "getFileResourceMetadata":
+                String resourceId = request.getParameters().get("resourceId");
+                String resourceType = request.getParameters().get("resourceType");
+                String resourceToken = request.getParameters().get("resourceToken");
+                String mftAuthorizationToken = request.getParameters().get("mftAuthorizationToken");
+
+                Optional<MetadataCollector> metadataCollectorOp = MetadataCollectorResolver.resolveMetadataCollector(resourceType);
+                if (metadataCollectorOp.isPresent()) {
+                    MetadataCollector metadataCollector = metadataCollectorOp.get();
+                    metadataCollector.init(resourceServiceHost, resourceServicePort, secretServiceHost, secretServicePort);
+                    FileResourceMetadata fileResourceMetadata = metadataCollector.getFileResourceMetadata(resourceId, resourceToken);
+                    return mapper.writeValueAsString(fileResourceMetadata);
+                }
+                break;
+        }
+        logger.error("Unknown method type specified {}", request.getMethod());
+        throw new Exception("Unknown method " + request.getMethod());
+    }
+
+    public SyncRPCResponse processRPCRequest(SyncRPCRequest request) {
+        SyncRPCResponse response = new SyncRPCResponse();
+        response.setMessageId(request.getMessageId());
+        try {
+            String respStr = resolveRPCRequest(request);
+            response.setResponseAsStr(respStr);
+            response.setResponseStatus(SyncRPCResponse.ResponseStatus.SUCCESS);
+        } catch (Exception e) {
+            logger.error("Errored while processing the rpc request for message {} and method {}",
+                                                request.getMessageId(), request.getMethod(), e);
+            response.setErrorAsStr(e.getMessage());
+            response.setResponseStatus(SyncRPCResponse.ResponseStatus.FAIL);
+        }
+        return response;
+    }
+}
diff --git a/api/service/src/main/java/org/apache/airavata/mft/api/AppConfig.java b/api/service/src/main/java/org/apache/airavata/mft/api/AppConfig.java
index f46bf65..5e2ab0f 100644
--- a/api/service/src/main/java/org/apache/airavata/mft/api/AppConfig.java
+++ b/api/service/src/main/java/org/apache/airavata/mft/api/AppConfig.java
@@ -18,6 +18,7 @@
 package org.apache.airavata.mft.api;
 
 import org.apache.airavata.mft.admin.MFTConsulClient;
+import org.apache.airavata.mft.admin.SyncRPCClient;
 import org.apache.airavata.mft.admin.models.TransferRequest;
 import org.apache.airavata.mft.api.service.TransferApiRequest;
 import org.dozer.DozerBeanMapper;
@@ -34,12 +35,22 @@
     @org.springframework.beans.factory.annotation.Value("${consul.port}")
     public Integer consulPort;
 
+    @org.springframework.beans.factory.annotation.Value("${api.id}")
+    public String apiId;
+
     @Bean
     public MFTConsulClient mftConsulClient() {
         return new MFTConsulClient(consulHost, consulPort);
     }
 
     @Bean
+    public SyncRPCClient agentRPCClient() {
+        SyncRPCClient client = new SyncRPCClient("api-server-" + apiId, mftConsulClient());
+        client.init();
+        return client;
+    }
+
+    @Bean
     public DozerBeanMapper dozerBeanMapper() {
         DozerBeanMapper mapper = new DozerBeanMapper();
         BeanMappingBuilder mappingBuilder = new BeanMappingBuilder() {
diff --git a/api/service/src/main/java/org/apache/airavata/mft/api/handler/MFTApiHandler.java b/api/service/src/main/java/org/apache/airavata/mft/api/handler/MFTApiHandler.java
index dfa6ec4..a2c7511 100644
--- a/api/service/src/main/java/org/apache/airavata/mft/api/handler/MFTApiHandler.java
+++ b/api/service/src/main/java/org/apache/airavata/mft/api/handler/MFTApiHandler.java
@@ -17,11 +17,16 @@
 
 package org.apache.airavata.mft.api.handler;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import io.grpc.stub.StreamObserver;
 import org.apache.airavata.mft.admin.MFTConsulClient;
+import org.apache.airavata.mft.admin.SyncRPCClient;
 import org.apache.airavata.mft.admin.models.TransferRequest;
 import org.apache.airavata.mft.admin.models.TransferState;
+import org.apache.airavata.mft.admin.models.rpc.SyncRPCRequest;
+import org.apache.airavata.mft.admin.models.rpc.SyncRPCResponse;
 import org.apache.airavata.mft.api.service.*;
+import org.apache.airavata.mft.core.FileResourceMetadata;
 import org.apache.airavata.mft.core.MetadataCollectorResolver;
 import org.apache.airavata.mft.core.api.MetadataCollector;
 import org.dozer.DozerBeanMapper;
@@ -32,6 +37,7 @@
 
 import java.util.List;
 import java.util.Optional;
+import java.util.UUID;
 
 @GRpcService
 public class MFTApiHandler extends MFTApiServiceGrpc.MFTApiServiceImplBase {
@@ -44,6 +50,11 @@
     @Autowired
     private DozerBeanMapper dozerBeanMapper;
 
+    private ObjectMapper jsonMapper = new ObjectMapper();
+
+    @Autowired
+    private SyncRPCClient agentRPCClient;
+
     @org.springframework.beans.factory.annotation.Value("${resource.service.host}")
     private String resourceServiceHost;
 
@@ -131,4 +142,43 @@
             responseObserver.onError(new Exception("Failed to check the availability", e));
         }
     }
+
+    @Override
+    public void getFileResourceMetadata(FetchResourceMetadataRequest request, StreamObserver<FileMetadataResponse> responseObserver) {
+
+        try {
+            SyncRPCResponse rpcResponse = agentRPCClient.sendSyncRequest(SyncRPCRequest.SyncRPCRequestBuilder.builder()
+                    .withAgentId(request.getTargetAgentId())
+                    .withMessageId(UUID.randomUUID().toString())
+                    .withMethod("getFileResourceMetadata")
+                    .withParameter("resourceId", request.getResourceId())
+                    .withParameter("resourceType", request.getResourceType())
+                    .withParameter("resourceToken", request.getResourceToken())
+                    .withParameter("mftAuthorizationToken", request.getMftAuthorizationToken())
+                    .build());
+
+            switch (rpcResponse.getResponseStatus()) {
+                case SUCCESS:
+                    FileResourceMetadata fileResourceMetadata = jsonMapper.readValue(rpcResponse.getResponseAsStr(), FileResourceMetadata.class);
+                    FileMetadataResponse.Builder responseBuilder = FileMetadataResponse.newBuilder();
+                    dozerBeanMapper.map(fileResourceMetadata, responseBuilder);
+                    responseObserver.onNext(responseBuilder.build());
+                    responseObserver.onCompleted();
+                    return;
+                case FAIL:
+                    logger.error("Errored while processing the fetch file metadata response for resource id {}. Error msg : {}",
+                                                            request.getResourceId(), rpcResponse.getErrorAsStr());
+                    responseObserver.onError(new Exception("Errored while processing the the fetch file metadata response. Error msg : " +
+                                                            rpcResponse.getErrorAsStr()));
+            }
+        } catch (Exception e) {
+            logger.error("Error while fetching resource metadata for resource " + request.getResourceId(), e);
+            responseObserver.onError(new Exception("Failed to fetch resource metadata", e));
+        }
+    }
+
+    @Override
+    public void getDirectoryResourceMetadata(FetchResourceMetadataRequest request, StreamObserver<DirectoryMetadataResponse> responseObserver) {
+        super.getDirectoryResourceMetadata(request, responseObserver);
+    }
 }
diff --git a/api/service/src/main/resources/application.properties b/api/service/src/main/resources/application.properties
index df3864d..308e69c 100644
--- a/api/service/src/main/resources/application.properties
+++ b/api/service/src/main/resources/application.properties
@@ -19,6 +19,7 @@
 grpc.port=7004
 consul.host=localhost
 consul.port=8500
+api.id=0
 
 resource.service.host=localhost
 resource.service.port=7002
diff --git a/api/stub/src/main/proto/MFTApi.proto b/api/stub/src/main/proto/MFTApi.proto
index 1172422..c41bc4b 100644
--- a/api/stub/src/main/proto/MFTApi.proto
+++ b/api/stub/src/main/proto/MFTApi.proto
@@ -28,6 +28,7 @@
 
 message TransferStateApiRequest {
     string transferId = 1;
+    string mftAuthorizationToken = 2;
 }
 
 message TransferStateApiResponse {
@@ -43,12 +44,46 @@
     string resourceToken = 3;
     string resourceBackend = 4;
     string resourceCredentialBackend = 5;
+    string mftAuthorizationToken = 6;
 }
 
 message ResourceAvailabilityResponse {
     bool available = 1;
 }
 
+message FileMetadataResponse {
+    string friendlyName = 1;
+    int64 resourceSize = 2;
+    int64 createdTime = 3;
+    int64 updateTime = 4;
+    string md5sum = 5;
+    string resourcePath = 6;
+    string parentResourceId = 7;
+    string parentResourceType = 8;
+}
+
+message DirectoryMetadataResponse {
+    string friendlyName = 1;
+    int64 createdTime = 2;
+    int64 updateTime = 3;
+    string resourcePath = 4;
+    string parentResourceId = 5;
+    string parentResourceType = 6;
+    repeated DirectoryMetadataResponse directories = 7;
+    repeated FileMetadataResponse files = 8;
+    bool lazyInitialized = 9;
+}
+
+message FetchResourceMetadataRequest {
+    string resourceId = 1;
+    string resourceType = 2;
+    string resourceToken = 3;
+    string resourceBackend = 4;
+    string resourceCredentialBackend = 5;
+    string targetAgentId = 7;
+    string mftAuthorizationToken = 8;
+}
+
 service  MFTApiService {
 
     rpc submitTransfer(TransferApiRequest) returns (TransferApiResponse) {
@@ -70,4 +105,16 @@
     }
 
     rpc getResourceAvailability(ResourceAvailabilityRequest) returns (ResourceAvailabilityResponse) {}
+
+    rpc getFileResourceMetadata(FetchResourceMetadataRequest) returns (FileMetadataResponse) {
+        option (google.api.http) = {
+           get: "/v1.0/api/resource/metadata/file"
+        };
+    }
+
+    rpc getDirectoryResourceMetadata(FetchResourceMetadataRequest) returns (DirectoryMetadataResponse) {
+        option (google.api.http) = {
+           get: "/v1.0/api/resource/metadata/directory"
+        };
+    }
 }
\ No newline at end of file
diff --git a/examples/pom.xml b/examples/pom.xml
index 28cc03a..6c81e5f 100644
--- a/examples/pom.xml
+++ b/examples/pom.xml
@@ -39,5 +39,10 @@
             <groupId>org.apache.airavata</groupId>
             <version>0.01-SNAPSHOT</version>
         </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>log4j-over-slf4j</artifactId>
+            <version>${log4j.over.slf4j}</version>
+        </dependency>
     </dependencies>
 </project>
diff --git a/examples/src/main/java/org/apache/airavata/mft/examples/metadata/SCPExample.java b/examples/src/main/java/org/apache/airavata/mft/examples/metadata/SCPExample.java
new file mode 100644
index 0000000..ed378b8
--- /dev/null
+++ b/examples/src/main/java/org/apache/airavata/mft/examples/metadata/SCPExample.java
@@ -0,0 +1,24 @@
+package org.apache.airavata.mft.examples.metadata;
+
+import org.apache.airavata.mft.api.client.MFTApiClient;
+import org.apache.airavata.mft.api.service.FetchResourceMetadataRequest;
+import org.apache.airavata.mft.api.service.FileMetadataResponse;
+import org.apache.airavata.mft.api.service.MFTApiServiceGrpc;
+
+public class SCPExample {
+    public static void main(String args[]) throws Exception {
+        MFTApiServiceGrpc.MFTApiServiceBlockingStub client = MFTApiClient.buildClient("localhost", 7004);
+
+        long startTime = System.currentTimeMillis();
+        FileMetadataResponse fileResourceMetadata = client.getFileResourceMetadata(FetchResourceMetadataRequest.newBuilder()
+                .setResourceId("remote-ssh-resource2")
+                .setResourceType("SCP")
+                .setResourceToken("local-ssh-cred")
+                .setTargetAgentId("agent0")
+                .build());
+        long endTime = System.currentTimeMillis();
+        System.out.println("File metadata response ");
+        System.out.println(fileResourceMetadata);
+        System.out.println("Time for processing : " + (endTime - startTime) + " ms");
+    }
+}
diff --git a/examples/src/main/java/org/apache/airavata/mft/examples/BoxExample.java b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/BoxExample.java
similarity index 93%
rename from examples/src/main/java/org/apache/airavata/mft/examples/BoxExample.java
rename to examples/src/main/java/org/apache/airavata/mft/examples/transfer/BoxExample.java
index d8b6dd6..0072e6f 100644
--- a/examples/src/main/java/org/apache/airavata/mft/examples/BoxExample.java
+++ b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/BoxExample.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.airavata.mft.examples;
+package org.apache.airavata.mft.examples.transfer;
 
 public class BoxExample {
 }
diff --git a/examples/src/main/java/org/apache/airavata/mft/examples/DriveExample.java b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/DriveExample.java
similarity index 93%
rename from examples/src/main/java/org/apache/airavata/mft/examples/DriveExample.java
rename to examples/src/main/java/org/apache/airavata/mft/examples/transfer/DriveExample.java
index 2a23736..526159d 100644
--- a/examples/src/main/java/org/apache/airavata/mft/examples/DriveExample.java
+++ b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/DriveExample.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.airavata.mft.examples;
+package org.apache.airavata.mft.examples.transfer;
 
 public class DriveExample {
 }
diff --git a/examples/src/main/java/org/apache/airavata/mft/examples/LocalExample.java b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/LocalExample.java
similarity index 97%
rename from examples/src/main/java/org/apache/airavata/mft/examples/LocalExample.java
rename to examples/src/main/java/org/apache/airavata/mft/examples/transfer/LocalExample.java
index af77098..53bfa71 100644
--- a/examples/src/main/java/org/apache/airavata/mft/examples/LocalExample.java
+++ b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/LocalExample.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.airavata.mft.examples;
+package org.apache.airavata.mft.examples.transfer;
 
 import org.apache.airavata.mft.api.client.MFTApiClient;
 import org.apache.airavata.mft.api.service.*;
diff --git a/examples/src/main/java/org/apache/airavata/mft/examples/S3Example.java b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/S3Example.java
similarity index 97%
rename from examples/src/main/java/org/apache/airavata/mft/examples/S3Example.java
rename to examples/src/main/java/org/apache/airavata/mft/examples/transfer/S3Example.java
index 60aae80..8443cf2 100644
--- a/examples/src/main/java/org/apache/airavata/mft/examples/S3Example.java
+++ b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/S3Example.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.airavata.mft.examples;
+package org.apache.airavata.mft.examples.transfer;
 
 import org.apache.airavata.mft.api.client.MFTApiClient;
 import org.apache.airavata.mft.api.service.*;
diff --git a/examples/src/main/java/org/apache/airavata/mft/examples/SCPExample.java b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/SCPExample.java
similarity index 97%
rename from examples/src/main/java/org/apache/airavata/mft/examples/SCPExample.java
rename to examples/src/main/java/org/apache/airavata/mft/examples/transfer/SCPExample.java
index df9fca8..5977598 100644
--- a/examples/src/main/java/org/apache/airavata/mft/examples/SCPExample.java
+++ b/examples/src/main/java/org/apache/airavata/mft/examples/transfer/SCPExample.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
- package org.apache.airavata.mft.examples;
+ package org.apache.airavata.mft.examples.transfer;
 
 import org.apache.airavata.mft.api.client.MFTApiClient;
 import org.apache.airavata.mft.api.service.*;
diff --git a/examples/src/main/resources/logback.xml b/examples/src/main/resources/logback.xml
new file mode 100644
index 0000000..a1e67fe
--- /dev/null
+++ b/examples/src/main/resources/logback.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+
+    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.
+
+-->
+<configuration>
+
+    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <pattern>%d [%t] %-5p %c{30} %m [%X]%n</pattern>
+        </encoder>
+    </appender>
+
+    <appender name="LOGFILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <File>../logs/airavata.log</File>
+        <Append>true</Append>
+        <encoder>
+            <pattern>%d [%t] %-5p %c{30} %m [%X]%n</pattern>
+        </encoder>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>../logs/airavata.log.%d{yyyy-MM-dd}</fileNamePattern>
+            <maxHistory>30</maxHistory>
+            <totalSizeCap>1GB</totalSizeCap>
+        </rollingPolicy>
+    </appender>
+
+    <logger name="ch.qos.logback" level="WARN"/>
+    <logger name="org.apache.helix" level="WARN"/>
+    <logger name="org.apache.zookeeper" level="ERROR"/>
+    <logger name="org.apache.airavata" level="INFO"/>
+    <logger name="org.hibernate" level="ERROR"/>
+    <logger name="net.schmizz.sshj" level="WARN"/>
+    <root level="INFO">
+        <appender-ref ref="CONSOLE"/>
+        <appender-ref ref="LOGFILE"/>
+    </root>
+</configuration>
diff --git a/services/resource-service/stub/src/main/proto/common/common.proto b/services/resource-service/stub/src/main/proto/common/common.proto
index 4d69533..a2cf567 100644
--- a/services/resource-service/stub/src/main/proto/common/common.proto
+++ b/services/resource-service/stub/src/main/proto/common/common.proto
@@ -26,6 +26,4 @@
 
 message DirectoryResource {
     string resourcePath = 1;
-    repeated FileResource files = 2;
-    repeated DirectoryResource directories = 3;
 }
\ No newline at end of file