2019-09-04 14:58:06 +02:00
package org.gcube.informationsystem.publisher ;
import java.io.StringWriter ;
2019-09-09 14:24:44 +02:00
import java.util.Date ;
import java.util.ArrayList ;
2019-09-04 14:58:06 +02:00
import java.util.Arrays ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.List ;
import java.util.UUID ;
import javax.xml.ws.soap.SOAPFaultException ;
import org.gcube.common.clients.stubs.jaxws.JAXWSUtils ;
import org.gcube.common.resources.gcore.Resource ;
import org.gcube.common.resources.gcore.ResourceMediator ;
import org.gcube.common.resources.gcore.Resources ;
import org.gcube.common.resources.gcore.ScopeGroup ;
import org.gcube.common.scope.api.ScopeProvider ;
import org.gcube.common.scope.impl.ScopeBean ;
import org.gcube.common.scope.impl.ScopeBean.Type ;
import org.gcube.informationsystem.publisher.exception.RegistryNotFoundException ;
import org.gcube.informationsystem.publisher.scope.ValidatorProvider ;
import org.gcube.informationsystem.publisher.stubs.registry.RegistryStub ;
import org.gcube.informationsystem.publisher.stubs.registry.faults.CreateException ;
import org.gcube.informationsystem.publisher.stubs.registry.faults.InvalidResourceException ;
import org.gcube.informationsystem.publisher.stubs.registry.faults.ResourceNotAcceptedException ;
import org.gcube.informationsystem.publisher.stubs.registry.faults.UpdateException ;
import org.gcube.informationsystem.publisher.utils.RegistryStubs ;
2019-09-09 14:24:44 +02:00
import org.gcube.informationsystem.publisher.utils.Utils ;
2019-09-04 14:58:06 +02:00
import org.gcube.informationsystem.publisher.utils.ValidationUtils ;
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
public class RegistryPublisherImpl implements RegistryPublisher {
private static final Logger log = LoggerFactory . getLogger ( RegistryPublisher . class ) ;
private static final int REGISTRY_THRESHOLD = 5 ;
private RegistryStubs registry ;
/ * *
* Used in create operation . If is not null the update on this scope will never be done
* /
private String scopeCreated ;
protected RegistryPublisherImpl ( ) {
registry = new RegistryStubs ( ) ;
} ;
/ * *
* The resource is created in the current scope and it is updated in the other scopes that are presents in the resource .
* If is a VRE scope then in the resource will be added also the VO and INFRA scope if they are not present
* If is a VO scope then in the resource will be added also the INFRA scope if it is not present
* @throws RegistryNotFoundException if no service endpoints can be discovered
* @throws InvalidResourceExceptionwhen the resource type is invalid service .
* @throws ResourceNotAcceptedException when the resource is not accepted cause it doesn ' t satisfy a requirement
* @throws CreateException when something is failed on creation
* /
public < T extends Resource > T create ( T resource ) {
String scope = ScopeProvider . instance . get ( ) ;
T res = internalCreate ( resource , scope ) ;
scopeCreated = scope ;
res = update ( res ) ;
return res ;
}
public < T extends Resource > T vosCreate ( T resource , List < String > scopes ) {
T res = internalVosCreate ( resource , scopes ) ;
return res ;
}
2019-09-09 14:24:44 +02:00
/ * *
* From version 1 . 3 , during a create operation an exception is thrown only if it occurs in the VO where the creation is invoked .
* In the previous versions the exception was always thrown
* @param resource
* @param scopes
* @return
* /
2019-09-04 14:58:06 +02:00
private < T extends Resource > T internalVosCreate ( T resource , List < String > scopes ) {
2019-09-09 14:24:44 +02:00
log . trace ( " internalVosCreate method " ) ;
2019-09-04 14:58:06 +02:00
String currentScope = ScopeProvider . instance . get ( ) ;
ValidationUtils . valid ( " resource " , resource ) ; // helper that throws an IllegalArgumentException if resource are null
ValidationUtils . valid ( " scopes " , scopes ) ; // helper that throws an IllegalArgumentException if scopes are null
if ( ( resource . id ( ) = = null ) | | ( resource . id ( ) . isEmpty ( ) ) ) {
// set id
String id = UUID . randomUUID ( ) . toString ( ) ;
log . debug ( " id generated: " + id ) ;
ResourceMediator . setId ( resource , id ) ;
}
2019-09-09 14:24:44 +02:00
HashSet < String > vosScopes = updateResourceScopes ( resource ) ;
// add the new scopes
2019-09-04 14:58:06 +02:00
for ( String scope : scopes ) {
2019-09-09 14:24:44 +02:00
log . debug ( " [VOCREATE] new scope added {} " , scope ) ;
2019-09-04 14:58:06 +02:00
ResourceMediator . setScope ( resource , scope ) ;
}
2019-09-09 14:24:44 +02:00
// validating the resource
2019-09-04 14:58:06 +02:00
try {
Resources . validate ( resource ) ;
} catch ( Exception e ) {
log . error ( " the resource is not valid " , e ) ;
throw new IllegalArgumentException ( " the resource is not valid " , e . getCause ( ) ) ;
}
try {
2019-09-09 14:24:44 +02:00
// checking the current scope: if the operation fails in the current VO it will give an exception, if it fails in another VO no exception will be given
String currentVO = Utils . getCurrentVO ( currentScope ) ;
if ( currentVO ! = null ) {
RegistryStub stub = getRegistryStub ( ) ;
createResource ( resource , currentVO , stub ) ;
vosScopes . remove ( currentVO ) ;
2019-10-22 18:45:18 +02:00
//in this case it is a root-vo scope so we need to create the resource only at root-vo level
} else {
RegistryStub stub = getRegistryStub ( ) ;
createResource ( resource , currentVO , stub ) ;
return resource ;
2019-09-09 14:24:44 +02:00
}
// update the resource for each VO
2019-09-04 14:58:06 +02:00
for ( String voScope : vosScopes ) {
// if update is calling on create operation and the scope is not equal to create operation scope or if is a simple update operation, try to update it
log . trace ( " [VOCREATE] resource " + resource . id ( ) + " update in scope {} with scopes {} " , voScope , resource . scopes ( ) . asCollection ( ) ) ;
ScopeProvider . instance . set ( voScope ) ;
2019-09-09 14:24:44 +02:00
// 20190902: added the try/catch inside the for in order to update the scope in all the reachable VOs and no stop the update if a VO is not reachable
try {
//retrieve registry stub
RegistryStub stub = getRegistryStub ( ) ;
createResource ( resource , voScope , stub ) ;
} catch ( Exception e ) {
log . error ( " resource update problem on scope: " + voScope + " try the next scope if any " ) ;
} finally {
ScopeProvider . instance . set ( currentScope ) ;
}
2019-09-04 14:58:06 +02:00
}
} finally {
ScopeProvider . instance . set ( currentScope ) ;
}
log . trace ( " [VOCREATE] resource created with scopes {} " , resource . scopes ( ) . asCollection ( ) ) ;
return resource ;
}
private < T extends Resource > T internalCreate ( T resource , String scope ) {
log . trace ( " registry-publisher: create method " ) ;
ValidationUtils . valid ( " resource " , resource ) ; // helper that throws an IllegalArgumentException if resource are null
ValidationUtils . valid ( " scopes " , scope ) ; // helper that throws an IllegalArgumentException if scopes are null
if ( ValidationUtils . isPresent ( resource , scope ) )
throw new IllegalStateException ( " The scope " + scope + " is already present in the resource. The create operation can't be performed " ) ;
log . debug ( " resource id found: " + resource . id ( ) ) ;
if ( ( resource . id ( ) = = null ) | | ( resource . id ( ) . isEmpty ( ) ) ) {
// set id
String id = UUID . randomUUID ( ) . toString ( ) ;
log . debug ( " id generated: " + id ) ;
ResourceMediator . setId ( resource , id ) ;
}
// set scope on resource
log . debug ( " scope set in resource: {} " , scope ) ;
ResourceMediator . setScope ( resource , scope ) ;
// check if the scope is compatible with the scopes defined in the resources
ValidatorProvider . getValidator ( resource ) . checkScopeCompatibility ( resource , Arrays . asList ( scope ) ) ;
try {
Resources . validate ( resource ) ;
} catch ( Exception e ) {
log . error ( " the resource is not valid " , e ) ;
throw new IllegalArgumentException ( " the resource is not valid " , e . getCause ( ) ) ;
}
//retrieve registry stub
RegistryStub stub = getRegistryStub ( ) ;
createResource ( resource , scope , stub ) ;
log . trace ( " resource created in scope {} with scopes {} " , scope , resource . scopes ( ) . asCollection ( ) ) ;
return resource ;
}
/ * *
* The resource will be updated on all the scopes that are defined in the resource .
* If an updating operation fail . It will be repeated with best - effort delivery approach
* @throws RegistryNotFoundException if no service endpoints can be discovered
* @throws InvalidResourceException when the resource type is invalid service .
* @throws ResourceNotAcceptedException when the resource is not accepted cause it doesn ' t satisfy a requirement
* @throws CreateException when something is failed on creation
* /
public < T extends Resource > T update ( T resource ) {
log . trace ( " [UPDATE] update resource with id : " + resource . id ( ) ) ;
String currentScope = ScopeProvider . instance . get ( ) ;
ValidationUtils . valid ( " resource " , resource ) ; // helper that throws an IllegalArgumentException if resource are null
validateScope ( resource ) ; // is empty
try {
Resources . validate ( resource ) ;
} catch ( Exception e ) {
log . error ( " the resource is not valid " , e ) ;
throw new IllegalArgumentException ( " the resource is not valid " , e ) ;
}
// retrieves the scopes on resource
ScopeGroup < String > scopes = resource . scopes ( ) ;
int tries = 0 ;
try {
for ( String scope : scopes ) {
log . debug ( " [UPDATE] check update operation on scope " + scope ) ;
// if update is calling on create operation and the scope is not equal to create operation scope or if is a simple update operation, try to update it
if ( ( scopeCreated = = null ) | | ( ( scopeCreated ! = null ) & & ( ! scopeCreated . equals ( scope ) ) ) ) {
log . trace ( " [UPDATE] resource update in scope {} with scopes {} " , scope , resource . scopes ( ) . asCollection ( ) ) ;
ScopeProvider . instance . set ( scope ) ;
registryUpdate ( resource , tries ) ;
tries = 0 ;
} else {
log . trace ( " skip updating on scope " + scopeCreated ) ;
}
}
} finally {
scopeCreated = null ;
// reset the scope
ScopeProvider . instance . set ( currentScope ) ;
}
return resource ;
}
@Override
public < T extends Resource > T vosUpdate ( T resource ) {
log . trace ( " [VOUPDATE] update resource with id : " + resource . id ( ) ) ;
String currentScope = ScopeProvider . instance . get ( ) ;
ValidationUtils . valid ( " resource " , resource ) ; // helper that throws an IllegalArgumentException if resource are null
validateScope ( resource ) ; // is empty
try {
Resources . validate ( resource ) ;
} catch ( Exception e ) {
log . error ( " the resource is not valid " , e ) ;
throw new IllegalArgumentException ( " the resource is not valid " , e ) ;
}
2019-09-09 14:24:44 +02:00
HashSet < String > vosScopes = Utils . getInternalVOScopes ( resource ) ;
2019-09-04 14:58:06 +02:00
try {
2019-09-09 14:24:44 +02:00
// checking the current scope: if the operation fail in the current VO it will give an exception, if it fails in another VO no exception will be given
String currentVO = Utils . getCurrentVO ( currentScope ) ;
if ( currentVO ! = null ) {
ScopeProvider . instance . set ( currentVO ) ;
registryUpdate ( resource , 0 ) ;
vosScopes . remove ( currentVO ) ;
2019-10-22 18:53:49 +02:00
// in this case it is a root-vo scope so we need to update the resource only at root-vo level
} else {
RegistryStub stub = getRegistryStub ( ) ;
createResource ( resource , currentVO , stub ) ;
return resource ;
2019-09-09 14:24:44 +02:00
}
2019-10-22 18:53:49 +02:00
2019-09-09 14:24:44 +02:00
int tries = 0 ;
2019-09-04 14:58:06 +02:00
for ( String voScope : vosScopes ) {
log . debug ( " [VOUPDATE] check update operation on scope {} " , voScope ) ;
// if update is calling on create operation and the scope is not equal to create operation scope or if is a simple update operation, try to update it
if ( ( scopeCreated = = null ) | | ( ( scopeCreated ! = null ) & & ( ! scopeCreated . equals ( voScope ) ) ) ) {
log . trace ( " [VOUPDATE] resource " + resource . id ( ) + " update in scope {} with scopes {} " , voScope , resource . scopes ( ) . asCollection ( ) ) ;
2019-09-09 14:24:44 +02:00
try {
ScopeProvider . instance . set ( voScope ) ;
registryUpdate ( resource , tries ) ;
tries = 0 ;
} catch ( Exception e ) {
log . error ( " resource update problem on scope: " + voScope + " try the next scope if any " ) ;
} finally {
scopeCreated = null ;
ScopeProvider . instance . set ( currentScope ) ;
}
2019-09-04 14:58:06 +02:00
} else {
log . trace ( " [VOUPDATE] skip updating on scope {} " , scopeCreated ) ;
}
}
} finally {
scopeCreated = null ;
ScopeProvider . instance . set ( currentScope ) ;
}
return resource ;
}
/ * *
* The resource will be removed from current scope
* if the scope is the last scope in the resource , the profile will be deleted from IS else
* if it is a VRE scope then the profile will be updated without the VRE scope ,
* if it is a VO scope but there is another VRE scope , belong to the VO , defined in the resource then throw IllegalArgumentException
*
* @throws IllegalArgumentException if no service endpoints can be discovered or if there is another VRE scope defined in the resource
* /
public < T extends Resource > T remove ( T resource ) {
String currentScope = ScopeProvider . instance . get ( ) ;
log . info ( " remove resource with id : " + resource . id ( ) + " from scope: " + currentScope ) ;
ValidationUtils . valid ( " resource " , resource ) ; // helper that throws an IllegalArgumentException if resource are null
ValidationUtils . valid ( " scopes " , currentScope ) ; // helper that throws an IllegalArgumentException if scopes are null
validateScope ( resource ) ;
2019-09-09 14:24:44 +02:00
// the returned voScopes list is not used yet. it should be used if the update/remove operation will be done at VO level
// HashSet<String> vosScopes = updateResourceScopes(resource);
updateResourceScopes ( resource ) ;
2019-09-04 14:58:06 +02:00
try {
Resources . validate ( resource ) ;
} catch ( Exception e ) {
log . error ( " the resource is not valid " , e ) ;
throw new IllegalArgumentException ( " the resource is not valid " , e ) ;
}
log . info ( " remove " + currentScope + " scope from resource " + resource . id ( ) ) ;
ResourceMediator . removeScope ( resource , currentScope ) ;
// retrieves the scopes on resource and update it
// updateResource(resource, currentScope);
try {
updateResourceRemoveOperation ( resource , currentScope ) ;
} catch ( Exception e ) {
ResourceMediator . setScope ( resource , currentScope ) ;
log . error ( " exception message: " + e . getMessage ( ) ) ;
throw new RuntimeException ( e . getMessage ( ) ) ;
}
return resource ;
}
private void registryUpdate ( Resource resource , int tries ) {
log . trace ( " try to update resource with id: " + resource . id ( ) + " times " + ( tries + 1 ) + " on scope: " + ScopeProvider . instance . get ( ) ) ;
try {
registry . getStubs ( ) . update ( resource . id ( ) , resource . type ( ) . toString ( ) , toXml ( resource ) ) ;
} catch ( RegistryNotFoundException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( InvalidResourceException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( ResourceNotAcceptedException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( UpdateException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( SOAPFaultException e ) {
log . warn ( " Failed update resource on " + registry . getEndPoints ( ) . get ( 0 ) + " times: " + ( tries + 1 ) ) ;
if ( tries < REGISTRY_THRESHOLD ) {
tries + + ;
try {
Thread . sleep ( 3000 ) ;
} catch ( InterruptedException e1 ) {
// TODO Auto-generated catch block
e1 . printStackTrace ( ) ;
}
registryUpdate ( resource , tries ) ;
}
throw new IllegalArgumentException ( JAXWSUtils . remoteCause ( e ) ) ;
}
}
private String toXml ( Resource resource ) {
StringWriter writer = new StringWriter ( ) ;
Resources . marshal ( resource , writer ) ;
return writer . toString ( ) ;
}
private void validateScope ( Resource resource ) {
ValidatorProvider . getValidator ( resource ) . validate ( resource ) ;
}
/ * *
* If is the last scope on Resource , the resource will be removed else the resource will be updated
* @param resource
* @param currentScope
* /
private < T extends Resource > void updateResourceRemoveOperation ( T resource , String currentScope ) {
if ( ! isRemoveNeeded ( resource , currentScope ) ) {
2019-09-09 14:24:44 +02:00
// updateResource(resource, currentScope);
// v 1.3 (20190902) try to update the resource just at vo level
vosUpdate ( resource ) ;
2019-09-04 14:58:06 +02:00
} else { // remove the profile from IC
log . info ( " the resource have only the " + currentScope + " scope defined. Remove the resource " + resource . id ( ) + " from IC " ) ;
2019-09-09 14:24:44 +02:00
// if the resource hasn't any scope, the resource will be removed
2019-09-04 14:58:06 +02:00
try {
log . debug ( " remove from IS scope " + currentScope ) ;
registry . getStubs ( ) . remove ( resource . id ( ) , resource . type ( ) . toString ( ) ) ;
} catch ( Exception e ) {
log . error ( " the resource can't be removed " , e ) ;
throw new IllegalArgumentException ( " the resource can't be removed from scope " + currentScope , e ) ;
}
updateResource ( resource , currentScope ) ;
}
}
private < T extends Resource > boolean isRemoveNeeded ( T resource , String scope ) {
if ( ValidationUtils . isCompatibleScopeForRemove ( resource , scope ) ) {
return true ;
} else {
return false ;
}
}
private < T extends Resource > void createResource ( T resource , String scope , RegistryStub stub ) {
try {
log . info ( " create resource with id " + resource . id ( ) + " in scope: " + scope ) ;
String type = null ;
type = resource . type ( ) . toString ( ) ;
log . info ( " resource type is: " + type ) ;
if ( resource . type ( ) . equals ( " ServiceEndpoint " ) )
type = " RuntimeResource " ;
stub . create ( toXml ( resource ) , type ) ;
} catch ( InvalidResourceException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( ResourceNotAcceptedException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( CreateException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
} catch ( SOAPFaultException e ) {
throw new IllegalArgumentException ( JAXWSUtils . remoteCause ( e ) ) ;
}
log . info ( " created resource " + resource . id ( ) + " on scope " + scope ) ;
}
private RegistryStub getRegistryStub ( ) {
RegistryStub stub = null ;
try {
stub = registry . getStubs ( ) ;
} catch ( RegistryNotFoundException e ) {
throw new IllegalArgumentException ( e . getCause ( ) ) ;
}
return stub ;
}
private < T extends Resource > void updateResource ( T resource , String currentScope ) {
ScopeGroup scopes = resource . scopes ( ) ;
int tries = 0 ;
2019-09-09 14:24:44 +02:00
try {
for ( Iterator it = scopes . iterator ( ) ; it . hasNext ( ) ; ) {
String scope = ( String ) it . next ( ) ;
ScopeProvider . instance . set ( scope ) ;
registryUpdate ( resource , tries ) ;
}
} finally {
// reset the scope
ScopeProvider . instance . set ( currentScope ) ;
}
}
private < T extends Resource > void updateResourceVOLevel ( T resource , List < String > voScopes , String currentScope ) {
int tries = 0 ;
try {
for ( String scope : voScopes ) {
ScopeProvider . instance . set ( scope ) ;
registryUpdate ( resource , tries ) ;
}
} finally {
// reset the scope
ScopeProvider . instance . set ( currentScope ) ;
2019-09-04 14:58:06 +02:00
}
}
2019-09-09 14:24:44 +02:00
private < T extends Resource > HashSet < String > updateResourceScopes ( T resource ) {
HashSet < String > vosScopes = Utils . getInternalVOScopes ( resource ) ;
//extract the scopes from the more recent resource found at vo level
List < String > latestScopesFound = Utils . setLatestInternalScopes ( resource , vosScopes ) ;
log . debug ( " latest scope found are " + latestScopesFound ) ;
if ( ( latestScopesFound = = null ) | | ( latestScopesFound . isEmpty ( ) ) ) {
// if it is a new resource the latestScopesFound should be null, in this case the more recent scopes are the new scopes
latestScopesFound = new ArrayList < String > ( vosScopes . size ( ) ) ;
for ( String scope : vosScopes ) {
latestScopesFound . add ( scope ) ;
}
} else {
// remove all the scope from the resource
ResourceMediator . cleanAllScopes ( resource ) ;
// add the scope found on the resource more recent at vo level
for ( String scope : latestScopesFound ) {
log . debug ( " [VOCREATE] scope added {} " , scope ) ;
ResourceMediator . setScope ( resource , scope ) ;
ScopeBean scopeBean = new ScopeBean ( scope ) ;
// check if the scope was already present inside the resource, if not, it will be added to the voScopes
if ( ( ! scopeBean . is ( Type . VRE ) ) & & ( ! vosScopes . contains ( scope ) ) ) {
vosScopes . add ( scope ) ;
}
}
}
return vosScopes ;
}
2019-09-04 14:58:06 +02:00
}