resource-registry/src/main/java/org/gcube/informationsystem/resourceregistry/contexts/ContextUtility.java

253 lines
8.7 KiB
Java

package org.gcube.informationsystem.resourceregistry.contexts;
import java.util.HashMap;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.UUID;
import org.gcube.common.security.ContextBean;
import org.gcube.common.security.providers.SecretManagerProvider;
import org.gcube.informationsystem.base.reference.IdentifiableElement;
import org.gcube.informationsystem.contexts.reference.entities.Context;
import org.gcube.informationsystem.contexts.reference.relations.IsParentOf;
import org.gcube.informationsystem.model.reference.properties.Header;
import org.gcube.informationsystem.resourceregistry.api.contexts.ContextCache;
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextException;
import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException;
import org.gcube.informationsystem.resourceregistry.contexts.security.AdminSecurityContext;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext;
import org.gcube.informationsystem.resourceregistry.contexts.security.SecurityContext.PermissionMode;
import org.gcube.informationsystem.resourceregistry.instances.base.ElementManagementUtility;
import org.gcube.informationsystem.resourceregistry.utils.Utility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.orientechnologies.orient.core.db.ODatabaseRecordThreadLocal;
import com.orientechnologies.orient.core.db.document.ODatabaseDocument;
import com.orientechnologies.orient.core.record.ODirection;
import com.orientechnologies.orient.core.record.OVertex;
import com.orientechnologies.orient.core.record.impl.ODocument;
import com.orientechnologies.orient.core.sql.executor.OResult;
import com.orientechnologies.orient.core.sql.executor.OResultSet;
/**
* @author Luca Frosini (ISTI - CNR)
*/
public class ContextUtility {
private static final Logger logger = LoggerFactory.getLogger(ContextUtility.class);
private Map<UUID,SecurityContext> contexts;
private static ContextUtility contextUtility;
public static ContextUtility getInstance() {
if(contextUtility == null) {
contextUtility = new ContextUtility();
}
return contextUtility;
}
private ContextUtility() {
contexts = new HashMap<>();
}
private static final InheritableThreadLocal<Boolean> hierarchicalMode = new InheritableThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
public static InheritableThreadLocal<Boolean> getHierarchicalMode() {
return hierarchicalMode;
}
private static final InheritableThreadLocal<Boolean> includeInstanceContexts = new InheritableThreadLocal<Boolean>() {
@Override
protected Boolean initialValue() {
return false;
}
};
public static InheritableThreadLocal<Boolean> getIncludeInstanceContexts() {
return includeInstanceContexts;
}
public static String getCurrentContextFullName() {
return SecretManagerProvider.instance.get().getContext();
}
public static SecurityContext getCurrentSecurityContext() throws ResourceRegistryException {
String fullName = getCurrentContextFullName();
if(fullName == null) {
throw new ContextException("Null Token and Scope. Please set your token first.");
}
return ContextUtility.getInstance().getSecurityContextByFullName(fullName);
}
public static AdminSecurityContext getAdminSecurityContext() throws ResourceRegistryException {
AdminSecurityContext adminSecurityContext = AdminSecurityContext.getInstance();
return adminSecurityContext;
}
public synchronized void addSecurityContext(SecurityContext securityContext) {
contexts.put(securityContext.getUUID(), securityContext);
}
public synchronized void addSecurityContext(String fullname, SecurityContext securityContext) {
contexts.put(securityContext.getUUID(), securityContext);
}
public synchronized SecurityContext getSecurityContextByFullName(String fullName) throws ContextException {
ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
ODatabaseDocument oDatabaseDocument = null;
try {
SecurityContext securityContext = null;
logger.trace("Trying to get {} for {}", SecurityContext.class.getSimpleName(), fullName);
UUID uuid = ContextCache.getInstance().getUUIDByFullName(fullName);
if(uuid != null) {
securityContext = contexts.get(uuid);
}
if(securityContext==null) {
logger.trace("{} for {} is not in cache. Going to get it", SecurityContext.class.getSimpleName(),
fullName);
oDatabaseDocument = getAdminSecurityContext().getDatabaseDocument(PermissionMode.READER);
OVertex contextVertex = getContextVertexByFullName(oDatabaseDocument, fullName);
ODocument oDocument = contextVertex.getProperty(IdentifiableElement.HEADER_PROPERTY);
uuid = UUID.fromString(oDocument.getProperty(Header.UUID_PROPERTY));
securityContext = getSecurityContextByUUID(uuid, contextVertex);
addSecurityContext(fullName, securityContext);
}
return securityContext;
} catch(ContextException e) {
throw e;
} catch(Exception e) {
throw new ContextException("Unable to retrieve Context UUID from current Context", e);
} finally {
if(oDatabaseDocument!=null) {
oDatabaseDocument.close();
}
if(current!=null) {
current.activateOnCurrentThread();
}
}
}
public SecurityContext getSecurityContextByUUID(UUID uuid) throws ResourceRegistryException {
return getSecurityContextByUUID(uuid, null);
}
public static ODatabaseDocument getCurrentODatabaseDocumentFromThreadLocal() {
ODatabaseDocument current = null;
try {
current = (ODatabaseDocument) ODatabaseRecordThreadLocal.instance().get();
}catch (Exception e) {
// It is possible that there is no current ODatabaseDocument
}
return current;
}
private OVertex getContextVertexByUUID(UUID uuid) throws ResourceRegistryException {
ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
ODatabaseDocument oDatabaseDocument = null;
try {
oDatabaseDocument = getAdminSecurityContext().getDatabaseDocument(PermissionMode.READER);
OVertex oVertex = Utility.getElementByUUID(oDatabaseDocument, Context.NAME, uuid,
OVertex.class);
return oVertex;
} finally {
if(oDatabaseDocument!=null) {
oDatabaseDocument.close();
}
if(current!=null) {
current.activateOnCurrentThread();
}
}
}
private SecurityContext getSecurityContextByUUID(UUID uuid, OVertex contextVertex) throws ResourceRegistryException {
SecurityContext securityContext = contexts.get(uuid);
if(securityContext == null) {
securityContext = new SecurityContext(uuid);
try {
if(contextVertex == null) {
contextVertex = getContextVertexByUUID(uuid);
}
OVertex parentVertex = contextVertex.getVertices(ODirection.IN, IsParentOf.NAME).iterator().next();
if(parentVertex != null) {
UUID parentUUID = Utility.getUUID(parentVertex);
securityContext.setParentSecurityContext(getSecurityContextByUUID(parentUUID, parentVertex));
}
} catch(NoSuchElementException e) {
// No parent
}
contexts.put(uuid, securityContext);
}
return securityContext;
}
/*
protected UUID getContextUUIDFromFullName(String fullName) throws ResourceRegistryException {
OVertex contextVertex = getContextVertexByFullName(fullName);
return Utility.getUUID(contextVertex);
}
*/
private OVertex getContextVertexByFullName(ODatabaseDocument oDatabaseDocument, String fullName) throws ResourceRegistryException {
logger.trace("Going to get {} {} with full name '{}'", Context.NAME, OVertex.class.getSimpleName(), fullName);
ContextBean scopeBean = new ContextBean(fullName);
String name = scopeBean.name();
// TODO Rewrite better query. This query works because all the scope parts has a different name
String select = "SELECT FROM " + Context.class.getSimpleName() + " WHERE " + Context.NAME_PROPERTY + " = :name";
Map<String, String> map = new HashMap<>();
map.put("name", name);
OResultSet resultSet = oDatabaseDocument.query(select, map);
if(resultSet == null || !resultSet.hasNext()) {
throw new ContextNotFoundException("Error retrieving context with name " + fullName);
}
OResult oResult = resultSet.next();
OVertex context = ElementManagementUtility.getElementFromOptional(oResult.getVertex());
logger.trace("Context Representing Vertex : {}", Utility.toJsonString(context, true));
if(resultSet.hasNext()) {
throw new ContextNotFoundException("Found more than one context with name " + name
+ "but required the one with path" + fullName + ". Please Reimplement the query");
}
return context;
}
}