diff --git a/Integrations/src/test/java/io/deephaven/integrations/python/CalendarsHelper.java b/Integrations/src/test/java/io/deephaven/integrations/python/CalendarsHelper.java new file mode 100644 index 00000000000..f923d055317 --- /dev/null +++ b/Integrations/src/test/java/io/deephaven/integrations/python/CalendarsHelper.java @@ -0,0 +1,15 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.integrations.python; + +import io.deephaven.time.calendar.BusinessCalendar; +import io.deephaven.time.calendar.Calendars; + +public final class CalendarsHelper { + public static void addCalendarsFromConfiguration() { + for (BusinessCalendar calendar : Calendars.calendarsFromConfiguration()) { + Calendars.addCalendar(calendar); + } + } +} diff --git a/Plot/src/test/java/io/deephaven/plot/axistransformations/CalendarInit.java b/Plot/src/test/java/io/deephaven/plot/axistransformations/CalendarInit.java new file mode 100644 index 00000000000..ebdde9a5891 --- /dev/null +++ b/Plot/src/test/java/io/deephaven/plot/axistransformations/CalendarInit.java @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.plot.axistransformations; + +import io.deephaven.time.calendar.BusinessCalendar; +import io.deephaven.time.calendar.Calendars; + +final class CalendarInit { + static { + for (BusinessCalendar calendar : Calendars.calendarsFromConfiguration()) { + Calendars.addCalendar(calendar); + } + } + + static void noop() { + + } +} diff --git a/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransformBusinessCalendar.java b/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransformBusinessCalendar.java index 5251e6eac42..9aac997fc67 100644 --- a/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransformBusinessCalendar.java +++ b/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransformBusinessCalendar.java @@ -3,16 +3,19 @@ */ package io.deephaven.plot.axistransformations; -import io.deephaven.base.testing.BaseArrayTestCase; import io.deephaven.time.DateTimeUtils; import io.deephaven.time.calendar.Calendars; +import junit.framework.TestCase; import java.nio.file.Paths; import java.time.Instant; import java.time.ZoneId; import java.util.Objects; -public class TestAxisTransformBusinessCalendar extends BaseArrayTestCase { +public class TestAxisTransformBusinessCalendar extends TestCase { + static { + CalendarInit.noop(); + } private static final ZoneId TZ_JP = ZoneId.of("Asia/Tokyo"); diff --git a/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransforms.java b/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransforms.java index aee90400503..8e676e96af5 100644 --- a/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransforms.java +++ b/Plot/src/test/java/io/deephaven/plot/axistransformations/TestAxisTransforms.java @@ -16,6 +16,9 @@ import static org.junit.Assert.assertTrue; public class TestAxisTransforms { + static { + CalendarInit.noop(); + } final double d1 = 3.5; final double d2 = 4.2; diff --git a/engine/time/build.gradle b/engine/time/build.gradle index be02e75d3c5..6a854e5c222 100644 --- a/engine/time/build.gradle +++ b/engine/time/build.gradle @@ -17,6 +17,7 @@ dependencies { implementation project(':Configuration') implementation project(':log-factory') implementation depJdom2 + Classpaths.inheritDagger(project) testImplementation TestTools.projectDependency(project, 'Base') diff --git a/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendar.java b/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendar.java index 539c2b1b681..c68543e832a 100644 --- a/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendar.java +++ b/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendar.java @@ -147,7 +147,7 @@ private YearData getYearData(final int year) { * is different from the schedule for a standard business day or weekend. * @throws RequirementFailure if any argument is null. */ - BusinessCalendar(final String name, final String description, final ZoneId timeZone, + public BusinessCalendar(final String name, final String description, final ZoneId timeZone, final LocalDate firstValidDate, final LocalDate lastValidDate, final CalendarDay standardBusinessDay, final Set weekendDays, final Map> holidays) { diff --git a/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendarXMLParser.java b/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendarXMLParser.java index 0d1220a6c51..3b975e021c3 100644 --- a/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendarXMLParser.java +++ b/engine/time/src/main/java/io/deephaven/time/calendar/BusinessCalendarXMLParser.java @@ -13,8 +13,10 @@ import org.jdom2.input.SAXBuilder; import org.jetbrains.annotations.NotNull; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.time.*; import java.util.HashSet; import java.util.List; @@ -25,6 +27,7 @@ /** * A parser for reading business calendar XML files. * + *

* Business calendar XML files should be formatted as: * *

@@ -54,7 +57,7 @@
  * }
  * 
*/ -class BusinessCalendarXMLParser { +public final class BusinessCalendarXMLParser { private static class BusinessCalendarInputs { private String calendarName; @@ -89,38 +92,78 @@ public static BusinessCalendar loadBusinessCalendar(@NotNull final String file) public static BusinessCalendar loadBusinessCalendar(@NotNull final File file) { Require.neqNull(file, "file"); final BusinessCalendarInputs in = parseBusinessCalendarInputs(file); + return new BusinessCalendar(in.calendarName, in.description, + in.timeZone, in.firstValidDate, in.lastValidDate, + in.standardBusinessDay, in.weekendDays, in.holidays); + } + /** + * Loads a business calendar from an XML input stream. + * + * @param inputStream XML input stream + * @return business calendar. + * @throws RequirementFailure if the input is null + */ + public static BusinessCalendar loadBusinessCalendar(@NotNull final InputStream inputStream) { + Require.neqNull(inputStream, "inputStream"); + final BusinessCalendarInputs in = parseBusinessCalendarInputs(inputStream); return new BusinessCalendar(in.calendarName, in.description, in.timeZone, in.firstValidDate, in.lastValidDate, in.standardBusinessDay, in.weekendDays, in.holidays); } + /** + * Loads a business calendar from an XML resource. + * + * @param resource XML input stream + * @return business calendar. + */ + public static BusinessCalendar loadBusinessCalendarFromResource(String resource) throws IOException { + final InputStream in = Calendars.class.getResourceAsStream(resource); + if (in == null) { + throw new RuntimeException("Could not open resource " + resource + " from classpath"); + } + try (final InputStream bin = new BufferedInputStream(in)) { + return BusinessCalendarXMLParser.loadBusinessCalendar(bin); + } + } + private static BusinessCalendarInputs parseBusinessCalendarInputs(@NotNull final File file) { Require.neqNull(file, "file"); try { - final BusinessCalendarInputs calendarElements = new BusinessCalendarInputs(); - - Element root = loadXMLRootElement(file); - calendarElements.calendarName = getText(getRequiredChild(root, "name")); - calendarElements.timeZone = TimeZoneAliases.zoneId(getText(getRequiredChild(root, "timeZone"))); - calendarElements.description = getText(getRequiredChild(root, "description")); - calendarElements.firstValidDate = - DateTimeUtils.parseLocalDate(getText(getRequiredChild(root, "firstValidDate"))); - calendarElements.lastValidDate = - DateTimeUtils.parseLocalDate(getText(getRequiredChild(root, "lastValidDate"))); - calendarElements.holidays = parseHolidays(root, calendarElements.timeZone); - - // Set the default values - final Element defaultElement = getRequiredChild(root, "default"); - calendarElements.weekendDays = parseWeekendDays(defaultElement); - calendarElements.standardBusinessDay = parseCalendarDaySchedule(defaultElement); - - return calendarElements; + return fill(loadXMLRootElement(file)); } catch (Exception e) { throw new RuntimeException("Unable to load calendar file: file=" + file.getPath(), e); } } + private static BusinessCalendarInputs parseBusinessCalendarInputs(@NotNull final InputStream in) { + Require.neqNull(in, "in"); + try { + return fill(loadXMLRootElement(in)); + } catch (Exception e) { + throw new RuntimeException("Unable to load calendar file: inputStream=" + in, e); + } + } + + private static BusinessCalendarInputs fill(Element root) throws Exception { + final BusinessCalendarInputs calendarElements = new BusinessCalendarInputs(); + calendarElements.calendarName = getText(getRequiredChild(root, "name")); + calendarElements.timeZone = TimeZoneAliases.zoneId(getText(getRequiredChild(root, "timeZone"))); + calendarElements.description = getText(getRequiredChild(root, "description")); + calendarElements.firstValidDate = + DateTimeUtils.parseLocalDate(getText(getRequiredChild(root, "firstValidDate"))); + calendarElements.lastValidDate = + DateTimeUtils.parseLocalDate(getText(getRequiredChild(root, "lastValidDate"))); + calendarElements.holidays = parseHolidays(root, calendarElements.timeZone); + + // Set the default values + final Element defaultElement = getRequiredChild(root, "default"); + calendarElements.weekendDays = parseWeekendDays(defaultElement); + calendarElements.standardBusinessDay = parseCalendarDaySchedule(defaultElement); + return calendarElements; + } + private static Element loadXMLRootElement(File calendarFile) throws Exception { final Document doc; @@ -136,6 +179,21 @@ private static Element loadXMLRootElement(File calendarFile) throws Exception { return doc.getRootElement(); } + private static Element loadXMLRootElement(InputStream in) throws Exception { + final Document doc; + + try { + final SAXBuilder builder = new SAXBuilder(); + doc = builder.build(in); + } catch (JDOMException e) { + throw new Exception("Error parsing business calendar: inputStream=" + in, e); + } catch (IOException e) { + throw new Exception("Error loading business calendar: inputStream=" + in, e); + } + + return doc.getRootElement(); + } + private static Element getRequiredChild(@NotNull final Element root, final String child) throws Exception { Element element = root.getChild(child); if (element != null) { diff --git a/engine/time/src/main/java/io/deephaven/time/calendar/Calendars.java b/engine/time/src/main/java/io/deephaven/time/calendar/Calendars.java index 50b640cc4cc..c0743d01a35 100644 --- a/engine/time/src/main/java/io/deephaven/time/calendar/Calendars.java +++ b/engine/time/src/main/java/io/deephaven/time/calendar/Calendars.java @@ -12,10 +12,11 @@ import org.jetbrains.annotations.NotNull; import java.io.*; -import java.nio.file.NoSuchFileException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.TreeMap; -import java.util.function.Consumer; /** * A collection of business calendars. @@ -26,84 +27,49 @@ public class Calendars { private static final String BUSINESS_CALENDAR_PROP_INTERNAL = "Calendar.importPath"; private static final String BUSINESS_CALENDAR_PROP_USER = "Calendar.userImportPath"; private static String defaultName = Configuration.getInstance().getProperty("Calendar.default"); + private static final Map calMap = new TreeMap<>(); - // Variable should only be accessed through getMap() - private static volatile Map calMap; - - private Calendars() {} - - // region Load - - // Get the initialized map of calendars. - // Initilization is deferred to so that errors are easier for users to find. - private static Map getMap() { - if (calMap != null) { - return calMap; - } - - synchronized (Calendars.class) { - if (calMap != null) { - return calMap; - } - - calMap = new TreeMap<>(); - final Configuration configuration = Configuration.getInstance(); - - loadProperty(configuration, BUSINESS_CALENDAR_PROP_INTERNAL); - - if (configuration.hasProperty(BUSINESS_CALENDAR_PROP_USER)) { - loadProperty(configuration, BUSINESS_CALENDAR_PROP_USER); - } - - return calMap; + /** + * Loads the line-separated calendar XML resources from the resource file configuration value + * {@value BUSINESS_CALENDAR_PROP_INTERNAL}. If the resource file configuration value + * {@value BUSINESS_CALENDAR_PROP_USER} exists, those line-separated calendar XML resources will be returned as + * well. + * + * @return the calendars + * @see BusinessCalendarXMLParser#loadBusinessCalendarFromResource(String) + */ + public static List calendarsFromConfiguration() { + final Configuration configuration = Configuration.getInstance(); + final List configurationCalendars = new ArrayList<>( + loadCalendarsFromResourceList(configuration.getProperty(BUSINESS_CALENDAR_PROP_INTERNAL))); + if (configuration.hasProperty(BUSINESS_CALENDAR_PROP_USER)) { + configurationCalendars.addAll( + loadCalendarsFromResourceList(configuration.getProperty(BUSINESS_CALENDAR_PROP_USER))); } + return configurationCalendars; } - private static void loadProperty(final Configuration configuration, final String property) { - final String location = configuration.getProperty(property); - try { - load(location); - } catch (Exception e) { - logger.warn().append("Problem loading calendars. property=").append(property) - .append(" importPath=").append(location).append(e).endl(); - throw new RuntimeException("Problem loading calendars. property=" + property + - " importPath=" + location, e); - } - } + private Calendars() {} - private static void load(final String businessCalendarConfig) throws NoSuchFileException { - final InputStream configToLoad = Calendars.class.getResourceAsStream(businessCalendarConfig); + // region Load - if (configToLoad == null) { - logger.warn("Could not find " + businessCalendarConfig + " on classpath"); - throw new RuntimeException("Could not open " + businessCalendarConfig + " from classpath"); + private static List loadCalendarsFromResourceList(String resource) { + final InputStream in = Calendars.class.getResourceAsStream(resource); + if (in == null) { + logger.warn("Could not find resource " + resource + " on classpath"); + throw new RuntimeException("Could not open resource " + resource + " from classpath"); } - - final Consumer consumer = (filePath) -> { - try { - final InputStream inputStream = Calendars.class.getResourceAsStream(filePath); - if (inputStream != null) { - final File calendarFile = inputStreamToFile(inputStream); - final BusinessCalendar businessCalendar = - BusinessCalendarXMLParser.loadBusinessCalendar(calendarFile); - addCalendar(businessCalendar); - // noinspection ResultOfMethodCallIgnored - calendarFile.delete(); - } else { - logger.warn("Could not open " + filePath + " from classpath"); - throw new RuntimeException("Could not open " + filePath + " from classpath"); - } - } catch (Exception e) { - logger.warn("Problem loading calendar: location=" + businessCalendarConfig, e); - throw new RuntimeException("Problem loading calendar: location=" + businessCalendarConfig, e); + final List calendars = new ArrayList<>(); + try (final BufferedReader config = new BufferedReader(new InputStreamReader(in))) { + final Iterator it = config.lines().iterator(); + while (it.hasNext()) { + final String calendarResource = it.next(); + calendars.add(BusinessCalendarXMLParser.loadBusinessCalendarFromResource(calendarResource)); } - }; - - try (final BufferedReader config = new BufferedReader(new InputStreamReader(configToLoad))) { - config.lines().forEach(consumer); + return calendars; } catch (Exception e) { - logger.warn("Problem loading calendar: location=" + businessCalendarConfig, e); - throw new RuntimeException("Problem loading calendar: location=" + businessCalendarConfig, e); + logger.warn("Problem loading calendar: location=" + resource, e); + throw new RuntimeException("Problem loading calendar: location=" + resource, e); } } @@ -115,7 +81,7 @@ private static void load(final String businessCalendarConfig) throws NoSuchFileE */ public synchronized static void removeCalendar(final String name) { Require.neqNull(name, "name"); - getMap().remove(name); + calMap.remove(name); } /** @@ -131,8 +97,7 @@ public synchronized static void addCalendar(final BusinessCalendar cal) { if (!NameValidator.isValidQueryParameterName(name)) { throw new IllegalArgumentException("Invalid name for calendar: name='" + name + "'"); } - - final Map map = getMap(); + final Map map = calMap; if (map.containsKey(name)) { final Calendar oldCalendar = map.get(name); @@ -219,7 +184,7 @@ public synchronized static BusinessCalendar calendar(final String name) { } final String n = name.toUpperCase(); - final Map map = getMap(); + final Map map = calMap; if (!map.containsKey(n)) { throw new IllegalArgumentException("No such calendar: " + name); @@ -258,7 +223,7 @@ public synchronized static String calendarName() { * @return names of all available calendars */ public synchronized static String[] calendarNames() { - return getMap().keySet().toArray(String[]::new); + return calMap.keySet().toArray(String[]::new); } // endregion diff --git a/engine/time/src/main/java/io/deephaven/time/calendar/CalendarsFromConfigurationModule.java b/engine/time/src/main/java/io/deephaven/time/calendar/CalendarsFromConfigurationModule.java new file mode 100644 index 00000000000..213965056db --- /dev/null +++ b/engine/time/src/main/java/io/deephaven/time/calendar/CalendarsFromConfigurationModule.java @@ -0,0 +1,24 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.time.calendar; + +import dagger.Module; +import dagger.Provides; +import dagger.multibindings.ElementsIntoSet; + +import java.util.HashSet; +import java.util.Set; + +/** + * Provides the {@link BusinessCalendar business calendars} from {@link Calendars#calendarsFromConfiguration()}. + */ +@Module +public interface CalendarsFromConfigurationModule { + + @Provides + @ElementsIntoSet + static Set providesCalendarsFromConfiguration() { + return new HashSet<>(Calendars.calendarsFromConfiguration()); + } +} diff --git a/engine/time/src/test/java/io/deephaven/time/calendar/CalendarInit.java b/engine/time/src/test/java/io/deephaven/time/calendar/CalendarInit.java new file mode 100644 index 00000000000..4632150154b --- /dev/null +++ b/engine/time/src/test/java/io/deephaven/time/calendar/CalendarInit.java @@ -0,0 +1,17 @@ +/** + * Copyright (c) 2016-2023 Deephaven Data Labs and Patent Pending + */ +package io.deephaven.time.calendar; + +final class CalendarInit { + + static { + for (BusinessCalendar calendar : Calendars.calendarsFromConfiguration()) { + Calendars.addCalendar(calendar); + } + } + + static void noop() { + + } +} diff --git a/engine/time/src/test/java/io/deephaven/time/calendar/TestCalendars.java b/engine/time/src/test/java/io/deephaven/time/calendar/TestCalendars.java index 75549000ef0..e76e3cbbb0a 100644 --- a/engine/time/src/test/java/io/deephaven/time/calendar/TestCalendars.java +++ b/engine/time/src/test/java/io/deephaven/time/calendar/TestCalendars.java @@ -12,6 +12,10 @@ public class TestCalendars extends BaseArrayTestCase { + static { + CalendarInit.noop(); + } + public void testDefault() { final BusinessCalendar calendar = Calendars.calendar(); assertEquals(Configuration.getInstance().getProperty("Calendar.default"), Calendars.calendarName()); diff --git a/engine/time/src/test/java/io/deephaven/time/calendar/TestStaticCalendarMethods.java b/engine/time/src/test/java/io/deephaven/time/calendar/TestStaticCalendarMethods.java index 00a4c644194..684b643edd4 100644 --- a/engine/time/src/test/java/io/deephaven/time/calendar/TestStaticCalendarMethods.java +++ b/engine/time/src/test/java/io/deephaven/time/calendar/TestStaticCalendarMethods.java @@ -22,6 +22,10 @@ */ public class TestStaticCalendarMethods extends BaseArrayTestCase { + static { + CalendarInit.noop(); + } + private final Map, Object[]> data = new HashMap<>(); { diff --git a/py/embedded-server/java-runtime/src/main/java/io/deephaven/python/server/EmbeddedServer.java b/py/embedded-server/java-runtime/src/main/java/io/deephaven/python/server/EmbeddedServer.java index 467ecdb15ba..c81f408a88d 100644 --- a/py/embedded-server/java-runtime/src/main/java/io/deephaven/python/server/EmbeddedServer.java +++ b/py/embedded-server/java-runtime/src/main/java/io/deephaven/python/server/EmbeddedServer.java @@ -13,6 +13,7 @@ import io.deephaven.io.logger.LogBuffer; import io.deephaven.io.logger.LogBufferOutputStream; import io.deephaven.server.auth.CommunityAuthorizationModule; +import io.deephaven.time.calendar.CalendarsFromConfigurationModule; import io.deephaven.server.console.ExecutionContextModule; import io.deephaven.server.console.groovy.GroovyConsoleSessionModule; import io.deephaven.server.console.python.PythonConsoleSessionModule; @@ -56,6 +57,7 @@ public class EmbeddedServer { CommunityAuthorizationModule.class, ClientDefaultsModule.class, ObfuscatingErrorTransformerModule.class, + CalendarsFromConfigurationModule.class, }) public interface PythonServerComponent extends JettyServerComponent { @Component.Builder diff --git a/py/server/tests/test_calendar.py b/py/server/tests/test_calendar.py index 00eec21dd2c..bff9f704626 100644 --- a/py/server/tests/test_calendar.py +++ b/py/server/tests/test_calendar.py @@ -15,6 +15,12 @@ class CalendarTestCase(BaseTestCase): + @classmethod + def setUpClass(cls) -> None: + super().setUpClass() + jpy.get_type('io.deephaven.integrations.python.CalendarsHelper').addCalendarsFromConfiguration() + + def setUp(self) -> None: super().setUp() diff --git a/server/src/main/java/io/deephaven/server/runner/CommunityDefaultsModule.java b/server/src/main/java/io/deephaven/server/runner/CommunityDefaultsModule.java index f65c829f0b6..9e18fe625e9 100644 --- a/server/src/main/java/io/deephaven/server/runner/CommunityDefaultsModule.java +++ b/server/src/main/java/io/deephaven/server/runner/CommunityDefaultsModule.java @@ -5,6 +5,7 @@ import dagger.Module; import io.deephaven.client.ClientDefaultsModule; +import io.deephaven.time.calendar.CalendarsFromConfigurationModule; import io.deephaven.server.console.ExecutionContextModule; import io.deephaven.server.console.groovy.GroovyConsoleSessionModule; import io.deephaven.server.console.python.PythonConsoleSessionModule; @@ -36,6 +37,7 @@ * @see ExecutionContextModule * @see ClientDefaultsModule * @see ObfuscatingErrorTransformerModule + * @see CalendarsFromConfigurationModule */ @Module(includes = { DeephavenApiServerModule.class, @@ -49,6 +51,7 @@ ExecutionContextModule.class, ClientDefaultsModule.class, ObfuscatingErrorTransformerModule.class, + CalendarsFromConfigurationModule.class, }) public interface CommunityDefaultsModule { } diff --git a/server/src/main/java/io/deephaven/server/runner/DeephavenApiServer.java b/server/src/main/java/io/deephaven/server/runner/DeephavenApiServer.java index 54eea4795e8..18211618049 100644 --- a/server/src/main/java/io/deephaven/server/runner/DeephavenApiServer.java +++ b/server/src/main/java/io/deephaven/server/runner/DeephavenApiServer.java @@ -23,6 +23,8 @@ import io.deephaven.server.plugin.PluginRegistration; import io.deephaven.server.session.SessionService; import io.deephaven.server.util.Scheduler; +import io.deephaven.time.calendar.BusinessCalendar; +import io.deephaven.time.calendar.Calendars; import io.deephaven.uri.resolver.UriResolver; import io.deephaven.uri.resolver.UriResolvers; import io.deephaven.uri.resolver.UriResolversInstance; @@ -36,6 +38,7 @@ import javax.inject.Provider; import java.io.IOException; import java.util.Map; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; @@ -53,6 +56,7 @@ public class DeephavenApiServer { private final GrpcServer server; private final UpdateGraph ug; private final LogInit logInit; + private final Provider> calendars; private final Scheduler scheduler; private final Provider scriptSessionProvider; private final PluginRegistration pluginRegistration; @@ -68,6 +72,7 @@ public DeephavenApiServer( final GrpcServer server, @Named(PeriodicUpdateGraph.DEFAULT_UPDATE_GRAPH_NAME) final UpdateGraph ug, final LogInit logInit, + final Provider> calendars, final Scheduler scheduler, final Provider scriptSessionProvider, final PluginRegistration pluginRegistration, @@ -80,6 +85,7 @@ public DeephavenApiServer( this.server = server; this.ug = ug; this.logInit = logInit; + this.calendars = calendars; this.scheduler = scheduler; this.scriptSessionProvider = scriptSessionProvider; this.pluginRegistration = pluginRegistration; @@ -135,6 +141,10 @@ public DeephavenApiServer run() throws IOException, ClassNotFoundException, Time log.info().append("Creating/Clearing Script Cache...").endl(); AbstractScriptSession.createScriptCache(); + for (BusinessCalendar calendar : calendars.get()) { + Calendars.addCalendar(calendar); + } + log.info().append("Initializing Script Session...").endl(); checkScopeChanges(scriptSessionProvider.get()); pluginRegistration.registerAll(); diff --git a/server/src/test/java/io/deephaven/server/runner/DeephavenApiServerTestBase.java b/server/src/test/java/io/deephaven/server/runner/DeephavenApiServerTestBase.java index a064a1ef415..d3c683ce331 100644 --- a/server/src/test/java/io/deephaven/server/runner/DeephavenApiServerTestBase.java +++ b/server/src/test/java/io/deephaven/server/runner/DeephavenApiServerTestBase.java @@ -18,6 +18,7 @@ import io.deephaven.proto.DeephavenChannelImpl; import io.deephaven.server.auth.AuthorizationProvider; import io.deephaven.server.auth.CommunityAuthorizationProvider; +import io.deephaven.time.calendar.CalendarsFromConfigurationModule; import io.deephaven.server.config.ServerConfig; import io.deephaven.server.console.NoConsoleSessionModule; import io.deephaven.server.log.LogModule; @@ -58,7 +59,8 @@ public abstract class DeephavenApiServerTestBase { ClientDefaultsModule.class, ObfuscatingErrorTransformerModule.class, JsPluginNoopConsumerModule.class, - SchedulerDelegatingImplModule.class + SchedulerDelegatingImplModule.class, + CalendarsFromConfigurationModule.class }) public interface TestComponent {