package org.gcube.informationsystem.resourceregistry.contexts; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import org.gcube.com.fasterxml.jackson.core.JsonProcessingException; import org.gcube.common.context.ContextUtility; import org.gcube.common.gxhttp.reference.GXConnection; import org.gcube.common.gxhttp.request.GXHTTPStringRequest; import org.gcube.common.http.GXHTTPUtility; import org.gcube.informationsystem.contexts.reference.entities.Context; import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache; import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCacheRenewal; import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException; import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException; import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextAlreadyPresentException; import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException; import org.gcube.informationsystem.resourceregistry.api.request.BaseRequestInfo; import org.gcube.informationsystem.resourceregistry.api.rest.ContextPath; import org.gcube.informationsystem.resourceregistry.api.rest.httputils.HTTPUtility; import org.gcube.informationsystem.serialization.ElementMapper; import org.gcube.informationsystem.utils.UUIDManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class ResourceRegistryContextClientImpl extends BaseRequestInfo implements ResourceRegistryContextClient { private static final Logger logger = LoggerFactory.getLogger(ResourceRegistryContextClientImpl.class); private static final String ACCEPT_HTTP_HEADER_KEY = "Accept"; private static final String CONTENT_TYPE_HTTP_HEADER_KEY = "Content-Type"; protected final String address; protected Map headers; protected ContextCache contextCache; private void addOptionalQueryParameters(Map queryParams) throws UnsupportedEncodingException { addIncludeMeta(queryParams); } private GXHTTPStringRequest includeAdditionalQueryParameters(GXHTTPStringRequest gxHTTPStringRequest) throws UnsupportedEncodingException{ Map queryParams = new HashMap<>(); return includeAdditionalQueryParameters(gxHTTPStringRequest, queryParams); } private GXHTTPStringRequest includeAdditionalQueryParameters(GXHTTPStringRequest gxHTTPStringRequest, Map queryParams) throws UnsupportedEncodingException{ if(queryParams==null) { queryParams = new HashMap<>(); } addOptionalQueryParameters(queryParams); return gxHTTPStringRequest.queryParams(queryParams); } private void addIncludeMeta(Map queryParams) throws UnsupportedEncodingException{ addIncludeMeta(queryParams, includeMeta); } private void addIncludeMeta(Map queryParams, boolean includeMeta) throws UnsupportedEncodingException{ if(includeMeta) { queryParams.put(ContextPath.INCLUDE_META_QUERY_PARAMETER, Boolean.toString(includeMeta)); } } /* private void addOffset(Map queryParams) throws UnsupportedEncodingException{ addOffset(queryParams, offset); } */ private void addOffset(Map queryParams, Integer offset) throws UnsupportedEncodingException{ if(offset!=null) { queryParams.put(ContextPath.OFFSET_QUERY_PARAMETER, offset.toString()); } } /* private void addLimit(Map queryParams) throws UnsupportedEncodingException{ addLimit(queryParams, limit); } */ private void addLimit(Map queryParams, Integer limit) throws UnsupportedEncodingException{ if(limit!=null) { queryParams.put(ContextPath.LIMIT_QUERY_PARAMETER, limit.toString()); } } protected ContextCacheRenewal contextCacheRenewal = new ContextCacheRenewal() { @Override public List renew() throws ResourceRegistryException { return getAllContextFromServer(true, 0, BaseRequestInfo.UNBOUNDED_LIMIT); } }; @Override public void addHeader(String name, String value) { headers.put(name, value); } protected GXHTTPStringRequest getGXHTTPStringRequest() { GXHTTPStringRequest gxHTTPStringRequest = GXHTTPUtility.getGXHTTPStringRequest(address); gxHTTPStringRequest.from(this.getClass().getSimpleName()); for(String name : headers.keySet()) { gxHTTPStringRequest.header(name, headers.get(name)); } return gxHTTPStringRequest; } public ResourceRegistryContextClientImpl(String address) { this(address, true); } public ResourceRegistryContextClientImpl(String address, boolean sharedContextCache) { this.address = address; this.headers = new HashMap<>(); this.includeMeta = false; if(sharedContextCache) { contextCache = ContextCache.getInstance(); }else { contextCache = new ContextCache(); } contextCache.setContextCacheRenewal(contextCacheRenewal); } private void forceCacheRefresh() { try { contextCache.cleanCache(); contextCache.refreshContextsIfNeeded(); }catch (Exception e) { logger.warn("Unable to force cache refresh.", e); } } /** * It reads all the contexts from server. * The cache used for contexts is bypassed and not updated. * @return All Contexts read from server * @throws ResourceRegistryException */ public List getAllContextFromServer() throws ResourceRegistryException { return getAllContextFromServer(includeMeta, offset, limit); } protected List getAllContextFromServer(boolean includeMeta, Integer offset, Integer limit) throws ResourceRegistryException { try { logger.info("Going to read all {}s", Context.NAME); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); Map parameters = new HashMap<>(); addIncludeMeta(parameters, includeMeta); addOffset(parameters, offset); addLimit(parameters, limit); gxHTTPStringRequest.queryParams(parameters); HttpURLConnection httpURLConnection = gxHTTPStringRequest.get(); String all = HTTPUtility.getResponse(String.class, httpURLConnection); logger.debug("Got contexts are {}", Context.NAME, all); return ElementMapper.unmarshalList(Context.class, all); } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } @Override public List all() throws ResourceRegistryException { return contextCache.getContexts(); } @Override public ContextCache getContextCache() { return contextCache; } protected String internalCreate(Context context) throws ContextAlreadyPresentException, ResourceRegistryException { try { UUID uuid = context.getID(); if(uuid == null) { uuid = UUIDManager.getInstance().generateValidUUID(); context.setID(uuid); } String contextString = ElementMapper.marshal(context); logger.trace("Going to create {}", contextString); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.header(CONTENT_TYPE_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); gxHTTPStringRequest.path(uuid.toString()); includeAdditionalQueryParameters(gxHTTPStringRequest); HttpURLConnection httpURLConnection = gxHTTPStringRequest.put(contextString); String c = HTTPUtility.getResponse(String.class, httpURLConnection); forceCacheRefresh(); logger.trace("{} successfully created", c); return c; } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } @Override public Context create(Context context) throws ContextAlreadyPresentException, ResourceRegistryException { try { String res = internalCreate(context); return ElementMapper.unmarshal(Context.class, res); } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } @Override public String create(String context) throws ContextAlreadyPresentException, ResourceRegistryException { try { Context c = ElementMapper.unmarshal(Context.class, context); return internalCreate(c); } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } public boolean existFromServer(String uuid) throws ContextNotFoundException, ResourceRegistryException { try { logger.trace("Going to read {} with UUID {}", Context.NAME, uuid); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); gxHTTPStringRequest.path(uuid); HttpURLConnection httpURLConnection = gxHTTPStringRequest.head(); HTTPUtility.getResponse(String.class, httpURLConnection); return true; } catch (NotFoundException e) { return false; } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } @Override public boolean exist(String uuid) throws ResourceRegistryException { return exist(UUID.fromString(uuid)); } @Override public boolean exist(UUID uuid) throws ResourceRegistryException { try { read(uuid); return true; }catch (ContextNotFoundException e) { return false; } } @Override public Context read(Context context) throws ContextNotFoundException, ResourceRegistryException { return read(context.getID()); } @Override public Context read(UUID uuid) throws ContextNotFoundException, ResourceRegistryException { Context context = contextCache.getContextByUUID(uuid);; if(context == null) { String contextJson = readFromServer(uuid.toString()); try { context = ElementMapper.unmarshal(Context.class, contextJson); } catch (IOException e) { throw new RuntimeException(e); } forceCacheRefresh(); Context c = contextCache.getContextByUUID(context.getID()); if(c!=null){ context = c; }else { logger.error("Context with UUID {} is {}. It is possibile to get it from the server but not from the cache. This is very strange and should not occur.", uuid, context); } } return context; } @Override public Context readCurrentContext() throws ContextNotFoundException, ResourceRegistryException { String contextFullName = ContextUtility.getCurrentContextFullName(); UUID uuid = contextCache.getUUIDByFullName(contextFullName); return read(uuid); } @Override public String read(String uuid) throws ContextNotFoundException, ResourceRegistryException { try { return ElementMapper.marshal(read(UUID.fromString(uuid))); } catch (ContextNotFoundException e) { throw e; } catch (JsonProcessingException e) { throw new RuntimeException(e); } catch (ResourceRegistryException e) { throw e; } } public String readFromServer(String uuid) throws ContextNotFoundException, ResourceRegistryException { try { logger.trace("Going to read {} with UUID {}", Context.NAME, uuid); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); gxHTTPStringRequest.path(uuid); includeAdditionalQueryParameters(gxHTTPStringRequest); HttpURLConnection httpURLConnection = gxHTTPStringRequest.get(); String c = HTTPUtility.getResponse(String.class, httpURLConnection); logger.debug("Got {} is {}", Context.NAME, c); return c; } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } public String internalUpdate(Context context) throws ContextNotFoundException, ResourceRegistryException { try { String contextString = ElementMapper.marshal(context); logger.trace("Going to update {}", contextString); UUID uuid = context.getID(); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.header(CONTENT_TYPE_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); gxHTTPStringRequest.path(uuid.toString()); includeAdditionalQueryParameters(gxHTTPStringRequest); HttpURLConnection httpURLConnection = gxHTTPStringRequest.put(contextString); String c = HTTPUtility.getResponse(String.class, httpURLConnection); forceCacheRefresh(); logger.trace("{} successfully updated", c); return c; } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); } } @Override public Context update(Context context) throws ContextNotFoundException, ResourceRegistryException { try { String res = internalUpdate(context); return ElementMapper.unmarshal(Context.class, res); } catch(ResourceRegistryException e) { // logger.trace("Error Updating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Updating {}", facet, e); throw new RuntimeException(e); } } @Override public String update(String context) throws ContextNotFoundException, ResourceRegistryException { try { Context c = ElementMapper.unmarshal(Context.class, context); return internalUpdate(c); } catch(ResourceRegistryException e) { // logger.trace("Error Updating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Updating {}", facet, e); throw new RuntimeException(e); } } @Override public boolean delete(Context context) throws ContextNotFoundException, ResourceRegistryException { return delete(context.getID()); } @Override public boolean delete(UUID uuid) throws ContextNotFoundException, ResourceRegistryException { return delete(uuid.toString()); } @Override public boolean delete(String uuid) throws ContextNotFoundException, ResourceRegistryException { try { logger.trace("Going to delete {} with UUID {}", Context.NAME, uuid); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); gxHTTPStringRequest.path(uuid); HttpURLConnection httpURLConnection = gxHTTPStringRequest.delete(); HTTPUtility.getResponse(String.class, httpURLConnection); boolean deleted = true; logger.info("{} with UUID {} {}", Context.NAME, uuid, deleted ? " successfully deleted" : "was NOT deleted"); return deleted; } catch(ResourceRegistryException e) { // logger.trace("Error Creating {}", facet, e); throw e; } catch(Exception e) { // logger.trace("Error Creating {}", facet, e); throw new RuntimeException(e); }finally { try { forceCacheRefresh(); }catch (Exception e) { } } } }