package eu.geoknow.generator.configuration; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Calendar; import java.util.Collection; import java.util.GregorianCalendar; import java.util.Iterator; import org.apache.log4j.Logger; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; 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.rdf.model.Resource; import com.hp.hpl.jena.sparql.vocabulary.FOAF; import com.hp.hpl.jena.vocabulary.DCTerms; import com.hp.hpl.jena.vocabulary.RDF; import com.ontos.ldiw.vocabulary.LDIS; import com.ontos.ldiw.vocabulary.LDIWO; import eu.geoknow.generator.exceptions.InformationMissingException; import eu.geoknow.generator.exceptions.SPARQLEndpointException; import eu.geoknow.generator.rdf.RdfStoreManager; import eu.geoknow.generator.rdf.SecureRdfStoreManagerImpl; import eu.geoknow.generator.users.FrameworkUserManager; import eu.geoknow.generator.users.UserManager; import eu.geoknow.generator.users.VirtuosoUserManager; /** * Class to store the configuration in the triple store * * @author taleksaschina on 30.06.2014. * @author mvoigt * @author alejandragarciarojas added componentsGraph, and re-stuctured the setup * * TODO: roles have to be defined also in he framework-user.ttl instead of the ontology * */ public class FrameworkSetup { private static final Logger log = Logger.getLogger(FrameworkSetup.class); private FrameworkConfiguration config; private UserManager rdfStoreUserManager; private SecureRdfStoreManagerImpl frameworkRdfStoreManager; public FrameworkSetup() throws IOException, InformationMissingException { // init this.config = FrameworkConfiguration.getInstance(); this.frameworkRdfStoreManager = config.getSystemRdfStoreManager(); this.rdfStoreUserManager = config.getRdfStoreUserManager(); this.rdfStoreUserManager.setup(); } /** * Method to setup, thus, to store the configuration of the workbench in the triple store. * * @param config the framework configuration to store * @param reset if true, the system config already stored will be overwritten in the triple store * @throws Exception */ public void setUp(boolean reset) throws Exception { // if setup is already done but not reset is wanted, exit here if (config.isSetUp() && !reset) { log.debug("System is already initialized, and reset is " + reset + ". Will update components data... "); frameworkRdfStoreManager.dropGraph(config.getComponentsGraph()); setupComponentsGraph(); return; } // if setup already done and reset is want, delete flag and delete // config else if (reset) { clear(); if (config.isSetUp()) { if (!config.removeInitFile()) { throw new Exception("Failed to delete init flag file"); } else { log.info("Old config removed, flag cleaned"); } } else { log.info("Old config removed, but no flage cleaned since it wasn't there. You maybe changed the framework data drectory."); } } // check if auth user doesn't exists boolean authSparqlUserExist = rdfStoreUserManager.checkUserExists(config.getWorkbenchSystemAdmin(), null); if (authSparqlUserExist) throw new Exception("Auth SPARQL user " + config.getWorkbenchSystemAdmin() + " already exists"); // at this point workbench admin user is not created, // but in Virtuoso we can query graphs via public sparql endpoint checkGraphs(); log.info("System Initialization "); // create user rdfStoreUserManager.createUser(config.getWorkbenchSystemAdmin(), config.getWorkbenchSystemAdminPassword()); rdfStoreUserManager.setDefaultRdfPermissions(config.getWorkbenchSystemAdmin(), UserManager.GraphPermissions.WRITE); // Virtuoso fix if (rdfStoreUserManager instanceof VirtuosoUserManager) { ((VirtuosoUserManager) rdfStoreUserManager).grantLOLook(config.getWorkbenchSystemAdmin()); } log.info("System Graphs creation and configuration "); // create required named graphs and load the configuration files // using framework default user frameworkRdfStoreManager.createGraph(config.getSettingsGraph()); frameworkRdfStoreManager.createGraph(config.getAccountsGraph()); frameworkRdfStoreManager.createGraph(config.getGroupsGraph()); frameworkRdfStoreManager.createGraph(config.getJobsGraph()); frameworkRdfStoreManager.createGraph(config.getAuthSessionsGraph()); // Make graphs no accessible by default rdfStoreUserManager.setPublicRdfPermissions(UserManager.GraphPermissions.NO); // add creation dates of the graphs to the SystemGraphsModel, this metadata is going // to be added to the settingsGraph addDates(config.getSettingsGraph(), FrameworkConfiguration.getSystemGraphsModel()); addDates(config.getAccountsGraph(), FrameworkConfiguration.getSystemGraphsModel()); addDates(config.getComponentsGraph(), FrameworkConfiguration.getSystemGraphsModel()); addDates(config.getGroupsGraph(), FrameworkConfiguration.getSystemGraphsModel()); addDates(config.getAuthSessionsGraph(), FrameworkConfiguration.getSystemGraphsModel()); addDates(config.getJobsGraph(), FrameworkConfiguration.getSystemGraphsModel()); // sets the graph permissions to accountsGraph, groupsGraph, jobsGraph and authSessionsGrapg. // all are writable by the System user rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getGroupsGraph(), UserManager.GraphPermissions.WRITE); rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getJobsGraph(), UserManager.GraphPermissions.WRITE); rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getAuthSessionsGraph(), UserManager.GraphPermissions.WRITE); rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getAccountsGraph(), UserManager.GraphPermissions.WRITE); // setup the settingsGraph with corresponding metadata setupSettingsGraph(); // setup the componentsGraph with corresponding metadata setupComponentsGraph(); // add the roles to the accounts graph setupRolesGraph(); // get accounts to be created form the configuration file log.info("create users from framework configuration"); FrameworkUserManager frameworkUserManager = config.getFrameworkUserManager(); String query = "PREFIX gkg: <http://ldiw.ontos.com/ontology/> PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " + " PREFIX foaf: <http://xmlns.com/foaf/0.1/> PREFIX lds: <http://stack.linkeddata.org/ldis-schema/> " + " SELECT ?accountName ?password ?mailto ?role WHERE { " + " ?account <" + RDF.type.getURI() + "> gkg:Account . ?account <" + FOAF.accountName.getURI() + "> ?accountName . " + " ?account <" + LDIS.password + "> ?password . ?account <" + FOAF.mbox + "> ?mailto . ?account <" + LDIWO.role + "> ?role . } "; QueryExecution qexec = QueryExecutionFactory.create(query, FrameworkConfiguration.getUsersModel()); ResultSet results = qexec.execSelect(); while (results.hasNext()) { QuerySolution soln = results.next(); String accountName = soln.getLiteral("accountName").getString(); String password = soln.getLiteral("password").getString(); String email = soln.get("mailto").toString().substring("mailto:".length()); String role = soln.getResource("role").getURI(); if (frameworkUserManager.checkUserExists(accountName, email)) { if (reset) { frameworkUserManager.dropUser(accountName); frameworkUserManager.createUser(accountName, password, email); } else log.warn("User " + accountName + " already exists, and is going to be kept"); } else frameworkUserManager.createUser(accountName, password, email); frameworkUserManager.setRole(accountName, role); } qexec.close(); // init is done, that the flag finally boolean created = config.createInitFile(); if (!created) { log.error("Failed to create init flag file"); } else { log.info("System was initialized successfully."); } } private void addDates(String ngraph, Model m) { Calendar cal = GregorianCalendar.getInstance(); Resource namedGraph = m.getResource(ngraph); m.add(namedGraph, DCTerms.modified, m.createTypedLiteral(cal)); m.add(namedGraph, DCTerms.created, m.createTypedLiteral(cal)); } /** * clear rdf store using configuration: drop system graphs, sparql auth user, all registered users * (if exists) * * @throws Exception */ public void clear() throws Exception { log.info("Checking if system SPARQL user exists"); if (!rdfStoreUserManager.checkUserExists(config.getWorkbenchSystemAdmin(), null)) { // if user doesn't exists than we cannot drop registered users and // system graphs // if system graphs exists than it may be used by another // installation, so drop it manually if you need return; } FrameworkUserManager frameworkUserManager = config.getFrameworkUserManager(); // drop registered users log.debug("Drop registered users"); Collection<String> users = frameworkUserManager.getAllUsernames(); for (String user : users) { frameworkUserManager.dropUser(user); } // drop system graphs log.debug("Drop system graphs"); for (String graph : config.getSystemGraphs().values()) frameworkRdfStoreManager.dropGraph(graph); // drop sparql user log.debug("Drop system SPARQL user"); rdfStoreUserManager.dropUser(config.getWorkbenchSystemAdmin()); } /** * Check if system graphs already exists. Throws exception if one of system graphs exists. * * @param rdfStoreManager - RDF store manager used to check graphs * @param config - framework configuration (to get system graphs URIs) * @throws Exception if one of system graphs exists */ private void checkGraphs() throws Exception { RdfStoreManager rdfStoreManager = config.getPublicRdfStoreManager(); log.info("Check if system graphs already exists"); String queryString = "SELECT DISTINCT ?g WHERE {GRAPH ?g {?s ?p ?o}}"; String response = rdfStoreManager.execute(queryString, "json"); ObjectMapper mapper = new ObjectMapper(); JsonNode rootNode = mapper.readTree(response); Iterator<JsonNode> bindingsIter = rootNode.path("results").path("bindings").elements(); while (bindingsIter.hasNext()) { JsonNode bindingNode = bindingsIter.next(); String graph = bindingNode.path("g").path("value").textValue(); if (config.getSystemGraphs().containsKey(graph)) throw new Exception("Graph " + graph + " already exists"); } } private void setupSettingsGraph() throws Exception { log.debug("setting up " + config.getSettingsGraph()); frameworkRdfStoreManager.createGraph(config.getSettingsGraph()); // only admin user can read/write the graph rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getSettingsGraph(), UserManager.GraphPermissions.WRITE); // write the system settings model (include system graphs data) // insert configuration data, system graphs and datasources to the settings model Model settingsModel = ModelFactory.createDefaultModel(); settingsModel.add(FrameworkConfiguration.getConfigurationModel()); settingsModel.add(FrameworkConfiguration.getDatasourceModel()); ByteArrayOutputStream os = new ByteArrayOutputStream(); os = new ByteArrayOutputStream(); settingsModel.write(os, "N-TRIPLES"); String queryString = "INSERT DATA { GRAPH <" + config.getSettingsGraph() + "> { " + os.toString() + " } }"; os.close(); frameworkRdfStoreManager.execute(queryString, null); } /** * Creates the components graph and provides corresponding privileges. Then, loads the file in the * graph. * * @throws Exception */ private void setupComponentsGraph() throws Exception { // components graph are writable by admin and readable by framework // users log.debug("setting up " + config.getComponentsGraph()); frameworkRdfStoreManager.createGraph(config.getComponentsGraph()); // only admin user can read/write the graph rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getComponentsGraph(), UserManager.GraphPermissions.WRITE); ByteArrayOutputStream os = new ByteArrayOutputStream(); FrameworkConfiguration.getComponentsModel().write(os, "N-TRIPLES"); String queryString = "INSERT DATA { GRAPH <" + config.getComponentsGraph() + "> { " + os.toString() + " } }"; os.close(); try { frameworkRdfStoreManager.execute(queryString, null); } catch (Exception e) { log.error(e); throw new SPARQLEndpointException(e.getMessage()); } } /** * Set up Accounts Graph * * @throws Exception */ private void setupRolesGraph() throws Exception { // components graph are writable by admin and readable by framework // users log.debug("setting up " + config.getRolesGraph()); frameworkRdfStoreManager.createGraph(config.getRolesGraph()); // only admin user can read/write the graph rdfStoreUserManager.setRdfGraphPermissions(config.getWorkbenchSystemAdmin(), config.getRolesGraph(), UserManager.GraphPermissions.WRITE); ByteArrayOutputStream os = new ByteArrayOutputStream(); FrameworkConfiguration.getRolesModel().write(os, "N-TRIPLES"); String queryString = "INSERT DATA { GRAPH <" + config.getRolesGraph() + "> { " + os.toString() + " } }"; os.close(); try { frameworkRdfStoreManager.execute(queryString, null); } catch (Exception e) { log.error(e); throw new SPARQLEndpointException(e.getMessage()); } } }