package eu.geoknow.generator.configuration;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.jena.riot.RiotException;
import org.apache.log4j.Logger;
import com.hp.hpl.jena.query.QueryExecution;
import com.hp.hpl.jena.query.QueryExecutionFactory;
import com.hp.hpl.jena.query.QuerySolution;
import com.hp.hpl.jena.query.ResultSet;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ModelFactory;
import com.hp.hpl.jena.sparql.vocabulary.FOAF;
import com.hp.hpl.jena.vocabulary.RDFS;
import com.ontos.ldiw.vocabulary.LDIS;
import com.ontos.ldiw.vocabulary.LDIWO;
import com.ontos.ldiw.vocabulary.SD;
import eu.geoknow.generator.exceptions.InformationMissingException;
import eu.geoknow.generator.rdf.GraphGroupManager;
import eu.geoknow.generator.rdf.RdfStoreManager;
import eu.geoknow.generator.rdf.RdfStoreManagerImpl;
import eu.geoknow.generator.rdf.SecureRdfStoreManagerImpl;
import eu.geoknow.generator.rdf.VirtuosoGraphGroupManager;
import eu.geoknow.generator.users.FrameworkUserManager;
import eu.geoknow.generator.users.UserManager;
import eu.geoknow.generator.users.VirtuosoUserManager;
import eu.geoknow.generator.utils.EmailSender;
import eu.geoknow.generator.utils.SSLEmailSender;
import eu.geoknow.generator.utils.TLSEmailSender;
import eu.geoknow.generator.utils.Utils;
/**
* This class will read the framework configuration file and make content available in its
* properties.
*
* @author alejandragarciarojas
*
*/
public class FrameworkConfiguration {
private static final Logger log = Logger.getLogger(FrameworkConfiguration.class);
// email registration notifications
private String smtpHost = "";
private String smtpTLSPort = "587";
private String smtpSSLPort = "465";
private String emailAddress = "";
private String emailUsername = "";
private String emailPassword = "";
private String resourceNS = "";
private String defaultDataset = "";
// in this file all main configs are stored
private final static String configurationFile = "system-configuration.ttl";
private final static String datasourcesFile = "system-datasources.ttl";
private final static String componentsFile = "system-components.ttl";
private final static String usersFile = "system-users.ttl";
private final static String sysgraphsFile = "system-graphs.ttl";
private final static String rolesFile = "system-roles.ttl";
private static Model configurationModel = null;
private static Model datasourceModel = null;
private static Model componentsModel = null;
private static Model usersModel = null;
private static Model sysgraphsModel = null;
private static Model rolesModel = null;
// RDF store admin, who has rights to manage RDF store users (create,
// delete, grant permissions, etc.).
// This special user is not created or configured on Workbench setup, it
// should be configured previously in RDF store.
// Configuration details depends on concrete RDF store.
private String rdfStoreAdmin = "";
private String rdfStoreAdminPassword = "";
private String virtuosoJdbcConnString = "";
// admin service for user management (is used for OntoQuad only)
private String adminServiceUrl;
private String publicSparqlEndpoint = "";
private String authSparqlEndpoint = "";
// RDF store user, who manages all Workbench system graphs.
// This user will be created on Workbench setup, just specify user name and
// password in config file.
private String workbenchSystemAdmin = "";
private String workbenchSystemAdminPassword = "";
// system graphs
private String frameworkUri;
private String homepage;
// system graphs
private static HashMap<String, String> systemGraphs;
private String springBatchUri = "";
private String springBatchJobsDir = "";
private String frameworkDataDir = "";
private File initFile;
private static FrameworkConfiguration instance;
private final ReentrantLock dataMappingLock = new ReentrantLock();
/**
* This class provides access to properties form the framework configuration file. And also it
* loads to Jena Models the other configuration files, so they can be reused in the application.
*
* @param context
* @return
* @throws IOException
* @throws InformationMissingException
* @throws Exception
*/
public static synchronized FrameworkConfiguration getInstance() throws IOException,
InformationMissingException {
if (instance == null) {
instance = new FrameworkConfiguration();
// get uri endpoint and dir framework
// the dir to store workbench specific data that should not
// be deleted and where the init.txt will be created
// join the configuration and components models to get the endpoing information
Model allModels = ModelFactory.createDefaultModel();
allModels.add(getConfigurationModel());
allModels.add(getComponentsModel());
allModels.add(getSystemGraphsModel());
String query =
"SELECT ?uri ?endpoint ?dir ?homepage WHERE { ?uri <" + RDFS.label.getURI()
+ "> ?label . " + " ?uri <" + LDIS.integrates.getURI() + "> ?component ."
+ " ?component <" + LDIS.providesService.getURI() + "> ?service ." + " ?uri <"
+ LDIWO.frameworkDataDir.getURI() + "> ?dir . ?uri <" + FOAF.homepage.getURI()
+ "> ?homepage . optional { ?service a <" + LDIS.SPARQLEndPointService.getURI()
+ "> ." + " ?service <" + LDIS.serviceUrl.getURI() + ">?endpoint . }"
+ " FILTER regex(?label, \"LDWorkbench\", \"i\" )}";
log.debug("get uri endpoint and dir framework");
log.debug(query);
QueryExecution qexec = QueryExecutionFactory.create(query, allModels);
ResultSet results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new InformationMissingException(
"Invalid initialization parameter in the framework-configratio file");
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
instance.setFrameworkUri(soln.get("uri").toString());
if (soln.get("endpoint") != null)
instance.setPublicSparqlEndpoint(soln.get("endpoint").toString()); // ontoquad
// does
// not
// support
// public
// endpoints
instance.setResourceNamespace(instance.getFrameworkUri().substring(0,
instance.getFrameworkUri().lastIndexOf("/") + 1));
instance.setFrameworkDataDir(soln.getLiteral("dir").getString());
instance.setHomepage(soln.getResource("homepage").getURI());
}
qexec.close();
log.info("Framework URI: " + instance.getFrameworkUri());
log.info("Framework endpoint: " + instance.getPublicSparqlEndpoint());
log.info("Framework ResourceNamespace: " + instance.getResourceNamespace());
log.info("Framework Data Directory: " + instance.getFrameworkDataDir());
log.info("Framework Homepage: " + instance.getHomepage());
// get the email specific information
query =
" SELECT ?user ?pass ?mail ?host ?tls ?ssl WHERE { <" + instance.getFrameworkUri()
+ "> <" + LDIS.providesService.getURI() + "> ?service ." + " ?service a <"
+ LDIS.EmailService.getURI() + "> ;" + " <" + LDIS.password.getURI() + "> ?pass ;"
+ " <" + LDIS.user.getURI() + "> ?user ;" + " <" + FOAF.mbox.getURI() + "> ?mail ;"
+ " <" + LDIWO.smtpHost.getURI() + "> ?host ;" + " <" + LDIWO.smtpTlsPort.getURI()
+ "> ?tls ;" + " <" + LDIWO.smtpSslPort.getURI() + "> ?ssl }";
log.debug("get system registration email");
log.debug(query);
qexec = QueryExecutionFactory.create(query, allModels);
results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new InformationMissingException(
"Invalid initialization of the email registration service configuration");
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
instance.setSmtpHost(soln.getLiteral("host").getString());
instance.setSmtpTLSPort(soln.getLiteral("tls").getString());
instance.setSmtpSSLPort(soln.getLiteral("ssl").getString());
instance.setEmailAddress(soln.getResource("mail").getURI().replace("mailto:", ""));
instance.setEmailUsername(soln.getLiteral("user").getString());
instance.setEmailPassword(soln.getLiteral("pass").getString());
}
qexec.close();
log.info("Read email config for host:" + instance.getSmtpHost() + " and account:"
+ instance.getEmailUsername());
// get the endpoint for authenticated users, and user and password
// of the system framework
query =
" SELECT ?endpoint ?user ?password WHERE { <" + instance.getFrameworkUri() + "> <"
+ LDIS.integrates.getURI() + "> ?component ." + " ?component <"
+ LDIS.providesService.getURI() + "> ?service ." + " ?service a <"
+ LDIS.SecuredSPARQLEndPointService.getURI() + "> ." + " ?service <"
+ LDIS.serviceUrl.getURI() + "> ?endpoint ." + " ?service <" + LDIS.user.getURI()
+ "> ?user ." + " ?service <" + LDIS.password.getURI() + "> ?password }";
log.debug("RDFStore user");
log.debug(query);
qexec = QueryExecutionFactory.create(query, allModels);
results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new InformationMissingException(
"Invalid initialization of RDFStore user configuration ");
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
instance.setAuthSparqlEndpoint(soln.get("endpoint").toString());
instance.setWorkbenchSystemAdmin(soln.get("user").asLiteral().getString());
instance.setWorkbenchSystemAdminPassword(soln.get("password").asLiteral().getString());
}
qexec.close();
// get and set the database configuration (Virtuoso)
query =
" SELECT ?connectionString ?serviceUrl ?user ?password ?endpoint ?graph WHERE {<"
+ instance.getFrameworkUri() + "> <" + LDIS.integrates.getURI() + "> ?component ."
+ " ?component <" + LDIS.providesService.getURI() + "> ?service ." + " ?service a <"
+ LDIS.StorageService.getURI() + "> ." + " optional {?service <"
+ LDIS.connectionString.getURI() + "> ?connectionString} ."
+ " optional {?service <" + LDIS.serviceUrl.getURI() + "> ?serviceUrl .} "
+ " ?service <" + LDIS.user.getURI() + "> ?user ." + " ?service <"
+ LDIS.password.getURI() + "> ?password }";
log.debug("RDFStore DB connection");
log.debug(query);
qexec = QueryExecutionFactory.create(query, allModels);
results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new InformationMissingException("Invalid initialization of RDF Store service ");
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
if (soln.contains("connectionString")) {
instance.setVirtuosoJdbcConnString(soln.get("connectionString").asLiteral().getString());
}
if (soln.contains("serviceUrl")) {
instance.setAdminServiceUrl(soln.get("serviceUrl").asResource().getURI());
}
instance.setRdfStoreAdmin(soln.get("user").asLiteral().getString());
instance.setRdfStoreAdminPassword(soln.get("password").asLiteral().getString());
}
qexec.close();
// get and set the system named graphs
systemGraphs = new HashMap<String, String>();
query =
"SELECT ?name ?label " + "WHERE { ?s <" + SD.namedGraph.getURI() + "> ?o . ?o <"
+ SD.name.getURI() + "> ?name . ?o <" + SD.graph.getURI() + "> ?g . ?g <"
+ RDFS.label.getURI() + "> ?label } ";
qexec = QueryExecutionFactory.create(query, allModels);
results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new NullPointerException("Invalid initial parameter required");
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
String graph = soln.get("label").asLiteral().getString();
String name = soln.get("name").toString();
systemGraphs.put(graph, name);
log.debug(graph + " added to the system graphs as " + name);
}
qexec.close();
// TODO: experiment to not define system graphs in the configuration file
instance.getSystemGraphs().put("components", instance.getResourceNamespace() + "components");
instance.getSystemGraphs().put("roles", instance.getResourceNamespace() + "roles");
// get the path to the workflow engine
query =
" SELECT ?endpoint ?dir WHERE {<" + instance.getFrameworkUri() + "> <"
+ LDIS.integrates.getURI() + "> ?component . ?component <"
+ LDIS.providesService.getURI() + "> ?service . ?service a <"
+ LDIS.WorkflowService.getURI() + "> ; <" + LDIWO.springBatchAdminJobsDir.getURI()
+ "> ?dir ; <" + LDIS.serviceUrl.getURI() + "> ?endpoint .}";
log.debug("Workflow service");
log.debug(query);
qexec = QueryExecutionFactory.create(query, allModels);
results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new NullPointerException("Invalid initialization parameter for the Workflow Service");
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
instance.setSpringBatchUri(soln.get("endpoint").toString());
instance.setSpringBatchJobsDir(soln.get("dir").asLiteral().getString());
}
qexec.close();
log.info("Spring Batch URI:" + instance.getSpringBatchUri());
/*
* This query execution was added on May 7th, 2015 by Jonas the default-dataset Uri is needed
* for graph management. If refactor this class, keep that in mind! also attribute
* "defaultDataset" and getter/setter should be checked when merging code. need also in
* components ttl: :LDWorkbench lds:providesService :LDWorkbenchService
*/
query =
" SELECT ?defaultDataset WHERE {" + "<" + instance.getFrameworkUri() + "> <"
+ SD.defaultDataset + "> ?defaultDataset. " + "}";
qexec = QueryExecutionFactory.create(query, getConfigurationModel());
results = qexec.execSelect();
if (!results.hasNext()) {
instance = null;
throw new NullPointerException("Invalid initial parameter required at:\n" + query);
}
for (; results.hasNext();) {
QuerySolution soln = results.next();
instance.setDefaultDataset((soln.get("defaultDataset").toString()));
}
qexec.close();
// create the file path for the flag
instance.initFile = new File(instance.frameworkDataDir, "init.txt");
}
return instance;
}
/**
* Method to check if the framework is already initialized. It is checked via a flag in the file
* system.
*
* @return true is already initialized, false otherwise
*/
public boolean isSetUp() {
log.info("Checking if " + initFile.getPath() + " exists");
return initFile.exists();
}
/**
* Method to create the init.txt file in the framwork data dir. If it already exists, the file
* isn't touched.
*
* @return true is created, false if not or the flag already exists
*/
public boolean createInitFile() {
if (!isSetUp()) {
try {
return this.initFile.createNewFile();
} catch (IOException e) {
log.error(e);
return false;
}
} else {
log.error("You need to delete the inti flag before creating it again.");
return false;
}
}
/**
* Method to delete the init.txt file.
*
* @return true if successful, false if not or the file is not existing.
*/
public boolean removeInitFile() {
if (isSetUp())
return this.initFile.delete();
return false;
}
/**
* Method to get the lock of adding new data mappings
*
* @return
*/
public ReentrantLock getDataMappingLock() {
return dataMappingLock;
}
public FrameworkUserManager getFrameworkUserManager() {
return new FrameworkUserManager(getRdfStoreUserManager(), getSystemRdfStoreManager(), instance);
}
public SecureRdfStoreManagerImpl getSystemRdfStoreManager() {
return getUserRdfStoreManager(workbenchSystemAdmin, workbenchSystemAdminPassword);
}
public SecureRdfStoreManagerImpl getUserRdfStoreManager(String user, String password) {
return new SecureRdfStoreManagerImpl(authSparqlEndpoint, user, password);
}
public RdfStoreManager getPublicRdfStoreManager() { // todo OntoQuad doesn't
// support public
// endpoint, so need
// some work around
return new RdfStoreManagerImpl(getPublicSparqlEndpoint());
}
public UserManager getRdfStoreUserManager() {
return new VirtuosoUserManager(this.virtuosoJdbcConnString, this.rdfStoreAdmin,
this.rdfStoreAdminPassword);
}
public EmailSender getDefaultEmailSender() {
return getTLSEmailSender();
}
public EmailSender getTLSEmailSender() {
return new TLSEmailSender(this.smtpHost, this.smtpTLSPort, this.emailAddress,
this.emailUsername, this.emailPassword);
}
public EmailSender getSSLEmailSender() {
return new SSLEmailSender(this.smtpHost, this.smtpSSLPort, this.emailAddress,
this.emailUsername, this.emailPassword);
}
public String getSmtpHost() {
return smtpHost;
}
public void setSmtpHost(String smtpHost) {
this.smtpHost = smtpHost;
}
public String getSmtpTLSPort() {
return smtpTLSPort;
}
public void setSmtpTLSPort(String smtpTLSPort) {
this.smtpTLSPort = smtpTLSPort;
}
public String getSmtpSSLPort() {
return smtpSSLPort;
}
public void setSmtpSSLPort(String smtpSSLPort) {
this.smtpSSLPort = smtpSSLPort;
}
public String getEmailAddress() {
return emailAddress;
}
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailUsername() {
return emailUsername;
}
public void setEmailUsername(String emailUsername) {
this.emailUsername = emailUsername;
}
public String getEmailPassword() {
return emailPassword;
}
public void setEmailPassword(String emailPassword) {
this.emailPassword = emailPassword;
}
public void setRdfStoreAdmin(String rdfStoreAdmin) {
this.rdfStoreAdmin = rdfStoreAdmin;
}
public String getRdfStoreAdmin() {
return rdfStoreAdmin;
}
public void setRdfStoreAdminPassword(String rdfStoreAdminPassword) {
this.rdfStoreAdminPassword = rdfStoreAdminPassword;
}
public String getRdfStoreAdminPassword() {
return rdfStoreAdminPassword;
}
public String getAuthSparqlEndpoint() {
return authSparqlEndpoint;
}
public void setAuthSparqlEndpoint(String authSparqlEndpoint) {
this.authSparqlEndpoint = authSparqlEndpoint;
}
public String getWorkbenchSystemAdmin() {
return workbenchSystemAdmin;
}
public void setWorkbenchSystemAdmin(String workbenchSystemAdmin) {
this.workbenchSystemAdmin = workbenchSystemAdmin;
}
public String getWorkbenchSystemAdminPassword() {
return workbenchSystemAdminPassword;
}
public void setWorkbenchSystemAdminPassword(String workbenchSystemAdminPassword) {
this.workbenchSystemAdminPassword = workbenchSystemAdminPassword;
}
public String getResourceNamespace() {
return resourceNS;
}
public void setResourceNamespace(String resourceNamespace) {
this.resourceNS = resourceNamespace;
}
public String getPublicSparqlEndpoint() {
return publicSparqlEndpoint;
}
public void setPublicSparqlEndpoint(String publicSparqlEndpoint) {
this.publicSparqlEndpoint = publicSparqlEndpoint;
}
public String getVirtuosoJdbcConnString() {
return virtuosoJdbcConnString;
}
public void setVirtuosoJdbcConnString(String virtuosoJdbcConnString) {
this.virtuosoJdbcConnString = virtuosoJdbcConnString;
}
public String getAdminServiceUrl() {
return this.adminServiceUrl;
}
public void setAdminServiceUrl(String adminServiceUrl) {
this.adminServiceUrl = adminServiceUrl;
}
public String getFrameworkUri() {
return frameworkUri;
}
public void setFrameworkUri(String frameworkUri) {
this.frameworkUri = frameworkUri;
}
public String getHomepage() {
return homepage;
}
public void setHomepage(String homepage) {
this.homepage = homepage;
}
public String getDefaultDataset() {
return defaultDataset;
}
public void setDefaultDataset(String defaultDataset) {
this.defaultDataset = defaultDataset;
}
public HashMap<String, String> getSystemGraphs() {
return systemGraphs;
}
public void setSystemGraphs(HashMap<String, String> systemGraphs) {
this.systemGraphs = systemGraphs;
}
public GraphGroupManager getGraphGroupManager() {
return new VirtuosoGraphGroupManager(virtuosoJdbcConnString, rdfStoreAdmin,
rdfStoreAdminPassword);
}
public String getSpringBatchUri() {
return springBatchUri;
}
public void setSpringBatchUri(String springBatchUri) {
this.springBatchUri = springBatchUri;
}
/**
* Get the directory where to store framework-specific data that is outside the webapps folder,
* thus, not delete on re-install
*
* @return folder as String
*/
public String getFrameworkDataDir() {
return frameworkDataDir;
}
/**
* Set the directory where to store framework-specific data that is outside the webapps folder,
* thus, not delete on re-install.
*
* @param frameworkDataDir folder string
* @throws IOException
*/
public void setFrameworkDataDir(String frameworkDataDir) throws IOException {
this.frameworkDataDir = Utils.createDir(frameworkDataDir);
}
public String getSpringBatchJobsDir() {
return springBatchJobsDir;
}
public void setSpringBatchJobsDir(String springBatchJobsDir) {
this.springBatchJobsDir = springBatchJobsDir;
}
/**
* Returns a Jena Model with the framework configuration file loaded
*
* @return Model
* @throws IOException in case the file cannot be loaded or a parsing error is presented
*/
public static Model getConfigurationModel() throws IOException {
// Read configuration
try {
if (configurationModel == null) {
configurationModel = ModelFactory.createDefaultModel();
configurationModel.read(configurationFile);
}
} catch (RiotException e) {
e.printStackTrace();
throw new IOException("Couldn't read " + configurationFile + " file: " + e.getMessage());
}
return configurationModel;
}
/**
* Returns a Jena Model with the dataset file loaded
*
* @return Model
* @throws IOException in case the file cannot be loaded or a parsing error is presented
*/
public static Model getDatasourceModel() throws IOException {
try {
if (datasourceModel == null) {
datasourceModel = ModelFactory.createDefaultModel();
datasourceModel.read(datasourcesFile);
}
} catch (RiotException e) {
e.printStackTrace();
throw new IOException("Couldn't read " + datasourcesFile + " file: " + e.getMessage());
}
return datasourceModel;
}
/**
* Returns a Jena Model with the components configuration file loaded
*
* @return Model
* @throws IOException in case the file cannot be loaded or a parsing error is presented
*/
public static Model getComponentsModel() throws IOException {
try {
if (componentsModel == null) {
componentsModel = ModelFactory.createDefaultModel();
componentsModel.read(componentsFile);
}
} catch (RiotException e) {
e.printStackTrace();
throw new IOException("Couldn't read " + componentsFile + " file: " + e.getMessage());
}
return componentsModel;
}
/**
* Returns a Jena Model with the users configuration file loaded
*
* @return Model
* @throws IOException in case the file cannot be loaded or a parsing error is presented
*/
public static Model getUsersModel() throws IOException {
try {
if (usersModel == null) {
usersModel = ModelFactory.createDefaultModel();
usersModel.read(usersFile);
}
} catch (RiotException e) {
e.printStackTrace();
throw new IOException("Couldn't read " + usersFile + " file: " + e.getMessage());
}
return usersModel;
}
/**
* Returns a Jena Model with the system graphs configuration file loaded
*
* @return Model
* @throws IOException in case the file cannot be loaded or a parsing error is presented
*/
public static Model getSystemGraphsModel() throws IOException {
try {
if (sysgraphsModel == null) {
sysgraphsModel = ModelFactory.createDefaultModel();
sysgraphsModel.read(sysgraphsFile);
}
} catch (RiotException e) {
e.printStackTrace();
throw new IOException("Couldn't read " + sysgraphsFile + " file: " + e.getMessage());
}
return sysgraphsModel;
}
/**
* Returns a Jena Model with the system graphs configuration file loaded
*
* @return Model
* @throws IOException in case the file cannot be loaded or a parsing error is presented
*/
public static Model getRolesModel() throws IOException {
try {
if (rolesModel == null) {
rolesModel = ModelFactory.createDefaultModel();
rolesModel.read(rolesFile);
}
} catch (RiotException e) {
e.printStackTrace();
throw new IOException("Couldn't read " + rolesFile + " file: " + e.getMessage());
}
return rolesModel;
}
public String getAccountsGraph() {
return instance.getSystemGraphs().get("accounts");
}
public String getGroupsGraph() {
return instance.getSystemGraphs().get("groups");
}
public String getJobsGraph() {
return instance.getSystemGraphs().get("jobs");
}
public String getAuthSessionsGraph() {
return instance.getSystemGraphs().get("sessions");
}
public String getSettingsGraph() {
return instance.getSystemGraphs().get("settings");
}
public String getComponentsGraph() {
return instance.getSystemGraphs().get("components");
}
public String getRolesGraph() {
return instance.getSystemGraphs().get("roles");
}
}