/* * Copyright 2013 Cloud4SOA, www.cloud4soa.eu * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * To change this template, choose Tools | Templates * and open the template in the editor. */ package eu.cloud4soa.repository.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.commons.io.IOUtils; import org.ontoware.rdf2go.ModelFactory; import org.ontoware.rdf2go.RDF2Go; import org.ontoware.rdf2go.exception.ModelRuntimeException; import org.ontoware.rdf2go.impl.jena26.ModelImplJena26; import org.ontoware.rdf2go.model.Model; import org.ontoware.rdf2go.model.Syntax; import org.openrdf.rdf2go.RepositoryModel; import org.openrdf.repository.Repository; import org.openrdf.repository.RepositoryException; import org.openrdf.repository.http.HTTPRepository; import org.openrdf.repository.sail.SailRepository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import com.hp.hpl.jena.sdb.SDBFactory; import com.hp.hpl.jena.sdb.Store; import com.hp.hpl.jena.sdb.StoreDesc; import com.hp.hpl.jena.sdb.sql.SDBConnection; import com.hp.hpl.jena.sdb.store.LayoutType; import com.hp.hpl.jena.sdb.util.StoreUtils; import com.viceversatech.rdfbeans.RDFBeanManager; import javax.sql.DataSource; import org.springframework.beans.factory.annotation.Autowired; /** * * @author vins */ public class RepositoryManager { protected final static String DEFAULT_REPO_FILE_NAME = "repositoryFile.rdf"; protected final static String DATA_FILE_NAME = "dataFile.ttl"; protected final static String ONTOLOGY_FILE_NAME = "c4sOntology.ttl"; protected final static String ONTOLOGY_PATH = "ontology"; protected final static String FILE_BACKEND_OPT = "FILE"; protected final static String DATABASE_BACKEND_OPT = "DATABASE"; protected final static String EXT_SERVER_BACKEND_OPT = "EXT_SERVER"; protected final static String HOME_DIR_PROPERTY = "c4s_home"; protected final static String PROPERTY_FILE_NAME = "repository.properties"; protected final static String REPO_NAME_PROPERTY = "fileBackend.fileName"; protected final static String RDF2GO_IMPLEMENTATION = "implementation"; protected final static String BACKEND_PROPERTY = "backend"; protected final static String DB_CONF_PROPERTY = "dbBackend"; protected final static String SESAME_CONF_PROPERTY = "extServerBackend"; protected final static String SESAME_SERVER_URL_PROP = "serverUrl"; protected enum SUPPORTED_DB { mysql, hsqldb; public static boolean contains(String s) { for(SUPPORTED_DB elem :values()) if (elem.name().equals(s)) return true; return false; } } //Properties loaded by using Spring PropertyPlaceholderConfigurer @Value("ORD{rdf2go.jena.implementationClass}") protected String JENA_MODEL_FACTORY = ""; @Value("ORD{rdf2go.implementationClass}") protected String rdf2GOImplementation = ""; @Value("ORD{backend.file.name}") protected String repoFileName = ""; @Value("ORD{backend.type}" ) protected String backend = ""; @Value("ORD{backend.ext.serverUrl}") protected String sesameServerUrl = ""; /* @Value("ORD{backend.db.type}") */ protected String dbType = ""; @Value("ORD{dataSource.host}") protected String dbHost = ""; @Value("ORD{dataSource.port}") protected String dbPort = ""; @Value("ORD{dataSource.database}") protected String dbName = ""; @Value("ORD{dataSource.user}") protected String dbUser = ""; @Value("ORD{dataSource.password}") protected String dbPass = ""; @Value("ORD{dataSource.driverClass}") protected String dbDriver = ""; @Value("ORD{dataSource.protocol}") protected String dbProtocol = ""; @Value("ORD{dataSource.properties}") protected String dbProperties = ""; private static final Logger logger = LoggerFactory.getLogger( RepositoryManager.class ); protected RDFBeanManager manager; protected SesameMysqlRepository mysqlRepository; protected HTTPRepository sesameServerRepository; protected Model rdf2goModel; protected SDBConnection sdbConn; protected Store store; protected com.hp.hpl.jena.rdf.model.Model jenaModel; @Autowired protected DataSource dataSource; /** * @return the manager */ public RDFBeanManager getManager() { return manager; } public Model getModel() { return rdf2goModel; } public void setDataSource(DataSource dataSource) { this.dataSource = dataSource; } public void initRepository() throws Exception { logger.info("***********************************"); this.setDbType(); RDF2Go.register( this.rdf2GOImplementation ); logger.info("creating the model "); rdf2goModel = this.modelBuilder( this.backend ); rdf2goModel.open(); if ( rdf2goModel.isEmpty() ) { logger.info("Loading data into model"); this.loadDataIntoModel(rdf2goModel, backend); } logger.info("Creating the RDFBeanManager"); manager = new RDFBeanManager(rdf2goModel); manager.setAutocommit(true); logger.info("Repository successfully created"); } protected void loadDataIntoModel(Model model, String backendOption) throws Exception { if( this.backend.equals( FILE_BACKEND_OPT ) ) { logger.debug( "Loading data into model from " + this.repoFileName ); this.readDataFromFile( model, this.repoFileName); } else if ( model.isEmpty() ) { logger.debug("Loading data into model from default ontology " + this.ONTOLOGY_FILE_NAME ); this.readDataFromFile( model, ONTOLOGY_FILE_NAME); } } protected void readDataFromFile(Model model, String filename) throws Exception { InputStream resourceStream; File file; Syntax syntax; resourceStream = this.getResourceStream(filename); try { model.readFrom(resourceStream, Syntax.Turtle); // model.readFrom(resourceStream); if (resourceStream != null) { resourceStream.close(); } } catch (ModelRuntimeException e) { logger.error("Error in loading data in the model ", e); throw e; } catch (FileNotFoundException e) { logger.error("Error in loading data in the model ", e); throw e; } catch (IOException e) { logger.error("Error in loading data in the model ", e); throw e; } } protected InputStream getResourceStream( String filename ) { InputStream resourceStream = null; File file; file = new File( filename ); String abs = file.getAbsolutePath(); if (!file.exists() && this.rdf2goModel.isEmpty() ) { logger.debug(" File " + filename + " not found; reading from " + RepositoryManager.ONTOLOGY_FILE_NAME); resourceStream = RepositoryManager.class.getClassLoader().getResourceAsStream( RepositoryManager.ONTOLOGY_PATH+"/"+RepositoryManager.ONTOLOGY_FILE_NAME); } else { logger.debug("Reading from " + filename); try { resourceStream = new FileInputStream(file); } catch (FileNotFoundException ex) { logger.error( "Problems reading file " + filename, ex); } if (resourceStream == null) { throw new IllegalArgumentException( "Could not open file " + filename ); } } return resourceStream; } private void ensureFileExistsOrCopyFromDefault(File configFolder, String name, String defaultSourceName) throws IOException { File target = new File(configFolder,name); if(!target.exists()){ copyFromResourceToFile( defaultSourceName ,target); } } private void copyFromResourceToFile(String resource, File target) throws IOException { try{ InputStream in = RepositoryManager.class.getClassLoader().getResourceAsStream(resource); if(in == null){ logger.warn(" %%%missing "+resource+" from classpath"); }else{ // try to write the application logging file so admin can change it. try{ target.getParentFile().mkdirs(); FileOutputStream out = new FileOutputStream(target); try{ byte[] buff = new byte[1024]; int read = 0; while((read = in.read(buff))>0){ out.write(buff,0,read); } }finally{ out.close(); } }finally{ in.close(); } } }catch(IOException e){ logger.warn("couldn't write file "+target, e); throw e; } } protected File ensureDirectory( String directoryName ) throws IOException { File configFolder; configFolder = new File( directoryName ); if( !(configFolder.exists() && configFolder.isDirectory()) ){ logger.warn("Missing configuration folder "+configFolder); if(configFolder.mkdirs()){ logger.warn("Creating default configuration at "+configFolder); }else{ logger.error("Cannot create directory " + directoryName); throw new IOException("Cannot create directory " + directoryName); } } return configFolder; } public void closeModel() { FileOutputStream outputStream; Model usedModel; logger.debug(" **************** Closing the model ***************"); usedModel = manager.getModel(); if (this.backend.equals(FILE_BACKEND_OPT)) { try { outputStream = new FileOutputStream( this.repoFileName ); usedModel.writeTo(outputStream, Syntax.Turtle); outputStream.close(); } catch (FileNotFoundException fnfe) { logger.error( "Problems handling writing into file " + repoFileName, fnfe); } catch ( IOException ioe) { logger.error( "Problem writing model into file " + repoFileName, ioe ); } } else if ( this.backend.equals( DATABASE_BACKEND_OPT) ) { this.sdbConn.close(); } usedModel.close(); /* try { this.mysqlRepository.shutDown(); } catch (SailException se) { logger.error( "Problems shutting down repository", se); } * */ } protected Model getDatabaseRepository() throws Exception { Model model; Repository repo; logger.info("configuring repository on " + this.dbType + " database: " + this.getDBConnectString() ); if ( this.hasJenaImplementation() ) { logger.info("Loading db properties file"); // Building the Store object loading it from a ttl configuration file // String configurationPath = "sdbconfig.ttl"; // logger.error("CONFIGURATION FILE: " + configurationPath); // store = this.getStoreFromTTLConfigurationFile( configurationPath); // Building the Store from the PlaceHolder properties StoreDesc storeDesc = new StoreDesc( LayoutType.LayoutTripleNodesHash.getName(), this.dbType ); // this.sdbConn = new SDBConnection( this.getDBConnectString(), this.dbUser, this.dbPass); // Connection con = DataSourceUtils.doGetConnection( dataSource ); // logger.debug( "Is the JDBC connection transactional? " + DataSourceUtils.isConnectionTransactional(con, dataSource)); // this.sdbConn = new SDBConnection( con ); this.sdbConn = new SDBConnection(dataSource); // enable query logging (log level must be set to INFO in logback.xml in order to actually get the query logged) this.sdbConn.setLogSQLStatements(true); this.store = SDBFactory.connectStore( sdbConn, storeDesc); // in case of in memory database, first I remove previous db // if ( dbType.equals("hsqldb") && dbProtocol.substring(0, 15).equals("jdbc:hsqldb:mem") ) { // this.store.getTableFormatter().format(); // } if ( !StoreUtils.isFormatted( this.store) ) { this.store.getTableFormatter().create(); } jenaModel = SDBFactory.connectDefaultModel( this.store ); model = new ModelImplJena26( jenaModel ); } else { mysqlRepository = new SesameMysqlRepository(); repo = new SailRepository( mysqlRepository ); logger.info("initializing repository on mysql database "); try { repo.initialize(); logger.info("Repository initialized"); } catch (RepositoryException e) { logger.error( "Cannot initialize repository", e); throw e; } model = new RepositoryModel( repo ); } return model; } protected Store getStoreFromTTLConfigurationFile(String fileUrl) throws Exception { Store store = null; String configurationPath = fileUrl; logger.error("CONFIGURATION FILE: " + configurationPath); try { File file = null; OutputStream out = null; file = File.createTempFile("sdbconfigTemp", ".ttl"); out=new FileOutputStream(file); IOUtils.copy(RepositoryManager.class.getClassLoader().getResourceAsStream(configurationPath), out); out.flush(); out.close(); store = SDBFactory.connectStore(file.getAbsolutePath()); file.deleteOnExit(); } catch (Exception exception) { logger.error("CONFIGURATION ERROR while configure Store from the ttl file: " + configurationPath, exception); throw exception; } return store; } protected Repository getExternalRepository() throws RepositoryException { Repository repository; logger.debug("|||| Creating the httpRepository" + this.sesameServerUrl ); this.sesameServerRepository = new HTTPRepository( this.sesameServerUrl); logger.debug("|||| Created the httpRepository: " + this.sesameServerUrl ); try { sesameServerRepository.initialize(); } catch (RepositoryException re) { logger.error( "Error initializing the repository",re); throw re; } logger.debug("Repository initialized"); // model = new RepositoryModel ( this.sesameServerRepository ); return this.sesameServerRepository; } protected Model getFileRepository() throws IOException { //----------------------- RDF2go -------------------------- ModelFactory modelFactory = RDF2Go.getModelFactory(); return modelFactory.createModel( ); } protected Model modelBuilder( String backedType) throws Exception { Repository resultingRepository; Model resultingModel; if ( backedType.equals( FILE_BACKEND_OPT ) ) { resultingModel = this.getFileRepository(); } else { if ( backedType.equals( DATABASE_BACKEND_OPT) ) { resultingModel = this.getDatabaseRepository(); } else { resultingRepository = this.getExternalRepository(); resultingModel = new RepositoryModel( resultingRepository ); } } return resultingModel; } protected boolean hasJenaImplementation() { return ( this.rdf2GOImplementation.equals( JENA_MODEL_FACTORY ) ); } // protected Properties getDProperties() { // Properties jenaProperties; // // jenaProperties = new Properties(); // jenaProperties.setProperty( ModelFactoryImpl.BACKEND, this.backend); // jenaProperties.setProperty( ModelFactoryImpl.DB_CONNECT_STRING, this.getDBConnectString() ); // jenaProperties.setProperty( ModelFactoryImpl.SQL_DRIVERNAME, this.getSqlDriver()); // jenaProperties.setProperty( ModelFactoryImpl.DB_USER, this.getDBUser()); // jenaProperties.setProperty( ModelFactoryImpl.DB_PASSWD, this.getDBPass()); // // return jenaProperties; // } protected String getDBConnectString() { StringBuffer dbConnectString; String serverName; String portNumber; dbConnectString = new StringBuffer(""); dbConnectString.append( this.dbProtocol); if ( dbHost != null && !dbHost.equals("")) { if ( dbConnectString.length() > 2 && !dbConnectString.substring( dbConnectString.length() - 2, dbConnectString.length() ).equals("//") ) { logger.info( "^^^^^^ " + dbConnectString.substring( dbConnectString.length() - 2, dbConnectString.length() )); dbConnectString.append("//"); } dbConnectString.append(this.dbHost); if ( this.dbPort != null && !this.dbPort.equals("") ) { dbConnectString.append( ":").append( this.dbPort ); } if ( this.dbName != null && !dbName.equals("") ) { dbConnectString.append("/").append( this.dbName ); } } if (dbProperties != null ) { dbConnectString.append(dbProperties); } /* if ( this.dbType.equals("hsqldb") ) { dbConnectString.append(";sql.enforce_size=false"); } * */ logger.debug( "DB connection string: " + dbConnectString.toString()); return dbConnectString.toString(); } public void closeStore() { this.store.close(); } public boolean checkAutocommit() { return this.jenaModel.supportsTransactions(); } public void rollbackTxSemRepo() { this.jenaModel.abort(); } public void commitTxSemRepo() { this.jenaModel.commit(); this.manager.setAutocommit(true); } public void beginTxOnSemRepo() { this.manager.setAutocommit(false); this.jenaModel.begin(); } protected void setDbType() throws Exception { String dbType; dbType = this.dbProtocol.substring( this.dbProtocol.indexOf(":") + 1 ); dbType = dbType.substring(0, dbType.indexOf(":") ); logger.debug( "database type: " + dbType); if ( SUPPORTED_DB.contains( dbType ) ) { this.dbType = dbType; } else { throw new Exception("Unknown database type"); } } }