save user status in maven project - maven

I am writing a javaFX project with netbeans IDE and maven.
I am saving user edits in a property file and i loading it when the application start up and i want to update it when application shuts down to reuse it next time.
So I am reading the property file as below:
public static Properties propConfig = new Properties();
InputStream input;
input = Config.class.getClassLoader().getResourceAsStream("config/displayConfig.properties");
propConfig.load(input);
which works fine..
but i don't know how to update the property file :( as
output = new FileOutputStream( new File(Config.class.getClassLoader().getResource("config/displayConfig.properties").toURI()) );
is not working since it reads the resource file from jar
jar:file:/D:/freelance%20projects/01%20school%20tool%20bar/mavenprojectFX/target/racer40-1.0-SNAPSHOT.jar!/config/displayConfig.properties

Normally it's not recommended to update files in JARs.
Use local files instead, e.g.:
Path userDirPath = Paths.get(System.getProperty("user.home"), ".<myAppSymbolicName>", "<myAppVersion>");
Path configDirPath = userDirPath.resolve("config");
Path displayConfigFilePath = configDirPath.resolve("displayConfig.properties");
// read file

well i have done a workaround, since I can only read files from jar i have defined a new properties file and i have defined the configuration path in it.
i have modified resources in POM.xml to set filtering true
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
i have placed the path property file in "src/main/resources/config" folder
the path file contains
Path=${project.build.directory}
and i am reading it as the following
InputStream pathStream
= Config.class.getClassLoader().getResourceAsStream("config/path.properties");
Properties pathProperties = new Properties();
pathProperties.load(pathStream);
path = pathProperties.get("Path").toString().replace("target", "");
System.out.println(pathProperties.get("Path"));
pathStream.close();
then i am using 'path' variable as the following
OutputStream output = new FileOutputStream(new File(path + displayConfig.properties"));
so I am now putting the configuration file "displayConfig.properties" in the same path of jar.

Related

"Unit testing" a Maven build

I have a complex Maven build, and I would like to have some automated check that the JAR files and POM files produced by the build actually contain what I expect them to contain.
For instance, I would like to check for the presence of an Automatic-Module-Name entry in the manifest file. It's a multi-release JAR, so I would like to check that the proper class files exist inside of META-INF/versions. I'm going to publish to Maven Central, so I'd also like to check that the produced pom file contains the dependencies the project needs, but that the produced pom file for the fat jar that I also publish, doesn't contain these dependencies.
Basically, I'd like to unit test my build :).
Unfortunately, it's hard to google for this, because of the words I would use to describe this ("test", "verify") already have very specific different meanings in Maven.
Is there a nice way to do this? I would prefer a Maven plugin, since I'm obviously already using that, but I'm open to other things too.
I ended up, as #khmarbaise suggested in the comments, creating a new Maven submodule. In its pom I used the copy-rename-maven-plugin to copy over the files I actually want to check, like this:
<plugin>
<groupId>com.coderplus.maven.plugins</groupId>
<artifactId>copy-rename-maven-plugin</artifactId>
<version>${version.copy-rename-maven-plugin}</version>
<executions>
<execution>
<id>copy-artifacts</id>
<phase>compile</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<fileSets>
<fileSet>
<sourceFile>${project.basedir}../core/target/.flattened-pom.xml</sourceFile>
<destinationFile>${project.basedir}/src/test/resources/flattened.pom</destinationFile>
</fileSet>
<fileSet>
<sourceFile>${project.basedir}../core/target/myArtifactId-${project.version}.jar</sourceFile>
<destinationFile>${project.basedir}/src/test/resources/myArtifactId.jar</destinationFile>
</fileSet>
<!-- more fileSets here -->
</fileSets>
</configuration>
</execution>
</executions>
</plugin>
Then I was able to read the pom file and do assertions on it. I ended up using Java's built-in XPath API, but you can use whatever.
I was also able to read the JAR file by turning it into a NIO FileSystem:
var filename = "myArtifactId.jar"; // or "flattened.pom"
var file = getClass().getClassLoader().getResource(filename);
var uri = URI.create("jar:" + file.toURI().toString());
FileSystem fs = FileSystems.newFileSystem(uri, Map.of());
You can get a list of files:
var path = fs.getPath("/");
Set<String> filenames = StreamSupport
.stream(walk.spliterator(), false)
.map(Path::toString)
.collect(Collectors.toSet());
Or read the content of a file:
var path = fs.getPath("/META-INF/MANIFEST.MF");
var out = new ByteArrayOutputStream();
Files.copy(path, out);
String content = out.toString();
assertTrue(content.contains("Multi-Release: true"));
var path = fs.getPath("/com/example/MyClass.class");
var out = new ByteArrayOutputStream();
Files.copy(path, out);
byte[] content = out.toByteArray();
var actualVersion = content[7]; // the major version of the class file is at this location
assertEquals(52, actualVersion); // 52 = Java 8
(Note that for this answer, I didn't bother to handle exception or close resources; you'll have to do that yourself.)

Spring cloud loading keystore from classpath vs file

I have a spring cloud config server that uses keystore to decrypt values from git server. If I reference the keystore using file path, it works as expected and decrypts the {cipher} values. However, if I try to load the keystore from classpath it stops working with this error :
CipherEnvironmentEncryptor.decrypt - Cannot decrypt key: username (class java.lang.IllegalStateException: Cannot load keys from store: class path resource [mykey.p12])
Im setting the encrypt properties on the class instead of yaml since I need to lookup different passwords from external vault system for dev/prod keystores.
I can also see p.12 file under target/classes after the build, so it is not filtered out during the build. Not sure what I'm missing.
SpringApplication sa = new SpringApplication(Myclass.class);
Properties springProperties = new Properties();
springProperties.setProperty("encrypt.enabled", "true");
springProperties.setProperty("encrypt.key-store.location", "file:///Users/user/IdeaProjects/project/src/main/resources/configuration/mykey.p12"); //working fine
springProperties.setProperty("encrypt.key-store.location", "classpath:/configuration/mykey.p12"); //does not work
springProperties.setProperty("encrypt.key-store.type", "PKCS12");
springProperties.setProperty("encrypt.key-store.password", "password");
springProperties.setProperty("encrypt.key-store.secret", "password");
springProperties.setProperty("encrypt.key-store.alias", "vault");
sa.setDefaultProperties(springProperties);
sa.run(args);
Using
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
<version>2.2.0.RELEASE</version>
<name>spring-cloud-config-server</name>
My issue was actually related to this : generated certificate stops working when moved to resources folder
I had maven filtering configuration on the resources which was corrupting the final p12 file. For now I just moved files that need filtering to another resource directory and it works.
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/resources-filtered</directory>
<filtering>true</filtering>
<includes>
<include>*.yml</include>
<include>logback.xml</include>
</includes>
</resource>
</resources>

Activate profile while submitting Apache storm topology of a maven project (Without recompiling)

I have to activate the profile while submitting the jar to storm like we do for a spring/boot project. like below
java -jar project-xyz.jar --spring.profiles.active=dev.
It is a maven project with multiple sub modules. we have the resources structured
Anything that is common to all the profiles will go in the root directory of resources, and anything that is specific to a profile (like DB connections) will go in that particular profile directory.
The root directory file will have the place holders for profile specific properties and will be replaced by the actual properties defined in profile directory.
Ex: ${mysql.host} will be resolved to localhost when local profile is active.
This final file will be placed in the classpath when we build the jar using
mvn clean install -P{profile}
And then the topology is submitted to storm like the following.
storm jar project-xyz.jar path.to.class.containing.main.method
The final properties file generated by maven will be read by a property reader, stored and served whenever requested.
private static final Map<String, Properties> properties = new HashMap<>();
public static String getProperty( String file, String key )
{
try {
if ( !properties.containsKey( file ) ) {
synchronized ( properties ) {
if ( !properties.containsKey( file ) ) {
loadProps( file );
}
}
}
return properties.get( file ).getProperty( key );
} catch ( IOException e ) {
throw new PropertyException( "There was a problem getting " + key + " from " + file + ".properties", e );
}
}
private static void loadProps( String file ) throws IOException
{
InputStream inputStream = PropertyFileHandler.class.getClassLoader().getResourceAsStream( file + ".properties" );
if ( inputStream == null ) {
throw new FileNotFoundException( "Property file " + file + ".properties not found" );
}
Properties prop = new Properties();
prop.load( inputStream );
properties.put( file, prop );
}
I've already gone through this question and its different in a way that I use maven and I have to activate the profile instead of providing specific property.
So, is there a way I can activate the profile while submitting the jar to storm somewhat like the following?
storm jar project-xyz.jar --profiles.active=dev
If not, what can I do to achieve this without re-compiling the source? Does converting it to a spring boot project help?
You won't be able to do this as long as you're using Maven to generate a jar containing a single properties file. That jar can only be used in the environment you generated it for.
Instead, you could include all the possible properties files in the jar, and decide which one to read based on a system or environment property.
A better option is probably that you generate the property files separately to the jar, and then put the jar plus property file into Storm. You can pass the property file path to your Storm submission code as a command line argument to your main method. You would then read the properties into memory, and pass them to your bolts/spouts. You need to do this loading eagerly (i.e. read the entire properties at topology submission time, rather than when you need a specific property), so your lazy loading configuration code should be discarded.
You might want something like Flux for convenience:
To enable property filtering, use the --filter command line option and
specify a .properties file. For example, if you invoked flux like so:
storm jar myTopology-0.1.0-SNAPSHOT.jar org.apache.storm.flux.Flux
--local my_config.yaml --filter dev.properties
With the following dev.properties file:
kafka.zookeeper.hosts: localhost:2181
You would then be able to reference those properties by key in your
.yaml file using ${} syntax:
- id: "zkHosts"
className: "org.apache.storm.kafka.ZkHosts"
constructorArgs:
- "${kafka.zookeeper.hosts}"
See the documentation at https://storm.apache.org/releases/2.1.0/flux.html.

How to set file location in application properties - Spring boot

I have a Spring Boot application, the code need to access a file under resources/templates folder.
here is my application.properties file:
pont.email.template.location=templates/mailTemplate.html
This is the java file where I use the variable:
#Value("${pont.email.template.location}")
private String templateLocation;
----------------
BufferedReader reader = new BufferedReader(new FileReader(templateLocation));
The problem is not get the varibale, it returns correctly, The problem is that the application do not found any file for this path.
I always get
java.io.FileNotFoundException: templates/mailTemplate.html (No such file or directory)
I have checked that the file is in the path..
what is wrong in my code?
Help please, thanks.
You cannot read a File from inside a JAR. This fails due to the fact that the File has to point to an actual file resource on the file system and not something inside a JAR.
Let Spring do the heavy lifting and use the Resource abstraction to hide the nasty internals. So instead of using a String use a Resource and prefix the value of the property with classpath: to make sure it is loaded from the classpath. Then use an InputStreamReader instead of FileReader to obtain the information you need.
#Value("${pont.email.template.location}")
private Resource templateLocation;
----------------
BufferedReader reader = new BufferedReader(new InputStreamReader(templateLocation.getInputStream()));
In your application.properties prefix with classpath:.
pont.email.template.location=classpath:templates/mailTemplate.html
Now it should work regardless of the environment you are running in.

How to load resource file in jenkins plugin?

I am trying to load a resource file which is in src/main/resources folder as part of Jenkins plugin. It is always giving me FileNotFoundException. Can someone please explain how to make it work?
Exception message:
java.io.FileNotFoundException: file:/var/lib/jenkins/plugins/Report/WEB -INF/lib/Report.jar!/properties.txt (No such file or directory)
The question is asked long back but I just thought to share my answer in case it helps someone out there who faced this issue similar to me.
Follow these steps: It works in my case:
Place your file in the "resources" folder thats typically on the
path "src/main/resources". In IntelliJ IDE, mark the resources
directory as "resource root".
As the file(s) are placed inside resources, they are in a directory
thats on the build path so maven should be able to load this without
setting additional build path.
Let say the file name is "application-env.properties". Following code block should
pull the file from resource folder at jenkins plugin run time.
InputStream inputStream = null;
try{
String resourceName = "application-env.properties";
Properties props = new Properties();
ClassLoader cl = <NameOfThisClass>.class.getClassLoader();
try (InputStream stream = cl.getResourceAsStream(resourceName)) {
props.load(stream);
}
//read props or return the same to the caller
}
finally {
if (inputStream != null) {
inputStream.close();
}
}

Resources