package org.gcube.informationsystem.resourceregistry.schema; import java.io.UnsupportedEncodingException; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.gcube.common.gxhttp.reference.GXConnection; import org.gcube.common.gxhttp.request.GXHTTPStringRequest; import org.gcube.common.http.GXHTTPUtility; import org.gcube.informationsystem.model.knowledge.ModelKnowledge; import org.gcube.informationsystem.model.reference.ModelElement; import org.gcube.informationsystem.model.reference.properties.Metadata; 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.exceptions.types.SchemaException; import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaNotFoundException; import org.gcube.informationsystem.resourceregistry.api.rest.AccessPath; import org.gcube.informationsystem.resourceregistry.api.rest.TypePath; import org.gcube.informationsystem.resourceregistry.api.rest.httputils.HTTPUtility; import org.gcube.informationsystem.tree.Node; import org.gcube.informationsystem.types.TypeMapper; import org.gcube.informationsystem.types.knowledge.TypeInformation; import org.gcube.informationsystem.types.knowledge.TypesKnowledge; import org.gcube.informationsystem.types.reference.Type; import org.gcube.informationsystem.utils.TypeUtility; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class ResourceRegistrySchemaClientImpl implements ResourceRegistrySchemaClient { private static final Logger logger = LoggerFactory.getLogger(ResourceRegistrySchemaClientImpl.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 TypesKnowledge typesKnowledge; /** * Track if the client must request to include {@link Metadata} */ protected boolean includeMeta; public boolean includeMeta() { return includeMeta; } public void setIncludeMeta(boolean includeMeta) { this.includeMeta = includeMeta; } 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{ if(includeMeta) { queryParams.put(AccessPath.INCLUDE_META_QUERY_PARAMETER, Boolean.toString(includeMeta)); } } @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 ResourceRegistrySchemaClientImpl(String address) { this(address, true); } public ResourceRegistrySchemaClientImpl(String address, boolean sharedModelKnowledge) { this.address = address; this.headers = new HashMap<>(); this.includeMeta = false; if(sharedModelKnowledge) { this.typesKnowledge = TypesKnowledge.getInstance(); }else { this.typesKnowledge = new TypesKnowledge(); } typesKnowledge.setTypesDiscoverer(new RRCCTypesDiscoverer(this)); } @Override public ModelKnowledge getModelKnowledge() { return typesKnowledge.getModelKnowledge(); } @Override public void renewModelKnowledge() { typesKnowledge.renew(); } @Override public Type create(Class clz) throws SchemaException, ResourceRegistryException { try { String typeDefinition = TypeMapper.serializeType(clz); // String type = AccessType.getAccessType(clz).getName(); String res = create(typeDefinition); return TypeMapper.deserializeTypeDefinition(res); } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new RuntimeException(e); } } @Override public String create(String typeDefinitition) throws ContextAlreadyPresentException, ResourceRegistryException { try { logger.trace("Going to create: {}", typeDefinitition); Type typeDefinitionObj = TypeMapper.deserializeTypeDefinition(typeDefinitition); 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(TypePath.TYPES_PATH_PART); gxHTTPStringRequest.path(typeDefinitionObj.getName()); includeAdditionalQueryParameters(gxHTTPStringRequest); HttpURLConnection httpURLConnection = gxHTTPStringRequest.put(typeDefinitition); String c = HTTPUtility.getResponse(String.class, httpURLConnection); Type t = TypeMapper.deserializeTypeDefinition(c); typesKnowledge.getModelKnowledge().addType(t); logger.trace("{} successfully created", c); return c; } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new RuntimeException(e); } } @Override public boolean exist(Class clazz) throws ResourceRegistryException { return exist(TypeUtility.getTypeName(clazz)); } @Override public boolean exist(String typeName) throws ResourceRegistryException { try { return typesKnowledge.getModelKnowledge().getTypeByName(typeName) != null; }catch (RuntimeException e) { return false; } } public List getTypeFromTypesKnowledge(String typeName, Boolean polymorphic) throws SchemaNotFoundException, ResourceRegistryException { return getTypeFromTypesKnowledge(typeName, polymorphic, -1); } public List getTypeFromTypesKnowledge(String typeName, int level) throws SchemaNotFoundException, ResourceRegistryException { return getTypeFromTypesKnowledge(typeName, true, level); } protected List addChildren(Node node, List types, int currentLevel, int maxLevel) { if(maxLevel>=0 && maxLevel <= currentLevel) { return types; } Set> children = node.getChildrenNodes(); if(children!=null && children.size()>0) { for(Node child : children) { types.add(child.getNodeElement()); types = addChildren(child, types, ++currentLevel, maxLevel); } } return types; } public List getTypeFromTypesKnowledge(String typeName, Boolean polymorphic, int level) throws SchemaNotFoundException, ResourceRegistryException { Node node = getTypeTreeNode(typeName); List types = new ArrayList<>(); types.add(node.getNodeElement()); if (polymorphic) { addChildren(node, types, 0, level); } return types; } @Override public String read(String typeName, Boolean polymorphic) throws SchemaNotFoundException, ResourceRegistryException { try { List types = getTypeFromTypesKnowledge(typeName, polymorphic); return TypeMapper.serializeTypeDefinitions(types); } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException(e); } } @Override public List read(Class clazz, Boolean polymorphic) throws SchemaNotFoundException, ResourceRegistryException { try { String typeName = TypeUtility.getTypeName(clazz); return getTypeFromTypesKnowledge(typeName, polymorphic); } catch (Exception e) { throw new ResourceRegistryException(e); } } @Override public String read(String typeName, int level) throws SchemaNotFoundException, ResourceRegistryException { try { List types = getTypeFromTypesKnowledge(typeName, level); return TypeMapper.serializeTypeDefinitions(types); } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException(e); } } @Override public List read(Class clazz, int level) throws SchemaNotFoundException, ResourceRegistryException { try { String typeName = TypeUtility.getTypeName(clazz); return getTypeFromTypesKnowledge(typeName, level); } catch (Exception e) { throw new ResourceRegistryException(e); } } @Override public Node getTypeTreeNode(String typeName) throws SchemaNotFoundException, ResourceRegistryException { try { Node node = null; try { node = typesKnowledge.getModelKnowledge().getNodeByName(typeName); } catch (RuntimeException e) { throw new SchemaNotFoundException(e); } return node; } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException(e); } } @Override public Node getTypeTreeNode(Class clazz) throws SchemaNotFoundException, ResourceRegistryException { try { String typeName = TypeUtility.getTypeName(clazz); return getTypeTreeNode(typeName); } catch (Exception e) { throw new ResourceRegistryException(e); } } public boolean existTypeFromServer(String typeName) throws ResourceRegistryException { try { logger.info("Going to get {} schema", typeName); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(TypePath.TYPES_PATH_PART); gxHTTPStringRequest.path(typeName); Map parameters = new HashMap<>(); parameters.put(TypePath.POLYMORPHIC_QUERY_PARAMETER, Boolean.FALSE.toString()); gxHTTPStringRequest.queryParams(parameters); HttpURLConnection httpURLConnection = gxHTTPStringRequest.head(); HTTPUtility.getResponse(String.class, httpURLConnection); return true; } catch (NotFoundException e) { return false; } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new RuntimeException(e); } } public List getTypeFromServer(Class clz, Boolean polymorphic) throws SchemaNotFoundException, ResourceRegistryException { try { String typeName = TypeUtility.getTypeName(clz); String json = getTypeFromServer(typeName, polymorphic); return TypeMapper.deserializeTypeDefinitions(json); } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new ResourceRegistryException(e); } } public String getTypeFromServer(String typeName, Boolean polymorphic) throws ContextNotFoundException, ResourceRegistryException { try { logger.info("Going to get {} schema", typeName); GXHTTPStringRequest gxHTTPStringRequest = getGXHTTPStringRequest(); gxHTTPStringRequest.header(ACCEPT_HTTP_HEADER_KEY, GXConnection.APPLICATION_JSON_CHARSET_UTF_8); gxHTTPStringRequest.path(TypePath.TYPES_PATH_PART); gxHTTPStringRequest.path(typeName); Map parameters = new HashMap<>(); if(polymorphic != null) { parameters.put(TypePath.POLYMORPHIC_QUERY_PARAMETER, polymorphic.toString()); } includeAdditionalQueryParameters(gxHTTPStringRequest, parameters); HttpURLConnection httpURLConnection = gxHTTPStringRequest.get(); String json = HTTPUtility.getResponse(String.class, httpURLConnection); logger.debug("Got schema for {} is {}", typeName, json); return json; } catch(ResourceRegistryException e) { throw e; } catch(Exception e) { throw new RuntimeException(e); } } }