Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,6 @@ public List<ImageTask> getProcessedImages(
String inputGathering,
String inputPreprocessing,
String algorithmExecution) throws SQLException;

List<ImageTask> getImageTasks(String[] imageTasksIds) throws SQLException;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package org.fogbowcloud.saps.engine.core.database;

import java.sql.Array;
import java.sql.Connection;
import java.sql.JDBCType;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.dbcp2.BasicDataSource;
Expand Down Expand Up @@ -1020,6 +1017,27 @@ public List<ImageTask> getAllTasks() throws SQLException {
}
}

private static final String SELECT_IMAGES_IN_ID_LIST_SQL = "SELECT * FROM " + IMAGE_TABLE_NAME
+ " WHERE " + TASK_ID_COL + " IN (?)";

@Override
public List<ImageTask> getImageTasks(String[] imageTasksIds) throws SQLException {
PreparedStatement statement = null;
Connection conn = null;
try {
conn = getConnection();
statement = conn.prepareStatement(SELECT_IMAGES_IN_ID_LIST_SQL);
Array imageTasksIdsArray = conn.createArrayOf(JDBCType.VARCHAR.getName(), imageTasksIds);
statement.setArray(1, imageTasksIdsArray);
statement.setQueryTimeout(300);
statement.execute();
ResultSet rs = statement.getResultSet();
return extractImageTaskFrom(rs);
} finally {
close(statement, conn);
}
}

private static final String SELECT_USER_SQL = "SELECT * FROM " + USERS_TABLE_NAME + " WHERE "
+ USER_EMAIL_COL + " = ?";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ void removeUserNotification(String submissionId, String taskId, String userEmail
boolean isUserNotifiable(String userEmail) throws SQLException;

List<ImageTask> searchProcessedTasks(SubmissionParameters submissionParameters);

List<ImageTask> getImageTasks(String[] imageTasksIds) throws SQLException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ public List<ImageTask> getTaskListInDB() throws SQLException, ParseException {
return imageStore.getAllTasks();
}

@Override
public List<ImageTask> getImageTasks(String[] imageTasksIds) throws SQLException {
return imageStore.getImageTasks(imageTasksIds);
}

@Override
public List<Ward> getUsersToNotify() throws SQLException {
List<Ward> wards = imageStore.getUsersToNotify();
Expand Down
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) {
Copy link
Collaborator

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?)

Copy link
Owner Author

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

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The 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;
Copy link
Collaborator

Choose a reason for hiding this comment

The 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?

Copy link
Owner Author

Choose a reason for hiding this comment

The 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 {

Copy link
Collaborator

Choose a reason for hiding this comment

The 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.
Also, why no passing the properties file to a constructor as a regular object instead of the more staless design

Copy link
Owner Author

Choose a reason for hiding this comment

The 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);
}

}
Loading