Running embedded H2 database with mvn jetty:run - java

I've been trying to figure out how to run an embedded database through a profile and be able to run REST calls through postman.
This is what I have so far:
<profile>
<id>developRest</id>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>sql-maven-plugin</artifactId>
<version>1.5</version>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
<configuration>
<driver>org.h2.Driver</driver>
<url>jdbc:h2:mem:test</url>
<username>sa</username>
<password>sa</password>
</configuration>
<executions>
<execution>
<id>my-execution</id>
<goals>
<goal>execute</goal>
</goals>
<configuration>
<autocommit>true</autocommit>
<srcFiles>
<srcFile>src/test/resources/table-ddl.sql</srcFile>
<srcFile>src/test/resources/insert-into-table.sql</srcFile>
</srcFiles>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>${jetty.version}</version>
<configuration>
<webApp>
<descriptor>src/main/webapp/WEB-INF/jetty.xml</descriptor>
</webApp>
<stopKey></stopKey>
<stopPort></stopPort>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>${h2.version}</version>
</dependency>
</dependencies>
</profile>
I've played around with phases but nothing really seems to stick. When I run this with mvn sql:execute#my-execution jetty:run, the servlet runs but once I call a rest method I get
Failed to execute goal org.codehaus.mojo:sql-maven-plugin:1.5:execute (my-execution) on project myProject: The parameters 'driver', 'url' for goal org.codehaus.mojo:sql-maven-plugin:1.5:execute are missing or invalid
What am I missing that will get the driver and url to be valid? Thanks for your help.
Update: Used mvn -PdevelopRest sql:execute#my-execution jetty:run to get rid of the driver and url error but still stuck with:
### Error querying database. Cause: org.h2.jdbc.JdbcSQLException: Table "myTable" not found; SQL statement:
When calling a GET from postman. Any Thoughts?

I find it hard to believe that you get a Maven error when you call a REST method (Failed to execute goal ...).
That aside, I think your real problem is this: you are using H2 as an in-memory database, that means that it's available as long as your application runs. When your application goes away, so does your database.
In the context of Maven, where you have multiple plugins executing, the database does not outlive the execution of a single plugin. Your my-execution instantiates an in-memory database, which then goes away. The jetty-maven-plugin creates its own in-memory database, which then does not have any of the DDL/SQL that went into the previous one.
There is probably a number of ways to fix this, like these:
Don't use an in-memory database, rather have H2 write out files, e.g. jdbc:h2:/data/test, or, since you're using Maven: jdbc:h2:${project.build.directory}/data/test
Don't initialize the database using the sql-maven-plugin, but directly inside the application. You could do that:
With some custom code, that you only put on the test classpath
By adding the DDL/SQL to the connection string of the application ("Execute SQL on Connection"), like so:
jdbc:h2:mem:test;INIT=runscript from '~/table-ddl.sql'\\;runscript from '~/insert-into-table.sql'";
H2 is an awesome database. Good luck!

Related

How to run a Java/Maven application with external libraries in Heroku?

I've been building a Java application, which runs as expected when executing it locally. Now I'm trying the next step, to move it into an external platform. I chose Heroku because of their free plans for a starter, and also because it lets me have a small PostGreSQL database, which I use along with the application.
Due to the way Heroku works, I was forced to integrate Java with Maven, which I know little to none about. But I was still able to work my way there until I was able to compile and deploy the application (source code is in GitHub), albeit with errors.
For once, I'm using a couple external libraries:
jsoup-1.13.1.jar – Jsoup, for easier parsing of HTML files
mail.jar – Java mail, for emailing reports
Whenever the application is deployed in Heroku, there's an Exception in thread "main" java.lang.NoClassDefFoundError: org/jsoup/Jsoup, ultimately triggered by the Jsoup.connect invocation. From what I understand, Maven only add the references to the program but does not include the actual libraries there for runtime, which I think may be the cause of the issue.
I've tried modifying my pom.xml file by adding these dependencies manually:
<dependencies>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.2.18</version>
</dependency>
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>1.13.1</version>
</dependency>
</dependencies>
And also these plugins in the build section:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>checker</finalName>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
What am I doing wrong? I would be very grateful for hints to help me get my application running, at least resolving the reason why Jsoup isn't working at all in Heroku. Thanks in advance!

Deploy restful api on azure successfully but always return 404 error when i meet the url

In my project, i deployed the jersey api on the azure successfully, and i put the ROOT.war file in the /wwwroot/webapps, and the tomcat successfully to extract the file and all the project stuff showed on this directory.But the app always return 404, i dont know why.
Here is my pom.xml file:
<groupId>patientinformationdisplayer</groupId>
<artifactId>pom</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.glassfish.jersey</groupId>
<artifactId>jersey-bom</artifactId>
<version>2.28</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<inherited>true</inherited>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-webapp-maven-plugin</artifactId>
<version>1.5.3</version>
<configuration>
<!-- App information -->
<resourceGroup>team19backend</resourceGroup>
<appName>team19backend</appName>
<region>UK south</region>
<!-- Java Runtime Stack for App on Linux-->
<linuxRuntime>tomcat 8.5-jre8</linuxRuntime>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>HoloBackend.Main</mainClass>
</configuration>
</plugin>
</plugins>
</build>
I dont know what going on with the deployment , and it took me whole day to do this. Please help me to fix this, so many thanks for you.
If you deploy the application to local Tomcat, can you access the site using root URL?
Recommened way to remove the out-of-the-box ROOT/ directory. Please double check whether you have done that.
You may also want to refer to http://tomcat.apache.org/tomcat-7.0-doc/config/context.html, where it states:
The context path of this web application, which is matched against the beginning of each request URI to select the appropriate web application for processing. All of the context paths within a particular Host must be unique. If you specify a context path of an empty string (""), you are defining the default web application for this Host, which will process all requests not assigned to other Contexts.
This attribute must only be used when statically defining a Context in server.xml. In all other circumstances, the path will be inferred from the filenames used for either the .xml context file or the docBase.
Even when statically defining a Context in server.xml, this attribute must not be set unless either the docBase is not located under the Host's appBase or both deployOnStartup and autoDeploy are false. If this rule is not followed, double deployment is likely to result.
And this link(http://stackoverflow.com/questions/16160565/configure-the-path-localhost-of-the-war-application-to-be-the-root-java-ee ) may help you.
Hope it helps.

neo4j procedure depending on signed jar (mapdb)

I have created a neo4j user-defined procedure. It also compiles and works in neo4j.
Recently though, I added a dependency to my procedure plugin that prevents neo4j from starting when I try to run the newly built jar. Concretely, I receive following exception at the bottom of the stack trace:
Caused by: java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
The only thing I changed is to add MapDB to my dependencies. So I suspect that it depends on some signed artifact. As it turns out neo4j plugins are "uber-jars" (i.e., shaded jars) which doesn't work very well with signed dependencies.
I figured I could try to exclude MapDB from the shading by changing the scope to provided and additionally adding the mapdb jar to plugins folder of neo4j. So the plugins folder of neo4j now includes both mapdb.jar and myprocedure.jar.
This doesn't seem to work though: neo4j starts, but when calling my procedure I receive a ClassNotFound Exception.
Any ideas on how I can solve this dilemma? I really depend on something like MapDB as my graph is very large and keeping everything in my procedure in-memory regularly leads to memory exceptions.
Many thanks in advance!
The important part of my pom.xml should it help (I started off with the procedure template so it still looks quite similar):
<dependencies>
<!-- other dependencies that don't make a difference ... -->
<dependency>
<groupId>org.mapdb</groupId>
<artifactId>mapdb</artifactId>
<version>3.0.7</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j</artifactId>
<version>${neo4j.version}</version>
<scope>provided</scope>
</dependency>
<!-- Test Dependencies -->
<dependency>
<groupId>org.neo4j.test</groupId>
<artifactId>neo4j-harness</artifactId>
<version>${neo4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>1.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<!-- Neo4j Procedures require Java 8 -->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<!-- This generates a jar-file with our procedure code,
plus any dependencies marked as `compile` scope.
This should then be deployed in the `plugins` directory
of each Neo4j instance in your deployment.
After a restart, the procedure is available for calling. -->
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
So, one solution that worked was to use the maven-assembly-plugin instead of the maven-shade-plugin. The assembly plugin creates a standalone jar with all dependencies without re-packaging all dependencies.
Of course, I had to remove the <scope>provided</scope> for mapdb so it is also included in the assembled jar.
The rest is just replacing the shade plugin with following snippet (thanks to this question here):
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
Afterwards I received another exception which I thought was due to a wrong signature:
Caused by: java.lang.VerifyError ...
Turns out this was just because I had another procedure in neo4j that uses the same dependencies as mapdb. Quick fix was to remove that procedure library.
Of course, there are also other solutions, including removing the signature, or re-signing it. However, I explicitly did not want to remove any signatures.
I'm not aware that neo4j is checking any jar signatures by default. I suspect the repackaging of mapdb artifact being the culprit.
To validate that, remove the shade or assembly plugin in and build a jar that solely contains your code. Copy that jar and the mapdb.jar into the plugin folder and observe logs during a restart.

Try to use flyway for multiple DB instances

Running the Maven flyway-plugin
mvn flyway:migrate
with this configuration:
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>4.0.3</version>
<configuration>
<driver>com.mysql.jdbc</driver>
<url>jdbc:mysql://localhost:3306/schema2?createDatabaseIfNotExist=true</url>
<user>root</user>
<password>root</password>
</configuration>
</plugin>
I try to create number of executions like in this solution:
How to use Flyway configuration to handle multiple databases
Start from one execution:
<plugin>
<groupId>org.flywaydb</groupId>
<artifactId>flyway-maven-plugin</artifactId>
<version>4.0.3</version>
<executions>
<execution>
<id>migrate-database</id>
<phase>compile</phase>
<goals>
<goal>migrate</goal>
</goals>
<configuration>
<driver>com.mysql.jdbc</driver>
<url>jdbc:mysql://localhost:3306/schema2?createDatabaseIfNotExist=true</url>
<user>root</user>
<password>root</password>
</configuration>
</execution>
</executions>
</plugin>
See exception:
[ERROR] Failed to execute goal org.flywaydb:flyway-maven-plugin:4.0.3:migrate (default-cli) on project UrbanLife: org.flywaydb.core.api.FlywayException: Unable to connect to the database. Configure the url, user and password! -> [Help 1]
Looks like flyway can't see configuration inside
(Interesting that, in link, I mentioned before, it works)
Please help to create flyway multyDB integration via maven.
When you have multiple (or just one) <execution> in your maven plugin configuration and are attempting to run a specific execution from the command line you need to specify the execution by the execution id like so in your case
mvn flyway:migrate#migrate-database
see also: How to execute maven plugin execution directly from command line?
Lastly, if you want a specific execution to be the default, you can give it the execution id of default-cli as explained in these maven docs. Then you can simply run mvn flyway:migrate.
The FQN of the driver is incorrect, it should be com.mysql.jdbc.Driver or you could also simply remove it as it will be auto-detected from the URL.
You will also need to add the driver as dependency of your plugin by adding
<plugin>
...
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
</dependencies>
</plugin>

Can't access Maven properties with Spring

Hello I am new to Maven in general so I'd like to apologise in advance if I get things wrong.
I have a Maven project with spring in which I also access a MySQL database.often the MySQL database is not accessible so I use a local database for testing, I swap between the two by changing the active profile.
I set up the profiles by putting this in my POM.xml:
<profiles>
<profile>
<id>Local</id>
<dependencies>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>2.3.3</version>
<classifier>jdk5</classifier>
</dependency>
</dependencies>
<properties>
<jdbc.url>jdbc:hsqldb:file:databaseName</jdbc.url>
<jdbc.username>a</jdbc.username>
<jdbc.password></jdbc.password>
<jdbc.driver>org.hsqldb.jdbcDriver</jdbc.driver>
</properties>
</profile>
<profile>
<id>MySQL</id>
<dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.38</version>
</dependency>
</dependencies>
<properties>
<jdbc.url>jdbc:mysql://mysql.website.ac.uk:3306</jdbc.url>
<jdbc.username>user</jdbc.username>
<jdbc.password>1234</jdbc.password>
<jdbc.driver>com.mysql.jdbc.Driver</jdbc.driver>
</properties>
</profile>
</profiles>
When I try to access the properties variables through for example ${jdbc.url} they are not converted to the actual values as defined in the profile and I get errors. I suspect it might have something to do with Spring Boot.
Apart from the specific sprint-boot problem I think you are missing the maven resource filtering configuration.
Maven properties are not automatically propagated to Spring unless you put them into a separate properties files which must then be managed by spring (Usually via PropertyPlaceholderConfigurer).
But without maven filtering turned on properties are not automatically resolved, usually if you do not have many items under tour src/resources folder you can just enable filtering globally with
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
And your properties file should replace placeholders with maven values.
If, on the other hand in you have several resources in src/main/resources, you should check documentation more deeply to avoid binary files corruption
I think that spring boot is simply wrapping up all the process automatically in your application properties files.
You specified properties in profile, so there is a workaround. Annotations such as #Value("${name}") are referencing to externalized configuration, e.g. from application.yml. You should use this file to load properties you want. #property_name# loads property from your maven profile.
jdbc:
url: #jdbc.url#
username: #jdbc.username#
and so on...
Then these properties will be accessible in your code.
Maven properties are not put into environment variables or JVM variables that you can access by Spring.
However you can usually instruct maven plugin to do it for you.
For example configuration of maven-failsafe-plugin I use to set up test db:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<includes>**/*Integration.java</includes>
<environmentVariables>
<mysql.version>${mysql.version}</mysql.version>
<test.mysql.username>${test.mysql.username}</test.mysql.username>
<test.mysql.password>${test.mysql.password}</test.mysql.password>
<test.mysql.port>${test.mysql.port}</test.mysql.port>
<test.mysql.db>${test.mysql.db}</test.mysql.db>
</environmentVariables>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>

Categories