edu.cornell.mannlib.vitro.webapp.servlet.setup.ContentModelSetup.java Source code

Java tutorial

Introduction

Here is the source code for edu.cornell.mannlib.vitro.webapp.servlet.setup.ContentModelSetup.java

Source

/* $This file is distributed under the terms of the license in /doc/license.txt$ */

package edu.cornell.mannlib.vitro.webapp.servlet.setup;

import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.ABOX_ASSERTIONS;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.APPLICATION_METADATA;
import static edu.cornell.mannlib.vitro.webapp.modelaccess.ModelNames.TBOX_ASSERTIONS;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.hp.hpl.jena.ontology.OntModel;
import com.hp.hpl.jena.rdf.model.Model;
import com.hp.hpl.jena.rdf.model.ResIterator;
import com.hp.hpl.jena.rdf.model.Resource;
import com.hp.hpl.jena.shared.Lock;
import com.hp.hpl.jena.util.ResourceUtils;
import com.hp.hpl.jena.util.iterator.ClosableIterator;
import com.hp.hpl.jena.vocabulary.RDF;

import edu.cornell.mannlib.vitro.webapp.dao.VitroVocabulary;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ContextModelAccess;
import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess;
import edu.cornell.mannlib.vitro.webapp.rdfservice.adapters.VitroModelFactory;
import edu.cornell.mannlib.vitro.webapp.startup.StartupStatus;

/**
 * Sets up the content models, OntModelSelectors and webapp DAO factories.
 * 
 * Why the firstTimeStartup flag? Because you can't ask a large SDB model
 * whether it is empty. SDB translates  this into a call to size(), which
 * in turn becomes find(null, null, null) and a count, and this gives an
 * OutOfMemoryError because it tries to read the entire model into memory.
 */
public class ContentModelSetup extends JenaDataSourceSetupBase implements javax.servlet.ServletContextListener {

    private static final Log log = LogFactory.getLog(ContentModelSetup.class);

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext ctx = sce.getServletContext();
        StartupStatus ss = StartupStatus.getBean(ctx);

        long begin = System.currentTimeMillis();
        setUpJenaDataSource(ctx);
        ss.info(this, secondsSince(begin) + " seconds to set up models and DAO factories");
    }

    private void setUpJenaDataSource(ServletContext ctx) {
        ContextModelAccess models = ModelAccess.on(ctx);
        boolean firstTimeStartup = false;

        Model applicationMetadataModel = models.getOntModel(APPLICATION_METADATA);
        if (applicationMetadataModel.isEmpty()) {
            firstTimeStartup = true;
            initializeApplicationMetadata(ctx, applicationMetadataModel);
        } else {
            checkForNamespaceMismatch(applicationMetadataModel, ctx);
        }

        OntModel baseABoxModel = models.getOntModel(ABOX_ASSERTIONS);
        if (firstTimeStartup) {
            RDFFilesLoader.loadFirstTimeFiles("abox", baseABoxModel, true);
        }
        RDFFilesLoader.loadEveryTimeFiles("abox", baseABoxModel);

        OntModel baseTBoxModel = models.getOntModel(TBOX_ASSERTIONS);
        if (firstTimeStartup) {
            RDFFilesLoader.loadFirstTimeFiles("tbox", baseTBoxModel, true);
        }
        RDFFilesLoader.loadEveryTimeFiles("tbox", baseTBoxModel);
    }

    private long secondsSince(long startTime) {
        return (System.currentTimeMillis() - startTime) / 1000;
    }

    /* ===================================================================== */

    /**
     * We need to read the RDF files and change the Portal from a blank node to
     * one with a URI in the default namespace.
     * 
     * Do this before adding the data to the RDFService-backed model, to avoid
     * warnings about editing a blank node.
     */
    private void initializeApplicationMetadata(ServletContext ctx, Model applicationMetadataModel) {
        OntModel temporaryAMModel = VitroModelFactory.createOntologyModel();
        RDFFilesLoader.loadFirstTimeFiles("applicationMetadata", temporaryAMModel, true);
        setPortalUriOnFirstTime(temporaryAMModel, ctx);
        applicationMetadataModel.add(temporaryAMModel);
    }

    /**
     * If we are loading the application metadata for the first time, set the
     * URI of the Portal based on the default namespace.
     */
    private void setPortalUriOnFirstTime(Model model, ServletContext ctx) {
        // Only a single portal is permitted in the initialization data
        Resource portalResource = null;
        ClosableIterator<Resource> portalResIt = model.listSubjectsWithProperty(RDF.type,
                model.getResource(VitroVocabulary.PORTAL));
        try {
            if (portalResIt.hasNext()) {
                Resource portalRes = portalResIt.next();
                if (portalRes.isAnon()) {
                    portalResource = portalRes;
                }
            }
        } finally {
            portalResIt.close();
        }

        if (portalResource != null) {
            ResourceUtils.renameResource(portalResource, getDefaultNamespace(ctx) + "portal1");
        }
    }

    /**
     * If we find a "portal1" portal (and we should), its URI should use the
     * default namespace.
     */
    private void checkForNamespaceMismatch(Model model, ServletContext ctx) {
        String expectedNamespace = getDefaultNamespace(ctx);

        List<Resource> portals = getPortal1s(model);

        if (!portals.isEmpty() && noPortalForNamespace(portals, expectedNamespace)) {
            // There really should be only one portal 1, but if there happen to 
            // be multiple, just arbitrarily pick the first in the list.
            Resource portal = portals.get(0);
            String oldNamespace = portal.getNameSpace();
            renamePortal(portal, expectedNamespace, model);
            StartupStatus ss = StartupStatus.getBean(ctx);
            ss.warning(this, "\nThe default namespace has been changed \n" + "from " + oldNamespace + "\nto "
                    + expectedNamespace + ".\n" + "The application will function normally, but "
                    + "any individuals in the \n" + oldNamespace + " " + "namespace will need to have their URIs \n"
                    + "changed in order to be served as linked data. "
                    + "You can use the Ingest Tools \nto change the " + "URIs for a batch of resources.");
        }
    }

    private List<Resource> getPortal1s(Model model) {
        List<Resource> portals = new ArrayList<Resource>();
        try {
            model.enterCriticalSection(Lock.READ);
            ResIterator portalIt = model.listResourcesWithProperty(RDF.type, PORTAL);
            while (portalIt.hasNext()) {
                Resource portal = portalIt.nextResource();
                if ("portal1".equals(portal.getLocalName())) {
                    portals.add(portal);
                }
            }
        } finally {
            model.leaveCriticalSection();
        }
        return portals;
    }

    private boolean noPortalForNamespace(List<Resource> portals, String expectedNamespace) {
        for (Resource portal : portals) {
            if (expectedNamespace.equals(portal.getNameSpace())) {
                return false;
            }
        }
        return true;
    }

    private void renamePortal(Resource portal, String namespace, Model model) {
        model.enterCriticalSection(Lock.WRITE);
        try {
            ResourceUtils.renameResource(portal, namespace + portal.getLocalName());
        } finally {
            model.leaveCriticalSection();
        }
    }

    /* ===================================================================== */

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // Nothing to do.
    }

}