podd.util.WebappInitialisationUtil.java Source code

Java tutorial

Introduction

Here is the source code for podd.util.WebappInitialisationUtil.java

Source

/*
 * Copyright (c) 2009 - 2010. School of Information Technology and Electrical
 * Engineering, The University of Queensland.  This software is being developed
 * for the "Phenomics Ontoogy Driven Data Management Project (PODD)" project.
 * PODD is a National e-Research Architecture Taskforce (NeAT) project
 * co-funded by ANDS and ARCS.
 *
 * PODD 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.
 *
 * PODD 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 PODD.  If not, see <http://www.gnu.org/licenses/>.
 */

package podd.util;

import info.aduna.collections.iterators.CloseableIterator;
import org.apache.log4j.Logger;
import org.apache.tika.io.IOUtils;
import org.hibernate.SessionFactory;
import org.openrdf.repository.RepositoryConnection;
import org.openrdf.rio.RDFFormat;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.io.OWLOntologyDocumentTarget;
import org.semanticweb.owlapi.io.RDFXMLOntologyFormat;
import org.semanticweb.owlapi.io.StringDocumentTarget;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLClassAxiom;
import org.semanticweb.owlapi.model.OWLClassExpression;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyChangeException;
import org.semanticweb.owlapi.model.OWLOntologyIRIMapper;
import org.semanticweb.owlapi.model.OWLOntologyManager;
//import org.semanticweb.owlapi.model.OWLOntologyURIMapper;
import org.semanticweb.owlapi.model.OWLSubClassOfAxiom;
import org.springframework.core.io.AbstractResource;
import org.springframework.core.io.Resource;
import podd.client.PoddClientException;
import podd.client.owl.PoddClientOntologyRegistry;
import podd.dataaccess.AdministrationSettingsDAO;
import podd.dataaccess.DatastoreRegistryDAO;
import podd.dataaccess.PoddConceptDAO;
import podd.dataaccess.RepositoryRoleDAO;
import podd.dataaccess.UserDAO;
import podd.dataaccess.exception.DataAccessException;
import podd.dataaccess.hibernate.HibernateSessionHelper;
import podd.model.EntityFactory;
import podd.model.datastore.Datastore;
import podd.model.entity.PoddConcept;
import podd.model.user.AdministrationSettings;
import podd.model.user.RepositoryRole;
import podd.model.user.User;
import podd.model.user.RepositoryRole;
import podd.owl.OntologyHelper;
import podd.owl.OntologyRegistry;
import podd.triples.SesameRepoWrapper;
import podd.util.common.vocabulary.EnumerableRDFNamespace;
import uk.ac.manchester.cs.owl.owlapi.OWLOntologyIRIMapperImpl;
//import uk.ac.manchester.cs.owl.OWLOntologyURIMapperImpl;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import org.semanticweb.owlapi.model.IRI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import static org.semanticweb.owlapi.model.AxiomType.SUBCLASS_OF;
import static podd.model.user.AdministrationSettings.SELF_REGISTRATION_ENABLED;
import static podd.model.user.AdministrationSettings.USER_STATUS_ACTIVE;
import static podd.model.user.UserStatus.ACTIVE;
import static podd.util.common.Constants.PODD_URI;
import static podd.util.common.vocabulary.PoddModelNamespace.PODD_MODEL;
import static podd.util.common.vocabulary.PoddNamespaceHelper.PODD_NAMESPACE_HELPER;

/**
 * @author Yuan-Fang Li
 * @version $Id$
 */

public class WebappInitialisationUtil {
    private static final int TWENTY_MILLISECONDS = 20;
    private static final String USERNAME_KEY = "userName";

    private final Logger logger = Logger.getLogger(getClass());

    private User adminUser;
    private Resource repoAdminUserResource;
    private Resource datastoreResource;

    private AbstractResource ontologyDirectory;
    private String ontologyNames;
    private boolean toReset;
    private boolean toIngest;
    private UserDAO userDao;
    private DatastoreRegistryDAO datastoreRegistryDao;
    private RepositoryRoleDAO rrDao;
    private AdministrationSettingsDAO adminSettingsDao;
    private PoddConceptDAO conceptDao;
    private OntologyHelper ontologyHelper;
    private EntityFactory entityFactory;
    private SesameRepoWrapper repoWrapper;

    private OntologyRegistry ontologyRegistry;
    private List<File> ontologyFiles;
    private SessionFactory sessionFactory;

    public void setToReset(boolean toRest) {
        this.toReset = toRest;
    }

    public void setOntologyDirectory(AbstractResource ontologyDirectory) {
        this.ontologyDirectory = ontologyDirectory;
    }

    public void setOntologyNames(String ontologies) {
        this.ontologyNames = ontologies;
    }

    public void setRepoAdminUserResource(Resource repoAdminUserResource) {
        this.repoAdminUserResource = repoAdminUserResource;
    }

    public void setDatastoreResource(Resource datastoreResource) {
        this.datastoreResource = datastoreResource;
    }

    public void setUserDao(UserDAO userDao) {
        this.userDao = userDao;
    }

    public void setDatastoreRegistryDao(DatastoreRegistryDAO datastoreRegistryDao) {
        this.datastoreRegistryDao = datastoreRegistryDao;
    }

    public void setConceptDao(PoddConceptDAO conceptDao) {
        this.conceptDao = conceptDao;
    }

    public void setRrDao(RepositoryRoleDAO rrDao) {
        this.rrDao = rrDao;
    }

    public void setAdminSettingsDao(AdministrationSettingsDAO adminSettingsDao) {
        this.adminSettingsDao = adminSettingsDao;
    }

    public void setOntologyHelper(OntologyHelper ontologyHelper) {
        this.ontologyHelper = ontologyHelper;
    }

    public void setEntityFactory(EntityFactory entityFactory) {
        this.entityFactory = entityFactory;
    }

    public void setOntologyRegistry(OntologyRegistry ontologyRegistry) {
        this.ontologyRegistry = ontologyRegistry;
    }

    public void setToIngest(boolean toIngest) {
        this.toIngest = toIngest;
    }

    public void setRepoWrapper(SesameRepoWrapper repoWrapper) {
        this.repoWrapper = repoWrapper;
    }

    public SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void doInitialize() throws Exception {
        HibernateSessionHelper.openSession(sessionFactory);
        try {
            if (toReset) {
                logger.info("Initializing PODD repository.");
                setupDefaultRepoRoles();
                setupDefaultAdministrationSettings();
                adminUser = createRepoAdminUser(repoAdminUserResource);
                createDefaultDatastore(datastoreResource);
                processAndAddOWLClasses();
                initializePoddClientOntologyRegistry();
                addOntologiesToTripleStore();
            }
        } finally {
            HibernateSessionHelper.closeSession(sessionFactory);
        }
    }

    private void addOntologiesToTripleStore() throws Exception {
        RDFXMLOntologyFormat format = new RDFXMLOntologyFormat();
        final RepositoryConnection conn = repoWrapper.getConnection();
        try {
            for (OWLOntology ont : ontologyRegistry.getOntologies()) {
                OWLOntologyDocumentTarget target = new StringDocumentTarget();
                ont.getOWLOntologyManager().saveOntology(ont, format, target);
                final InputStream in = IOUtils.toInputStream(target.toString());
                try {
                    conn.add(in, ont.getOntologyID().getOntologyIRI().toString(), RDFFormat.RDFXML);
                    logger.info(
                            "Added ontology to triple store: " + ont.getOntologyID().getOntologyIRI().toString());
                } finally {
                    IOUtils.closeQuietly(in);
                }
            }
            conn.commit();
        } finally {
            conn.close();
        }
    }

    private void processAndAddOWLClasses() throws DataAccessException {
        ontologyFiles = new LinkedList<File>();
        for (String filename : ontologyNames.split(",")) {
            try {
                File file = new File(ontologyDirectory.getFile().getAbsolutePath() + File.separator + filename);
                ontologyFiles.add(file);
            } catch (IOException e) {
                throw new DataAccessException("Error loading ontology from directory: "
                        + ontologyDirectory.getFilename() + " : " + filename, e);
            }
        }
        ingestPoddConceptsFromOntologies();
    }

    /**
     * Initialize the PODD Client ontology registry
     * @throws PoddClientException
     */
    private void initializePoddClientOntologyRegistry() throws PoddClientException {
        List<IRI> ontologyURIs = new ArrayList<IRI>();
        for (File file : ontologyFiles) {
            ontologyURIs.add(IRI.create(file.toURI()));
        }

        PoddClientOntologyRegistry.getInstance().setModels(ontologyURIs);
    }

    public User getRepoAdmin() {
        return adminUser;
    }

    private User createRepoAdminUser(Resource resource) {
        try {
            File propertyFile = resource.getFile();
            final FileReader fileReader = new FileReader(propertyFile);
            Properties properties = new Properties();
            properties.load(fileReader);

            // try to load the user and if it doesn't exist create a new one
            String username = properties.get(USERNAME_KEY).toString();
            User admin = userDao.loadByUserName(username);
            if (null == admin) {
                admin = entityFactory.createUser(null);
            }
            // add properties to the user
            for (Object key : properties.keySet()) {
                final String value = properties.get(key).toString();
                String methodName = getSetterMethodName((String) key);
                final Method method = User.class.getDeclaredMethod(methodName, String.class);
                method.invoke(admin, value);
            }
            admin.setStatus(ACTIVE);
            admin.setRepositoryRole(rrDao.getRepositoryRole(RepositoryRole.REPOSITORY_ADMINISTRATOR.getName()));
            logger.info("Creating repository administrator user: " + admin.getUserName());
            userDao.saveOrUpdate(admin);
            return admin;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private void createDefaultDatastore(Resource resource) {
        if (null == resource)
            return;
        try {
            File propertyFile = resource.getFile();
            final FileReader fileReader = new FileReader(propertyFile);
            Properties properties = new Properties();
            properties.load(fileReader);

            // try to load the datastore and if it doesn't exist create a new one
            String ip = properties.get("ip").toString();
            int port = Integer.parseInt(properties.get("port").toString());
            String login = properties.get("login").toString();
            String defaultDirectory = properties.get("defaultDirectory").toString();
            Datastore datastore = datastoreRegistryDao.loadByIP(ip);
            if (null == datastore) {
                datastore = new Datastore(ip, port, login, defaultDirectory);
            } else {
                datastore.setPort(port);
                datastore.setLoginId(login);
                datastore.setDefaultDirectory(defaultDirectory);
            }
            datastore.setAccessMethod(properties.get("accessMethod").toString());
            logger.info("Creating default datastore: " + datastore.getLoginId() + "@" + datastore.getIp() + ":"
                    + datastore.getPort());
            datastoreRegistryDao.saveOrUpdate(datastore);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private String getSetterMethodName(String fieldName) {
        String methodName = "set";
        String capitalFieldName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        return methodName + capitalFieldName;
    }

    private void ingestPoddConceptsFromOntologies() {
        Map<OWLClass, Set<OWLAxiom>> conceptClasses = new HashMap<OWLClass, Set<OWLAxiom>>();
        try {
            PODD_NAMESPACE_HELPER.addNamespace(PODD_MODEL.uri, PODD_MODEL);
            OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
            final OWLClass poddClass = manager.getOWLDataFactory()
                    .getOWLClass(IRI.create(PODD_MODEL.PODD_CONCEPT.getURI()));
            final OWLOntologyIRIMapperImpl mapper = new OWLOntologyIRIMapperImpl();
            manager.addIRIMapper(mapper);
            for (File file : ontologyFiles) {
                processOneOntology(file, conceptClasses, poddClass, mapper, manager);
            }
            if (toIngest) {
                logger.info("Ingesting a total of " + conceptClasses.size() + " concepts.");
                int i = 0;
                for (OWLClass cls : conceptClasses.keySet()) {
                    createPoddConcept(cls, manager, conceptClasses.get(cls), ++i);
                }
            }
        } catch (Exception e) {
            logger.error("Error ingesting concepts", e);
            throw new RuntimeException(e);
        }
    }

    private void processOneOntology(File file, Map<OWLClass, Set<OWLAxiom>> map, OWLClass poddClass,
            OWLOntologyIRIMapperImpl mapper, OWLOntologyManager manager) throws Exception {
        //        OWLOntologyManager manager = ontologyRegistry.getOntologyManager();
        logger.debug("Loading ontology file: " + file.toURI().toString());
        final OWLOntology ontology = manager.loadOntologyFromOntologyDocument(file);
        mapper.addMapping(ontology.getOntologyID().getOntologyIRI(), IRI.create(file.toURI()));
        ontologyRegistry.addModel(ontology);
        enrichNamespace(ontology);
        final Set<OWLSubClassOfAxiom> owlSubClassAxiomSet = ontology.getAxioms(SUBCLASS_OF);
        for (OWLSubClassOfAxiom axiom : owlSubClassAxiomSet) {
            final OWLClassExpression owlClass = axiom.getSubClass();
            if (!owlClass.isAnonymous()
                    && ontologyRegistry.isSubClassOf(owlClass.asOWLClass(), poddClass, ontology)) {
                addToMap(owlClass.asOWLClass(), ontology, map);
            }
        }
    }

    private void enrichNamespace(OWLOntology ontology) throws URISyntaxException {
        String namespace = ontology.getOntologyID().getOntologyIRI().toString();
        if (!namespace.endsWith("#")) {
            namespace = namespace + "#";
        }
        if (null == PODD_NAMESPACE_HELPER.getNamespace(namespace)) {
            PODD_NAMESPACE_HELPER.addNewNamespace(namespace);
        }
        addOrUpdateEntities(ontology, PODD_NAMESPACE_HELPER.getNamespace(namespace));
    }

    private void addOrUpdateEntities(OWLOntology ontology, EnumerableRDFNamespace namespace) {
        final Set<OWLEntity> entities = ontology.getSignature();
        for (OWLEntity entity : entities) {
            if (entity.getIRI().toString().startsWith(namespace.uri)) {
                namespace.addElement(entity.getIRI());
            }
        }
    }

    private OWLOntologyIRIMapper createOntologyMapper() {
        final OWLOntologyIRIMapperImpl mapper = new OWLOntologyIRIMapperImpl();
        for (File file : ontologyFiles) {
            final String ontName = file.getName().substring(0, file.getName().indexOf('.'));
            mapper.addMapping(IRI.create(PODD_URI + ontName), IRI.create(file.toURI()));
        }
        return mapper;
    }

    private void addToMap(OWLClass owlClass, OWLOntology ontology, Map<OWLClass, Set<OWLAxiom>> map) {
        final Set<OWLClassAxiom> classAxiomSet = ontology.getAxioms(owlClass);
        Set<OWLAxiom> set = map.get(owlClass);
        if (null == set) {
            set = new HashSet<OWLAxiom>();
        }
        set.addAll(classAxiomSet);
        map.put(owlClass, set);

        set.addAll(ontology.getAnnotationAssertionAxioms(owlClass.getIRI()));
    }

    private void createPoddConcept(OWLClass owlClass, OWLOntologyManager manager, Set<OWLAxiom> axiomSet, int idx)
            throws Exception {
        //        OWLOntologyManager manager = ontologyRegistry.getOntologyManager();
        final String conceptName = owlClass.getIRI().toString();

        logger.info("conceptName=" + conceptName);

        // try to load the concept and if it doesn't exist create a new one
        PoddConcept concept = getFirstConcept(conceptDao.loadByLocalName(conceptName));
        if (null != concept) {
            final OWLOntology ontology = concept.getCurrentDefinition();
            boolean isChanged = ontologyChanged(axiomSet, concept, ontology, owlClass);
            if (isChanged) {
                conceptDao.update(concept);
            }
        } else {
            concept = createConcept(axiomSet, conceptName, manager, owlClass);
        }
        if (null != concept) {
            logger.info("Ingested concept " + idx + ": " + concept.getConceptName());
        }
    }

    private PoddConcept createConcept(Set<OWLAxiom> axiomSet, String conceptName, OWLOntologyManager manager,
            OWLClass owlClass) throws Exception {
        PoddConcept concept = entityFactory.createPoddConcept(adminUser);
        concept.setConceptName(conceptName);
        concept.setLabel("Predefined concept: " + conceptName);
        //IRI baseUri = IRI.create(PODD_MODEL.uri.replace('#', '/') + conceptName + "_Ontology");
        IRI baseUri = IRI.create(conceptName + "_Ontology");
        final OWLOntology ontology = ontologyHelper.getTimestampedOntology(baseUri);
        boolean isChanged = ontologyChanged(axiomSet, concept, ontology, owlClass);
        if (isChanged) {
            conceptDao.save(concept);
        }
        return concept;
    }

    private boolean ontologyChanged(Set<OWLAxiom> axiomSet, PoddConcept concept, OWLOntology ontology,
            OWLClass owlClass) throws OWLOntologyChangeException, DataAccessException {
        //        try {
        final boolean sameOntology = testSameOntology(ontology, owlClass, axiomSet);
        if (!sameOntology) {
            ParameterUtil.wait(TWENTY_MILLISECONDS);
            ontology.getOWLOntologyManager().addAxioms(ontology, axiomSet);
            concept.setCurrentDefinition(ontology);
            return true;
        } else {
            return false;
        }
        //        } finally {
        //           ontology.getOWLOntologyManager().removeOntology(ontology);
        //        }
    }

    private boolean testSameOntology(OWLOntology curOntology, OWLClass concept, Set<OWLAxiom> axiomSet) {
        final Set<OWLAxiom> oldAxiomSet = new HashSet<OWLAxiom>();
        oldAxiomSet.addAll(curOntology.getAxioms(concept));
        oldAxiomSet.addAll(curOntology.getAnnotationAssertionAxioms(concept.getIRI()));
        final int oldCount = oldAxiomSet.size();
        final int newCount = axiomSet.size();
        return oldCount == newCount && oldAxiomSet.containsAll(axiomSet);
    }

    private void setupDefaultRepoRoles() {
        try {
            saveOrUpdateRole(RepositoryRole.PUBLIC);
            saveOrUpdateRole(RepositoryRole.REPOSITORY_USER);
            saveOrUpdateRole(RepositoryRole.PROJECT_CREATOR);
            saveOrUpdateRole(RepositoryRole.REPOSITORY_ADMINISTRATOR);
        } catch (DataAccessException e) {
            throw new RuntimeException(e);
        }
    }

    private void saveOrUpdateRole(RepositoryRole role) throws DataAccessException {
        RepositoryRole repositoryRole = rrDao.getRepositoryRole(role.getName());
        if (null == repositoryRole) {
            repositoryRole = role;
        } else {
            repositoryRole.setDescription(role.getDescription());
        }
        rrDao.saveOrUpdate(repositoryRole);
    }

    private void setupDefaultAdministrationSettings() throws DataAccessException {
        saveOrUpdateAdminSetting(SELF_REGISTRATION_ENABLED);
        saveOrUpdateAdminSetting(USER_STATUS_ACTIVE);
    }

    private void saveOrUpdateAdminSetting(AdministrationSettings setting) throws DataAccessException {
        AdministrationSettings adminSetting = adminSettingsDao.getAdministrationSetting(setting.getName());
        if (null == adminSetting) {
            adminSetting = setting;
        } else {
            adminSetting.setValue(setting.getValue());
        }
        adminSettingsDao.saveOrUpdate(adminSetting);
    }

    private <T> T getFirstConcept(CloseableIterator<T> iterator) {
        try {
            if (iterator.hasNext()) {
                return iterator.next();
            } else {
                return null;
            }
        } finally {
            iterator.close();
        }
    }
}