Cannot launch GUI programs from systemd service - spring

I've a Spring boot app, i execute it through systemd service in Ubuntu, after starting the X server with sudo startkde, i cannot launch GUI programs from the app using command line like gedit in the meantime it works when i launch the app using sudo java -jar demo.jar, i've tried putting gedit commande inside a shell script but the problem persists.
is there any solution to use the service and launch GUI programs, or launch the spring boot with another kind services that could solve the the problem.
here's the systemd service :
[Unit]
Description=demo
After=syslog.target
[Service]
User=ubuntu
ExecStart=/home/ubuntu/demo.jar --logging.file=logfile.log
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
here's the spring boot code :
#RestController
#EnableAutoConfiguration
#SpringBootApplication
public class DemoApplication {
#RequestMapping("/")
String home() {
ProcessBuilder builder = new ProcessBuilder("gedit");
builder.redirectErrorStream(true);
try {
final Process process = builder.start();
try {
process.waitFor();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return "Hello World!";
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}

systemd isn't a good fit for auto-starting GUI apps directly. As #jaysee explained, it's not connected to particularly GUI.
What systemd can do is start a window-manager, the window manager can be set to automatically log in a particular user, and that user can use the window manager's "autostart" feature to launch the GUI app.
I went down the same path myself trying to use exclusively systemd and the other route is what I found to work.
This is a common use-case for Raspberry Pis. So if you search for tutorials about [Raspberry PI autostart kiosk], you should find a number of options (whether you are using a Raspberry Pi or not). The newer Raspberry Pis use a newer systemd-based version of Debian, so in practice it's very similar to what you want to do with Ubuntu 16.04.

Related

How to debug quarkus lambda locally

I am beginner to Quarkus lambda and when I am looking for how to debug the Quarkus lambda then everyone is showing with REST API endpoints, is there any way to debug the Quarkus app using lambda handler ?
I know how to start the app in dev mode but I am struggling with invoking the handler method.
You can use SAM CLI for local debugging and testing. Here is the official documentation from quarkus.
It's really important that you follow the sequence.
Step-1:
sam local start-api --template target/sam.jvm.yaml -d 5005
Step-2:
Hit your API using your favourite rest client
Step-3
Add a Remote JVM debug configuration in your IDE, set your breakpoints and start debugging.
You can actually just add a Main class and set up a usual Run Configuration.
import io.quarkus.runtime.annotations.QuarkusMain;
import io.quarkus.runtime.Quarkus;
#QuarkusMain
public class Main {
public static void main(String ... args) {
System.out.println("Running main method");
Quarkus.run(args);
}
}
After that, just use curl or Postman to invoke the endpoint.
By default, the lambda handler starts on port 8080.
You can override it by passing
-Dquarkus.lambda.mock-event-server.dev-port=9999
So the curl will look like:
curl -XGET "localhost:9999/hello"
if the definition of the resource class looks like:
#Path("/hello")
public class GreetingResource {
#GET
#Produces(MediaType.TEXT_PLAIN)
public String hello() {
return "hello jaxrs";
}
}
Add a breakpoint in the Resource class and start the Main class in Debug mode. This will actually pause during a debug on a breakpoint.
You can just run mvn quarkus:dev and connect a remote debugger to it on port 5005 as shown in this image
Once quarkus is started in dev mode and you connect the remote debugger you can use Postman to send a request. Your breakpoints will be evaluated.

Spring Integration FTP in Docker container: not triggering flow

I am having quite a time figuring out where my issue is stemming from. I can run locally, I have built my .jar and ran that locally too.
I have my integration flow set as follows
#Bean
IntegrationFlow integrationFlow(final DataSource datasource) {
return IntegrationFlows.from(
Ftp.inboundStreamingAdapter(template())
.remoteDirectory("/folder/")
.patternFilter("file_name.txt")
.filter(
new FtpPersistentAcceptOnceFileListFilter(metadataStore(datasource), "")),
spec -> spec.poller(Pollers.fixedDelay(5, TimeUnit.SECONDS)))
.transform(streamToBytes())
.handle(handler())
.get()
}
#Bean
FtpRemoteFileTemplate template() {
return new FtpRemoteFileTemplate(ftpSessionFactory());
}
#Bean
public StreamTransformer streamToBytes() {
return new StreamTransformer(); // transforms to byte[]
}
#Bean
public ConcurrentMetadataStore metadataStore(final DataSource dataSource) {
return new JdbcMetadataStore(dataSource);
}
#Bean
public SessionFactory<FTPFile> ftpSessionFactory() {
DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
sf.setHost(host);
sf.setPort(port);
sf.setUsername(userName);
sf.setPassword(password);
return sf;
}
I have my datasource and my ftp information set in my application.yml
When I run this locally, I have no problems. When I run gradle build and run my .jar with several different openjdk versions (8u181, 8u191, 11.04), I have no issues.
When I run inside of a docker container using my .jar file, the problem arises.
My docker file
FROM openjdk:8u212-jdk-alpine
WORKDIR /app
COPY build/libs/app-1.0.jar .
RUN apk add --update ttf-dejavu && rm -rf /var/cache/apk/*
ENTRYPOINT ["java", "-jar", "app-1.0.jar"]
I turned DEBUG on and watched output.
Running locally and running the built .jar, I can see that the poller is working and it triggers the SQL queries to the metadataStore table that has been created in my remote db (postgresql).
Running in the docker container, I do not see the sql queries being run. which tells me that somewhere therein lies the issue.
With debug on my startup logs in the console are the same INFOs and WARNs regardless of running locally, running the built .jar, or running in the docker container.
There is this info message that might be of some assistance
Bean with key 'metadataStore' has been registered as an MBean but has no exposed attributes or operations
I checked to see if there might be a hidden SessionFactory connection issue by trying to connect to an invalid host, but I indeed get exceptions in my docker container for the invalid host. So I can confidently say that the FTP connection is valid and running with the correct host and port.
I am thinking it has to do with either the poller or my datasource.
Inside of this application, I am also running Spring Data Rest using JDBC and JPA, would there be any issue with the usage of the datasource bean across the different libraries?
Any help or guidance would be greatly appreciated.
so the default client mode for the DefaultFtpSessionFactory is "ACTIVE", but in my case, inside of a docker container, the client mode must be set to "PASSIVE"
to do this, i needed to add one line of code to the DefaultFtpSessionFactory
you must set client mode to 2 ... sf.setClientMode(2);
below is the final DefaultFtpSessionFactory bean.
#Bean
public SessionFactory<FTPFile> ftpSessionFactory() {
DefaultFtpSessionFactory sf = new DefaultFtpSessionFactory();
sf.setHost(host);
sf.setPort(port);
sf.setUsername(userName);
sf.setPassword(password);
sf.setClientMode(2);
return sf;
}

How to programatically tell Spring Boot application that application.yml is in app user home directory?

I am attempting to move my application.yml outside of my application to the user directory that the application runs under. I am aware that a common approach is to use startup params at runtime like -Dconfig.location=/path/to/external.properties (which incidentally I can't seem to make work propertly), but I need to be able to do this without changing the startup script if at all possible.
My goal was to do this in the main() method of the application groovy file that starts the app. In that method, I am detecting the user's home directory, and am attempting to set that as a property for the app to use. However, all approaches I have attempted have ended up with a FileNotFound (application.yml). can someone offer any advice on achieving what I want? Below is the most recent attempt
static void main(String[] args) throws NoSuchAlgorithmException, IOException, URISyntaxException {
String configPath = "${System.getProperty('user.home')}"
ConfigurableApplicationContext applicationContext = new SpringApplicationBuilder(Angular4SpringbootApplication)
.properties("spring.config.name:application,conf",
"spring.config.location=classpath:$configPath/application.yml")
.build().run(args)
SpringApplication.run(Angular4SpringbootApplication, args)
}
Since you pass the command line parameters to SpringApplication.run you could simply modify them before. I don't know much about Groovy, but I think this should work:
static void main(String[] args) {
SpringApplication.run(Angular4SpringbootApplication, ["--spring.config.location=file:${System.getProperty('user.home')}/application.yml"] + args)
}
You could also set a system property before starting the Spring context:
static void main(String[] args) {
System.setProperty('spring.config.location', "${System.getProperty('user.home')}/application.yml")
SpringApplication.run(Angular4SpringbootApplication, args)
}
If you do not like application.properties as the configuration file
name, you can switch to another file name by specifying a
spring.config.name environment property. You can also refer to an
explicit location by using the spring.config.location environment
property (which is a comma-separated list of directory locations or
file paths). The following example shows how to specify a different
file name:
java -jar myproject.jar --spring.config.name=myproject
Or you can use location (if rour file is outside your app, prefix with file: ) :
java -jar myproject.jar --spring.config.location=classpath:/default.properties
spring.config.name and spring.config.location are used very early to
determine which files have to be loaded, so they must be defined as an
environment property (typically an OS environment variable, a system
property, or a command-line argument).
Edit
If you want to do it without changing the startup script, you can do it like this :
#SpringBootApplication
public class SimpleBoot {
public static void main(String[] args) {
System.setProperty("spring.config.location","file:/path/to/application.yml")
SpringApplication.run(SimpleBoot.class, args);
}
}

spring boot commandline runner is using windows default character encoding

I am running spring boot application on windows and its using windows-1252 encoding. However stand alone java program is using UTF-8 encodeing. How do I force spring boot to use UTF-8. below code outputs ????. I use the below command using jar -jar target\spring-boot-example.jar
I verified that in power shell program that default character set is windows-1252 (System.Text.Encoding)::Default
public class SpringBootConsoleApplication implements CommandLineRunner {
public static void main(String[] args) throws Exception {
SpringApplication.run(SpringBootConsoleApplication.class, args);
}
#Override
public void run(String... args) throws Exception {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("test::" +"الرياض");
}
}
I tried the below options in application.properties without success:
# Charset of HTTP requests and responses. Added to the "Content-Type" header if not set explicitly.
spring.http.encoding.charset=UTF-8
# Enable http encoding support.
spring.http.encoding.enabled=true
# Force the encoding to the configured charset on HTTP requests and responses.
spring.http.encoding.force=true
Try running your app with -Dfile.encoding=UTF8 in the command line.
Example:
java -jar -Dfile.encoding=UTF8 target/myapp-0.0.1-SNAPSHOT.jar
The problem seems to be your stdout, not the code. I suggest you create a simple main class, without Spring Boot, or any external dependencies, and print UTF-8 characters. I'm on a Mac, and the following code prints find for me:
public class Main {
public static void main(String[] args) {
System.out.println("Default Charset=" + Charset.defaultCharset());
System.out.println("test::" + "الرياض");
}
}
Default Charset=UTF-8
test::الرياض
Another thing you may want to try is writing it to a file instead of stdout.
Edit:
I think you're barking the wrong tree. No one uses Spring Boot for printing to stdout. The spring.http.encoding properties you'd set are actually HttpEncodingProperties which Boot uses to auto configure encoding using HttpEncodingAutoConfiguration. But all that's for a HTTP request, not for printing to stdout. Any application that deserves to go to Prod should use a logger, and not System.out.println.
#AbjitSarkar #JC Carrillo this issue seems to be with windows environment. I deployed the same code on UbuntuVM and everything seems to be fine.
Thank you for listening to me and giving me tips to explore !!

Run exe outside of gradle scope

I am trying to kick of an exe (mongodb) from gradle, but need that exe to run outside of gradle scope so that the gradle task is not blocked for ever.
task startMongo(type: Exec) {
executable "$buildDir/mongo/mongod.exe"
args "--dbpath=$buildDir/mongo/data/db"
}
Mongodb starts fine, but the task is blocked as the mongo server waits for connections.
2014-12-10T14:30:33.018-0700 [initandlisten] waiting for connections on port 27017
Robert - thank you. I wrote a custom gradle task and started the exe in background.
class MyTask extends DefaultTask {
#TaskAction
void startProcess() {
ProcessBuilder processBuilder = new ProcessBuilder()
processBuilder.command('exe-path', 'arg')
processBuilder.start()
}

Resources