How can I read the MANIFEST.MF file during the test execution? - java

I am trying to automate acceptance test using TestLink, Cucumber, Jenkins and Maven. To do that, I am asking to read the MANIFEST.MF file created by Maven. I have to do it during the test execution.
I found out this example of code :
`public static String readVersion() throws IOException {
InputStream in = VersionUtil.class.getResourceAsStream("/META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(in);
// Lire la propriété "Implementation-Version" du Manifest
String version = manifest.getMainAttributes().getValue(Attributes.Name.IMPLEMENTATION_VERSION);
return version;
}`
But I am getting a NullPointerException when trying to execute it... Do you have any idea why ?
I am launching Maven with the simple command : mvn package test.
I think the problem comes from the moment when this code is launching, I should launch it after the package phase, is there any way to do that ?
Thank you !

I think you can try the code below, since most classloader can be cast to URLClassLoader
URLClassLoader cl = (URLClassLoader) getClass().getClassLoader();
try {
URL url = cl.findResource("META-INF/MANIFEST.MF");
Manifest manifest = new Manifest(url.openStream());
...
} catch (IOException E) {
// handle
}

Related

Maven: Access POM at runtime - How to get 'pom.xml' available from anywhere?

I want to access some information from the pom.xml to display in a Info dialog. So I googled and found this post:
public class MavenModelExample {
public static void main(String[] args) throws IOException, XmlPullParserException {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(new FileReader("pom.xml"));
System.out.println(model.getId());
System.out.println(model.getGroupId());
System.out.println(model.getArtifactId());
System.out.println(model.getVersion());
}
}
I implemented it in my tool, added
<dependency>
<groupId>org.apache.maven</groupId>
<artifactId>maven-model</artifactId>
<version>3.3.9</version>
</dependency>
to my pom and was happy that everything ran as expected when I run the tool from the project root directory with java -jar target\mytool.jar.
When I move to any other directory, e.g. directly into target and execute my tool with java -jar mytool.jar, I get:
java.io.FileNotFoundException: pom.xml (The system cannot find the specified file)
at java.base/java.io.FileInputStream.open0(Native Method)
at java.base/java.io.FileInputStream.open(FileInputStream.java:213)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:155)
at java.base/java.io.FileInputStream.<init>(FileInputStream.java:110)
at java.base/java.io.FileReader.<init>(FileReader.java:60)
Which is kind of comprehensible. How should the code know, where the pom.xml is located, as it is not a resource. Is there any way to work around that?
In the mean time I use the approach from this thread to obtain the version and artifactID.
The problem is that
Model model = reader.read(new FileReader("pom.xml"));
tries to read the POM from the directory where your program is executed. Normally, pom.xml won't get copied to target, but it is embedded in the resulting artifact. You can override and force Maven to copy the POM to the target directory if you want to (for your own project), but it won't help you for other Maven artifacts.
Most of the time, a Maven artifact will have the POM coordinates included in the JAR/WAR/EAR output. If you unpack such a file, you'll notice that there are two files stored under META-INF/maven/<groupId>/<artifactId>: pom.xml and pom.properties where the latter is far easier to parse than pom.xml but it doesn't include the dependencies.
Parsing the embedded pom.xml from the classpath (and not from disk) should work better for you, especially if you always run your program with java -jar target\mytool.jar. In your program, try this:
try (InputStream is = MavenModelExample.class.getClassLoader().getResourceAsStream("META-INF/maven/<your groupId>/<your artifactId>/pom.xml")) {
MavenXpp3Reader reader = new MavenXpp3Reader();
Model model = reader.read(is);
System.out.println(model.getId());
System.out.println(model.getGroupId());
System.out.println(model.getArtifactId());
System.out.println(model.getVersion());
// If you want to get fancy:
model.getDependencies().stream().forEach(System.out::println);
}
catch (IOException e) {
// Do whatever you need to do if the operation fails.
}
<your groupId> and <your artifactId> should be fairly static, but if you do relocate your artifact's coordinates, then you need to change this in your code as well.
problem is that :
read(new FileReader("pom.xml"))
works fine when you start your application from STS or else, but when you build your application as JAR the path of the pom.xml file change to :
META- INF/maven/${groupId}/${artifactId}/pom.xml.
for that, try this code :
MavenXpp3Reader mavenXpp3Reader = new MavenXpp3Reader();
Model model;
if ((new File("pom.xml")).exists()) {
model = mavenXpp3Reader.read(new FileReader("pom.xml"));
}
else {
// Packaged artifacts contain a META- INF/maven/${groupId}/${artifactId}/pom.properties
model = mavenXpp3Reader.read(new
InputStreamReader(Application.class.getResourceAsStream(
"/META-INF/maven/groupId/artifactId/pom.xml")));
}

Update java desktop app

I am trying to develop a module that can update my running Java Desktop App.
The problem is that I have to replace the actual running jar with another jar, all the while displaying an image and a progress bar with the remaining time of the update process.
One solution I thought about is that I can put a jar in my main jar, and when launching the update process, to extract that second jar which will display the image and the progess bar, and also which will replace the old main jar with a new main jar.
My question is if this is possible and how can I do it.
I do not have a lot of experience with java and java packaging so if you have any examples or links, it would be of great help for me.
Thank you very much.
R.
Run this code when press UPDATE button ..
if(Desktop.isDesktopSupported()){
try {
Desktop.getDesktop().open(new File("update.jar"));
System.exit(0);
} catch (IOException ex) {
}
}
This will open update.jar and close main.jar. Now run this code from main class of update.jar
//wait sometime for terminate main.jar
try{
Thread.sleep(5000);
} catch(Exception e){
e.printStackTrace();
}
if(isUpdateVersionAvailable()) { //first check update from database
if(copyMainJarFileFromServer()){ //copy newMain.jar from server and paste
new File("main.jar").delete(); //delete main.jar
rename(new File("newMain.jar")); //rename newMain.jar to main.jar
}
}
boolean isUpdateVersionAvailable() {
//todo
}
boolean copyMainJarFileFromServer() {
//todo
}
void rename(File file){
file.renameTo(new File("main.jar"));
}
You can have a starter jar that checks for updates and launches the app from the main jar.
It will show start logo, an image, that standard java can display at start-up.
The start0er could also be used to restart the app in another interface language.
package starter;
...
public class StarterApp {
public static void main(String[] args) {
String workDir = System.getProperty("user.dir");
Path mainJar = Paths.get(workDir + "...");
Path nextMainJar = Paths.get(workDir + "...");
if (Files.exists(nextMainJar)) {
Files.copy(nextMainJar, mainJar, StandardCopyAction.REPLACE_EXISTING);
}
URLClassLoader classLoader = new URLClassLoader(new URL[] {mainJar.toURL()});
Class<?> appClass = classLoader.find("mainjar.MainApp");
... instantiate the app
}
As you see the main jar must not be loaded from too early, maybe not be on the class path entirely, and hence the use of a separate ClassLoader. The same might probably be done with the main jar on the class path of the starter app, and using Class.forName("mainjar.MainApp"). The Class-Path can be specified in META-INF/MANIFEST.MF.
The secundary jars may reside in a lib/ directory.
For those readers wanting more modular, service oriented, updateable apps, one could make an OSGi application, a container for bundles (=jars), that provide exchangable services and life-time control.

load class from another class within same jar in java web start fails

I've a javafx application which is run by web start. In my fx application, I try to load the classes using ClassLoader as in below code. The parameter passed is a package name like "com.example.project.abcd"
public final static List<Class<?>> find(final String scannedPackage)
{
final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
final String scannedPath = scannedPackage.replace(DOT, SLASH);
final Enumeration<URL> resources;
try {
resources = classLoader.getResources(scannedPath);
} catch (IOException e) {
throw new IllegalArgumentException(String.format(BAD_PACKAGE_ERROR, scannedPath, scannedPackage), e);
}
final List<Class<?>> classes = new LinkedList<Class<?>>();
while (resources.hasMoreElements()) {
final File file = new File(resources.nextElement().getFile());
classes.addAll(find(file, scannedPackage));
}
return classes;
}
Now I'm not able to get all the classes present inside "com.example.project.abcd" package when I run it thru java web start but through IDE it is working fine.
I'm using JDK 7, JavaFX 2.
As per http://docs.oracle.com/javase/7/docs/technotes/guides/javaws/developersguide/faq.html#s211 Thread.currentThread().getContextClassLoader() should work fine but it is not!.
Tried searching on net/googling but in vain. Checked http://lopica.sourceforge.net/faq.html#customcl as well and tried using URLClassLoader as suggested. But that didn't work as well (Though did not know what should be passed to the parameter 'urls')
Any help is much apreciated.
I think this works in IDE because your BIN/classes directory is used to get all the files.
In Webstart-Mode, all your classes are inside JARs.

Java Trouble compiling maxmind geoip LookupService class

I wonder if some one can please help as I am struggling to compile maxmind.geoip.LookupService.java
I have downloaded geoip-api-1.2.10.jar for inclusion in WEB-INF\lib and I have referenced it in my classes path, but it just won't compile.
I have compiled the following successfully so I'm a bit at a loss:
com.maxmind.geoip.Country
com.maxmind.geoip.DatabaseInfo
com.maxmind.geoip.Location
com.maxmind.geoip.Region
com.maxmind.geoip.timeZone
Can't seem to find a full set of compiled java classes for com.maxmind.geoip, any help would be much appreciated :-)
I resolved this by downloading the latest java files from http://dev.maxmind.com/geoip/legacy/downloadable/ unpacked the folder and then opened a command prompt and typed the following:
cd source/com/maxmind/geoip/
javac *.java
I'm using jdk1.6.0_34 and all classes compiled with no errors.
I copied the com.maxmind.geoip folder to \WEB-INF\classes and downloaded geoip-api-1.2.10.jar and placed that in the WEB-INF\lib folder.
Finally I download GeoIP.dat from http://dev.maxmind.com/geoip/legacy/geolite/ and placed it in a new folder called GeoIP under webapps so that all my applications can use it.
The following code is to obtain the country code from a users IP Address:
import com.maxmind.geoip.*;
import java.io.IOException;
class CountryLookupTest {
public static void main(String[] args) {
try {
String sep = System.getProperty("file.separator");
String dir = "C:/Program Files/Apache Software Foundation/Tomcat 7.0/GeoIP";
String dbfile = dir + sep + "GeoIP.dat";
LookupService cl = new LookupService(dbfile,LookupService.GEOIP_MEMORY_CACHE);
System.out.println(cl.getCountry("151.38.39.114").getCode());
System.out.println(cl.getCountry("151.38.39.114").getName());
System.out.println(cl.getCountry("12.25.205.51").getName());
System.out.println(cl.getCountry("64.81.104.131").getName());
System.out.println(cl.getCountry("200.21.225.82").getName());
cl.close();
}
catch (IOException e) {
System.out.println("IO Exception");
}
}
}
Hope this proves useful to others.
According to the MaxMind dev site, the API is available on the Maven Central Repository. You shouldn't need to compile anything unless you downloaded the source package.
You have to download a Jar file called geoIP-api from this link to maven repository,In case you haven't downloaded the other Jar files from go this geoIP2 also don't forget to download the .DAT file from geoIP.dat. Then add the files to your project class path from project properties and then libraries finally add Jar in netbeans.
Now use this code:
public String IpGeoLocation(String IP) {
try {
String dbfile = "C:\\Users\\User Name \\Documents\\NetBeansProjects\\IP Tools\\resources/GeoIP.dat";
String location = "";
LookupService cl = new LookupService(dbfile, LookupService.GEOIP_MEMORY_CACHE);
location = cl.getCountry(IP).getName() + " " + cl.getCountry(IP).getCode();
cl.close();
return location;
} catch (Exception e) {
return "Error";
}
}
I was able to find the country and country code only !!

Class not found exception when trying to create web service client

I am trying to consume a web service from a Java client.
I generated the classes using wsimport:
wsimport -keep -verbose http://localhost:5382/Service1.svc?wsdl
Code looks something like:
private String CreateSalesforceIssue() {
IssueService service = new IssueService();
IIssueService binding = service.getBasicHttpBindingIIssueService();
String issueID = binding.createIssue(type, description, steps,
expected, workaround, storage,
docType, actions, tools, external,
repeatability, workaroundType, severity,
pmSeverity, products, extensions, versions,
os, status, project, resolution, fixversions);
return issueID;
}
When it hits this line:
IssueService service = new IssueService();
Stepping into the code far enough and it gets to javax.xml.ws.spi.Provider and fails there.
On
public static Provider provider() {
try {
Object provider =
FactoryFinder.find(JAXWSPROVIDER_PROPERTY,
DEFAULT_JAXWSPROVIDER);
if (!(provider instanceof Provider)) {
Class pClass = Provider.class;
String classnameAsResource = pClass.getName().replace('.', '/') + ".class";
ClassLoader loader = pClass.getClassLoader();
if(loader == null) {
loader = ClassLoader.getSystemClassLoader();
}
URL targetTypeURL = loader.getResource(classnameAsResource);
throw new LinkageError("ClassCastException: attempting to cast" +
provider.getClass().getClassLoader().getResource(classnameAsResource) +
"to" + targetTypeURL.toString() );
}
return (Provider) provider;
} catch (WebServiceException ex) {
throw ex;
} catch (Exception ex) {
throw new WebServiceException("Unable to createEndpointReference Provider", ex);
}
}
on this line:
if (!(provider instanceof Provider)) {
with a ClassNotFoundException: Provider com.sun.xml.ws.spi.ProviderImpl
I feel like I am missing something, unfortunately I am not sure what... Do I need to initialize the provider anywhere?
You should add Provider class into your classpath.
If you use IDE you can add the library easily by right click on library and choose "add Jar file" (or something like that!). But if you try to compile and run your application via terminal use the following commands:
javac -d [bin folder] -cp [jar files] [java source files]
java -classpath [jar files] [Main class]
you should split the jar files using : in Linux and MAC OS and ; in MS Windows. As you said this is a web service, I think you are using IDE and first solution may help you.
P.S. If you also added this jar file into class path and this exception occurs again, please add this jar file into your web server/container library directory. (for example lib folder in tomcat.

Categories