/* The contents of this file are subject to the license and copyright terms * detailed in the license directory at the root of the source tree (also * available online at http://fedora-commons.org/license/). */ package org.fcrepo.server; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.sql.Connection; import java.util.Date; import java.util.Map; import org.w3c.dom.Element; import org.fcrepo.common.Constants; import org.fcrepo.common.Models; import org.fcrepo.common.PID; import org.fcrepo.common.rdf.RDFName; import org.fcrepo.server.errors.ModuleInitializationException; import org.fcrepo.server.errors.ServerInitializationException; import org.fcrepo.server.storage.ConnectionPool; import org.fcrepo.server.storage.DOManager; import org.fcrepo.server.storage.DOWriter; import org.fcrepo.server.utilities.SQLUtility; import org.fcrepo.server.utilities.status.ServerState; import org.fcrepo.server.utilities.status.ServerStatusFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Fedora Server. * * @author Chris Wilper */ public class BasicServer extends Server { private static final Logger logger = LoggerFactory.getLogger(BasicServer.class); public BasicServer(File fedoraHomeDir) throws ServerInitializationException, ModuleInitializationException { super(fedoraHomeDir); } public BasicServer(Element rootElement, File fedoraHomeDir) throws ServerInitializationException, ModuleInitializationException { super(rootElement, fedoraHomeDir); } public BasicServer(Map<String,String> params, File fedoraHomeDir) throws ServerInitializationException, ModuleInitializationException { super(params, fedoraHomeDir); } @Override public void initServer() throws ServerInitializationException { super.initServer(); String fedoraServerHost = null; String fedoraServerPort = null; // fedoraServerHost (required) fedoraServerHost = getParameter("fedoraServerHost"); if (fedoraServerHost == null) { throw new ServerInitializationException("Parameter fedoraServerHost " + "not given, but it's required."); } // fedoraServerPort (required) fedoraServerPort = getParameter("fedoraServerPort"); if (fedoraServerPort == null) { throw new ServerInitializationException("Parameter fedoraServerPort " + "not given, but it's required."); } logger.info("Fedora Version: {}", Server.VERSION); logger.info("Fedora Build Date: {}", Server.BUILD_DATE); ServerStatusFile status = getStatusFile(); try { status.append(ServerState.STARTING, "Fedora Version: " + Server.VERSION); status.append(ServerState.STARTING, "Fedora Build Date: " + Server.BUILD_DATE); status.append(ServerState.STARTING, "Server Host Name: " + fedoraServerHost); status.append(ServerState.STARTING, "Server Port: " + fedoraServerPort); } catch (Exception e) { e.printStackTrace(); throw new ServerInitializationException("Unable to write to status file: " + e.getMessage()); } } /** * Gets the names of the roles that are required to be fulfilled by modules * specified in this server's configuration file. * * @return String[] The roles. */ @Override public String[] getRequiredModuleRoles() { return new String[] {DOManager.class.getName()}; } @Override public void postInitServer() throws ServerInitializationException { // check for system objects and pre-ingest them if necessary DOManager doManager = (DOManager) getModule(DOManager.class.getName()); try { boolean firstRun = checkFirstRun(); preIngestIfNeeded(firstRun, doManager, Models.CONTENT_MODEL_3_0); preIngestIfNeeded(firstRun, doManager, Models.FEDORA_OBJECT_3_0); preIngestIfNeeded(firstRun, doManager, Models.SERVICE_DEFINITION_3_0); preIngestIfNeeded(firstRun, doManager, Models.SERVICE_DEPLOYMENT_3_0); checkRebuildHasRun(firstRun); } catch (Exception e) { throw new ServerInitializationException("Failed to ingest " + "system object(s)", e); } } private boolean checkFirstRun() throws IOException { File hasStarted = new File(FEDORA_HOME, "server/fedora-internal-use/has-started.txt"); if (hasStarted.exists()) { return false; } else { hasStarted.createNewFile(); return true; } } /** * Ingests the given system object if it doesn't exist, OR if it * exists, but this instance of Fedora has never been started. * This ensures that, upon upgrade, the old system object * is replaced with the new one. */ private void preIngestIfNeeded(boolean firstRun, DOManager doManager, RDFName objectName) throws Exception { PID pid = new PID(objectName.uri.substring("info:fedora/".length())); boolean exists = doManager.objectExists(pid.toString()); if (exists && firstRun) { logger.info("Purging old system object: {}", pid); Context context = ReadOnlyContext.getContext(null, null, null, false); DOWriter w = doManager.getWriter(USE_DEFINITIVE_STORE, context, pid.toString()); w.remove(); try { w.commit("Purged by Fedora at startup (to be re-ingested)"); exists = false; } finally { doManager.releaseWriter(w); } } if (!exists) { logger.info("Ingesting new system object: {}", pid); InputStream xml = getStream("org/fcrepo/server/resources/" + pid.toFilename() + ".xml"); Context context = ReadOnlyContext.getContext(null, null, null, false); DOWriter w = doManager.getIngestWriter(USE_DEFINITIVE_STORE, context, xml, Constants.FOXML1_1.uri, "UTF-8", null); try { w.commit("Pre-ingested by Fedora at startup"); } finally { doManager.releaseWriter(w); } } } private InputStream getStream(String path) throws IOException { InputStream stream = getClass().getClassLoader().getResourceAsStream( path); if (stream == null) { throw new IOException("Classloader cannot find resource: " + path); } else { return stream; } } @SuppressWarnings("deprecation") protected void checkRebuildHasRun(boolean firstRun) throws Exception { Connection conn = null; ConnectionPool cpm = SQLUtility.getConnectionPool(getConfig()); try { conn = cpm.getReadWriteConnection(); long mostRecentRebuildDate = SQLUtility.getMostRecentRebuild(conn); if (firstRun && mostRecentRebuildDate == -1) { // if first run and rebuildStatus has NO ROWS, create one SQLUtility.recordSuccessfulRebuild(conn, System.currentTimeMillis()); } else { // otherwise, verify that the most recent rebuild was successful boolean rebuildFinished = SQLUtility.getRebuildStatus(conn, mostRecentRebuildDate); if (!rebuildFinished) { throw new ServerInitializationException( "The SQL Rebuild attempted on " + new Date(mostRecentRebuildDate).toGMTString() + " did not finish successfully, which may compromise" + " the repo. Please re-run the SQL rebuild."); } } } finally { if (conn != null) cpm.free(conn); } } }