Merged changes made to solve bug #25650
This commit is contained in:
parent
88c1ee60d8
commit
95b86d8a40
|
@ -13,6 +13,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm
|
|||
- Metadata are added only if requested by the client [#25040]
|
||||
- Restored Encrypted Property Type and removed Vault [#25041]
|
||||
- Cleaned RequestInfo in RequestFilter class [#25211]
|
||||
- Solved bug which allow to create two query template with the same name if a null id was provided [#25650]
|
||||
|
||||
|
||||
## [v4.2.0]
|
||||
|
|
|
@ -1,23 +1,34 @@
|
|||
package org.gcube.informationsystem.resourceregistry.queries.templates;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
|
||||
import org.gcube.com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
|
||||
import org.gcube.com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.gcube.com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import org.gcube.com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
|
||||
import org.gcube.informationsystem.base.reference.AccessType;
|
||||
import org.gcube.informationsystem.base.reference.IdentifiableElement;
|
||||
import org.gcube.informationsystem.queries.templates.reference.entities.QueryTemplate;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.AvailableInAnotherContextException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.NotFoundException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.InvalidQueryException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.templates.QueryTemplateAlreadyPresentException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.templates.QueryTemplateNotFoundException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.types.SchemaViolationException;
|
||||
import org.gcube.informationsystem.resourceregistry.contexts.ContextUtility;
|
||||
import org.gcube.informationsystem.resourceregistry.contexts.security.QueryTemplatesSecurityContext;
|
||||
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.instances.base.entities.EntityElementManagement;
|
||||
import org.gcube.informationsystem.resourceregistry.instances.model.Operation;
|
||||
import org.gcube.informationsystem.resourceregistry.queries.json.JsonQuery;
|
||||
import org.gcube.informationsystem.resourceregistry.utils.OrientDBUtility;
|
||||
import org.gcube.informationsystem.serialization.ElementMapper;
|
||||
|
@ -129,7 +140,7 @@ public class QueryTemplateManagement extends EntityElementManagement<QueryTempla
|
|||
return select;
|
||||
}
|
||||
|
||||
protected void checkIfNameAlreadyExists() throws AlreadyPresentException {
|
||||
protected void checkIfNameAlreadyExists() throws QueryTemplateAlreadyPresentException {
|
||||
StringBuffer select = getSelectQuery();
|
||||
|
||||
StringBuffer errorMessage = new StringBuffer();
|
||||
|
@ -146,7 +157,13 @@ public class QueryTemplateManagement extends EntityElementManagement<QueryTempla
|
|||
if (resultSet != null) {
|
||||
try {
|
||||
if(resultSet.hasNext()) {
|
||||
throw new AlreadyPresentException(errorMessage.toString());
|
||||
OResult oResult = resultSet.next();
|
||||
try {
|
||||
element = ElementManagementUtility.getElementFromOptional(oResult.getVertex());
|
||||
} catch (ResourceRegistryException e) {
|
||||
|
||||
}
|
||||
throw new QueryTemplateAlreadyPresentException(errorMessage.toString());
|
||||
}
|
||||
}finally {
|
||||
resultSet.close();
|
||||
|
@ -179,7 +196,7 @@ public class QueryTemplateManagement extends EntityElementManagement<QueryTempla
|
|||
if(resultSet!=null) {
|
||||
resultSet.close();
|
||||
}
|
||||
throw new NotFoundException("Error retrieving " + QueryTemplate.NAME + " with name " + getName());
|
||||
throw new QueryTemplateNotFoundException("Error retrieving " + QueryTemplate.NAME + " with name " + getName());
|
||||
}
|
||||
|
||||
OResult oResult = resultSet.next();
|
||||
|
@ -203,6 +220,80 @@ public class QueryTemplateManagement extends EntityElementManagement<QueryTempla
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String createOrUpdate()
|
||||
throws NotFoundException, AvailableInAnotherContextException, ResourceRegistryException {
|
||||
ODatabaseDocument current = ContextUtility.getCurrentODatabaseDocumentFromThreadLocal();
|
||||
try {
|
||||
oDatabaseDocument = getWorkingContext().getDatabaseDocument(PermissionMode.WRITER);
|
||||
oDatabaseDocument.begin();
|
||||
boolean update = false;
|
||||
setAsEntryPoint();
|
||||
try {
|
||||
checkIfNameAlreadyExists();
|
||||
setOperation(Operation.CREATE);
|
||||
String calledMethod = CalledMethodProvider.instance.get();
|
||||
calledMethod = calledMethod.replace("update", "create");
|
||||
CalledMethodProvider.instance.set(calledMethod);
|
||||
internalCreate();
|
||||
} catch(QueryTemplateAlreadyPresentException e) {
|
||||
String uuidVertexString = element.getProperty(QueryTemplate.ID_PROPERTY).toString();
|
||||
this.uuid = UUID.fromString(uuidVertexString);
|
||||
/*
|
||||
* The service accepts the update if:
|
||||
* - the JSON does NOT contains the field 'id': because the name is an id too;
|
||||
* - the JSON contains the field 'id' and the value is null: because some serializators could set to null a missing value;
|
||||
* - the JSON contains the field 'id' and the value is the same value contained in the vertex in the DB.
|
||||
*
|
||||
* In other words, the service refuse the update with Bad Request if
|
||||
* the JSON contains the field 'id' and the value differs from the value contained in the vertex in the DB.
|
||||
*/
|
||||
JsonNode idNode = jsonNode.get(QueryTemplate.ID_PROPERTY);
|
||||
if(idNode != null && !idNode.isNull() && idNode.isTextual()) {
|
||||
String jsonID = idNode.asText();
|
||||
if(uuidVertexString.compareTo(jsonID)!=0) {
|
||||
throw new ResourceRegistryException("If you provide the id of the " + QueryTemplate.NAME + " it must has the same value of the id contained in the IS (i.e. " + uuidVertexString + ")");
|
||||
}
|
||||
}
|
||||
|
||||
setOperation(Operation.UPDATE);
|
||||
update = true;
|
||||
internalUpdate();
|
||||
}
|
||||
|
||||
oDatabaseDocument.commit();
|
||||
|
||||
if(update) {
|
||||
setReload(true);
|
||||
}
|
||||
|
||||
// TODO Notify to subscriptionNotification
|
||||
|
||||
return serializeAsJsonNode().toString();
|
||||
|
||||
} catch(ResourceRegistryException e) {
|
||||
logger.error("Unable to update {} with UUID {}", accessType.getName(), uuid);
|
||||
if(oDatabaseDocument != null) {
|
||||
oDatabaseDocument.rollback();
|
||||
}
|
||||
throw e;
|
||||
} catch(Exception e) {
|
||||
logger.error("Unable to update {} with UUID {}", accessType.getName(), uuid, e);
|
||||
if(oDatabaseDocument != null) {
|
||||
oDatabaseDocument.rollback();
|
||||
}
|
||||
throw new ResourceRegistryException(e);
|
||||
} finally {
|
||||
if(oDatabaseDocument != null) {
|
||||
oDatabaseDocument.close();
|
||||
}
|
||||
|
||||
if(current!=null) {
|
||||
current.activateOnCurrentThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected OVertex reallyCreate() throws AlreadyPresentException, InvalidQueryException, ResourceRegistryException {
|
||||
try {
|
||||
|
@ -218,7 +309,7 @@ public class QueryTemplateManagement extends EntityElementManagement<QueryTempla
|
|||
throw new ResourceRegistryException("Error Creating " + typeName + " with " + jsonNode, e.getCause());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected OVertex reallyUpdate() throws NotFoundException, ResourceRegistryException {
|
||||
try {
|
||||
|
@ -238,7 +329,9 @@ public class QueryTemplateManagement extends EntityElementManagement<QueryTempla
|
|||
@Override
|
||||
protected void reallyDelete() throws NotFoundException, ResourceRegistryException {
|
||||
logger.debug("Going to delete {} with name {}", accessType.getName(), name);
|
||||
getElement().delete();
|
||||
OVertex oVertex = getElement();
|
||||
uuid = UUID.fromString((String) oVertex.getProperty(IdentifiableElement.ID_PROPERTY));
|
||||
oVertex.delete();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -13,8 +13,8 @@ import org.gcube.common.authorization.utils.secret.JWTSecret;
|
|||
import org.gcube.common.authorization.utils.secret.Secret;
|
||||
import org.gcube.common.authorization.utils.secret.SecretUtility;
|
||||
import org.gcube.common.keycloak.KeycloakClientFactory;
|
||||
import org.gcube.common.keycloak.KeycloakClientHelper;
|
||||
import org.gcube.common.keycloak.model.TokenResponse;
|
||||
import org.gcube.common.scope.api.ScopeProvider;
|
||||
import org.gcube.informationsystem.model.reference.properties.Metadata;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
|
@ -39,14 +39,13 @@ public class ContextTest {
|
|||
public static final String NEXTNEXT;
|
||||
public static final String DEVSEC;
|
||||
public static final String DEVVRE;
|
||||
|
||||
|
||||
protected static final Properties properties;
|
||||
|
||||
protected static final String CLIENT_ID_PROPERTY_KEY = "client_id";
|
||||
protected static final String CLIENT_SECRET_PROPERTY_KEY = "client_secret";
|
||||
|
||||
protected static final String clientID;
|
||||
protected static final String clientSecret;
|
||||
public static final String TYPE_PROPERTY_KEY = "type";
|
||||
public static final String USERNAME_PROPERTY_KEY = "username";
|
||||
public static final String PASSWORD_PROPERTY_KEY = "password";
|
||||
public static final String CLIENT_ID_PROPERTY_KEY = "clientId";
|
||||
|
||||
static {
|
||||
GCUBE = "/gcube";
|
||||
|
@ -64,16 +63,17 @@ public class ContextTest {
|
|||
try {
|
||||
// load the properties file
|
||||
properties.load(input);
|
||||
|
||||
clientID = properties.getProperty(CLIENT_ID_PROPERTY_KEY);
|
||||
clientSecret = properties.getProperty(CLIENT_SECRET_PROPERTY_KEY);
|
||||
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum Type{
|
||||
USER, CLIENT_ID
|
||||
};
|
||||
|
||||
public static void set(Secret secret) throws Exception {
|
||||
SecretManagerProvider.instance.reset();
|
||||
SecretManager secretManager = new SecretManager();
|
||||
|
@ -83,15 +83,56 @@ public class ContextTest {
|
|||
}
|
||||
|
||||
public static void setContextByName(String fullContextName) throws Exception {
|
||||
logger.debug("Going to set credentials for context {}", fullContextName);
|
||||
Secret secret = getSecretByContextName(fullContextName);
|
||||
set(secret);
|
||||
}
|
||||
|
||||
|
||||
private static TokenResponse getJWTAccessToken(String context) throws Exception {
|
||||
ScopeProvider.instance.set(context);
|
||||
TokenResponse tr = KeycloakClientFactory.newInstance().queryUMAToken(clientID, clientSecret, context, null);
|
||||
return tr;
|
||||
Type type = Type.valueOf(properties.get(TYPE_PROPERTY_KEY).toString());
|
||||
|
||||
TokenResponse tr = null;
|
||||
|
||||
int index = context.indexOf('/', 1);
|
||||
String root = context.substring(0, index == -1 ? context.length() : index);
|
||||
|
||||
switch (type) {
|
||||
case CLIENT_ID:
|
||||
String clientId = properties.getProperty(CLIENT_ID_PROPERTY_KEY);
|
||||
String clientSecret = properties.getProperty(root);
|
||||
|
||||
tr = KeycloakClientFactory.newInstance().queryUMAToken(context, clientId, clientSecret, context, null);
|
||||
break;
|
||||
|
||||
case USER:
|
||||
default:
|
||||
String username = properties.getProperty(USERNAME_PROPERTY_KEY);
|
||||
String password = properties.getProperty(PASSWORD_PROPERTY_KEY);
|
||||
|
||||
switch (root) {
|
||||
case "/gcube":
|
||||
default:
|
||||
clientId = "next.d4science.org";
|
||||
break;
|
||||
|
||||
case "/pred4s":
|
||||
clientId = "pre.d4science.org";
|
||||
break;
|
||||
|
||||
case "/d4science.research-infrastructures.eu":
|
||||
clientId = "services.d4science.org";
|
||||
break;
|
||||
}
|
||||
clientSecret = null;
|
||||
|
||||
tr = KeycloakClientHelper.getTokenForUser(context, username, password);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return tr;
|
||||
|
||||
}
|
||||
|
||||
public static Secret getSecretByContextName(String context) throws Exception {
|
||||
|
|
|
@ -5,6 +5,9 @@ import java.io.IOException;
|
|||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import javax.ws.rs.BadRequestException;
|
||||
|
||||
import org.gcube.com.fasterxml.jackson.databind.JavaType;
|
||||
import org.gcube.com.fasterxml.jackson.databind.JsonNode;
|
||||
|
@ -19,6 +22,7 @@ import org.gcube.informationsystem.queries.templates.reference.properties.Templa
|
|||
import org.gcube.informationsystem.resourceregistry.ContextTest;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.AlreadyPresentException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
|
||||
import org.gcube.informationsystem.resourceregistry.api.exceptions.queries.templates.QueryTemplateAlreadyPresentException;
|
||||
import org.gcube.informationsystem.serialization.ElementMapper;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
@ -39,7 +43,9 @@ public class QueryTemplateManagementTest extends ContextTest {
|
|||
|
||||
public static void checkUUIDAndMetadata(IdentifiableElement previous, IdentifiableElement got) {
|
||||
Assert.assertTrue(got.getID()!= null);
|
||||
Assert.assertTrue(got.getID().compareTo(previous.getID()) == 0);
|
||||
if(previous.getID()!=null) {
|
||||
Assert.assertTrue(got.getID().compareTo(previous.getID()) == 0);
|
||||
}
|
||||
|
||||
Metadata gotMetadata = got.getMetadata();
|
||||
Metadata previousMetadata = previous.getMetadata();
|
||||
|
@ -68,10 +74,11 @@ public class QueryTemplateManagementTest extends ContextTest {
|
|||
}
|
||||
|
||||
protected QueryTemplate create(QueryTemplate queryTemplate) throws ResourceRegistryException, IOException {
|
||||
list();
|
||||
//list();
|
||||
|
||||
QueryTemplateManagement queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.setForceIncludeMeta(true);
|
||||
String json = ElementMapper.marshal(queryTemplate);
|
||||
queryTemplateManagement.setJson(json);
|
||||
String created = queryTemplateManagement.create();
|
||||
|
@ -79,7 +86,7 @@ public class QueryTemplateManagementTest extends ContextTest {
|
|||
QueryTemplate createdQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, created);
|
||||
|
||||
assertions(queryTemplate, createdQueryTemplate);
|
||||
list(createdQueryTemplate);
|
||||
// list(createdQueryTemplate);
|
||||
return createdQueryTemplate;
|
||||
}
|
||||
|
||||
|
@ -292,4 +299,102 @@ public class QueryTemplateManagementTest extends ContextTest {
|
|||
logger.debug("The DB should be now clean");
|
||||
}
|
||||
|
||||
@Test(expected = QueryTemplateAlreadyPresentException.class)
|
||||
public void doubleCreateTest() throws Exception {
|
||||
QueryTemplate queryTemplate = getQueryTemplate();
|
||||
try {
|
||||
create(queryTemplate);
|
||||
logger.info("Created {} with name '{}'", QueryTemplate.NAME, queryTemplate.getName());
|
||||
create(queryTemplate);
|
||||
throw new Exception("The second create should fails. You should not be here");
|
||||
} catch (QueryTemplateAlreadyPresentException e) {
|
||||
logger.info("As expected {} with name '{}' already exists", QueryTemplate.NAME, queryTemplate.getName());
|
||||
throw e;
|
||||
}finally {
|
||||
QueryTemplateManagement queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.delete();
|
||||
logger.info("{} with name '{}' successfully deleted", QueryTemplate.NAME, queryTemplate.getName());
|
||||
logger.debug("The DB should be now clean");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createUpdateTest() throws Exception {
|
||||
QueryTemplate queryTemplate = getQueryTemplate();
|
||||
try {
|
||||
QueryTemplate createdQueryTemplate = create(queryTemplate);
|
||||
|
||||
// test no UUID
|
||||
logger.info("Created {} with name '{}'", QueryTemplate.NAME, createdQueryTemplate.getName());
|
||||
QueryTemplateManagement queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.setForceIncludeMeta(true);
|
||||
String updatedDescription = "My 1st udpated description";
|
||||
queryTemplate = getQueryTemplate();
|
||||
queryTemplate.setDescription(updatedDescription);
|
||||
String json = ElementMapper.marshal(queryTemplate);
|
||||
queryTemplateManagement.setJson(json);
|
||||
String updated = queryTemplateManagement.createOrUpdate();
|
||||
logger.info("Updated {} is {}", QueryTemplate.NAME, updated);
|
||||
QueryTemplate updatedQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, updated);
|
||||
Assert.assertTrue(updatedQueryTemplate.getDescription().compareTo(updatedDescription)==0);
|
||||
|
||||
// test UUID null
|
||||
queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.setForceIncludeMeta(true);
|
||||
updatedDescription = "My 2nd udpated description";
|
||||
queryTemplate = getQueryTemplate();
|
||||
queryTemplate.setDescription(updatedDescription);
|
||||
queryTemplate.setID(null);
|
||||
json = ElementMapper.marshal(queryTemplate);
|
||||
queryTemplateManagement.setJson(json);
|
||||
updated = queryTemplateManagement.createOrUpdate();
|
||||
logger.info("Updated {} is {}", QueryTemplate.NAME, updated);
|
||||
updatedQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, updated);
|
||||
Assert.assertTrue(updatedQueryTemplate.getDescription().compareTo(updatedDescription)==0);
|
||||
|
||||
// test UUID same
|
||||
queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.setForceIncludeMeta(true);
|
||||
updatedDescription = "My 3rd udpated description";
|
||||
queryTemplate = getQueryTemplate();
|
||||
queryTemplate.setDescription(updatedDescription);
|
||||
queryTemplate.setID(createdQueryTemplate.getID());
|
||||
json = ElementMapper.marshal(queryTemplate);
|
||||
queryTemplateManagement.setJson(json);
|
||||
updated = queryTemplateManagement.createOrUpdate();
|
||||
logger.info("Updated {} is {}", QueryTemplate.NAME, updated);
|
||||
updatedQueryTemplate = ElementMapper.unmarshal(QueryTemplate.class, updated);
|
||||
Assert.assertTrue(updatedQueryTemplate.getDescription().compareTo(updatedDescription)==0);
|
||||
|
||||
|
||||
// test another UUID
|
||||
queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.setForceIncludeMeta(true);
|
||||
updatedDescription = "My 4th udpated description";
|
||||
queryTemplate = getQueryTemplate();
|
||||
queryTemplate.setDescription(updatedDescription);
|
||||
queryTemplate.setID(UUID.randomUUID());
|
||||
json = ElementMapper.marshal(queryTemplate);
|
||||
queryTemplateManagement.setJson(json);
|
||||
try {
|
||||
updated = queryTemplateManagement.createOrUpdate();
|
||||
throw new Exception("Trying to udpate the " + QueryTemplate.NAME + " using a different " + QueryTemplate.ID_PROPERTY + " must fails. Please check your code");
|
||||
}catch (ResourceRegistryException e) {
|
||||
logger.info("Trying to update {} with name '{}' failed as expected : {} ", QueryTemplate.NAME, queryTemplate.getName(), e.getMessage());
|
||||
}
|
||||
}finally {
|
||||
QueryTemplateManagement queryTemplateManagement = new QueryTemplateManagement();
|
||||
queryTemplateManagement.setName(QUERY_TEMPLATE_NAME);
|
||||
queryTemplateManagement.delete();
|
||||
logger.info("{} with name '{}' successfully deleted", QueryTemplate.NAME, queryTemplate.getName());
|
||||
logger.debug("The DB should be now clean");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue