-
Notifications
You must be signed in to change notification settings - Fork 0
Share ImageTask access URL #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: remote-sharing
Are you sure you want to change the base?
Changes from all commits
0176035
c9ef418
e0cdd52
021743f
0b794a6
70e7f42
d846927
2ce7dba
fe38904
c4d0739
c181d4e
3625889
e34b94f
55612e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package org.fogbowcloud.saps.engine.core.pojo; | ||
|
|
||
| import org.fogbowcloud.saps.engine.core.model.ImageTask; | ||
|
|
||
| /** | ||
| * Holds the information of a file generated by the processing of a {@link ImageTask}. | ||
| */ | ||
| public class ImageTaskFile { | ||
|
|
||
| private String path; | ||
| private String name; | ||
| private String URL; | ||
|
|
||
| public ImageTaskFile(String path, String name) { | ||
| this(path, name, null); | ||
| } | ||
|
|
||
| public ImageTaskFile(String path, String name, String URL) { | ||
| this.path = path; | ||
| this.name = name; | ||
| this.URL = URL; | ||
| } | ||
|
|
||
| public String getPath() { | ||
| return path; | ||
| } | ||
|
|
||
| public void setPath(String path) { | ||
| this.path = path; | ||
| } | ||
|
|
||
| public String getName() { | ||
| return name; | ||
| } | ||
|
|
||
| public void setName(String name) { | ||
| this.name = name; | ||
| } | ||
|
|
||
| public String getURL() { | ||
| return URL; | ||
| } | ||
|
|
||
| public void setURL(String URL) { | ||
| this.URL = URL; | ||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| package org.fogbowcloud.saps.engine.core.pojo; | ||
|
|
||
| import org.fogbowcloud.saps.engine.core.model.ImageTask; | ||
| import org.json.JSONArray; | ||
| import org.json.JSONException; | ||
| import org.json.JSONObject; | ||
|
|
||
| import java.util.List; | ||
|
|
||
| /** | ||
| * Represents a list of {@link ImageTaskFile} for a specific {@link ImageTask}. | ||
| */ | ||
| public class ImageTaskFileList { | ||
|
|
||
| private static final String IMAGE_TASK_ID = "imageTaskId"; | ||
| private static final String REGION = "region"; | ||
| private static final String COLLECTION_TIER_NAME = "collectionTierName"; | ||
| private static final String IMAGE_DATE = "imageDate"; | ||
| private static final String NAME = "name"; | ||
| private static final String URL = "url"; | ||
| private static final String FILES = "files"; | ||
| private static final String STATUS = "status"; | ||
| private static final String UNAVAILABLE = "UNAVAILABLE"; | ||
|
|
||
| private ImageTask imageTask; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add this declarations finals |
||
| private List<ImageTaskFile> imageTaskFiles; | ||
|
|
||
| public ImageTaskFileList(ImageTask imageTask, List<ImageTaskFile> imageTaskFiles) { | ||
| this.imageTask = imageTask; | ||
| this.imageTaskFiles = imageTaskFiles; | ||
| } | ||
|
|
||
| public JSONObject toJSON() throws JSONException { | ||
| JSONObject jsonObject = new JSONObject(); | ||
| jsonObject.put(IMAGE_TASK_ID, imageTask.getTaskId()); | ||
| try { | ||
| jsonObject.put(REGION, imageTask.getRegion()); | ||
| jsonObject.put(COLLECTION_TIER_NAME, imageTask.getCollectionTierName()); | ||
| jsonObject.put(IMAGE_DATE, imageTask.getImageDate()); | ||
| JSONArray filesJSONArray = new JSONArray(); | ||
| for (ImageTaskFile imageTaskFile : imageTaskFiles) { | ||
| JSONObject imageTaskFileJSONObject = new JSONObject(); | ||
| imageTaskFileJSONObject.put(NAME, imageTaskFile.getName()); | ||
| imageTaskFileJSONObject.put(URL, imageTaskFile.getURL()); | ||
| filesJSONArray.put(imageTaskFileJSONObject); | ||
| } | ||
| jsonObject.put(FILES, filesJSONArray); | ||
| } catch (JSONException e) { | ||
| jsonObject.put(STATUS, UNAVAILABLE); | ||
| throw e; | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why do we need to call this put if we throw the exception the line below?
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I was deciding between two approaches, but ended up doing none oh them. I wanted to built the json object even if there was an error, but I didn't want to put logging in an instance method of a pojo, then I added the throw so the caller method can log the error... But both strategies cannot coexist. I'll fix it |
||
| } | ||
| return jsonObject; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| package org.fogbowcloud.saps.engine.core.service; | ||
|
|
||
| import org.apache.http.HttpResponse; | ||
| import org.apache.http.client.HttpClient; | ||
| import org.apache.http.client.methods.HttpGet; | ||
| import org.apache.http.client.utils.URIBuilder; | ||
| import org.apache.http.impl.client.HttpClients; | ||
| import org.apache.http.util.EntityUtils; | ||
| import org.apache.log4j.Logger; | ||
| import org.fogbowcloud.manager.core.plugins.identity.openstack.KeystoneV3IdentityPlugin; | ||
| import org.fogbowcloud.manager.occi.model.Token; | ||
| import org.fogbowcloud.saps.engine.core.model.ImageTask; | ||
| import org.fogbowcloud.saps.engine.scheduler.util.SapsPropertiesConstants; | ||
|
|
||
| import java.io.IOException; | ||
| import java.net.URI; | ||
| import java.net.URISyntaxException; | ||
| import java.util.*; | ||
|
|
||
| /** | ||
| * Service that provides operations for communication with Object Store. | ||
| */ | ||
| public class ObjectStoreService { | ||
|
|
||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this class seems very coupled with SWIFT logic. I think it would be better to call it SwiftStorageService (or something like that). overall, I think it is a very nice idea to hide the complexity.
Owner
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, it is, I'll change it. About the properties file, it's because that conversation we had about services of restlet's architecture, but because of the deadline I couldn't use them. So, my strategy was to simplify the utilization of services, making all of its methods as static, in order to avoid instantiate the services. The expected strategy was to create an interface to define the contract of the services and the instantiations of its implementations be done by injection (or some like that, I don't know how restlet handle this) I'm open for suggestions, should I change the methods to be instance's and instantiate the services in constructors of its users? |
||
| private static final Logger LOGGER = Logger.getLogger(ObjectStoreService.class); | ||
|
|
||
| private static final String HTTPS_SCHEME = "https"; | ||
| private static final String PROJECT_ID = "projectId"; | ||
| private static final String USER_ID = "userId"; | ||
| private static final String PASSWORD = "password"; | ||
| private static final String AUTH_URL = "authUrl"; | ||
| private static final String PATH_PARAM = "path"; | ||
| private static final String X_AUTH_TOKEN = "X-Auth-Token"; | ||
| private static final String HTTP_RESPONSE_SEPARATOR = "\n"; | ||
| private static final String ARCHIVER_PATH = "archiver/"; | ||
| private static final String DATA_OUTPUT_PATH = "/data/output/"; | ||
|
|
||
| /** | ||
| * Returns all the paths for every file generated by the {@link ImageTask} | ||
| * that had its ID specified. | ||
| * | ||
| * @param properties Properties that contains Object Store information. | ||
| * @param imageTaskId ImageTask's ID. | ||
| * @return List of paths. | ||
| */ | ||
| public static List<String> getImageTaskFilesPaths(Properties properties, String imageTaskId) { | ||
| List<String> imageTaskFilesPaths = new ArrayList<>(); | ||
| try { | ||
| HttpClient client = HttpClients.createDefault(); | ||
| HttpGet httpget = prepareObjectStoreRequest(properties, imageTaskId); | ||
| HttpResponse response = client.execute(httpget); | ||
| imageTaskFilesPaths = parseHttpResponse(response); | ||
| } catch (IOException | URISyntaxException e) { | ||
| LOGGER.error("Error while retrieving path of files of ImageTask" + | ||
| " with ID: " + imageTaskId, e); | ||
| } | ||
| return imageTaskFilesPaths; | ||
| } | ||
|
|
||
| /** | ||
| * Parses the given {@link HttpResponse} to a list of Strings. | ||
| * | ||
| * @param response Response to be parsed. | ||
| * @return List of Strings parsed from response. | ||
| * @throws IOException | ||
| */ | ||
| private static List<String> parseHttpResponse(HttpResponse response) throws IOException { | ||
| return Arrays.asList(EntityUtils.toString(response.getEntity()).split(HTTP_RESPONSE_SEPARATOR)); | ||
| } | ||
|
|
||
| /** | ||
| * Prepares a {@link HttpGet} request for the Object Store. | ||
| * | ||
| * @param properties Properties that contains Object Store information. | ||
| * @param imageTaskId ImageTask's ID. | ||
| * @return A {@link HttpGet} request. | ||
| * @throws URISyntaxException | ||
| */ | ||
| private static HttpGet prepareObjectStoreRequest(Properties properties, | ||
| String imageTaskId) throws URISyntaxException { | ||
| String objectStoreHost = properties.getProperty(SapsPropertiesConstants.SWIFT_OBJECT_STORE_HOST); | ||
| String objectStorePath = properties.getProperty(SapsPropertiesConstants.SWIFT_OBJECT_STORE_PATH); | ||
| String objectStoreContainer = properties.getProperty(SapsPropertiesConstants.SWIFT_OBJECT_STORE_CONTAINER); | ||
| String pathParamValue = ARCHIVER_PATH + imageTaskId + DATA_OUTPUT_PATH; | ||
| URI uri = new URIBuilder() | ||
| .setScheme(HTTPS_SCHEME) | ||
| .setHost(objectStoreHost) | ||
| .setPath(objectStorePath + "/" + objectStoreContainer) | ||
| .addParameter(PATH_PARAM, pathParamValue) | ||
| .build(); | ||
| LOGGER.debug("Getting list of files for task " + imageTaskId + " from " + uri); | ||
| HttpGet httpget = new HttpGet(uri); | ||
| Token token = getKeystoneToken(properties); | ||
| httpget.addHeader(X_AUTH_TOKEN, token.getAccessId()); | ||
| return httpget; | ||
| } | ||
|
|
||
| /** | ||
| * Returns a Keystone Token for the given properties. | ||
| * | ||
| * @param properties Properties that contains Object Store information. | ||
| * @return Keystone Token. | ||
| */ | ||
| private static Token getKeystoneToken(Properties properties) { | ||
| Map<String, String> credentials = new HashMap<>(); | ||
| credentials.put(PROJECT_ID, properties.getProperty(SapsPropertiesConstants.SWIFT_PROJECT_ID)); | ||
| credentials.put(USER_ID, properties.getProperty(SapsPropertiesConstants.SWIFT_USER_ID)); | ||
| credentials.put(PASSWORD, properties.getProperty(SapsPropertiesConstants.SWIFT_PASSWORD)); | ||
| credentials.put(AUTH_URL, properties.getProperty(SapsPropertiesConstants.SWIFT_AUTH_URL)); | ||
| KeystoneV3IdentityPlugin keystone = new KeystoneV3IdentityPlugin(properties); | ||
| return keystone.createToken(credentials); | ||
| } | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need (sorry, I did not checkout the code) both these constructor (can we keep only one?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other constructor isn't used externally, I added just for precaution, so yes, it can be removed