diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java index c083d44f3d..563b1c9b44 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/beans/ApplicationBean.java @@ -20,6 +20,7 @@ public class ApplicationBean { public final static int VIVO_SEARCHBOX_SIZE = 20; private final static String DEFAULT_APPLICATION_NAME = "Vitro"; + private final static String DEFAULT_APPLICATION_AVAILABLE_LANGS_FILE = "available-langs"; private final static String DEFAULT_ROOT_LOGOTYPE_IMAGE = ""; private final static int DEFAULT_ROOT_LOGOTYPE_WIDTH = 0; private final static int DEFAULT_ROOT_LOGOTYPE_HEIGHT = 0; @@ -33,6 +34,7 @@ public class ApplicationBean { private boolean initialized = false; private String sessionIdStr = null; private String applicationName = DEFAULT_APPLICATION_NAME; + private String availableLangsFile = DEFAULT_APPLICATION_AVAILABLE_LANGS_FILE; private String rootLogotypeImage = DEFAULT_ROOT_LOGOTYPE_IMAGE; private int rootLogotypeWidth = DEFAULT_ROOT_LOGOTYPE_WIDTH; @@ -52,6 +54,7 @@ public String toString() { output += " initialized from DB: [" + initialized + "]\n"; output += " session id: [" + sessionIdStr + "]\n"; output += " application name: [" + applicationName + "]\n"; + output += " available langs file: [" + availableLangsFile + "]\n"; output += " root logotype image: [" + rootLogotypeImage + "]\n"; output += " root logotype width: [" + rootLogotypeWidth + "]\n"; output += " root logotype height: [" + rootLogotypeHeight + "]\n"; @@ -177,6 +180,10 @@ public String getShortHand() { return ""; } + public String getAvailableLangsFile() { + return availableLangsFile; + } + /** * Directory to find the images. Subdirectories include css, jsp and site_icons. * Example: "themes/enhanced/" diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java index 1c0ea33ce3..7cabec5728 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ConfigurationModelsSetup.java @@ -52,12 +52,12 @@ private void setupModel(ServletContext ctx, String modelUri, private void loadFirstTimeFiles(ServletContext ctx, String modelPath, OntModel baseModel) { - RDFFilesLoader.loadFirstTimeFiles(modelPath, baseModel, baseModel.isEmpty()); + RDFFilesLoader.loadFirstTimeFiles(ctx, modelPath, baseModel, baseModel.isEmpty()); } private void loadEveryTimeFiles(ServletContext ctx, String modelPath, OntModel memoryModel) { - RDFFilesLoader.loadEveryTimeFiles(modelPath, memoryModel); + RDFFilesLoader.loadEveryTimeFiles(ctx, modelPath, memoryModel); } @Override diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java index 84e2d68093..9103ab24e5 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/ContentModelSetup.java @@ -67,15 +67,15 @@ private void setUpJenaDataSource(ServletContext ctx) { OntModel baseABoxModel = models.getOntModel(ABOX_ASSERTIONS); if (firstTimeStartup) { - RDFFilesLoader.loadFirstTimeFiles("abox", baseABoxModel, true); + RDFFilesLoader.loadFirstTimeFiles(ctx, "abox", baseABoxModel, true); } - RDFFilesLoader.loadEveryTimeFiles("abox", baseABoxModel); + RDFFilesLoader.loadEveryTimeFiles(ctx, "abox", baseABoxModel); OntModel baseTBoxModel = models.getOntModel(TBOX_ASSERTIONS); if (firstTimeStartup) { - RDFFilesLoader.loadFirstTimeFiles("tbox", baseTBoxModel, true); + RDFFilesLoader.loadFirstTimeFiles(ctx, "tbox", baseTBoxModel, true); } - RDFFilesLoader.loadEveryTimeFiles("tbox", baseTBoxModel); + RDFFilesLoader.loadEveryTimeFiles(ctx, "tbox", baseTBoxModel); } private long secondsSince(long startTime) { @@ -94,7 +94,7 @@ private long secondsSince(long startTime) { private void initializeApplicationMetadata(ServletContext ctx, Model applicationMetadataModel) { OntModel temporaryAMModel = VitroModelFactory.createOntologyModel(); - RDFFilesLoader.loadFirstTimeFiles("applicationMetadata", temporaryAMModel, true); + RDFFilesLoader.loadFirstTimeFiles(ctx, "applicationMetadata", temporaryAMModel, true); setPortalUriOnFirstTime(temporaryAMModel, ctx); applicationMetadataModel.add(temporaryAMModel); } diff --git a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java index 35fdaf54df..f9055f5e06 100644 --- a/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java +++ b/api/src/main/java/edu/cornell/mannlib/vitro/webapp/servlet/setup/RDFFilesLoader.java @@ -2,7 +2,6 @@ package edu.cornell.mannlib.vitro.webapp.servlet.setup; -import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; @@ -10,9 +9,20 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; import java.util.Set; import java.util.TreeSet; +import edu.cornell.mannlib.vitro.webapp.beans.ApplicationBean; +import edu.cornell.mannlib.vitro.webapp.dao.WebappDaoFactory; +import edu.cornell.mannlib.vitro.webapp.i18n.VitroResourceBundle; +import edu.cornell.mannlib.vitro.webapp.i18n.selection.SelectedLocale; +import edu.cornell.mannlib.vitro.webapp.modelaccess.ModelAccess; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -23,6 +33,8 @@ import edu.cornell.mannlib.vitro.webapp.application.ApplicationUtils; +import javax.servlet.ServletContext; + /** * Help to load RDF files on first time and on every startup. */ @@ -34,8 +46,10 @@ public class RDFFilesLoader { private static final String FIRST_TIME = "firsttime"; private static final String EVERY_TIME = "everytime"; + private static List omittedLocales; + /** - * Path filter that ignores sub-directories, hidden files, and markdown + * Path filter that ignores sub-directories, hidden files, markdown and non-enabled language * files. */ private static final DirectoryStream.Filter RDF_FILE_FILTER = new DirectoryStream.Filter() { @@ -52,6 +66,15 @@ public boolean accept(Path p) throws IOException { if (p.toString().endsWith(".md")) { return false; } + // Skip language files that are not enabled + // ..Assumes all language files take the form: path/to/file/name-.extension + String basename = FilenameUtils.getBaseName(p.toString()); + for (String omit : omittedLocales) { + if (basename.endsWith(omit)) { + log.info("Ignoring file not enabled in i18n configuration: " + p); + return false; + } + } return true; } }; @@ -64,11 +87,11 @@ public boolean accept(Path p) throws IOException { * * The files from the directory are added to the model. */ - public static void loadFirstTimeFiles(String modelPath, Model model, + public static void loadFirstTimeFiles(ServletContext ctx, String modelPath, Model model, boolean firstTime) { if (firstTime) { String home = locateHomeDirectory(); - Set paths = getPaths(home, RDF, modelPath, FIRST_TIME); + Set paths = getPaths(ctx, home, RDF, modelPath, FIRST_TIME); for (Path p : paths) { log.info("Loading " + relativePath(p, home)); readOntologyFileIntoModel(p, model); @@ -87,11 +110,11 @@ public static void loadFirstTimeFiles(String modelPath, Model model, * * The files from the directory become a sub-model of the model. */ - public static void loadEveryTimeFiles(String modelPath, OntModel model) { + public static void loadEveryTimeFiles(ServletContext ctx, String modelPath, OntModel model) { OntModel everytimeModel = ModelFactory .createOntologyModel(OntModelSpec.OWL_MEM); String home = locateHomeDirectory(); - Set paths = getPaths(home, RDF, modelPath, EVERY_TIME); + Set paths = getPaths(ctx, home, RDF, modelPath, EVERY_TIME); for (Path p : paths) { log.info("Loading " + relativePath(p, home)); readOntologyFileIntoModel(p, everytimeModel); @@ -107,38 +130,14 @@ private static Path relativePath(Path p, String home) { } } - /** - * Create a model from all the RDF files in the specified directory. - */ - public static OntModel getModelFromDir(File dir) { - OntModel model = ModelFactory.createOntologyModel(OntModelSpec.OWL_MEM); - if (dir == null) { - log.warn("Must pass a File to getModelFromDir()"); - return model; - } - if (!dir.isDirectory()) { - log.warn("Directory must be a File object for a directory"); - return model; - } - if (!dir.canRead()) { - log.warn("getModelFromDir(): Directory " - + " must be readable, check permissions on " - + dir.getAbsolutePath()); - return model; - } - - Set paths = getPaths(dir.getPath()); - for (Path p : paths) { - readOntologyFileIntoModel(p, model); - } - return model; - } - /** * Find the paths to RDF files in this directory. Sub-directories, hidden - * files, and markdown files are ignored. + * files, markdown, and non-enabled language files are ignored. */ - private static Set getPaths(String parentDir, String... strings) { + private static Set getPaths(ServletContext ctx, String parentDir, String... strings) { + // Ensure that omitted locales are loaded and available + loadOmittedLocales(ctx); + Path dir = Paths.get(parentDir, strings); Set paths = new TreeSet<>(); @@ -158,6 +157,49 @@ private static Set getPaths(String parentDir, String... strings) { return paths; } + private static void loadOmittedLocales(ServletContext ctx) { + // Only load if 'omittedLocales' has not been initialized + if (omittedLocales == null) { + omittedLocales = new LinkedList<>(); + List enabledLocales = new LinkedList<>(); + + // Which locales are enabled in runtime.properties? + List locales = SelectedLocale.getSelectableLocales(ctx); + for (Locale locale : locales) { + enabledLocales.add(locale.toLanguageTag().replace('-', '_')); + } + + // Get ResourceBundle that contains listing of all available i18n languages + WebappDaoFactory wadf = ModelAccess.on(ctx).getWebappDaoFactory(); + ApplicationBean app = wadf.getApplicationDao().getApplicationBean(); + String availableLangsFilename = app.getAvailableLangsFile(); + String themeI18nPath = "/not-used"; + String appI18nPath = "/i18n"; + VitroResourceBundle bundle = VitroResourceBundle.getBundle( + availableLangsFilename, ctx, appI18nPath, themeI18nPath, + ResourceBundle.Control.getControl(ResourceBundle.Control.FORMAT_PROPERTIES)); + + // This should not happen + if (bundle == null) { + throw new RuntimeException("Unable to find bundle: " + availableLangsFilename); + } + + // If no languages were enabled in runtime.properties, add 'en_US' as the default + if (enabledLocales.isEmpty()) { + enabledLocales.add("en_US"); + } + + // Omitted locales are the available locales minus the enabled locales + Enumeration langs = bundle.getKeys(); + while (langs.hasMoreElements()) { + String available = (String) langs.nextElement(); + if (!enabledLocales.contains(available)) { + omittedLocales.add(available); + } + } + } + } + private static void readOntologyFileIntoModel(Path p, Model model) { String format = getRdfFormat(p); log.debug("Loading " + p); diff --git a/installer/webapp/pom.xml b/installer/webapp/pom.xml index a17179d147..4be7c1604f 100644 --- a/installer/webapp/pom.xml +++ b/installer/webapp/pom.xml @@ -45,11 +45,11 @@ war - + @@ -148,12 +148,12 @@ war - + javax.servlet