Skip to content

Commit

Permalink
start to implement #279 (unfinished)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathisdt committed Oct 19, 2024
1 parent b023225 commit 91cd624
Show file tree
Hide file tree
Showing 6 changed files with 142 additions and 20 deletions.
9 changes: 8 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@

<!-- dependency versions -->
<version.spring>6.1.13</version.spring>
<version.tomcat>11.0.0</version.tomcat>
<version.slf4j>2.0.16</version.slf4j>
<version.logback>1.5.11</version.logback>
<version.log4j>2.24.1</version.log4j>
Expand Down Expand Up @@ -149,7 +150,7 @@
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<artifactId>spring-webmvc</artifactId>
<version>${version.spring}</version>
<exclusions>
<exclusion>
Expand All @@ -162,6 +163,12 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>${version.tomcat}</version>
</dependency>


<!-- REMOTE -->
<dependency>
Expand Down
4 changes: 3 additions & 1 deletion src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,7 @@

requires org.eclipse.paho.client.mqttv3;
requires org.bitbucket.cowwoc.diffmatchpatch;

requires spring.web;
requires spring.webmvc;
requires org.apache.tomcat.embed.core;
}
55 changes: 43 additions & 12 deletions src/main/java/org/zephyrsoft/sdb2/Options.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,46 +37,50 @@ public static Options getInstance() {
private String propertiesFile = FileAndDirectoryLocations.getDefaultPropertiesFileName();

private static final String PROP_LANGUAGE = "language";
@Option(name = "--language", aliases = "-lang", metaVar = "<CODE>", usage = "use this language (2-char ISO code, e.g. de)")
@Option(name = "--" + PROP_LANGUAGE, aliases = "-lang", metaVar = "<CODE>", usage = "use this language (2-char ISO code, e.g. de)")
private String language = null;

private static final String PROP_COUNTRY = "country";
@Option(name = "--country", metaVar = "<CODE>", usage = "use this country (2-char ISO code, e.g. DE)")
@Option(name = "--" + PROP_COUNTRY, metaVar = "<CODE>", usage = "use this country (2-char ISO code, e.g. DE)")
private String country = null;

private static final String PROP_TIMEZONE = "timezone";
@Option(name = "--timezone", aliases = "-tz", metaVar = "<NAME>", usage = "use this time zone (e.g. Europe/Berlin)")
@Option(name = "--" + PROP_TIMEZONE, aliases = "-tz", metaVar = "<NAME>", usage = "use this time zone (e.g. Europe/Berlin)")
private String timezone = null;

private static final String PROP_STATISTICS_DIR = "statistics";
@Option(name = "--statistics", aliases = "-stat", metaVar = "<DIR>", usage = "use this directory as statistics storage (optional, the default is ~/.songdatabase/statistics/)")
@Option(name = "--" + PROP_STATISTICS_DIR, aliases = "-stat", metaVar = "<DIR>", usage = "use this directory as statistics storage (optional, the default is ~/.songdatabase/statistics/)")
private String statisticsDir = null;

private static final String PROP_SONGS_DIR = "songs";
@Option(name = "--songs", aliases = "-song", metaVar = "<DIR>", usage = "use this directory as songs storage (optional, the default is ~/.songdatabase/songs/)")
@Option(name = "--" + PROP_SONGS_DIR, aliases = "-song", metaVar = "<DIR>", usage = "use this directory as songs storage (optional, the default is ~/.songdatabase/songs/)")
private String songsDir = null;

private static final String PROP_SONGS_BACKUP_DIR = "songs-backup";
@Option(name = "--songs-backup", aliases = "-songback", metaVar = "<DIR>", usage = "use this directory as songs backup storage (optional, the default is ~/.songdatabase/songs/backup/)")
@Option(name = "--" + PROP_SONGS_BACKUP_DIR, aliases = "-songback", metaVar = "<DIR>", usage = "use this directory as songs backup storage (optional, the default is ~/.songdatabase/songs/backup/)")
private String songsBackupDir = null;

private static final String PROP_SETTINGS_DIR = "settings";
@Option(name = "--settings", aliases = "-sett", metaVar = "<DIR>", usage = "use this directory as settings storage (optional, the default is ~/.songdatabase/settings/)")
@Option(name = "--" + PROP_SETTINGS_DIR, aliases = "-sett", metaVar = "<DIR>", usage = "use this directory as settings storage (optional, the default is ~/.songdatabase/settings/)")
private String settingsDir = null;

private static final String PROP_LOGS_DIR = "logs";
@Option(name = "--logs", aliases = "-logs", metaVar = "<DIR>", usage = "use this directory as logs storage (optional, the default is ~/.songdatabase/log/)")
@Option(name = "--" + PROP_LOGS_DIR, aliases = "-logs", metaVar = "<DIR>", usage = "use this directory as logs storage (optional, the default is ~/.songdatabase/log/)")
private String logsDir = null;

private static final String PROP_LOGS_ROLLOVER_DIR = "logs-rollover";
@Option(name = "--logs-rollover", aliases = "-logsroll", metaVar = "<DIR>", usage = "use this directory as older logs storage (optional, the default is ~/.songdatabase/log/)")
@Option(name = "--" + PROP_LOGS_ROLLOVER_DIR, aliases = "-logsroll", metaVar = "<DIR>", usage = "use this directory as older logs storage (optional, the default is ~/.songdatabase/log/)")
private String logsRolloverDir = null;

private static final String PROP_DATABASE_DIR = "database";
/** this is used when remote control (via MQTT) is active */
@Option(name = "--database", aliases = "-db", metaVar = "<DIR>", usage = "use this directory as database storage (optional, the default is ~/.songdatabase/db/)")
@Option(name = "--" + PROP_DATABASE_DIR, aliases = "-db", metaVar = "<DIR>", usage = "use this directory as database storage (optional, the default is ~/.songdatabase/db/)")
private String databaseDir = null;


private static final String PROP_SPLIT_MODE = "split-mode";
@Option(name = "--" + PROP_SPLIT_MODE, aliases = "-sm", metaVar = "<MODE>", usage = "make SDB either a server (which takes orders via network) or a client (which gives orders)")
private SplitMode splitMode = null;

private static final String PROP_SONGS_FILE = "songs-file";
@Argument(metaVar = "<FILE>", usage = "use this file to load from and save to (optional, the default is ~/.songdatabase/songs/songs.xml)")
private String songsFile = null;
Expand Down Expand Up @@ -176,7 +180,15 @@ public String getDatabaseDir() {
private void setDatabaseDir(String databaseDir) {
this.databaseDir = databaseDir;
}


public SplitMode getSplitMode() {
return splitMode;
}

public void setSplitMode(final SplitMode splitMode) {
this.splitMode = splitMode;
}

public String getSongsFile() {
return songsFile;
}
Expand Down Expand Up @@ -219,8 +231,27 @@ void addMissingValuesFrom(Properties props) {
if (databaseDir == null && props.containsKey(PROP_DATABASE_DIR)) {
setDatabaseDir(props.getProperty(PROP_DATABASE_DIR));
}
if (splitMode == null && props.containsKey(PROP_SPLIT_MODE)) {
setSplitMode(SplitMode.byNameCaseInsensitive(props.getProperty(PROP_SPLIT_MODE)));
}
if (songsFile == null && props.containsKey(PROP_SONGS_FILE)) {
setSongsFile(props.getProperty(PROP_SONGS_FILE));
}
}

public enum SplitMode {
CLIENT,
SERVER;

public static SplitMode byNameCaseInsensitive(String name) {
if (name.equalsIgnoreCase(CLIENT.name())) {
return CLIENT;
} else if (name.equalsIgnoreCase(SERVER.name())) {
return SERVER;
} else {
throw new IllegalArgumentException("split mode '" + name + "' not recognized, try "
+ CLIENT.name().toLowerCase() + " or " + SERVER.name().toLowerCase());
}
}
}
}
34 changes: 32 additions & 2 deletions src/main/java/org/zephyrsoft/sdb2/SpringConfiguration.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,26 +19,56 @@
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.togglz.core.context.StaticFeatureManagerProvider;
import org.togglz.core.manager.FeatureManager;
import org.togglz.core.manager.FeatureManagerBuilder;
import org.togglz.core.repository.FeatureState;
import org.togglz.core.repository.mem.InMemoryStateRepository;
import org.togglz.core.user.NoOpUserProvider;
import org.zephyrsoft.sdb2.api.Endpoints;
import org.zephyrsoft.sdb2.gui.KeyboardShortcutManager;
import org.zephyrsoft.sdb2.gui.MainWindow;
import org.zephyrsoft.sdb2.service.ExportService;
import org.zephyrsoft.sdb2.service.IndexerService;
import org.zephyrsoft.sdb2.util.gui.ErrorDialog;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRegistration;

/**
* Configures the DI context.
*/
@Configuration
public class SpringConfiguration {
@EnableWebMvc
public class SpringConfiguration implements WebApplicationInitializer {

private static final Logger LOG = LoggerFactory.getLogger(SpringConfiguration.class);


@Override
public void onStartup(final ServletContext servletContext) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(SpringConfiguration.class);

servletContext.addListener(new ContextLoaderListener(rootContext));

AnnotationConfigWebApplicationContext dispatcherContext = new AnnotationConfigWebApplicationContext();

ServletRegistration.Dynamic dispatcher = servletContext.addServlet("dispatcher", new DispatcherServlet(dispatcherContext));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
}

@Bean
public Endpoints endpoints() {
return new Endpoints();
}

@Bean
public FeatureManager featureManager() {
FeatureManager featureManager = new FeatureManagerBuilder()
Expand Down
49 changes: 45 additions & 4 deletions src/main/java/org/zephyrsoft/sdb2/Start.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,27 @@

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.time.ZoneId;
import java.util.Locale;
import java.util.Properties;
import java.util.TimeZone;

import org.apache.catalina.startup.Tomcat;
import org.apache.commons.lang3.StringUtils;
import org.kohsuke.args4j.CmdLineException;
import org.kohsuke.args4j.CmdLineParser;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.zephyrsoft.sdb2.util.VersionTools;
import org.zephyrsoft.sdb2.util.gui.ErrorDialog;

import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRegistration;

/**
* Startup class for SDBv2.
*/
Expand Down Expand Up @@ -96,9 +102,33 @@ private Start(String[] args) {
log.debug("default locale is {}", Locale.getDefault());
log.debug("application version is {}", VersionTools.getCurrent());
log.debug("application commit hash is {}", VersionTools.getGitCommitHash());


// TODO remake startup process -> https://auth0.com/blog/spring-5-embedded-tomcat-8-gradle-tutorial/
log.debug("loading application context");
new AnnotationConfigApplicationContext(SpringConfiguration.class);
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringConfiguration.class);
context.refresh();

if (options.getSplitMode() == Options.SplitMode.SERVER) {
log.debug("starting API server");

// TODO make port configurable
// Tomcat tomcat = new Tomcat();
// tomcat.setBaseDir(createTempDir(8899));
// tomcat.setPort(8899);
// String appBase = ".";
// tomcat.getHost().setAppBase(appBase);
// tomcat.addWebapp("", appBase);
// tomcat.start();
// tomcat.getServer().await();

DispatcherServlet servlet = new DispatcherServlet(context);
ServletRegistration.Dynamic registration = context.getBean(ServletContext.class).addServlet("api", servlet);
registration.setLoadOnStartup(1);
registration.addMapping("/*");
} else {
log.debug("not starting API (not configured as split mode server)");
}
} catch (Exception e) {
log.error("problem while starting up the application", e);
ErrorDialog.openDialogBlocking(null, "There was a problem while starting the Song Database:\n\n"
Expand All @@ -109,5 +139,16 @@ private Start(String[] args) {
}
}
}


private static String createTempDir(int port) {
try {
File tempDir = File.createTempFile("tomcat.", "." + port);
tempDir.delete();
tempDir.mkdir();
tempDir.deleteOnExit();
return tempDir.getAbsolutePath();
} catch (IOException ex) {
throw new RuntimeException("Unable to create tempDir. java.io.tmpdir is set to " + System.getProperty("java.io.tmpdir"), ex);
}
}
}
11 changes: 11 additions & 0 deletions src/main/java/org/zephyrsoft/sdb2/api/Endpoints.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.zephyrsoft.sdb2.api;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;

public class Endpoints {
@GetMapping("/{name}")
public String getGreeting(@PathVariable String name) {
return "Hello " + name;
}
}

0 comments on commit 91cd624

Please sign in to comment.