Skip to content
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

Ea 4015 set client code #277

Merged
merged 22 commits into from
Dec 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
c7137ae
EA-4015 updated set client code
SrishtiSingh-eu Nov 21, 2024
8c5decf
EA-4015 added serach user set client methods and classes
SrishtiSingh-eu Nov 21, 2024
5724d0a
EA-4015 few tweaks
SrishtiSingh-eu Nov 22, 2024
7fa4917
EA-4015 fixed the url issues
SrishtiSingh-eu Nov 22, 2024
915dfd7
EA-4015 update class to private
SrishtiSingh-eu Nov 25, 2024
b7f4ba7
EA-4015 sonarq
SrishtiSingh-eu Nov 25, 2024
9bfdd58
EA-4015 remove apikey param
SrishtiSingh-eu Nov 25, 2024
6eeefd0
EA-4015 make properties public to instantiate the client with other a…
SrishtiSingh-eu Nov 25, 2024
291f697
EA-4015 Update set client to use http5, remove all spring dependency …
SrishtiSingh-eu Nov 28, 2024
be938be
EA-4015 add another condition
SrishtiSingh-eu Nov 28, 2024
47b5f56
EA-4015 aremove sysout
SrishtiSingh-eu Nov 28, 2024
b23ea1e
EA-4015 make serach return list of sets
SrishtiSingh-eu Nov 28, 2024
8812fe6
Merge branch 'develop' of https://github.com/europeana/set-api into E…
SrishtiSingh-eu Dec 2, 2024
ac9dc4b
EA-4015 handle profile
SrishtiSingh-eu Dec 2, 2024
fa4667a
EA-4015 remove sysout
SrishtiSingh-eu Dec 2, 2024
1ec71f6
EA-4015 FIX serach api client
SrishtiSingh-eu Dec 3, 2024
0f60373
EA-4015 sonar suggestation
SrishtiSingh-eu Dec 3, 2024
dc4a230
EA-4015 added get user set pagination function
SrishtiSingh-eu Dec 3, 2024
ee7594b
EA-4015 add has operations
SrishtiSingh-eu Dec 4, 2024
ca4857b
EA-4015 review comments
SrishtiSingh-eu Dec 10, 2024
a6b9ca0
EA-4015 fix desrialisation
SrishtiSingh-eu Dec 11, 2024
aa169ed
EA-4015 sonar issues
SrishtiSingh-eu Dec 12, 2024
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
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -56,13 +56,13 @@

<springdoc.version>1.6.14</springdoc.version>

<version.httpClient>3.1</version.httpClient>
<version.httpClient5>5.4.1</version.httpClient5>
<version.javax.annotation>1.3.2</version.javax.annotation>
<version.jettison>1.3</version.jettison>
<version.jaxb>2.3.1</version.jaxb>
<version.junit>5.7.2</version.junit>
<version.commonsIO>2.8.0</version.commonsIO>

<jackson.version>2.18.1</jackson.version>
<!-- java version properties -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
Expand Down
12 changes: 6 additions & 6 deletions set-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@
<artifactId>jettison</artifactId>
<version>${version.jettison}</version>
</dependency>


<!-- To fix : "Provider for jakarta.ws.rs.ext.RuntimeDelegate cannot be found error"
This issue is tagged with version 2.30 but it doesn't look like it was ever fixed in newer versions as well-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<!--
<version>${spring-framework.version}</version>
-->
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-common</artifactId>
<version>3.1.2</version>
</dependency>

<!-- test dependencies -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

import eu.europeana.set.client.config.ClientConfiguration;
import eu.europeana.set.client.connection.UserSetApiConnection;
import eu.europeana.set.client.exception.SetApiClientException;
import eu.europeana.set.common.http.HttpConnection;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.core5.http.HttpStatus;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

import java.io.IOException;

/**
* Base class for client API
Expand All @@ -12,25 +22,65 @@
public class BaseUserSetApi {

private final ClientConfiguration configuration;
protected final UserSetApiConnection apiConnection;

protected BaseUserSetApi(ClientConfiguration configuration, UserSetApiConnection apiConnection) {
this.configuration = configuration;
this.apiConnection = apiConnection;
private UserSetApiConnection apiConnection;

/**
* Creates BaseUserSetApi instance with client configuration
* This allows user to insert property file
* @param configuration
* @throws SetApiClientException
*/
protected BaseUserSetApi(ClientConfiguration configuration) throws SetApiClientException {
this.configuration = configuration;
if (this.configuration.getServiceUri() == null) {
throw new SetApiClientException(" Set Api Endpoint not provided !!!");
}

if (this.configuration.getOauthServiceUri() == null || this.configuration.getOauthRequestParams() == null) {
throw new SetApiClientException("Oauth uri and param not provided !!!");
}

this.apiConnection = new UserSetApiConnection(
this.configuration.getServiceUri(),
this.configuration.getApiKey(),
getOauthToken(this.configuration.getOauthServiceUri(), this.configuration.getOauthRequestParams()));
}

protected BaseUserSetApi() {
this.configuration = ClientConfiguration.getInstance();
this.apiConnection = new UserSetApiConnection(getConfiguration().getServiceUri(),
getConfiguration().getApiKey());
/**
* Constructor
* @throws SetApiClientException
*/
public BaseUserSetApi() throws SetApiClientException {
this(new ClientConfiguration());
}

private String getOauthToken(String oauthServiceUri, String oauthRequestParams ) throws SetApiClientException{
try {
String accessToken = "access_token";
HttpConnection connection = new HttpConnection();

CloseableHttpResponse response = connection.post(oauthServiceUri, oauthRequestParams, "application/x-www-form-urlencoded", null);
String body = EntityUtils.toString(response.getEntity());
if (HttpStatus.SC_OK == response.getCode()) {
JSONObject json = new JSONObject(body);
if (json.has(accessToken)) {
return "Bearer " + json.getString(accessToken);
} else {
throw new SetApiClientException("Cannot extract authentication token from reponse:" + body);
}
} else {
throw new SetApiClientException("Error occured when calling oath service! " + response);
}
} catch (IOException | JSONException | ParseException e) {
throw new SetApiClientException("Cannot retrieve authentication token!", 0 , e);
}
}

public UserSetApiConnection getApiConnection() {
return apiConnection;
return apiConnection;
}

public ClientConfiguration getConfiguration() {
return configuration;
return configuration;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package eu.europeana.set.client;

import eu.europeana.set.client.config.ClientConfiguration;
import eu.europeana.set.client.exception.SetApiClientException;
import eu.europeana.set.client.model.result.RecordPreview;
import eu.europeana.set.client.web.SearchUserSetApi;
import eu.europeana.set.client.web.WebUserSetApi;
import eu.europeana.set.definitions.model.UserSet;

import java.util.List;

/**
* Implementation of client api
*
* @author GordeaS
* Refractored by Srishti Singh
*/

public class UserSetApiClient extends BaseUserSetApi {

private final WebUserSetClient webUserSetClient;
private final SearchUserSetClient searchUserSetClient;

public UserSetApiClient(ClientConfiguration configuration) throws SetApiClientException {
super(configuration);
this.webUserSetClient = new WebUserSetClient();
this.searchUserSetClient = new SearchUserSetClient();
}

public WebUserSetApi getWebUserSetApi() {
return webUserSetClient;
}

public SearchUserSetApi getSearchUserSetApi() {
return searchUserSetClient;
}

/**
* Web User Set Client class
*/
private class WebUserSetClient implements WebUserSetApi {
@Override
public UserSet createUserSet(String set, String profile) throws SetApiClientException {
return getApiConnection().createUserSet(set, profile);

}

@Override
public String deleteUserSet(String identifier) throws SetApiClientException {
return getApiConnection().deleteUserSet(identifier);
}

@Override
public UserSet getUserSet(String identifier, String profile) throws SetApiClientException {
return getApiConnection().getUserSet(identifier, profile);
}

@Override
public UserSet updateUserSet(String identifier, String set, String profile) throws SetApiClientException {
return getApiConnection().updateUserSet(identifier, set, profile);
}

@Override
public List<RecordPreview> getPaginationUserSet(String identifier, String sort, String sortOrder, String page, String pageSize, String profile) throws SetApiClientException {
return getApiConnection().getPaginationUserSet(identifier, sort, sortOrder, page, pageSize, profile);
}
}

private class SearchUserSetClient implements SearchUserSetApi {

@Override
public List<? extends UserSet> searchUserSet(String query, String[] qf,
String sort, String page, String pageSize, String facet, int facetLimit, String profile) throws SetApiClientException {
return getApiConnection().searchUserSet(query, qf, sort, page, pageSize, facet, facetLimit, profile);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,126 +1,76 @@
package eu.europeana.set.client.config;

import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;

import eu.europeana.set.client.exception.TechnicalRuntimeException;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

/**
* configuration for accessing remote api
*
* @author GordeaS
*
*/

public final class ClientConfiguration {

private static final Logger LOGGER = LogManager.getLogger(ClientConfiguration.class);

protected static final String SET_CLIENT_PROPERTIES_FILE = "/set-client.user.properties";
protected static final String PROP_SET_API_KEY = "set.api.key";
protected static final String PROP_SET_SERVICE_URI = "set.service.uri";
protected static final String PROP_OAUTH_SERVICE_URI = "oauth.service.uri";
protected static final String PROP_OAUTH_REQUEST_PARAMS = "oauth.token.request.params";
public static final String PROP_SET_API_KEY = "set.api.key";
public static final String PROP_SET_SERVICE_URI = "set.service.uri";
public static final String PROP_OAUTH_SERVICE_URI = "oauth.service.uri";
public static final String PROP_OAUTH_REQUEST_PARAMS = "oauth.token.request.params";

private Properties properties;
private static ClientConfiguration singleton;

/**
* Hide the default constructor
*/
private ClientConfiguration() {
}

/**
* Accessor method for the singleton
*
* @return
* Creates ClientConfiguration instance with set client properties
*/
public static synchronized ClientConfiguration getInstance() {
if (singleton == null) {
singleton = new ClientConfiguration();
singleton.loadProperties();
}

return singleton;
public ClientConfiguration() {
loadProperties(SET_CLIENT_PROPERTIES_FILE);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a reason to change the configuration to not be a singleton anymore? We should avoid reading the properties files multiple times as that can generate major performance loss

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also, the filePath for the configuration file should be provided as parameter and stored as class attribute

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Usually, we use spring boot and create a bean, only a single instance is always created.
Also, when creating a client for any API, we create an instance of the Client class, and that class should be able to accept a configuration class.
public UserSetApiClient(ClientConfiguration configuration)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, but the properties still need to be read and currently we only support properties from the classpath

}

/**
* Laizy loading of configuration properties
* CConstructor to inject properties
* @param properties
*/
public synchronized void loadProperties() {

try {
properties = new Properties();
InputStream resourceAsStream = getClass().getResourceAsStream(SET_CLIENT_PROPERTIES_FILE);
if (resourceAsStream == null) {
throw new TechnicalRuntimeException(
"No properties file found in classpath! " + SET_CLIENT_PROPERTIES_FILE);
}
getProperties().load(resourceAsStream);

} catch (RuntimeException | IOException e) {
throw new TechnicalRuntimeException("Cannot read configuration file: " + SET_CLIENT_PROPERTIES_FILE, e);
}

public ClientConfiguration(Properties properties) {
this.properties = properties;
}

/**
* provides access to the configuration properties. It is not recommended to use
* the properties directly, but the
*
* @return
*/
Properties getProperties() {
return properties;
private Properties loadProperties(String propertiesFile) {
try {
properties = new Properties();
properties.load(getClass().getResourceAsStream(propertiesFile));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should support externalization of configurations, meaning to be able to handle absolute file path using the file protocol see: https://stackoverflow.com/questions/8406025/local-file-protocol-for-java-net-url. Third parties should be able to provide the location of configuration files. (absolute file path should use the fille:// protocol)

} catch (IOException e) {
LOGGER.error("Error loading the properties file {}", propertiesFile);
}
return properties;
}

/**
*
* @return the name of the file storing the client configuration
*/
String getConfigurationFile() {
return SET_CLIENT_PROPERTIES_FILE;
}

/**
* This method provides access to the API key defined in the configuration file
*
* @see PROP_EUROPEANA_API_KEY
*
* @return
*/
public String getApiKey() {
return getProperties().getProperty(PROP_SET_API_KEY);
return getProperty(PROP_SET_API_KEY);
}

/**
* This method provides access to the search uri value defined in the
* configuration file
*
* @see PROP_EUROPEANA_SEARCH_URI
*
* @return
*/

public String getServiceUri() {
return getProperties().getProperty(PROP_SET_SERVICE_URI);
return getProperty(PROP_SET_SERVICE_URI);
}

/**
* This method returns the uri of the oauth service as configured in
*
* @return
*/
public String getOauthServiceUri() {
return getProperties().getProperty(PROP_OAUTH_SERVICE_URI);
return getProperty(PROP_OAUTH_SERVICE_URI);
}

/**
* This method returns the request params needed to acquire a new token
*
* @return
*/
public String getOauthRequestParams() {
return getProperties().getProperty(PROP_OAUTH_REQUEST_PARAMS);
return getProperty(PROP_OAUTH_REQUEST_PARAMS);
}

private String getProperty(String propertyName) {
return properties.getProperty(propertyName);
}

}
Loading
Loading