package org.gcube.informationsystem.resourceregistry.contexts; import java.io.IOException; 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.model.impl.properties.HeaderImpl; import org.gcube.informationsystem.model.reference.properties.Header; 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.rest.ContextPath; import org.gcube.informationsystem.resourceregistry.api.rest.httputils.HTTPUtility; import org.gcube.informationsystem.serialization.ElementMapper; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class ResourceRegistryContextClientImpl 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; protected ContextCacheRenewal contextCacheRenewal = new ContextCacheRenewal() { @Override public List renew() throws ResourceRegistryException { return getAllContextFromServer(); } }; @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<>(); 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); } } protected List getAllContextFromServer() throws ResourceRegistryException { try { logger.trace("Going to read {} with UUID {}", Context.NAME); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(ContextPath.CONTEXTS_PATH_PART); 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(); } protected String internalCreate(Context context) throws ContextAlreadyPresentException, ResourceRegistryException { try { Header header = context.getHeader(); if(header == null) { header = new HeaderImpl(UUID.randomUUID()); context.setHeader(header); } UUID uuid = context.getHeader().getUUID(); 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()); 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.getHeader().getUUID()); } @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.getHeader().getUUID()); 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); 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.getHeader().getUUID(); 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()); 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.getHeader().getUUID()); } @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) { } } } }