package eu.europeana.cloud.client.uis.rest; import eu.europeana.cloud.client.uis.rest.web.DynamicUrlProvider; import eu.europeana.cloud.client.uis.rest.web.StaticUrlProvider; import eu.europeana.cloud.client.uis.rest.web.UrlProvider; import eu.europeana.cloud.common.model.CloudId; import eu.europeana.cloud.common.model.DataProvider; import eu.europeana.cloud.common.model.DataProviderProperties; import eu.europeana.cloud.common.model.LocalId; import eu.europeana.cloud.common.response.ErrorInfo; import eu.europeana.cloud.common.response.ResultSlice; import eu.europeana.cloud.common.web.UISParamConstants; import eu.europeana.cloud.service.coordination.provider.ServiceProvider; import eu.europeana.cloud.service.uis.status.IdentifierErrorTemplate; import org.glassfish.jersey.client.JerseyClientBuilder; import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import java.io.IOException; /** * The REST API client for the Unique Identifier Service. * * @author Yorgos.Mamakis@ kb.nl * */ public class UISClient { private Client client = JerseyClientBuilder.newClient(); private UrlProvider urlProvider; private static final Logger LOGGER = LoggerFactory.getLogger(UISClient.class); /** * Creates a new instance of this class. * * Since no URL is provided, * default properties will be read from the properties file. * */ public UISClient() { LOGGER.info("UISClient starting... no UIS-URL provided."); try { urlProvider = new DynamicUrlProvider(); } catch (final IOException e) { LOGGER.error("Error while starting UISClient... Could not start UrlProvider.. {}", e.getMessage()); } LOGGER.info("UISClient started successfully."); } /** * Creates a new instance of this class. * * Since no URL is provided, default properties will be read from the properties file. * Same as {@link #UISClient()} but includes username and password to * perform authenticated requests. */ public UISClient(final String username, final String password) { LOGGER.info("UISClient starting... no UIS-URL provided."); try { urlProvider = new DynamicUrlProvider(); } catch (final IOException e) { LOGGER.error("Error while starting UISClient... Could not start UrlProvider.. {}", e.getMessage()); } LOGGER.info("UISClient started successfully."); } /** * Creates a new instance of this class. * UIS url is dynamically provided from the specified {@link ServiceProvider} * * @param uisProvider */ public UISClient(final ServiceProvider uisProvider) { LOGGER.info("UISClient starting..."); try { urlProvider = new DynamicUrlProvider(uisProvider); } catch (final Exception e) { LOGGER.error("Error while starting UISClient... Could not start UrlProvider.. {}", e.getMessage()); } LOGGER.info("UISClient started successfully."); } /** * Creates a new instance of this class. Same as * {@link #UISClient(ServiceProvider)} but includes username and password to * perform authenticated requests. * */ public UISClient(final ServiceProvider uisProvider, final String username, final String password) { LOGGER.info("UISClient starting..."); client.register(HttpAuthenticationFeature.basic(username, password)); try { urlProvider = new DynamicUrlProvider(uisProvider); } catch (final Exception e) { LOGGER.error("Error while starting UISClient... Could not start UrlProvider.. {}", e.getMessage()); } LOGGER.info("UISClient started successfully."); } /** * Creates a new instance of this class. Same as {@link #UISClient(String)} * but includes username and password to perform authenticated requests. * */ public UISClient(final String uisUrl, final String username, final String password) { LOGGER.info("UISClient starting..."); client.register(HttpAuthenticationFeature.basic(username, password)); try { urlProvider = new StaticUrlProvider(uisUrl); } catch (final Exception e) { LOGGER.error("Error while starting UISClient... Could not start UrlProvider.. {}", e.getMessage()); } LOGGER.info("UISClient started successfully."); } /** * Creates a new instance of this class, with a static UIS url. * * @param uisUrl The URL of some UIS instance to connect to. */ public UISClient(final String uisUrl) { LOGGER.info("UISClient starting..."); try { urlProvider = new StaticUrlProvider(uisUrl); } catch (final Exception e) { LOGGER.error("Error while starting UISClient... Could not start UrlProvider.. {}", e.getMessage()); } LOGGER.info("UISClient started successfully."); } /** * Invoke the creation of a new CloudId REST call. * * @param providerId The provider Id * @param recordId The record Id * @return The newly generated CloudId * @throws CloudException The generic cloud exception wrapper */ public CloudId createCloudId(String providerId, String recordId) throws CloudException { Response resp = null; try { resp = client.target(urlProvider.getBaseUrl() + "/cloudIds") .queryParam(UISParamConstants.Q_PROVIDER_ID, providerId) .queryParam(UISParamConstants.Q_RECORD_ID, recordId).request() .post(null); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(CloudId.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Invoke the creation of a new CloudId REST call. * * @param providerId The provider Id * @return The newly generated CloudId * @throws CloudException The generic cloud exception wrapper */ public CloudId createCloudId(String providerId) throws CloudException { Response resp = null; try { resp = client.target(urlProvider.getBaseUrl() + "/cloudIds") .queryParam(UISParamConstants.Q_PROVIDER_ID, providerId) .request().post(null); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(CloudId.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Invoke the retrieval of a cloud identifier. * * @param providerId The provider Id * @param recordId The record Id * @return The retrieved cloud Id * @throws CloudException The generic cloud exception wrapper */ public CloudId getCloudId(String providerId, String recordId) throws CloudException { Response resp = null; try { resp = client.target(urlProvider.getBaseUrl() + "/cloudIds") .queryParam(UISParamConstants.Q_PROVIDER_ID, providerId) .queryParam(UISParamConstants.Q_RECORD_ID, recordId).request() .get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(CloudId.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Retrieve the local identifiers associated with a cloud identifier * * @param cloudId The cloud id to search for * @return The List of local ids associated with the cloud id * @throws CloudException The generic cloud exception wrapper */ @SuppressWarnings("unchecked") public ResultSlice<CloudId> getRecordId(String cloudId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/cloudIds/{CLOUD_ID}") .resolveTemplate("CLOUD_ID", cloudId).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(ResultSlice.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Retrieve records associated with a provider. * * @param providerId The provider Id * @return The List of Local ids associated with a provider * @throws CloudException The generic cloud exception wrapper */ @SuppressWarnings("unchecked") public ResultSlice<LocalId> getRecordIdsByProvider(String providerId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}/localIds") .resolveTemplate("PROVIDER_ID", providerId).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(ResultSlice.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Retrieve the Cloud ids associated with a provider. * * @param providerId The provider id * @return The list of cloud ids associated with the provider id * @throws CloudException The generic cloud exception wrapper */ @SuppressWarnings("unchecked") public ResultSlice<CloudId> getCloudIdsByProvider(String providerId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}/cloudIds") .resolveTemplate("PROVIDER_ID", providerId).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(ResultSlice.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Retrieve the record ids associated with a provider with pagination. * * @param providerId The provider id * @param startRecordId The local identifier to start retrieval from * @param limit The maximum number of records to fetch * @return A list of record ids associated with the provider * @throws CloudException The generic cloud exception wrapper */ @SuppressWarnings("unchecked") public ResultSlice<LocalId> getRecordIdsByProviderWithPagination( String providerId, String startRecordId, int limit) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}/localIds") .resolveTemplate("PROVIDER_ID", providerId) .queryParam(UISParamConstants.Q_FROM, startRecordId) .queryParam(UISParamConstants.Q_LIMIT, limit).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(ResultSlice.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Retrieve the cloud ids associated with a provider with pagination. * * @param providerId The provider id * @param startRecordId The local identifier to start retrieval from * @param limit The maximum number of records to fetch * @return A list of cloud ids associated with the provider * @throws CloudException The generic cloud exception wrapper */ @SuppressWarnings("unchecked") public ResultSlice<CloudId> getCloudIdsByProviderWithPagination( String providerId, String startRecordId, int limit) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}/cloudIds") .resolveTemplate("PROVIDER_ID", providerId) .queryParam(UISParamConstants.Q_FROM, startRecordId) .queryParam(UISParamConstants.Q_LIMIT, limit).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(ResultSlice.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Create a mapping between a cloud id and provider and record id. * * @param cloudId The cloud id * @param providerId The provider id * @param recordId The record id * @return A confirmation that the mapping has been created * @throws CloudException The generic cloud exception wrapper */ public boolean createMapping(String cloudId, String providerId, String recordId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}/cloudIds/{CLOUD_ID}") .resolveTemplate("PROVIDER_ID", providerId) .resolveTemplate("CLOUD_ID", cloudId) .queryParam(UISParamConstants.Q_RECORD_ID, recordId).request() .post(null); if (resp.getStatus() == Status.OK.getStatusCode()) { return true; } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Remove the association of a record id to a cloud id. * * @param providerId The provider id to use * @param recordId The record id to use * @return A confirmation that the mapping has removed correctly * @throws CloudException The generic cloud exception wrapper */ public boolean removeMappingByLocalId(String providerId, String recordId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}/localIds/{LOCAL_ID}") .resolveTemplate("PROVIDER_ID", providerId) .resolveTemplate("LOCAL_ID", recordId).request().delete(); if (resp.getStatus() == Status.OK.getStatusCode()) { return true; } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Delete a cloud id and all its mapped record ids. * * @param cloudId The cloud id to remove * @return A confirmation message that the mappings have been removed * correctly * @throws CloudException The generic cloud exception wrapper */ public boolean deleteCloudId(String cloudId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/cloudIds/{CLOUD_ID}") .resolveTemplate("CLOUD_ID", cloudId).request().delete(); if (resp.getStatus() == Status.OK.getStatusCode()) { return true; } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Create a data provider. * * @param providerId The data provider Id * @param dp The data provider properties * @return A URL that points to the data provider * @throws CloudException */ public String createProvider(String providerId, DataProviderProperties dp) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers") .queryParam(UISParamConstants.Q_PROVIDER, providerId).request() .post(Entity.json(dp)); if (resp.getStatus() == Status.CREATED.getStatusCode()) { return resp.toString(); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Update a Data Provider. * * @param providerId The provider to update * @param dp The data provider properties * @return True if successful, false else * @throws CloudException */ public boolean updateProvider(String providerId, DataProviderProperties dp) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}") .resolveTemplate("PROVIDER_ID", providerId).request() .put(Entity.json(dp)); if (resp.getStatus() == Status.NO_CONTENT.getStatusCode()) { return true; } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Get data providers * * @param from The record to start from * @return A predefined number of data providers * @throws CloudException */ @SuppressWarnings("unchecked") public ResultSlice<DataProvider> getDataProviders(String from) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers") .queryParam(UISParamConstants.Q_FROM, from).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(ResultSlice.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Retrieve a selected data provider. * * @param providerId The provider id to retrieve * @return The Data provider that corresponds to the selected id * @throws CloudException */ public DataProvider getDataProvider(String providerId) throws CloudException { Response resp = null; try { resp = client .target(urlProvider.getBaseUrl() + "/data-providers/{PROVIDER_ID}") .resolveTemplate("PROVIDER_ID", providerId).request().get(); if (resp.getStatus() == Status.OK.getStatusCode()) { return resp.readEntity(DataProvider.class); } else { throw generateException(resp.readEntity(ErrorInfo.class)); } } finally { closeResponse(resp); } } /** * Generates the exception to be returned to the client. * * @param e The error info that was generated * @return A CloudException that wraps the original exception */ public CloudException generateException(ErrorInfo e) { IdentifierErrorTemplate error = IdentifierErrorTemplate.valueOf(e .getErrorCode()); LOGGER.error(e.getDetails()); return new CloudException(e.getErrorCode(), error.getException(e)); } private void closeResponse(Response response) { if (response != null) { response.close(); } } @Override protected void finalize() throws Throwable { client.close(); } }