/* * * YAQP - Yet Another QSAR Project: * Machine Learning algorithms designed for the prediction of toxicological * features of chemical compounds become available on the Web. Yaqp is developed * under OpenTox (http://opentox.org) which is an FP7-funded EU research project. * This project was developed at the Automatic Control Lab in the Chemical Engineering * School of National Technical University of Athens. Please read README for more * information. * * Copyright (C) 2009-2010 Pantelis Sopasakis & Charalampos Chomenides * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * * Contact: * Pantelis Sopasakis * chvng@mail.ntua.gr * Address: Iroon Politechniou St. 9, Zografou, Athens Greece * tel. +30 210 7723236 */ package org.opentox.db.handlers; import com.hp.hpl.jena.rdf.model.Resource; import java.net.URI; import java.net.URISyntaxException; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.opentox.core.exceptions.Cause; import org.opentox.core.exceptions.YaqpException; import org.opentox.core.interfaces.JProcessor; import org.opentox.core.processors.BatchProcessor; import org.opentox.ontology.components.*; import org.opentox.db.exceptions.BadEmailException; import org.opentox.db.exceptions.DbException; import org.opentox.db.exceptions.DuplicateKeyException; import org.opentox.db.processors.DbPipeline; import org.opentox.db.queries.HyperResult; import org.opentox.db.queries.QueryFood; import org.opentox.db.table.collection.AlgOntTable; import org.opentox.db.table.collection.FeaturesTable; import org.opentox.db.table.collection.QSARModelsTable; import org.opentox.db.table.collection.SupportVecTable; import org.opentox.db.table.collection.UserAuthTable; import org.opentox.db.table.collection.UsersTable; import org.opentox.db.util.EmailSupervisor; import org.opentox.db.util.Page; import org.opentox.db.util.PrepStmt; import org.opentox.db.util.TheDbConnector; import org.opentox.ontology.exceptions.ImproperEntityException; import org.opentox.ontology.util.AlgorithmParameter; import org.opentox.ontology.util.YaqpAlgorithms; import org.opentox.ontology.util.vocabulary.ConstantParameters; import org.opentox.util.logging.YaqpLogger; import org.opentox.util.logging.levels.*; /** * Handles write operations in the database. Provides a collection of static methods * which can be used to write data and entities like {@link User }, {@link UserGroup }, * {@link QSARModel } etc. Each method throws a {@link DbException } in case the entity * could not be registered in the DB. Other more specific exceptions like {@link * BadEmailException * * @author Pantelis Sopasakis * @author Charalampos Chomenides */ @SuppressWarnings({"unchecked"}) public class WriterHandler { /** * * <p>Add an arbitrary entity in the database. The registration will take place * according to the type of the component you submit. For example * <code>WriterHandler.add(new UserGroup(...));</code> will add a new user group * while <code>WriterHandler.add(new Feature(..));</code> will add a new feature * in the corresponding table of the database. So, there is no need to know * anything about the structure of the database or even what you're adding.</p> * @param component A YAQP component such as a {@link User }, a {@link UserGroup Group}, * of users, a {@link QSARModel QSAR Model}, an Algorithm {@link AlgorithmOntology Ontology} etc. * @throws DbException In case the component could not be added in the database either * because it is already registered, or because the submitted entity is unacceptable, e.g. * a user with email <code>asdf.qwerty</code> (which is not valid). This method is void, so * there is no result expected from it, e.g. if you register a QSAR Model in the database using * this method you won't be able to know its UID. This being the case, you should * use other methods like {@link WriterHandler#addQSARModel(org.opentox.ontology.components.QSARModel) * addQSARModel(QSARModel model)}. * @see WriterHandler#addAlgorithm(org.opentox.ontology.components.Algorithm) add algorithm * @see WriterHandler#addFeature(org.opentox.ontology.components.Feature) add feature * @see WriterHandler#addUser(org.opentox.ontology.components.User) add user * @see WriterHandler#addUserGroup(org.opentox.ontology.components.UserGroup) add user group * @see WriterHandler#addTask(org.opentox.ontology.components.Task) add task */ public static YaqpComponent add(YaqpComponent component) throws DbException, ImproperEntityException { if (component == null) { throw new NullPointerException("Cannot add a null component into the database"); } if (component instanceof User) {// add user return addUser((User) component); } else if (component instanceof UserGroup) { // add user group return addUserGroup((UserGroup) component); } else if (component instanceof Algorithm) {// add algorithm return addAlgorithm((Algorithm) component); } else if (component instanceof AlgorithmOntology) { return addAlgorithmOntology((AlgorithmOntology) component); } else if (component instanceof Feature) {// add a feature return addFeature((Feature) component); } else if (component instanceof QSARModel) {// add QSAR model return addPredictiveModel((QSARModel) component); } else if (component instanceof Task) { return addTask((Task) component); } else if (component instanceof OmegaModel) { return addOmega((OmegaModel) component); } else {// This component cannot be added in the database String message = "This component cannot be added in the " + "database because it cannot be cast to any of the recognizable " + "datatypes "; YaqpLogger.LOG.log(new Debug(WriterHandler.class, message)); throw new ImproperEntityException(Cause.XIE0, message); } } /** * Add a new UserGroup in the database. The name and the user_level of the group * have to specified. * @param userGroup a user group with specified name and authorization level. * @throws NumberFormatException in case the provided user authorization level is not * an integer number */ protected static UserGroup addUserGroup(UserGroup userGroup) throws DuplicateKeyException, DbException { DbPipeline<QueryFood, HyperResult> addUserGroupPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_USER_GROUP); if (userGroup == null) { throw new NullPointerException("Cannot add a null user group in the database."); } if (userGroup.getName() == null) { throw new DbException(Cause.XDB321, "It seems you forgot to specify the name " + "of the userGroup"); } if (userGroup.getName().length() > 40) { throw new DbException(Cause.XDB490, "Very Big Name for the user group"); } try { QueryFood food = new QueryFood( new String[][]{ {UserAuthTable.NAME.getColumnName(), userGroup.getName()}, {UserAuthTable.USER_LEVEL.getColumnName(), Integer.toString(userGroup.getLevel())}, {UserAuthTable.MODEL_AUTH.getColumnName(), userGroup.getModelAuth()}, {UserAuthTable.USER_AUTH.getColumnName(), userGroup.getUserAuth()}, {UserAuthTable.ALGORITHM_AUTH.getColumnName(), userGroup.getAlgorithmAuth()}, {UserAuthTable.USER_GROUP_AUTH.getColumnName(), userGroup.getUserGroupAuth()}, {UserAuthTable.MAX_MODELS.getColumnName(), Integer.toString(userGroup.getMaxModels())} }); addUserGroupPipeline.process(food); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Added new user group '" + userGroup.getName() + "' with authorization level :" + userGroup.getLevel())); } catch (final DbException ex) { if (ex.getCode() == Cause.XDB800) { throw new DuplicateKeyException(Cause.XDH100, "UserGroup already registered", ex); } String message = "UserGroup could not be added"; YaqpLogger.LOG.log(new Debug(WriterHandler.class, message)); throw new DbException(Cause.XDH101, message, ex); } return userGroup; } /** * * Add a new algorithm ontology in the database. * @param ontology algorithm ontology to be added in the database with specified * name and uri. * @return The algorithm ontology itself as added in the database. * @throws DuplicateKeyException If the algorithm ontology is already registered * in the database * @throws DbException if the provided * algorithm ontology is <code>null</code> or its name or URI is not specified/missing. * @throws NullPointerException If the provided algorithm ontology is null */ protected static AlgorithmOntology addAlgorithmOntology(AlgorithmOntology ontology) throws DuplicateKeyException, DbException { DbPipeline<QueryFood, HyperResult> addAlgorithmOntologyPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_ALGORITHM_ONTOLOGY); if (ontology == null) { throw new NullPointerException("The algorithm ontology you provided in the db writer is null"); } if (ontology.getName() == null) { throw new DbException(Cause.XDB1002, "You have to specify the name of an algorithm ontology to add it in the database"); } if (ontology.getName() == null) { throw new DbException(Cause.XDB1003, "You have to specify the URI of an algorithm ontology to add it in the database"); } if (ontology.getName().length() > 40) { throw new DbException(Cause.XDB1004, "The name of the ontology you tried to add in the " + "database is too long : " + ontology.getName().length()); } if (ontology.getUri().length() > 200) { throw new DbException(Cause.XDB1004, "The URI of the ontology you try to add in the database is too long: " + ontology.getUri().length()); } QueryFood food = new QueryFood( new String[][]{ {AlgOntTable.NAME.getColumnName(), ontology.getName()}, {AlgOntTable.URI.getColumnName(), ontology.getUri()} }); try { addAlgorithmOntologyPipeline.process(food); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Added new algorithm ontology '" + ontology.getName() + "' with uri :" + ontology.getUri())); } catch (final DbException ex) { //TODO: verify that the ontology is indeed added! if (ex.getCode() == Cause.XDB800) { throw new DuplicateKeyException(Cause.XDB4301, "Algorithm Ontology already added in the database", ex); } else { throw new DbException(Cause.XDH102, "Error while adding the ontology with name = " + ontology.getName(), ex); } } return ontology; } /** * Add a new user in the database with specified username, email and other personal * information. For security reasons the password should be provided as a digest * (e.g. SHA-512). The information that should be privided are the username, the password, * first and last name of the user and the email. All other information like <code> * organization</code> are optional. For more information take a look at the class * {@link User } and documentation therein. * @param user The user to be added in the database * @throws DuplicateKeyException If the user is already registered. * @throws BadEmailException If the provided email is not acceptable. * @throws DbException If the provided user could not be added in the database. This is * the case when one tries to register a user like <code>User u = new User()</code>, i.e. * without specified the mandatory fields. * @see ReaderHandler#searchUsers(org.opentox.ontology.components.User) search for user * @see EmailSupervisor */ protected static User addUser(User user) throws BadEmailException, DbException { // CHECK IF THE MANDATORY PARAMETERS ARE SPECIFIED: if (user == null) { throw new NullPointerException("Cannot add a null user in the database"); } if (user.getUserName() == null) { throw new DbException(Cause.XDB5870, "Username has to be specified"); } if (user.getEmail() == null) { throw new DbException(Cause.XDB5871, "You have to specify the user's email"); } if (user.getUserPass() == null) { throw new DbException(Cause.XDB5872, "You must specify a password"); } if (user.getFirstName() == null) { throw new DbException(Cause.XDB5873, "You must specify your first name"); } if (user.getUserGroup() == null) { throw new DbException(Cause.XDB5874, "Usergroup has to be specified"); } if (user.getUserGroup().getName() == null) { throw new DbException(Cause.XDB5875, "You have to specify a user group with a group name"); } if (!EmailSupervisor.checkMail(user.getEmail())) { throw new BadEmailException(Cause.XDH103, "Bad user email"); } DbPipeline<QueryFood, HyperResult> addUserPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_USER); QueryFood food = new QueryFood( new String[][]{ {UsersTable.USERNAME.getColumnName(), user.getUserName()}, {UsersTable.PASSWORD.getColumnName(), user.getUserPass()}, {UsersTable.FIRSTNAME.getColumnName(), user.getFirstName()}, {UsersTable.LASTNAME.getColumnName(), user.getLastName()}, {UsersTable.EMAIL.getColumnName(), user.getEmail()}, {UsersTable.ORGANIZATION.getColumnName(), user.getOrganization() != null ? user.getOrganization() : "N/A"}, {UsersTable.COUNTRY.getColumnName(), user.getCountry() != null ? user.getCountry() : "N/A"}, {UsersTable.CITY.getColumnName(), user.getCity() != null ? user.getCity() : "N/A"}, {UsersTable.ADDRESS.getColumnName(), user.getAddress() != null ? user.getAddress() : "N/A"}, {UsersTable.WEBPAGE.getColumnName(), user.getWebpage() != null ? user.getWebpage() : "N/A"}, {UsersTable.ROLE.getColumnName(), user.getUserGroup().getName()} }); try { addUserPipeline.process(food); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "User added: \n" + user)); } catch (final DbException ex) { if (ex.getCode() == Cause.XDB800) { throw new DuplicateKeyException(Cause.XDB4300, "Username and/or email already registered"); } } return user; } /** * Add a new feature in the database. The URI of the feature has to be specified. * @param feature a feature to be added in the database. * @throws DbException In case the feature cannot be added in the database. This * is the case when the feature already exists ({@link DuplicateKeyException }), when * the URI of the feature is not set or if you try to add a <code>null</code> * feature. */ protected static Feature addFeature(Feature feature) throws DbException { if (feature == null) { throw new NullPointerException("The feature you provided is null"); } if (feature.getURI() == null) { throw new DbException(Cause.XDB3236, "Cannot register a feature with no URI provided"); } try { new URI(feature.getURI()); } catch (URISyntaxException ex) { throw new DbException(Cause.XDB3237, "Invalid URI for feature :" + feature.getURI()); } DbPipeline<QueryFood, HyperResult> addFeaturePipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_FEATURE); QueryFood food = new QueryFood( new String[][]{ {FeaturesTable.URI.getColumnName(), feature.getURI()} }); HyperResult result = null; try { result = addFeaturePipeline.process(food); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Feature added: \n" + feature)); if (result.getSize() == 1) { Iterator<String> it = result.getColumnIterator(1); int r = Integer.parseInt(it.next()); feature.setId(r); } } catch (DbException ex) { if (ex.getCode() == Cause.XDB800) { try { feature.setId(ReaderHandler.searchFeature(new Feature(feature.getURI()) , new Page(0,0)).get(0).getID()); } catch (DbException ex1) {// in this case feature failed to be added but is not in the DB either! throw new DbException(Cause.XDB3238, "Error {"+ex1+"}", ex1); } } } return feature; } /** * Add an algorithm in the database. You only have to provide the Name of the algorithm * in the algorithm object you provide and the algorithm types of the provided entity. * @param algorithm the algorithm to be added in the database. The algorithm is registered * in the database along with a set of algorithm-ontology-relation entries which facilitate * search for algorithms. * @throws DuplicateKeyException In case the algorithm already exists. * @throws DbException In case the algorithm cannot be added. Make sure that the corresponding * algorithm ontologies are already added in the database. */ protected static Algorithm addAlgorithm(Algorithm algorithm) throws DbException { if (algorithm == null) { throw new NullPointerException("Cannot add a null algorithm in the database"); } if (algorithm.getMeta() == null) { throw new NullPointerException("Cannot add an algorithm with unknown metadata"); } if (algorithm.getMeta().getName()==null || algorithm.getMeta().getName().equals("")){ throw new DbException(Cause.XDB3235, "Specify the name of the algorithm"); } if (algorithm.getMeta().getName() == null) { throw new DbException(Cause.XDB3235, "Specify the name of the algorithm"); } if (algorithm.getMeta().getAlgorithmType() == null) { throw new DbException(Cause.XDB3235, "Specify the type of the algorithm"); } DbPipeline<QueryFood, HyperResult> addAlgorithmPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_ALGORITHM); DbPipeline<QueryFood, HyperResult> addAlgOntRelationPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_ALGORITHM_ONTOL_RELATION); BatchProcessor bp = new BatchProcessor((JProcessor)addAlgOntRelationPipeline); bp.setfailSensitive(false); QueryFood algfood = new QueryFood( new String[][]{ {"NAME", algorithm.getMeta().getName()} }); // THE RELATIONS OF THE ALGORITHM: ArrayList<QueryFood> relfood = new ArrayList<QueryFood>(); // THE 'SMALLEST' ONTOLOGY FOR THE ALGORITHM: AlgorithmOntology ontology = new AlgorithmOntology(algorithm.getMeta().getAlgorithmType()); QueryFood food = new QueryFood( new String[][]{ {"ALGORITHM", algorithm.getMeta().getName()}, {"ONTOLOGY", ontology.getName()} }); relfood.add(food); // ALL OTHER SUPER-ONTOLOGIES: Set<Resource> r = algorithm.getMeta().getAlgorithmType().getSuperEntities(); Iterator<Resource> it = r.iterator(); while (it.hasNext()) { food = new QueryFood( new String[][]{ {"ALGORITHM", algorithm.getMeta().getName()}, {"ONTOLOGY", it.next().getLocalName()} }); relfood.add(food); } // ADD THE ALGORITH IN THE DATABASE... try { addAlgorithmPipeline.process(algfood); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Algorithm added: \n" + algorithm)); } catch (DbException ex) { if (ex.getCode() == Cause.XDB800) { String message = "Cannot add algorithm because it already exists."; throw new DuplicateKeyException(Cause.XDH105, message, ex); } YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Could not add the following algorithm :\n" + algorithm)); } // ADD ALL ALGORITHM ONTOLOGIES FOR THIS ALGORITHM. try { bp.process(relfood); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Algorithm-Ontology relations batch added")); } catch (YaqpException ex) { YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Could not batch add Algorithm-Ontology relations :\n" + algorithm)); } return algorithm; } /** * Register a QSAR model in the database for a certain user. QSAR Models include * <code>MLR</code> ones and all models that do not possess any tuning parameters. * <code>Tunable</code> models are registered in the database using the method * {@link WriterHandler#addPredictiveModel(org.opentox.ontology.components.TunableQSARModel) * addPredictiveModel() }. * @param model The model to be added in the database. * @return the unique id (UID) of the registered QSAR model. * @throws DbException In case the model cannot be added. This is the case when * you attempt to add a QSARModel providing incomplete information, i.e. when you * ommit the <code>prediction_feature</code>, or the <code>Algorithm</code> or * the <code>dataset_uri</code> and so on. Alse a {@link DbException } is thrown * if you atempt to add a <code>null</code> model or you somehow violate some * Foreign Key Constraint. * @see WriterHandler#addPredictiveModel(org.opentox.ontology.components.TunableQSARModel) add svm/svc models */ protected static int addQSARModel(QSARModel model) throws DbException { checkQSARModelIntegrity(model); DbPipeline<QueryFood, HyperResult> addQSARModelPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_QSAR_MODEL); DbPipeline<QueryFood, HyperResult> addIndepFeaturePipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_INDEP_FEATURE_RELATION); model.setDependentFeature(addFeature(model.getDependentFeature())); model.setPredictionFeature(addFeature(model.getPredictionFeature())); ArrayList<Feature> listIndependent = new ArrayList<Feature>(model.getIndependentFeatures().size()); for (Feature indep : model.getIndependentFeatures()) { listIndependent.add(addFeature(indep)); } model.setIndependentFeatures(listIndependent); QSARModel.ModelStatus modelStatus = model.getModelStatus(); if (model.getModelStatus() == null) { modelStatus = QSARModel.ModelStatus.UNDER_DEVELOPMENT; } BatchProcessor bp = new BatchProcessor(addIndepFeaturePipeline); int r = 0; HyperResult result = new HyperResult(); QueryFood food = new QueryFood( new String[][]{ {"CODE", model.getCode()}, {"PREDICTION_FEATURE", Integer.toString(model.getPredictionFeature().getID())}, {"DEPENDENT_FEATURE", Integer.toString(model.getDependentFeature().getID())}, {"ALGORITHM", model.getAlgorithm().getMeta().getName()}, {"CREATED_BY", model.getUser().getEmail()}, {"DATASET_URI", model.getDataset()}, {"STATUS", modelStatus.toString()} }); try { result = addQSARModelPipeline.process(food); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "QSarModel added")); } catch (DbException ex) { if (ex.getCode() == Cause.XDB800) throw new DbException(Cause.XDB7701, "Most likely" + " this exception was caused by violation of a foreign key like the user's email. " + "Check the existence of a user with e-mail addess :"+model.getUser().getEmail(), ex); throw new DbException(Cause.XDH107, "Foreign Key or Unique Entry Violation",ex); } if (result.getSize() == 1) { Iterator<String> it = result.getColumnIterator(1); r = Integer.parseInt(it.next()); }// TODO: Otherwise what? ArrayList<QueryFood> foodlist = new ArrayList<QueryFood>(); for (Feature feature : model.getIndependentFeatures()) { QueryFood f = new QueryFood( new String[][]{ {"MODEL_UID", Integer.toString(r)}, {"FEATURE_UID", Integer.toString(feature.getID())} }); foodlist.add(f); } try { bp.process(foodlist); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "EDD444 - Independent feature " + "relations batch added for model: " + model.getId())); } catch (Exception ex) { YaqpLogger.LOG.log(new Trace(WriterHandler.class, "XDD445 - Could not batch " + "add Independent feature relations for model :" + model.getId())); YaqpLogger.LOG.log(new Debug(WriterHandler.class, ex.toString())); throw new DbException(); } return r; } private static void checkQSARModelIntegrity(QSARModel model) throws DbException { if (model == null) { throw new NullPointerException("Cannot add null QSAR model"); } if (model.getCode() == null) { throw new DbException(Cause.XDB5001, "Cannot add a model with unspecified code"); } if (model.getDependentFeature() == null) { throw new DbException(Cause.XDB5002, "Cannot add a model with no dependent feature"); } if (model.getPredictionFeature() == null) { throw new DbException(Cause.XDB5003, "Cannot add a model with no prediction feature"); } if (model.getDataset() == null) { throw new DbException(Cause.XDB5004, "You did not specify a training dataset for the QSAΡ model"); } if (model.getUser() == null) { throw new DbException(Cause.XDB5005, "You must specify a user/creator for the QSAR model"); } if (model.getIndependentFeatures() == null || model.getIndependentFeatures().size() == 0) { throw new DbException(Cause.XDB5006, "You did not specify and independent features"); } if (model.getAlgorithm() == null) { throw new DbException(Cause.XDB5007, "You must specify an algorithm for the model you try to add"); } if (model.getParams() == null) { throw new DbException(Cause.XDB5008, "Algorithm parameters cannot be null"); } try{ new URI(model.getDataset()); }catch (URISyntaxException ex){ throw new DbException(Cause.XDB18, "Invalid URI for dataset : "+model.getDataset(), ex); } } /** * Add a model in the database along with its tuning parameters. SVM and SVC models * are added using this method. * @param model A model with some tuning parameters to be added in the models' table * in the database. * @return the ID of the model. * @throws DbException In case the model could not be added. This is a very usual * case when you don't submit all the needed parameters. For example, if you want * to add an SVM model and forget to provide the parameter <code>tolerance</code>, * this exception will be throws. Consider using {@link ConstantParameters#DEFAULTS the * defaults} for SVM models if you need to do so. */ protected static QSARModel addPredictiveModel(QSARModel model) throws DbException { checkQSARModelIntegrity(model); String algorithmName = model.getAlgorithm().getMeta().getName(); if (algorithmName.equals(YaqpAlgorithms.SVM.getMeta().getName()) || algorithmName.equals(YaqpAlgorithms.SVC.getMeta().getName())) { return addSuppVectModel(model); } else if ( algorithmName.equals(YaqpAlgorithms.MLR.getMeta().getName()) || algorithmName.equals(YaqpAlgorithms.NAIVE_BAYES.getMeta().getName()) ) { int new_id = addQSARModel(model); model.setId(new_id); return model; } return null; } private static QSARModel addSuppVectModel(QSARModel model) throws DbException { // CHECK THE INTEGRITY OF THE GIVEN MODEL... checkQSARModelIntegrity(model); // CHECK IF ALL NECESSARY PARAMETERS ARE PROVIDED. IF SOME ARE NOT, // USE THE DEFAULT VALUES PROVIDED IN ConstantParameters.SVMParams(). Map<String, AlgorithmParameter> params = model.getParams(); if (!params.containsKey(ConstantParameters.gamma)) { params.put(ConstantParameters.gamma, ConstantParameters.SVMParams().get(ConstantParameters.gamma)); } if (!params.containsKey(ConstantParameters.cost)) params.put(ConstantParameters.cost, ConstantParameters.SVMParams().get(ConstantParameters.cost)); if (!params.containsKey(ConstantParameters.coeff0)) params.put(ConstantParameters.coeff0, ConstantParameters.SVMParams().get(ConstantParameters.coeff0)); if (!params.containsKey(ConstantParameters.degree)) params.put(ConstantParameters.degree, ConstantParameters.SVMParams().get(ConstantParameters.degree)); if (!params.containsKey(ConstantParameters.epsilon)) params.put(ConstantParameters.epsilon, ConstantParameters.SVMParams().get(ConstantParameters.epsilon)); if ( !params.containsKey(ConstantParameters.kernel) || (params.containsKey(ConstantParameters.kernel) && params.get(ConstantParameters.kernel).paramValue.toString().equals("%%")) ) params.put(ConstantParameters.kernel, ConstantParameters.SVMParams().get(ConstantParameters.kernel)); if (!params.containsKey(ConstantParameters.cacheSize)) params.put(ConstantParameters.cacheSize, ConstantParameters.SVMParams().get(ConstantParameters.cacheSize)); if (!params.containsKey(ConstantParameters.tolerance)) params.put(ConstantParameters.tolerance, ConstantParameters.SVMParams().get(ConstantParameters.tolerance)); model.setParams(params); int r = 0; /* The id of the model */ try { r = WriterHandler.addQSARModel((QSARModel) model); } catch (DbException ex) { // Could not add the model to the parent table // Reproduce the exception! throw new DbException(Cause.XDH108, "Support Vector Could not be added in the database as QSAR Model", ex); } DbPipeline<QueryFood, HyperResult> addSupportVectorPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_SUPPORT_VECTOR); QueryFood food = new QueryFood(); food.add(SupportVecTable.UID.getColumnName(), Integer.toString(r)); for (Entry e : model.getParams().entrySet()) { String pName = e.getKey().toString(); AlgorithmParameter algParam = (AlgorithmParameter) e.getValue(); food.add(pName.toUpperCase(), algParam.paramValue.toString()); } try { addSupportVectorPipeline.process(food); } catch (DbException ex) { try { // First delete the model from the parent table! Statement delete = TheDbConnector.DB.getConnection().createStatement(); delete.executeUpdate("DELETE FROM " + QSARModelsTable.TABLE.getTableName() + " WHERE UID =" + r); } catch (SQLException ex1) { throw new DbException(Cause.XDH109, "Could not delete the QSAR model with uid : " + r, ex1); } if (ex.getCode() == Cause.XDB15) throw new DbException(Cause.XDB7702, "You did not specify all svm parameters", ex); if (ex.getCode() == Cause.XDB800) throw new DbException(Cause.XDB7703, "The SVM parameters you provided do not " + "comply with the requirements", ex); } model.setId(r); return model; } /** * Add a task in the database. Tasks are added upon creation where te following * parameters are specified: <code>name, status</code> (Always set to <code>RUNNING</code> * when the task is created), <code>user</code> that created the task, the <code>algorithm * </code> and the <code>estimated duarion</code> in seconds. * Note that the <code>STATUS</code> of the Task is always set to <code>RUNNING</code> * irrespective of the specified status of the provided task and the corresponding * <code>HTTP STATUS</code> is always set to <code>202</code>. These values are updated * when the task is completed, cancelled or deleted. * @param task A task to be registered in the database, which corresponds to a * running task which just started running. * @throws DbException In case the task cannot be added in the database. This is the * case if the specified <code>user</code> does not correspond to some existing user of the * provided <code>name</code> is not valid, the provided task is <code>null</code> or some * other issue occurs (e.g. DB connectivity). * @see WriterHandler#add(org.opentox.ontology.components.YaqpComponent) add an arbitrary * component */ protected static Task addTask(Task task) throws DbException { // SOME PRELIMINARY CONSISTENCY CHECKS: if (task == null) { throw new NullPointerException("Cannot add a null task in the database"); } if (task.getDuration() < 0) { throw new DbException(Cause.XDB4001, "You provided a negative duration for a task"); } if (task.getName() == null) { throw new DbException(Cause.XDB4002, "A task has to have a not-null name."); } if (task.getAlgorithm() == null) { throw new DbException(Cause.XDB4003, "You did not provide an algorithm for the task you attempted to register"); } if (task.getUser() == null) { throw new DbException(Cause.XDB4004, "You need to specify a user/creator or your task"); } if (task.getUser().getEmail() == null) { throw new DbException(Cause.XDB4005, "You did not specify the email of the user that created the task"); } DbPipeline<QueryFood, HyperResult> addTaskPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_TASK); QueryFood food = new QueryFood( new String[][]{ {"NAME", task.getName()}, {"CREATED_BY", task.getUser().getEmail()}, {"ALGORITHM", task.getAlgorithm().getMeta().getName()}, {"DURATION", Integer.toString(task.getDuration())}, {"RESULT", ""} }); try { addTaskPipeline.process(food); YaqpLogger.LOG.log(new Trace(WriterHandler.class, "Task added: \n" + task)); } catch (DbException ex) { if (ex.getCode() == Cause.XDB800) { throw new DbException(Cause.XDH110, "Cannot add task due to some constraint violation (user email or algorithm)"); } throw new DbException(Cause.XDH2, "Unexpected condition while trying to add a task", ex); } return task; } /** * Add a new Omega model in the database. * @param model * @return * @throws DbException */ protected static OmegaModel addOmega(OmegaModel model) throws DbException { // SOME PRELIMINARY CONSISTENCY CHECKS: if (model == null) { throw new NullPointerException("Cannot add a null Omega in the database"); } if (model.getCode() == null) { throw new DbException(Cause.XDB9090, "You did not provided the code for the Omega Model you try to register"); } if (model.getUser() == null) { throw new DbException(Cause.XDB9091, "You did not provide any user fot the Omega Model"); } if (model.getUser().getEmail() == null) { throw new DbException(Cause.XDB9092, "The user/created you provided for the Omega Modle has undefined email address"); } if (model.getDataset() == null) { throw new DbException(Cause.XDB9093, "You did not provide the dataset for the Omega Model"); } try { new URI(model.getDataset()); } catch (URISyntaxException ex) { throw new DbException(Cause.XDB9094, "Invalid dataset uri :" + model.getDataset()); } int r = 0; DbPipeline<QueryFood, HyperResult> addOmegaPipeline = new DbPipeline<QueryFood, HyperResult>(PrepStmt.ADD_OMEGA_MODEL); User u = model.getUser(); String userEmail = u.getEmail(); QueryFood food = new QueryFood(); food.add("CODE", model.getCode()); food.add("CREATED_BY", userEmail); food.add("DATASET_URI", model.getDataset()); try { HyperResult result = addOmegaPipeline.process(food); if (result.getSize() == 1) { Iterator<String> it = result.getColumnIterator(1); r = Integer.parseInt(it.next()); }// TODO: Otherwise what? model.setId(r); return model; } catch (DbException ex) { if (ex.getCode() == Cause.XDB800) throw new DbException(Cause.XDB9095, "Most likely the reason for this" + " exception is that you tried to add an Omega Model which does not correspond to a user. Check the" + "existence of user with email :"+model.getUser().getEmail()); throw ex; } } }