diff --git a/dspace-api/pom.xml b/dspace-api/pom.xml index fe07777d26..65bcd1d248 100644 --- a/dspace-api/pom.xml +++ b/dspace-api/pom.xml @@ -208,7 +208,7 @@ - + org.codehaus.mojo build-helper-maven-plugin 1.7 @@ -263,10 +263,10 @@ org.apache.lucene lucene-analyzers-common - - org.apache.lucene - lucene-queryparser - + + org.apache.lucene + lucene-queryparser + commons-cli commons-cli @@ -483,11 +483,11 @@ 2.0.6 - - org.elasticsearch - elasticsearch - 0.90.3 - + + org.elasticsearch + elasticsearch + 0.90.3 + com.coverity.security @@ -508,6 +508,10 @@ postgresql + + org.slf4j + slf4j-api + diff --git a/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java b/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java new file mode 100644 index 0000000000..f73f3d24dc --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/util/AbstractDSpaceWebapp.java @@ -0,0 +1,191 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.app.util; + +import java.io.IOException; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import org.apache.commons.httpclient.HttpClient; +import org.apache.commons.httpclient.HttpException; +import org.apache.commons.httpclient.HttpMethod; +import org.apache.commons.httpclient.HttpStatus; +import org.apache.commons.httpclient.methods.HeadMethod; +import org.dspace.core.ConfigurationManager; +import org.dspace.core.Context; +import org.dspace.storage.rdbms.DatabaseManager; +import org.dspace.storage.rdbms.TableRow; +import org.dspace.storage.rdbms.TableRowIterator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Represent a DSpace application while it is running. This helps us report + * which applications *are* running, by exposing a record that can be viewed + * externally. + * + * @author mwood + */ +abstract public class AbstractDSpaceWebapp + implements DSpaceWebappMXBean +{ + private static final Logger log = LoggerFactory.getLogger(AbstractDSpaceWebapp.class); + + protected String kind; + + protected Date started; + + protected String url; + + private TableRow row; + + /** Prevent null instantiation. */ + protected AbstractDSpaceWebapp() + { + } + + /** + * Construct a particular kind of DSpace application. + * + * @param kind what kind of application is this? (XMLUI, JSPUI, etc.) + */ + public AbstractDSpaceWebapp(String kind) + { + this.kind = kind; + + started = new Date(); + + url = ConfigurationManager.getProperty("dspace.url"); + if (null == url) + { + throw new IllegalStateException("dspace.url is undefined"); + } + } + + /** Record that this application is running. */ + public void register() + { + // Create the database entry + Timestamp now = new Timestamp(started.getTime()); + try { + Context context = new Context(); + row = DatabaseManager.create(context, "Webapp"); + row.setColumn("AppName", kind); + row.setColumn("URL", url); + row.setColumn("Started", now); + row.setColumn("isUI", isUI() ? 1 : 0); // update won't widen boolean to integer + DatabaseManager.update(context, row); + context.complete(); + } catch (SQLException e) { + log.error("Failed to record startup in Webapp table.", e); + } + } + + /** Record that this application is not running. */ + public void deregister() + { + // Remove the database entry + try { + Context context = new Context(); + DatabaseManager.delete(context, row); + context.complete(); + } catch (SQLException e) { + log.error("Failed to record shutdown in Webapp table.", e); + } + } + + /** Return the list of running applications. */ + static public List getApps() + { + ArrayList apps = new ArrayList(); + TableRowIterator tri; + + Context context = null; + HttpMethod request = null; + try { + context = new Context(); + tri = DatabaseManager.queryTable(context, "Webapp", + "SELECT * FROM Webapp"); + + for (TableRow row : tri.toList()) + { + DSpaceWebapp app = new DSpaceWebapp(); + app.kind = row.getStringColumn("AppName"); + app.url = row.getStringColumn("URL"); + app.started = row.getDateColumn("Started"); + app.uiQ = row.getBooleanColumn("isUI"); + + HttpClient client = new HttpClient(); + request = new HeadMethod(app.url); + int status = client.executeMethod(request); + request.getResponseBody(); + if (status != HttpStatus.SC_OK) + { + DatabaseManager.delete(context, row); + context.commit(); + continue; + } + + apps.add(app); + } + } catch (SQLException e) { + log.error("Unable to list running applications", e); + } catch (HttpException e) { + log.error("Failure checking for a running webapp", e); + } catch (IOException e) { + log.error("Failure checking for a running webapp", e); + } finally { + if (null != request) + { + request.releaseConnection(); + } + if (null != context) + { + context.abort(); + } + } + + return apps; + } + + /** Container for retrieved database rows. */ + static private class DSpaceWebapp + extends AbstractDSpaceWebapp + { + private boolean uiQ; + + @Override + public boolean isUI() + { + return uiQ; + } + } + + /* DSpaceWebappMXBean methods */ + + @Override + public String getKind() + { + return kind; + } + + @Override + public String getURL() + { + return url; + } + + @Override + public String getStarted() + { + return started.toString(); + } +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java b/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java index 47f285058a..102af41e1a 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java +++ b/dspace-api/src/main/java/org/dspace/app/util/DSpaceContextListener.java @@ -23,22 +23,24 @@ import java.util.Enumeration; /** * Class to initialize / cleanup resources used by DSpace when the web application - * is started or stopped + * is started or stopped. */ public class DSpaceContextListener implements ServletContextListener { private static Logger log = Logger.getLogger(DSpaceContextListener.class); /** - * The DSpace config parameter, this is where the path to the DSpace - * configuration file can be obtained + * Name of the context parameter giving the path to the DSpace configuration file. */ public static final String DSPACE_CONFIG_PARAMETER = "dspace-config"; - + + private AbstractDSpaceWebapp webApp; + /** - * Initialize any resources required by the application + * Initialize any resources required by the application. * @param event */ + @Override public void contextInitialized(ServletContextEvent event) { @@ -114,6 +116,23 @@ public class DSpaceContextListener implements ServletContextListener "either the local servlet or global context.\n\n",e); } + /** + * Stage 3 + * + * Register that this application is running. + */ + + try { + Class webappClass = Class.forName("org.dspace.utils.DSpaceWebapp"); + webApp = (AbstractDSpaceWebapp) webappClass.newInstance(); + webApp.register(); + } catch (ClassNotFoundException ex) { + event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); + } catch (InstantiationException ex) { + event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); + } catch (IllegalAccessException ex) { + event.getServletContext().log("Can't create webapp MBean: " + ex.getMessage()); + } } /** @@ -121,8 +140,11 @@ public class DSpaceContextListener implements ServletContextListener * * @param event */ + @Override public void contextDestroyed(ServletContextEvent event) { + webApp.deregister(); + try { // Remove the database pool diff --git a/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java b/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java new file mode 100644 index 0000000000..46c50b5744 --- /dev/null +++ b/dspace-api/src/main/java/org/dspace/app/util/DSpaceWebappMXBean.java @@ -0,0 +1,29 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.app.util; + +/** + * MBean type for discovering DSpace web applications. + * + * @author mwood + */ +public interface DSpaceWebappMXBean +{ + /** Is this webapp a user interface? False if machine interface such as SWORD. */ + public boolean isUI(); + + /** What kind of webapp? XMLUI, OAI, etc. */ + public String getKind(); + + /** What is the base URL of this application? */ + public String getURL(); + + /** When did this application start? */ + public String getStarted(); +} diff --git a/dspace-api/src/main/java/org/dspace/app/util/Version.java b/dspace-api/src/main/java/org/dspace/app/util/Version.java index b84ca09a3c..ad7cc685dc 100644 --- a/dspace-api/src/main/java/org/dspace/app/util/Version.java +++ b/dspace-api/src/main/java/org/dspace/app/util/Version.java @@ -49,7 +49,14 @@ public class Version sys.get("os.arch"), sys.get("os.version")); - // TODO UIs used + // UIs used + List apps = AbstractDSpaceWebapp.getApps(); + System.out.println(" Applications:"); + for (AbstractDSpaceWebapp app : apps) + { + System.out.printf(" %s at %s\n", + app.getKind(), app.getURL()); + } // Is Discovery available? ConfigurationService config = new DSpace().getConfigurationService(); @@ -57,11 +64,13 @@ public class Version List consumerList = Arrays.asList(consumers.split("\\s*,\\s*")); if (consumerList.contains("discovery")) { - System.out.println("Discovery enabled."); + System.out.println(" Discovery: enabled."); } + + // Is Lucene search enabled? if (consumerList.contains("search")) { - System.out.println("Lucene search enabled."); + System.out.println(" Lucene search: enabled."); } // Java version diff --git a/dspace-jspui/src/main/java/org/dspace/utils/DSpaceWebapp.java b/dspace-jspui/src/main/java/org/dspace/utils/DSpaceWebapp.java new file mode 100644 index 0000000000..33b5b7d039 --- /dev/null +++ b/dspace-jspui/src/main/java/org/dspace/utils/DSpaceWebapp.java @@ -0,0 +1,31 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.utils; + +import org.dspace.app.util.AbstractDSpaceWebapp; + +/** + * An MBean to identify this web application. + * + * @author mwood + */ +public class DSpaceWebapp + extends AbstractDSpaceWebapp +{ + public DSpaceWebapp() + { + super("JSPUI"); + } + + @Override + public boolean isUI() + { + return true; + } +} diff --git a/dspace-xmlui/pom.xml b/dspace-xmlui/pom.xml index 938d5ff1d6..8b949202bd 100644 --- a/dspace-xmlui/pom.xml +++ b/dspace-xmlui/pom.xml @@ -97,6 +97,10 @@ org.dspace dspace-api + + org.dspace + dspace-services + diff --git a/dspace-xmlui/src/main/java/org/dspace/utils/DSpaceWebapp.java b/dspace-xmlui/src/main/java/org/dspace/utils/DSpaceWebapp.java new file mode 100644 index 0000000000..25a1df760c --- /dev/null +++ b/dspace-xmlui/src/main/java/org/dspace/utils/DSpaceWebapp.java @@ -0,0 +1,31 @@ +/** + * The contents of this file are subject to the license and copyright + * detailed in the LICENSE and NOTICE files at the root of the source + * tree and available online at + * + * http://www.dspace.org/license/ + */ + +package org.dspace.utils; + +import org.dspace.app.util.AbstractDSpaceWebapp; + +/** + * An MBean to identify this web application. + * + * @author mwood + */ +public class DSpaceWebapp + extends AbstractDSpaceWebapp +{ + public DSpaceWebapp() + { + super("XMLUI"); + } + + @Override + public boolean isUI() + { + return true; + } +} diff --git a/dspace/etc/h2/database_schema.sql b/dspace/etc/h2/database_schema.sql index 5d54f9cdc8..e0048e35bf 100644 --- a/dspace/etc/h2/database_schema.sql +++ b/dspace/etc/h2/database_schema.sql @@ -116,6 +116,7 @@ CREATE SEQUENCE group2group_seq; CREATE SEQUENCE group2groupcache_seq; CREATE SEQUENCE harvested_collection_seq; CREATE SEQUENCE harvested_item_seq; +CREATE SEQUENCE webapp_seq; ------------------------------------------------------- -- BitstreamFormatRegistry table @@ -807,8 +808,11 @@ CREATE TABLE versionitem CREATE SEQUENCE versionitem_seq; CREATE SEQUENCE versionhistory_seq; - - - - - +CREATE TABLE Webapp +( + webapp_id INTEGER NOT NULL PRIMARY KEY, + AppName VARCHAR(32), + URL VARCHAR, + Started TIMESTAMP, + isUI INTEGER +); diff --git a/dspace/etc/oracle/database_schema.sql b/dspace/etc/oracle/database_schema.sql index 0915e98b2a..cf68931bc8 100644 --- a/dspace/etc/oracle/database_schema.sql +++ b/dspace/etc/oracle/database_schema.sql @@ -72,6 +72,7 @@ CREATE SEQUENCE harvested_collection_seq; CREATE SEQUENCE harvested_item_seq; CREATE SEQUENCE versionitem_seq; CREATE SEQUENCE versionhistory_seq; +CREATE SEQUENCE webapp_seq; ------------------------------------------------------- -- BitstreamFormatRegistry table @@ -751,3 +752,12 @@ CREATE TABLE versionitem version_summary VARCHAR2(255), versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id) ); + +CREATE TABLE Webapp +( + webapp_id INTEGER NOT NULL PRIMARY KEY, + AppName VARCHAR(32), + URL VARCHAR, + Started TIMESTAMP, + isUI INTEGER +); diff --git a/dspace/etc/oracle/database_schema_3-4.sql b/dspace/etc/oracle/database_schema_3-4.sql new file mode 100644 index 0000000000..475d01d534 --- /dev/null +++ b/dspace/etc/oracle/database_schema_3-4.sql @@ -0,0 +1,37 @@ +-- +-- database_schema_18-3.sql +-- +-- Version: $Revision$ +-- +-- Date: $Date: 2012-05-29 +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- +-- SQL commands to upgrade the database schema of a live DSpace 1.8 or 1.8.x +-- to the DSpace 3 database schema +-- +-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. +-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. +-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. +-- + +------------------------------------------- +-- Table of running web applications for 'dspace version' -- +------------------------------------------- + +CREATE SEQUENCE webapp_seq; + +CREATE TABLE Webapp +( + webapp_id INTEGER NOT NULL PRIMARY KEY, + AppName VARCHAR(32), + URL VARCHAR, + Started TIMESTAMP, + isUI INTEGER +); diff --git a/dspace/etc/oracle/update-sequences.sql b/dspace/etc/oracle/update-sequences.sql index e44b35a9fe..9288805c24 100644 --- a/dspace/etc/oracle/update-sequences.sql +++ b/dspace/etc/oracle/update-sequences.sql @@ -86,6 +86,7 @@ @updateseq.sql metadataschemaregistry_seq metadataschemaregistry metadata_schema_id "" @updateseq.sql harvested_collection_seq harvested_collection id "" @updateseq.sql harvested_item_seq harvested_item id "" +@updateseq.sql webapp_seq webapp id "" -- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq', -- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq' diff --git a/dspace/etc/postgres/database_schema.sql b/dspace/etc/postgres/database_schema.sql index d93ae9566f..ca65ebecca 100644 --- a/dspace/etc/postgres/database_schema.sql +++ b/dspace/etc/postgres/database_schema.sql @@ -109,6 +109,7 @@ CREATE SEQUENCE harvested_collection_seq; CREATE SEQUENCE harvested_item_seq; CREATE SEQUENCE versionitem_seq; CREATE SEQUENCE versionhistory_seq; +CREATE SEQUENCE webapp_seq; ------------------------------------------------------- -- BitstreamFormatRegistry table @@ -798,9 +799,11 @@ CREATE TABLE versionitem versionhistory_id INTEGER REFERENCES VersionHistory(versionhistory_id) ); - - - - - - +CREATE TABLE Webapp +( + webapp_id INTEGER NOT NULL PRIMARY KEY, + AppName VARCHAR(32), + URL VARCHAR, + Started TIMESTAMP, + isUI INTEGER +); diff --git a/dspace/etc/postgres/database_schema_3-4.sql b/dspace/etc/postgres/database_schema_3-4.sql new file mode 100644 index 0000000000..15d0315596 --- /dev/null +++ b/dspace/etc/postgres/database_schema_3-4.sql @@ -0,0 +1,37 @@ +-- +-- database_schema_18-3.sql +-- +-- Version: $Revision$ +-- +-- Date: $Date: 2012-05-29 +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- +-- SQL commands to upgrade the database schema of a live DSpace 1.8 or 1.8.x +-- to the DSpace 3 database schema +-- +-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. +-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. +-- DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. DUMP YOUR DATABASE FIRST. +-- + +------------------------------------------- +-- New columns and longer hash for salted password hashing DS-861 -- +------------------------------------------- + +CREATE SEQUENCE webapp_seq; + +CREATE TABLE Webapp +( + webapp_id INTEGER NOT NULL PRIMARY KEY, + AppName VARCHAR(32), + URL VARCHAR, + Started TIMESTAMP, + isUI INTEGER +); diff --git a/dspace/etc/postgres/update-sequences.sql b/dspace/etc/postgres/update-sequences.sql index 59ac6428c8..4df9d9e92f 100644 --- a/dspace/etc/postgres/update-sequences.sql +++ b/dspace/etc/postgres/update-sequences.sql @@ -84,6 +84,7 @@ SELECT setval('metadatavalue_seq', max(metadata_value_id)) FROM metadatavalue; SELECT setval('metadataschemaregistry_seq', max(metadata_schema_id)) FROM metadataschemaregistry; SELECT setval('harvested_collection_seq', max(id)) FROM harvested_collection; SELECT setval('harvested_item_seq', max(id)) FROM harvested_item; +SELECT setval('webapp_seq', max(id)) FROM webapp; -- Handle Sequence is a special case. Since Handles minted by DSpace use the 'handle_seq', -- we need to ensure the next assigned handle will *always* be unique. So, 'handle_seq' diff --git a/pom.xml b/pom.xml index 3dadd89811..2bee2943da 100644 --- a/pom.xml +++ b/pom.xml @@ -798,7 +798,7 @@ javax.servlet servlet-api - 2.4 + 2.5