Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvements to allow future deployment of multiple instances #7337

Merged
merged 23 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
81c3257
WRO4J / Move cache to HTML cache folder.
fxprunayre Apr 14, 2023
1300e5b
Data directory / Add parameter for XML schemas.
fxprunayre Jun 23, 2023
f078d30
API / Site info / Add all data directory info
joachimnielandt Jun 20, 2023
dc46128
Test / Fix related to XSD publication dir.
fxprunayre Jun 27, 2023
6d34a41
Translations / Add better message in case of harvester save issue.
fxprunayre Jul 12, 2023
c774e9c
Missing translations.
joachimnielandt Jun 28, 2023
e59ff9f
Bad configuration of a harvester could prevent geonetwork startup
joachimnielandt Jun 28, 2023
6637e48
Proposal to disable harvesters.
joachimnielandt Jun 29, 2023
d1c835a
Java header.
fxprunayre Jul 12, 2023
c5f5cd3
System info / Add env variables related to database migration and har…
fxprunayre Jul 12, 2023
83e4a51
Prettier.
fxprunayre Jul 13, 2023
94261f7
Merge branch '424-multipleinstances' into ha
fxprunayre Aug 31, 2023
71ed6ed
Merge branch '440-harvesterscheduleconfig' into ha
fxprunayre Aug 31, 2023
96ac3ca
Merge remote-tracking branch 'origin/main' into ha
fxprunayre Sep 7, 2023
ebcfdde
HA / Added hostname to the system information panel.
fxprunayre Sep 13, 2023
91b404d
HA / Introducing scheduled refresh of harvesterjobs.
fxprunayre Sep 13, 2023
3fc13fb
Test / Add new properties.
fxprunayre Sep 13, 2023
2d10959
Test / Remove duplicated prop.
fxprunayre Sep 14, 2023
0a95b58
Jetty / Form config consistent with default docker one
fxprunayre Sep 18, 2023
a53fc64
Jetty / Update version and fix sending mail
fxprunayre Sep 18, 2023
72b8521
Adding schemapublication_dir to admin info panel
joachimnielandt Sep 21, 2023
f216176
Java doc. Check also GeoNetworkDataDirectory for description of folders.
fxprunayre Sep 25, 2023
0e1b413
Update harvesters/src/main/java/org/fao/geonet/kernel/harvest/Refresh…
fxprunayre Sep 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 56 additions & 0 deletions common/src/main/java/org/fao/geonet/utils/Env.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//=============================================================================
//=== Copyright (C) 2001-2023 Food and Agriculture Organization of the
//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
//=== and United Nations Environment Programme (UNEP)
//===
//=== This program 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 2 of the License, or (at
//=== your option) any later version.
//===
//=== This program 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 this program; if not, write to the Free Software
//=== Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//===
//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
//=== Rome - Italy. email: [email protected]
//==============================================================================

package org.fao.geonet.utils;

import org.apache.commons.lang.StringUtils;

public final class Env {

/**
* Retrieves an environment variable with this priority:
* - Java environment variable.
* - System environment variable.
* - Default value provided as parameter.
*
* @param propertyName
* @param defaultValue
* @return
*/
public static String getPropertyFromEnv(String propertyName, String defaultValue) {
// Check if provided in Java environment variable
String propertyValue = System.getProperty(propertyName);

if (StringUtils.isEmpty(propertyValue)) {
// System environment variable
propertyValue = System.getenv(propertyName.toUpperCase().replace('.', '_'));
}

if (StringUtils.isEmpty(propertyValue)) {
propertyValue = defaultValue;
}

return propertyValue;
}

}
1 change: 1 addition & 0 deletions core/src/main/java/org/fao/geonet/constants/Geonet.java
Original file line number Diff line number Diff line change
Expand Up @@ -535,6 +535,7 @@ public static final class SortBy {
*/
public static final class Config {
public static final String HTMLCACHE_DIR = "htmlCacheDir";
public static final String SCHEMAPUBLICATION_DIR = "schemaPublicationDir";
public static final String INDEX_CONFIG_DIR = "indexConfigDir";
/**
* Profiles of languages for autodetection using https://code.google.com/p/language-detection/.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public class GeonetworkDataDirectory {
private Path metadataRevisionDir;
private Path resourcesDir;
private Path htmlCacheDir;
private Path schemaPublicationDir;
private Path uploadDir;
private Path formatterDir;
private Path nodeLessFiles;
Expand Down Expand Up @@ -302,10 +303,12 @@ private Path setDataDirectory(JeevesServlet jeevesServlet, String webappName,
);
formatterDir = setDir(jeevesServlet, webappName, handlerConfig, formatterDir,
".formatter" + KEY_SUFFIX, Geonet.Config.FORMATTER_PATH, "data", "formatter");

htmlCacheDir = setDir(jeevesServlet, webappName, handlerConfig, htmlCacheDir,
".htmlcache" + KEY_SUFFIX, Geonet.Config.HTMLCACHE_DIR, handlerConfig.getValue(Geonet.Config.RESOURCES_DIR), "htmlcache"
);
schemaPublicationDir = setDir(jeevesServlet, webappName, handlerConfig, schemaPublicationDir,
".schemapublication" + KEY_SUFFIX, Geonet.Config.SCHEMAPUBLICATION_DIR, handlerConfig.getValue(Geonet.Config.RESOURCES_DIR), "schemapublication"
);
backupDir = setDir(jeevesServlet, webappName, handlerConfig, backupDir,
".backup" + KEY_SUFFIX, Geonet.Config.BACKUP_DIR, "data", "backup"
);
Expand Down Expand Up @@ -719,6 +722,23 @@ public void setHtmlCacheDir(Path htmlCacheDir) {
this.htmlCacheDir = htmlCacheDir;
}

/**
* Get directory for publishing schemas and making them publicly available.
*
* @return directory for publishing schemas and making them publicly available.
*/
public Path getSchemaPublicationDir() {
return schemaPublicationDir;
}

/**
* Set directory for publishing schemas and making them publicly available.
* @param schemaPublicationDir
*/
public void setSchemaPublicationDir(Path schemaPublicationDir) {
this.schemaPublicationDir = schemaPublicationDir;
}

/**
* Get directory for caching where uploaded files go.
*
Expand Down
9 changes: 6 additions & 3 deletions core/src/main/java/org/fao/geonet/kernel/SchemaManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ public class SchemaManager {
private String defaultSchema;
private Path basePath;
private Path resourcePath;
private Path schemaPublicationDir;
private int numberOfCoreSchemasAdded = 0;

public static Path registerXmlCatalogFiles(Path webappDir, Path schemapluginUriCatalog) {
Expand Down Expand Up @@ -174,6 +175,7 @@ public static SchemaPlugin getSchemaPlugin(String schemaIdentifier) {
public void configureFrom(SchemaManager schemaManager, Path basePath, GeonetworkDataDirectory dataDir) {
this.basePath = basePath;
this.resourcePath = dataDir.getResourcesDir();
this.schemaPublicationDir = dataDir.getSchemaPublicationDir();
this.schemaPluginsDir = dataDir.getSchemaPluginsDir();
this.schemaPluginsCat = schemaPluginsDir.resolve("schemaplugin-uri-catalog.xml");
this.defaultLang = schemaManager.defaultLang;
Expand Down Expand Up @@ -206,13 +208,14 @@ private void addResolverRewriteDirectives(GeonetworkDataDirectory dataDir) {
* @param defaultLang the default language (taken from context)
* @param defaultSchema the default schema (taken from config.xml)
*/
public void configure(ApplicationContext applicationContext, Path basePath, Path resourcePath, Path schemaPluginsCat,
public void configure(ApplicationContext applicationContext, Path basePath, Path resourcePath, Path schemaPublicationDir, Path schemaPluginsCat,
fxprunayre marked this conversation as resolved.
Show resolved Hide resolved
Path sPDir, String defaultLang, String defaultSchema, boolean createOrUpdateSchemaCatalog) throws Exception {

hmSchemas.clear();

this.basePath = basePath;
this.resourcePath = resourcePath;
this.schemaPublicationDir = schemaPublicationDir;
this.schemaPluginsDir = sPDir;
this.schemaPluginsCat = schemaPluginsCat;
this.defaultLang = defaultLang;
Expand Down Expand Up @@ -1259,7 +1262,7 @@ private void removeSchemaDir(Path schemaDir, String name) {
}
deleteDir(schemaDir);

Path pubSchemaDir = resourcePath.resolve(Geonet.Path.SCHEMAS).resolve(name);
Path pubSchemaDir = schemaPublicationDir.resolve(Geonet.Path.SCHEMAS).resolve(name);
if (Log.isDebugEnabled(Geonet.SCHEMA_MANAGER)) {
Log.debug(Geonet.SCHEMA_MANAGER, "Removing published schemas directory " + pubSchemaDir);
}
Expand Down Expand Up @@ -1869,7 +1872,7 @@ public String getDefaultSchema() {
* @param schemaPluginDir the directory containing the schema plugin
*/
private void copySchemaXSDsToWebApp(String name, Path schemaPluginDir) throws Exception {
Path schemasDir = resourcePath.resolve(Geonet.Path.SCHEMAS);
Path schemasDir = schemaPublicationDir.resolve(Geonet.Path.SCHEMAS);
Files.createDirectories(schemasDir);

Path webAppDirSchemaXSD = schemasDir.resolve(name);
Expand Down
34 changes: 25 additions & 9 deletions core/src/main/java/org/fao/geonet/resources/ResourceFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,23 +24,19 @@
package org.fao.geonet.resources;

import com.google.common.collect.Maps;

import com.google.common.collect.Sets;
import jeeves.config.springutil.JeevesDelegatingFilterProxy;

import org.fao.geonet.NodeInfo;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.Pair;
import org.fao.geonet.kernel.GeonetworkDataDirectory;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.utils.Log;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.http.MediaType;
import org.springframework.web.context.request.ServletWebRequest;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.attribute.FileTime;
Expand Down Expand Up @@ -83,6 +79,7 @@ public class Instance {
private final ServletResponse response;

private final Path resourcesDir;
private final Path schemaPublicationDir;
private final Path appPath;
private final String nodeId;
private final String siteId;
Expand All @@ -96,6 +93,7 @@ public Instance(ServletRequest request, ServletResponse response) throws IOExcep
this.resources = applicationContext.getBean(Resources.class);
this.siteId = applicationContext.getBean(SettingManager.class).getSiteId();
this.resourcesDir = resources.locateResourcesDir(servletContext, applicationContext);
this.schemaPublicationDir = applicationContext.getBean(GeonetworkDataDirectory.class).getSchemaPublicationDir();
if (defaultImage == null) {
defaultImage = resources.loadResource(resourcesDir, servletContext, appPath, "images/logos/" + siteId + ".png", new byte[0], -1);
}
Expand Down Expand Up @@ -133,10 +131,8 @@ public void execute() throws IOException {
return;
}

// Resources are images for logos, XML for map config or XSD
String contentType = "xml".equals(ext) || "xsd".equals(ext)
? MediaType.APPLICATION_XML_VALUE
: "image/" + ext;
// Figure out the content type based on the extensions, defaulting to an image
String contentType = extensionToMediaType(ext);

httpServletResponse.setContentType(contentType);
httpServletResponse.addHeader("Cache-Control", "max-age=" + SIX_HOURS + ", public");
Expand All @@ -148,6 +144,14 @@ public void execute() throws IOException {
httpServletResponse.setContentLength(favicon.one().length);
httpServletResponse.addHeader("Cache-Control", "max-age=" + FIVE_DAYS + ", public");
response.getOutputStream().write(favicon.one());
} else if(filename.startsWith("/xml/schemas/")) {
Pair<byte[], Long> loadedResource = resources.loadResource(schemaPublicationDir, servletContext, appPath, filename, null, -1);
if(loadedResource.two() == -1) {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
} else {
httpServletResponse.setContentLength(loadedResource.one().length);
response.getOutputStream().write(loadedResource.one());
}
} else {
byte[] defaultData = null;

Expand Down Expand Up @@ -175,4 +179,16 @@ private synchronized void addFavIcon(String nodeId, Pair<byte[], Long> favicon)
}
}
}

private String extensionToMediaType(String ext) {
final String contentType;
if(Sets.newHashSet("xml", "xsd", "sch", "dtd").contains(ext)) {
contentType = MediaType.APPLICATION_XML_VALUE;
} else if(ext.equals("txt")) {
contentType = MediaType.TEXT_PLAIN_VALUE;
} else {
contentType = "image/" + ext;
}
return contentType;
}
}
3 changes: 2 additions & 1 deletion core/src/test/java/org/fao/geonet/GeonetTestFixture.java
Original file line number Diff line number Diff line change
Expand Up @@ -181,12 +181,13 @@ protected void addSourceUUID(GeonetworkDataDirectory dataDirectory) {
protected SchemaManager initSchemaManager(Path webappDir, GeonetworkDataDirectory geonetworkDataDirectory) throws Exception {
final Path schemaPluginsDir = geonetworkDataDirectory.getSchemaPluginsDir();
final Path resourcePath = geonetworkDataDirectory.getResourcesDir();
final Path schemaPublicationDir = geonetworkDataDirectory.getSchemaPublicationDir();
Path schemaPluginsCatalogFile = schemaPluginsDir.resolve("schemaplugin-uri-catalog.xml");

final SchemaManager schemaManager = _applicationContext.getBean(SchemaManager.class);

SchemaManager.registerXmlCatalogFiles(webappDir, schemaPluginsCatalogFile);
schemaManager.configure(_applicationContext, webappDir, resourcePath,
schemaManager.configure(_applicationContext, webappDir, resourcePath, schemaPublicationDir,
schemaPluginsCatalogFile, schemaPluginsDir, "eng", "iso19139", true);

assertRequiredSchemas(schemaManager);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public void testInit() throws Exception {
dataDirectory.setHtmlCacheDir(null);
dataDirectory.setSchemaPluginsDir(null);
dataDirectory.setThesauriDir(null);
dataDirectory.setSchemaPublicationDir(null);
final ArrayList<Element> serviceConfigParameterElements = getServiceConfigParameterElements();
final ServiceConfig handlerConfig = new ServiceConfig(serviceConfigParameterElements);
final Path webappDir = getWebappDir(getClass());
Expand All @@ -83,6 +84,7 @@ private void assertSystemDirSubFolders(Path expectedDataDir) {
final Path expectedResourcesDir = expectedDataDir.resolve("data").resolve("resources");
assertEquals(expectedResourcesDir, dataDirectory.getResourcesDir());
assertEquals(expectedResourcesDir.resolve("htmlcache"), dataDirectory.getHtmlCacheDir());
assertEquals(expectedResourcesDir.resolve("schemapublication"), dataDirectory.getSchemaPublicationDir());
assertEquals(expectedConfigDir.resolve("schema_plugins"), dataDirectory.getSchemaPluginsDir());
assertEquals(expectedConfigDir.resolve("codelist"), dataDirectory.getThesauriDir());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import org.fao.geonet.kernel.harvest.harvester.AbstractHarvester;
import org.jdom.Element;
import org.quartz.SchedulerException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;

import java.sql.SQLException;
Expand All @@ -52,6 +51,18 @@ public interface HarvestManager {
*/
void init(@Nonnull ServiceContext context, boolean isReadOnly) throws Exception;

/**
* Refresh the harvesters.
* - Stops the existing scheduled jobs.
* - Reloads the harvester definitions from the database.
* - Schedule the jobs again.
* <p>
* Useful when running multiple instances as one instance is not aware of new harvesters added on the other one.
* <p>
* TODO when a durable solution for running highly available is implemented this scheduled task could be deleted, e.g., when created harvesters are notified through a shared message queue.
*/
void refreshHarvesters();

/**
* Shutdown all harvesters and thread pools and jobs.
*/
Expand Down
Loading