2017-01-24 17:24:22 +01:00
package org.gcube.datacatalogue.ckanutillibrary.server ;
2016-06-07 16:00:05 +02:00
2016-06-29 11:44:24 +02:00
import static org.gcube.resources.discovery.icclient.ICFactory.client ;
2016-06-07 16:00:05 +02:00
import static org.gcube.resources.discovery.icclient.ICFactory.clientFor ;
import static org.gcube.resources.discovery.icclient.ICFactory.queryFor ;
2016-06-29 11:44:24 +02:00
import java.io.StringReader ;
2016-06-07 16:00:05 +02:00
import java.util.ArrayList ;
import java.util.Iterator ;
import java.util.List ;
2016-06-29 11:44:24 +02:00
import javax.xml.parsers.DocumentBuilder ;
import javax.xml.parsers.DocumentBuilderFactory ;
2016-06-16 18:09:26 +02:00
import org.gcube.common.encryption.StringEncrypter ;
2016-06-07 16:00:05 +02:00
import org.gcube.common.resources.gcore.ServiceEndpoint ;
import org.gcube.common.resources.gcore.ServiceEndpoint.AccessPoint ;
2016-07-14 18:00:38 +02:00
import org.gcube.common.resources.gcore.ServiceEndpoint.Property ;
2016-06-29 11:44:24 +02:00
import org.gcube.common.resources.gcore.utils.XPathHelper ;
2016-06-07 16:00:05 +02:00
import org.gcube.common.scope.api.ScopeProvider ;
2017-01-24 17:24:22 +01:00
import org.gcube.datacatalogue.ckanutillibrary.server.exceptions.ApplicationProfileNotFoundException ;
import org.gcube.datacatalogue.ckanutillibrary.server.exceptions.NoApplicationProfileMasterException ;
import org.gcube.datacatalogue.ckanutillibrary.server.exceptions.NoDataCatalogueRuntimeResourceException ;
import org.gcube.datacatalogue.ckanutillibrary.server.exceptions.ServiceEndPointException ;
2016-06-07 16:00:05 +02:00
import org.gcube.resources.discovery.client.api.DiscoveryClient ;
2016-06-29 11:44:24 +02:00
import org.gcube.resources.discovery.client.queries.api.Query ;
2016-06-07 16:00:05 +02:00
import org.gcube.resources.discovery.client.queries.api.SimpleQuery ;
2016-06-29 11:44:24 +02:00
import org.gcube.resources.discovery.client.queries.impl.QueryBox ;
2016-06-07 16:00:05 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
2016-06-29 11:44:24 +02:00
import org.w3c.dom.Node ;
import org.xml.sax.InputSource ;
2016-06-07 16:00:05 +02:00
/ * *
2016-06-10 14:15:38 +02:00
* Retrieve ckan running instance information in the infrastructure ( for both its database and data catalogue url )
2016-06-07 16:00:05 +02:00
* @author Costantino Perciante at ISTI - CNR ( costantino . perciante @isti.cnr.it )
* /
2016-09-28 14:49:40 +02:00
public class DataCatalogueRunningCluster {
2016-06-07 16:00:05 +02:00
//logger
2016-09-28 14:49:40 +02:00
private static final Logger logger = LoggerFactory . getLogger ( DataCatalogueRunningCluster . class ) ;
2016-06-07 16:00:05 +02:00
2016-06-13 12:29:21 +02:00
// database of the datacatalogue info
2016-06-10 14:15:38 +02:00
private final static String RUNTIME_DB_RESOURCE_NAME = " CKanDatabase " ;
private final static String PLATFORM_DB_NAME = " postgres " ;
2016-06-29 11:44:24 +02:00
private final static String APPLICATION_PROFILE_NAME = " CkanPortlet " ;
2016-06-16 18:09:26 +02:00
2016-06-13 12:29:21 +02:00
// data catalogue info
2016-06-10 16:32:27 +02:00
private final static String RUNTIME_CATALOGUE_RESOURCE_NAME = " CKanDataCatalogue " ;
2016-06-10 14:15:38 +02:00
private final static String PLATFORM_CATALOGUE_NAME = " Tomcat " ;
2016-06-16 18:09:26 +02:00
// api key property
private final static String API_KEY_PROPERTY = " API_KEY " ;
2016-07-14 18:00:38 +02:00
// property to retrieve the master service endpoint into the /root scope
private final static String IS_MASTER_ROOT_KEY_PROPERTY = " IS_ROOT_MASTER " ; // true, false.. missing means false as well
2016-11-29 10:28:50 +01:00
private final static String IS_MANAGE_PRODUCT_ENABLED = " IS_MANAGE_PRODUCT_ENABLED " ; // true, false.. missing means false as well (for GRSF records)
2016-07-14 18:00:38 +02:00
2016-12-06 19:01:21 +01:00
// url of the http uri for this scope
private final static String URL_RESOLVER = " URL_RESOLVER " ;
2016-06-07 16:00:05 +02:00
// retrieved data
2016-06-10 14:15:38 +02:00
private List < String > datacatalogueUrls = new ArrayList < String > ( ) ;
private List < String > hostsDB = new ArrayList < String > ( ) ;
private List < Integer > portsDB = new ArrayList < Integer > ( ) ;
private String nameDB ;
private String userDB ;
private String passwordDB ;
2016-06-29 11:44:24 +02:00
private String portletUrl ;
2016-11-29 10:28:50 +01:00
private boolean manageProductEnabled ;
2016-12-06 19:01:21 +01:00
private String urlResolver ;
2016-06-07 16:00:05 +02:00
2016-06-16 18:09:26 +02:00
// this token is needed in order to assign roles to user
private String sysAdminToken ;
2016-09-28 14:49:40 +02:00
public DataCatalogueRunningCluster ( String scope ) throws Exception {
2016-06-07 16:00:05 +02:00
2016-06-16 18:09:26 +02:00
if ( scope = = null | | scope . isEmpty ( ) )
throw new Exception ( " Invalid scope!! " ) ;
// retrieve the current scope and save it (it will be reset later)
String currentScope = ScopeProvider . instance . get ( ) ;
2016-11-08 15:06:59 +01:00
logger . info ( " Retrieving ckan database service end point information for scope " + scope ) ;
2016-06-07 16:00:05 +02:00
try {
2016-06-16 18:09:26 +02:00
// set the scope
ScopeProvider . instance . set ( scope ) ;
List < ServiceEndpoint > resources = getConfigurationFromISFORDB ( ) ;
2016-06-07 16:00:05 +02:00
2016-07-08 15:50:22 +02:00
if ( resources . size ( ) = = 0 ) {
2016-11-09 15:04:06 +01:00
throw new NoDataCatalogueRuntimeResourceException ( " There is no Runtime Resource having name " + RUNTIME_DB_RESOURCE_NAME + " and Platform " + PLATFORM_DB_NAME + " in this scope. " ) ;
2016-06-07 16:00:05 +02:00
}
else {
2016-07-14 18:00:38 +02:00
try {
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
if ( resources . size ( ) > 1 ) {
boolean oneWasMaster = false ;
2016-07-08 15:50:22 +02:00
2016-07-14 18:05:41 +02:00
logger . info ( " Too many Runtime Resource having name " + RUNTIME_DB_RESOURCE_NAME + " in this scope.. Looking for the one that has the property " + IS_MASTER_ROOT_KEY_PROPERTY ) ;
2016-07-14 18:00:38 +02:00
for ( ServiceEndpoint res : resources ) {
Iterator < AccessPoint > accessPointIterator = res . profile ( ) . accessPoints ( ) . iterator ( ) ;
while ( accessPointIterator . hasNext ( ) ) {
ServiceEndpoint . AccessPoint accessPoint = ( ServiceEndpoint . AccessPoint ) accessPointIterator
. next ( ) ;
// get the is master property
Property entry = accessPoint . propertyMap ( ) . get ( IS_MASTER_ROOT_KEY_PROPERTY ) ;
String isMaster = entry ! = null ? entry . value ( ) : null ;
if ( isMaster = = null | | ! isMaster . equals ( " true " ) )
continue ;
// set this variable
oneWasMaster = true ;
// add this host
hostsDB . add ( accessPoint . address ( ) . split ( " : " ) [ 0 ] ) ;
// save the port
int port = Integer . parseInt ( accessPoint . address ( ) . split ( " : " ) [ 1 ] ) ;
portsDB . add ( port ) ;
// save the name of the cluster (this should be unique)
nameDB = accessPoint . name ( ) ;
// save user and password
passwordDB = StringEncrypter . getEncrypter ( ) . decrypt ( accessPoint . password ( ) ) ;
userDB = accessPoint . username ( ) ;
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
// now break
break ;
}
}
// if none of them was master, throw an exception
if ( ! oneWasMaster )
2016-11-09 15:04:06 +01:00
throw new NoApplicationProfileMasterException ( " There is no application profile with MASTER property " ) ;
2016-07-14 18:00:38 +02:00
} else {
logger . debug ( resources . toString ( ) ) ;
for ( ServiceEndpoint res : resources ) {
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
Iterator < AccessPoint > accessPointIterator = res . profile ( ) . accessPoints ( ) . iterator ( ) ;
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
while ( accessPointIterator . hasNext ( ) ) {
ServiceEndpoint . AccessPoint accessPoint = ( ServiceEndpoint . AccessPoint ) accessPointIterator
. next ( ) ;
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
// add this host
hostsDB . add ( accessPoint . address ( ) . split ( " : " ) [ 0 ] ) ;
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
// save the port
int port = Integer . parseInt ( accessPoint . address ( ) . split ( " : " ) [ 1 ] ) ;
portsDB . add ( port ) ;
2016-06-16 18:09:26 +02:00
2016-07-14 18:00:38 +02:00
// save the name of the cluster (this should be unique)
nameDB = accessPoint . name ( ) ;
2016-06-10 14:15:38 +02:00
2016-07-14 18:00:38 +02:00
// save user and password
passwordDB = StringEncrypter . getEncrypter ( ) . decrypt ( accessPoint . password ( ) ) ;
userDB = accessPoint . username ( ) ;
2016-11-29 10:28:50 +01:00
2016-07-14 18:00:38 +02:00
}
2016-06-10 14:15:38 +02:00
}
}
} catch ( Exception e ) {
2016-11-09 15:04:06 +01:00
throw new ServiceEndPointException ( e . toString ( ) ) ;
2016-06-10 14:15:38 +02:00
}
}
2016-06-16 18:09:26 +02:00
logger . debug ( " Retrieving ckan data catalogue service end point information and sysadmin token. " ) ;
resources = getConfigurationFromISFORCatalogueUrl ( ) ;
2016-07-08 15:50:22 +02:00
if ( resources . size ( ) = = 0 ) {
2016-06-10 14:15:38 +02:00
logger . error ( " There is no Runtime Resource having name " + RUNTIME_CATALOGUE_RESOURCE_NAME + " and Platform " + PLATFORM_CATALOGUE_NAME + " in this scope. " ) ;
2016-09-28 14:49:40 +02:00
throw new NoDataCatalogueRuntimeResourceException ( ) ;
2016-06-10 14:15:38 +02:00
}
else {
2016-07-14 18:00:38 +02:00
logger . debug ( resources . toString ( ) ) ;
2016-06-10 14:15:38 +02:00
try {
2016-07-14 18:00:38 +02:00
if ( resources . size ( ) > 1 ) {
boolean oneWasMaster = false ;
2016-07-14 18:05:41 +02:00
logger . info ( " Too many Runtime Resource having name " + RUNTIME_CATALOGUE_RESOURCE_NAME + " in this scope.. Looking for the one that has the property " + IS_MASTER_ROOT_KEY_PROPERTY ) ;
2016-07-14 18:00:38 +02:00
for ( ServiceEndpoint res : resources ) {
Iterator < AccessPoint > accessPointIterator = res . profile ( ) . accessPoints ( ) . iterator ( ) ;
while ( accessPointIterator . hasNext ( ) ) {
ServiceEndpoint . AccessPoint accessPoint = ( ServiceEndpoint . AccessPoint ) accessPointIterator
. next ( ) ;
2016-06-10 14:15:38 +02:00
2016-07-14 18:00:38 +02:00
// get the is master property
Property entry = accessPoint . propertyMap ( ) . get ( IS_MASTER_ROOT_KEY_PROPERTY ) ;
String isMaster = entry ! = null ? entry . value ( ) : null ;
if ( isMaster = = null | | ! isMaster . equals ( " true " ) )
continue ;
// set this variable
oneWasMaster = true ;
// add this host
datacatalogueUrls . add ( accessPoint . address ( ) ) ;
// retrieve sys admin token
sysAdminToken = accessPoint . propertyMap ( ) . get ( API_KEY_PROPERTY ) . value ( ) ;
sysAdminToken = StringEncrypter . getEncrypter ( ) . decrypt ( sysAdminToken ) ;
2016-12-06 19:01:21 +01:00
// retrieve URL_RESOLVER
2016-12-12 17:04:21 +01:00
if ( accessPoint . propertyMap ( ) . containsKey ( URL_RESOLVER ) )
urlResolver = accessPoint . propertyMap ( ) . get ( URL_RESOLVER ) . value ( ) ;
2016-07-14 18:00:38 +02:00
// break now
break ;
}
}
2016-06-10 14:15:38 +02:00
2016-07-14 18:00:38 +02:00
// if none of them was master, throw an exception
if ( ! oneWasMaster )
2016-11-09 15:04:06 +01:00
throw new NoApplicationProfileMasterException ( " There is no application profile with MASTER property " ) ;
2016-06-10 14:15:38 +02:00
2016-07-14 18:00:38 +02:00
} else {
for ( ServiceEndpoint res : resources ) {
2016-06-10 14:15:38 +02:00
2016-07-14 18:00:38 +02:00
Iterator < AccessPoint > accessPointIterator = res . profile ( ) . accessPoints ( ) . iterator ( ) ;
2016-06-16 18:09:26 +02:00
2016-07-14 18:00:38 +02:00
while ( accessPointIterator . hasNext ( ) ) {
ServiceEndpoint . AccessPoint accessPoint = ( ServiceEndpoint . AccessPoint ) accessPointIterator
. next ( ) ;
2016-06-29 11:44:24 +02:00
2016-07-14 18:00:38 +02:00
// add this host
datacatalogueUrls . add ( accessPoint . address ( ) ) ;
2016-06-07 16:00:05 +02:00
2016-07-14 18:00:38 +02:00
// retrieve sys admin token
sysAdminToken = accessPoint . propertyMap ( ) . get ( API_KEY_PROPERTY ) . value ( ) ;
sysAdminToken = StringEncrypter . getEncrypter ( ) . decrypt ( sysAdminToken ) ;
2016-11-29 10:28:50 +01:00
// get the is manage product property
Property entry = accessPoint . propertyMap ( ) . get ( IS_MANAGE_PRODUCT_ENABLED ) ;
String isManageProduct = entry ! = null ? entry . value ( ) : null ;
if ( isManageProduct ! = null & & isManageProduct . equals ( " true " ) ) {
logger . info ( " Manage product is enabled in this scope " ) ;
manageProductEnabled = true ;
}
2016-12-06 19:01:21 +01:00
// retrieve URL_RESOLVER
2016-12-12 17:04:21 +01:00
if ( accessPoint . propertyMap ( ) . containsKey ( URL_RESOLVER ) )
urlResolver = accessPoint . propertyMap ( ) . get ( URL_RESOLVER ) . value ( ) ;
2016-07-14 18:00:38 +02:00
}
2016-06-07 16:00:05 +02:00
}
}
2016-11-09 15:04:06 +01:00
} catch ( Exception e ) {
throw new ServiceEndPointException ( " There is no service end point for such information " ) ;
2016-06-07 16:00:05 +02:00
}
}
2016-07-08 15:50:22 +02:00
2016-06-29 11:44:24 +02:00
// finally get the url in which the ckan portlet is deployed
logger . debug ( " Looking for portlet url in " + ScopeProvider . instance . get ( ) + " scope " ) ;
portletUrl = getPortletUrlFromInfrastrucure ( ) ;
2016-07-08 15:50:22 +02:00
2016-06-16 18:09:26 +02:00
} catch ( Exception e ) {
2016-11-09 15:04:06 +01:00
logger . warn ( " The following error occurred: " + e . toString ( ) ) ;
2016-06-16 18:09:26 +02:00
} finally {
ScopeProvider . instance . set ( currentScope ) ;
2016-06-07 16:00:05 +02:00
}
}
/ * *
2016-06-10 14:15:38 +02:00
* Retrieve endpoints information from IS for DB
* @return list of endpoints for ckan database
2016-06-07 16:00:05 +02:00
* @throws Exception
* /
2016-06-16 18:09:26 +02:00
private List < ServiceEndpoint > getConfigurationFromISFORDB ( ) throws Exception {
2016-06-07 16:00:05 +02:00
SimpleQuery query = queryFor ( ServiceEndpoint . class ) ;
2016-06-10 14:15:38 +02:00
query . addCondition ( " $resource/Profile/Name/text() eq ' " + RUNTIME_DB_RESOURCE_NAME + " ' " ) ;
query . addCondition ( " $resource/Profile/Platform/Name/text() eq ' " + PLATFORM_DB_NAME + " ' " ) ;
2016-06-07 16:00:05 +02:00
DiscoveryClient < ServiceEndpoint > client = clientFor ( ServiceEndpoint . class ) ;
List < ServiceEndpoint > toReturn = client . submit ( query ) ;
return toReturn ;
2016-06-10 14:15:38 +02:00
}
2016-06-16 18:09:26 +02:00
2016-06-10 14:15:38 +02:00
/ * *
* Retrieve endpoints information from IS for DataCatalogue URL
* @return list of endpoints for ckan data catalogue
* @throws Exception
* /
2016-06-16 18:09:26 +02:00
private List < ServiceEndpoint > getConfigurationFromISFORCatalogueUrl ( ) throws Exception {
2016-06-10 14:15:38 +02:00
SimpleQuery query = queryFor ( ServiceEndpoint . class ) ;
query . addCondition ( " $resource/Profile/Name/text() eq ' " + RUNTIME_CATALOGUE_RESOURCE_NAME + " ' " ) ;
query . addCondition ( " $resource/Profile/Platform/Name/text() eq ' " + PLATFORM_CATALOGUE_NAME + " ' " ) ;
DiscoveryClient < ServiceEndpoint > client = clientFor ( ServiceEndpoint . class ) ;
List < ServiceEndpoint > toReturn = client . submit ( query ) ;
return toReturn ;
}
2016-06-16 18:09:26 +02:00
2016-06-29 11:44:24 +02:00
/ * *
* Retrieve the url of the ckan portlet deployed into this scope
* @return
* /
private String getPortletUrlFromInfrastrucure ( ) {
String scope = ScopeProvider . instance . get ( ) ;
logger . debug ( " Trying to fetch applicationProfile profile from the infrastructure for " + APPLICATION_PROFILE_NAME + " scope: " + scope ) ;
try {
Query q = new QueryBox ( " for $profile in collection('/db/Profiles/GenericResource')//Resource " +
" where $profile/Profile/SecondaryType/string() eq 'ApplicationProfile' and $profile/Profile/Name/string() " +
" eq ' " + APPLICATION_PROFILE_NAME + " ' " +
" return $profile " ) ;
DiscoveryClient < String > client = client ( ) ;
List < String > appProfile = client . submit ( q ) ;
if ( appProfile = = null | | appProfile . size ( ) = = 0 )
throw new ApplicationProfileNotFoundException ( " Your applicationProfile is not registered in the infrastructure " ) ;
else {
String elem = appProfile . get ( 0 ) ;
DocumentBuilder docBuilder = DocumentBuilderFactory . newInstance ( ) . newDocumentBuilder ( ) ;
Node node = docBuilder . parse ( new InputSource ( new StringReader ( elem ) ) ) . getDocumentElement ( ) ;
XPathHelper helper = new XPathHelper ( node ) ;
List < String > currValue = null ;
currValue = helper . evaluate ( " /Resource/Profile/Body/url/text() " ) ;
if ( currValue ! = null & & currValue . size ( ) > 0 ) {
logger . debug ( " Portlet url found is " + currValue . get ( 0 ) ) ;
return currValue . get ( 0 ) ;
}
}
} catch ( Exception e ) {
logger . error ( " Error while trying to fetch applicationProfile profile from the infrastructure " , e ) ;
}
2016-07-08 15:50:22 +02:00
2016-06-29 11:44:24 +02:00
return null ;
}
2016-07-08 15:50:22 +02:00
2016-06-29 11:44:24 +02:00
/ * * Retrieve the ckan portlet url
* @return the portletUrl
* /
public String getPortletUrl ( ) {
return portletUrl ;
}
2016-06-10 14:15:38 +02:00
/ * *
* Retrieve data catalogue url
* /
public List < String > getDataCatalogueUrl ( ) {
return datacatalogueUrls ;
}
2016-06-07 16:00:05 +02:00
/ * *
* Get the hosts for such resource .
* @return
* /
2016-06-10 14:15:38 +02:00
public List < String > getDatabaseHosts ( ) {
return hostsDB ;
2016-06-07 16:00:05 +02:00
}
/ * *
* Get the ports for such resource .
* @return
* /
2016-06-10 14:15:38 +02:00
public List < Integer > getDatabasePorts ( ) {
return portsDB ;
2016-06-07 16:00:05 +02:00
}
/ * *
* Get the database name .
* @return
* /
public String getDataBaseName ( ) {
2016-06-10 14:15:38 +02:00
return nameDB ;
2016-06-07 16:00:05 +02:00
}
/ * *
* Get the database ' s user .
* @return
* /
public String getDataBaseUser ( ) {
2016-06-10 14:15:38 +02:00
return userDB ;
2016-06-07 16:00:05 +02:00
}
/ * *
* Get the database ' s password .
* @return
* /
public String getDataBasePassword ( ) {
2016-06-10 14:15:38 +02:00
return passwordDB ;
2016-06-07 16:00:05 +02:00
}
2016-06-16 18:09:26 +02:00
/ * *
* @return the sysAdminToken
* /
public String getSysAdminToken ( ) {
return sysAdminToken ;
}
2016-11-29 10:28:50 +01:00
/ * *
* Is manager product enabled ( e . g . , for GRSF records )
* @return
* /
public boolean isManageProductEnabled ( ) {
return manageProductEnabled ;
}
2016-12-06 19:01:21 +01:00
/ * *
* Get the url of the uri resolver for this instance / scope
* @return
* /
public String getUrlResolver ( ) {
return urlResolver ;
}
2016-06-07 16:00:05 +02:00
}