I have a multi-module Maven project (https://github.com/veniltonjr/msplearning)
One of my modules I need run programmatically the command from Maven build "clean install", but when I invoke the execution of these goals the following error occurs:
java.lang.IllegalStateException: Maven application directory was not specified, and ${maven.home} is not provided in the system properties. Please specify at least on of these.
In the Maven Invoker documentation is said that M2_HOME environment variable must exist.
Already have this variable set in my SO. This should not be enough to make the method invoke work? Follows the code snippet where I run the method in question:
Invoker invoker = new DefaultInvoker();
invoker.setLocalRepositoryDirectory(new File("C:\\git\\msplearning"));
InvocationRequest request = new DefaultInvocationRequest();
request.setGoals(Arrays.asList("clean", "install"));
InvocationResult result = invoker.execute(request); // Exception occours here...
Already, thanks!
EDITED (The Solution)
I had to set the POM and also set the Maven Home, which in my case is in the M3_HOME environment variable:
InvocationRequest request = new DefaultInvocationRequest();
request.setPomFile(new File("C:\\git\\msplearning\\pom.xml"));
request.setGoals(Collections.singletonList("verify"));
Invoker invoker = new DefaultInvoker();
invoker.setMavenHome(new File(System.getenv("M3_HOME")));
InvocationResult result = invoker.execute(request);
Thanks #RobertScholte and #khmarbaise!
Either set the request.pomFile or request.baseDirectory so the Invoker knows from which directory or file Apache Maven should be executed.
If you're running from a Maven-Surefire unit test then it's best to request that Surefire passes the maven.home system property on to its child processes. Per https://maven.apache.org/shared/maven-invoker/usage.html you can do this by adding the following config stanza:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version> <!-- see surefire-page for available versions -->
<configuration>
<systemPropertyVariables>
<maven.home>${maven.home}</maven.home>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
...
</build>
...
</project>
Related
import software.amazon.awscdk.services.lambda.Function;
Function helloLambda = new Function(helloStack, "hellocdkworld123", FunctionProps.builder()
.functionName("HelloLambda")
.code(Code.fromAsset("target/cdkhello-0.1.jar")) // <- x ?
.runtime(Runtime.JAVA_8)
.handler("com.myorg.functions.HelloLambda::sayHello") <- y?
.build());
There is also a possibility to reference it by S3 bucket. But when I run cdk bootstrap I get a generated bucket with generated name of the jar file. How should I be able to reference that before hand from code? Of course now I could write the exact bucket + file but then purpose of defining it from code is lost right?
First of all, assuming that the method that you want to execute when the Lambda is invoked is sayHello, from the com.myorg.functions.HelloLambda class, then that part of your solution is correct. The more difficult part is actually accessing the JAR with your Lambda code in it.
NOTE: I've updated my original answer with what I think is a better way to accomplish this. In order to avoid confusion and making this answer too wordy, I've removed the original answer, though much of it is common with this one. I credit this answer for helping to improve this answer.
Pass the path to the dependent resource's JAR to CDK
TL;DR
Create a new property for the full path to your Lambda JAR.
Associate dependency and execution related goals into the package phase of the build.
Update cdk.json to point to the the package phase.
Pass the full path via a system property to your CDK code.
Use the System property to pass to Code.asset(...).
Preparation
I've separated out the Lambda and the CDK infrastructure code into separate Maven modules. The intention being that once the Lambda code is compiled, packaged up into an uber JAR (its code plus all of its dependencies' code), the infrastructure module can refer to it as a dependency, passing the full path to the Lambda JAR to the App/Stack class to that it can use it as an asset.
Create a new property for the full path to your Lambda JAR.
In the properties section of your pom.xml, create a new property to refer to your Lambda JAR. Something like this:
<properties>
...
<lambda.jar>${GROUP_ID:ARTIFACT_ID:jar}</lambda.jar>
...
</properties>
Populate a property with the full path to your Lambda dependency's JAR, using the dependency plugin.
<build>
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<goals>
<goal>properties</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
</plugin>
...
<plugins>
</build>
This associates the properties goal with the process-resources phase. Whenever that phase of the build occurs, the property you've created previously will be populated with the full path to the JAR in your local repository.
Associate dependency and execution related goals into a single phase of the build.
When you create a new CDK Java project, it outputs a file called cdk.json, which points by default to the Maven exec:java goal. In order for your new lambda.jar property to be populated correctly, you need to associate the exec:java goal with the same phase as above.
<build>
<plugins>
...
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.6.0</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
<phase>package</phase>
</execution>
</executions>
<configuration>
<mainClass>com.myorg.TestingApp</mainClass>
</configuration>
</plugin>
...
</plugins>
</build>
In order for your code to get access to the JAR file that you've generated, you need to create a System property (I couldn't get environment variables to work) to your App class. Your pom.xml started with something like this:
Pass the full path via a system property to your CDK code.
In the configuration section (after mainClass), add a system property for your assets directory, something like this:
<systemProperties>
<systemProperty>
<key>lambda.jar</key>
<value>${lambda.jar}</value>
</systemProperty>
</systemProperties>
Update cdk.json to point to the the common phase you've used.
Your cdk.json of your CDK project should be changed to point to the process-resources phase. Once done it will look like this:
{
"app": "mvn package"
}
It will cause both the goals to be run in succession, and upon execution the path to your Lambda's JAR will be passed as a system property.
Access the property from your App/Stack code.
Finally, now that the system property is created, you can access it from your code by calling System.getProperty("lambda.jar"). Something like this:
final Code code = Code.fromAsset(System.getProperty("lambda.jar"));
You can then use the code reference wherever needed when defining your Lambda functions.
How can I write equivalent maven plugin for the following gradle plugin defined?
/*
* Plugin to copy system properties from gradle JVM to testing JVM
* Code was copied from gradle discussion froum:
* http://forums.gradle.org/gradle/topics/passing_system_properties_to_test_task
*/
class SystemPropertiesMappingPlugin implements Plugin{
public void apply(Project project){
project.tasks.withType(Test){ testTask ->
testTask.ext.mappedSystemProperties = []
doFirst{
mappedSystemProperties.each{mappedPropertyKey ->
def systemPropertyValue = System.getProperty(mappedPropertyKey)
if(systemPropertyValue){
testTask.systemProperty(mappedPropertyKey, systemPropertyValue)
}
}
}
}
}
}
It really depends on what exactly you want to achieve.
In case you want to help with writing a maven plugin in general, you'll have to read the documentation.
In case you want to filter system properties that Maven JVM passes to your test JVM, I don't see any other option than extending the maven-surefire-plugin plugin and add there an option to do such mapping. (Note that by default Maven passes all its System Properties to the test JVM.) That is definitely doable but maybe you can achieve your goal with something maven already offers.
You can definitely pass additional system properties to your test JVM from Maven by using:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<systemPropertyVariables>
<propertyName>propertyValue</propertyName>
<anotherProperty>${myMavenProperty}</buildDirectory>
</systemPropertyVariables>
</configuration>
</plugin>
as documented http://maven.apache.org/surefire/maven-surefire-plugin/examples/system-properties.html.
In this case you can set the value of anotherProperty from command line by invoking maven
mvn test -DmyMavenProperty=theValueThatWillBePassedToTheTestJVMAsProperty_anotherProperty
You can also use Surefire argline to pass multiple properties to the JVM. For instance
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19</version>
<configuration>
<argLine>${propertiesIWantToSetFromMvnCommandLine}</argLine>
</configuration>
</plugin>
and execute maven as follows
mvn test -DpropertiesIWantToSetFromMvnCommandLine="-Dfoo=bar -Dhello=ahoy"
in this case, you'll see properties foo and hello with values bar and ahoy, respectively, in your test JVM.
My Hudson job calls a single XML database collection and a single log file. E.g.
/db/project
${user.home}/logs/logging.log
I'd like to inject Hudson's env.EXECUTOR_NUMBER in both paths to avoid concurrent execution clashes. E.g.
/db/project {$EXECUTOR_NUMBER}
{$user.home}/logs {$EXECUTOR_NUMBER}/logging.log
I've found out the following:
Hudson site states that I need to pass Hudson's EXECUTOR_NUMBER to Maven as part of the build goal.
Log4J can only use system variables not environment variables (as these are a platform specific concept)
Now that I've got Hudson's EXECUTOR_NUMBER variable specified in the build goal, how can I use this as a system property for use by Log4J and Java's System.getProperties() class?
You can pass System Properties to any Java process using the -D syntax.
mvn clean install -DEXECUTOR_NUMBER={$EXECUTOR_NUMBER}
For a test class in a forked run, you will additionally have to configure the surefire plugin to pass the system property to the forked vm:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<systemPropertyVariables>
<EXECUTOR_NUMBER>${EXECUTOR_NUMBER}</EXECUTOR_NUMBER>
</systemPropertyVariables>
</configuration>
</plugin>
In my unit tests I want to create a tmp directory inside the ${project.build.directory}. How can I access the value of ${project.build.directory} inside my unit test?
One way, which I could think of, is to provide a filtered properties file in the test resources, which holdes that value. (I haven't tried yet, but I think that should work.)
Is there a direct way to access/ pass this property value?
I've used something like this with some success before. The unit test will still run even if not using Maven, the target directory will still get created two dirs up relative to the cwd of wherever the tests are run.
public File targetDir(){
String relPath = getClass().getProtectionDomain().getCodeSource().getLocation().getFile();
File targetDir = new File(relPath+"../../target");
if(!targetDir.exists()) {
targetDir.mkdir();
}
return targetDir;
}
I think using system properties is quite straightforward if you configure the surefire-plugin as explained here http://maven.apache.org/plugins/maven-surefire-plugin/examples/system-properties.html . Even the example there is answering your question directly:
<project>
[...]
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.9</version>
<configuration>
<systemPropertyVariables>
<propertyName>propertyValue</propertyName>
<buildDirectory>${project.build.directory}</buildDirectory>
[...]
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</build>
[...]
</project>
Remember, that your unit tests don't have to be executed from Maven surefire plugin, so ${project.build.directory} property might not be available. To make your tests more portable I would rather recommend using File.createTempFile().
I've been banging my head against a wall for about an hour on this: I'm trying to pass a simple property (java.library.path) to exec-maven-plugin. The goal is to have it integrate with Netbeans Right Click file > Run File procedure.
So I set my POM like this:
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<environmentVariables>
<java.library.path>native/win32-x86</java.library.path>
</environmentVariables>
</configuration>
</plugin>
</plugins>
</build>
(I use an old version so I can see the execution args, but its fully reproducible with 1.2)
Then I right click my file and click "Run File". Netbeans starts this process:
W:\programming\apache-maven-2.2.1\bin\mvn.bat -Dexec.classpathScope=runtime -Dexec.args=-classpath %classpath org.quackedcube.camera.CameraDemo -Dexec.executable=C:\Program Files\Java\jdk1.6.0_21\bin\java.exe -Dnetbeans.execution=true -Dmaven.repo.local=W:\programming\maven-repo process-classes exec:exec
(The original full classpath execution was changed to exec:exec so hopefully my configuration applied)
But my environment variable is apparently ignored, as the resulting executed program is:
Result of cmd.exe /X /C ""C:\Program Files\Java\jdk1.6.0_21\bin\java.exe" -classpath *snip* org.quackedcube.camera.CameraDemo" execution is: '1'.
I've tried
Using separate Key and Value tags inside an enviornmentVariable tag
Use a key and value tag directly inside an enviornmentVariables tag (worth a try)
binding to a phase
passing as a maven arg and using exec:java instead
Passing -Djava.library.path=native/win32-x86 as a Run argument and VM option in Project Configuration page
and all have failed. I'm really at a loss here.
I guess this is the disadvantage of using JNI in maven: You have to pass as an argument to your tests, your runtime, your module run POM, and your parent POM.
So my question: How can I pass a java.library.path property to an executed file? It would be nice if it integrated with Netbeans Run File functionality (therefor I don't have to change the class name in a POM, build, then run)
Didn't know this, but apparently when doing this you need to put this property first. I didn't think it was necessary since the classpath isn't immediately executed, but apparently it does make a difference.
To fix it, I simply changed this in Project Properties > Actions > Run File via Main
exec.classpathScope=${classPathScope}
exec.args=-Djava.library.path="native/win32-x86" -classpath %classpath ${packageClassName}
exec.executable=java
The reason you can't specifcy it in the POM is that NB passes the classpath and what its execution via command line exec.args, which overrides whats in your POM.
While this might be ugly and platform dependant, its what happens when you mix JNI and Maven. There isn't really another way that I can see.
Not sure if you tried this but as long as you need to set property on a level of JVM it should be done with -Djava.library.path=/some/path
So in order to specify it for exec-maven-plugin you could write something like this:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<executable>java</executable>
<arguments>
<argument>-Djava.library.path=${java.library.path}</argument>
</arguments>
</configuration>
</plugin>
You need, of course, to update the executable and maybe add another attributes.