I have this code which on the dev-environment return the information.
But when I run from the jar the code doesn't follow how it should.
The name of the jar is hardcoded and would like to get it's name, because versions vary.
private static String getManifestUrlForClass(Class<?> cl) throws URISyntaxException, IOException {
URL url = cl.getResource(cl.getSimpleName() + ".class");
String s = url.toString();
System.out.println("URL Path: " + url.getPath());
System.out.println("URL File: " + url.getFile());
String path = MYCLASS.class.getProtectionDomain().getCodeSource().getLocation().getPath();
String revisionNumber = "";
String decodedPath = "";
JarFile jarfile = null;
try {
decodedPath = URLDecoder.decode(path, "UTF-8").replace("classes", "");
try {
jarfile = new JarFile(decodedPath + "MYJAR-ver.si.on.jar");
} catch (IOException e1) {
System.out.println("or Path to file cannot decode...");
e1.printStackTrace();
}
Manifest manifestFromJar = jarfile.getManifest(); //
System.out.println("Manifest from " + jarfile.getName().toString() + " = "
+ manifestFromJar.getMainAttributes().getValue("Revision-Number").toString());
revisionNumber = manifestFromJar.getMainAttributes().getValue("Revision-Number").toString();
} catch (IOException e) {
System.out.println(url.getFile().toString() + "is not jar");// TODO Auto-generated catch block
System.out.println("or Path to file cannot decode...");
e.printStackTrace();
}
return revisionNumber;
}
MYJAR will always be the same but the |ver.si.on| will most likely vary and hardcoding the name isn't a best practice.
What I want to do?
1. Get the MYJAR-ver.si.on.jar's location no matter where it is located
2. Use the location to access it's Manifest
3. Use the Manifest to extract revision number
4. Show the revision number in the ui
I'm new yet to java and don't understand it pretty well. I've read something about using "rsrc:" to get to the jar, or something similar to this https://stackoverflow.com/a/40680501/6756124 .
Related
Till now my code works fine where I am creating file in temporary directory and processing it.
But now I am trying to provide specific directory where I actually want to create xml file. So in method createTmpXmlFile
private static Path createTmpXmlFile(final String prefix) {
try {
log.info("Creating temporary file {}{}", prefix, XML_SUFFIX);
return Files.createTempFile(Paths.get(gleifZipFile), prefix, XML_SUFFIX);
} catch (IOException e) {
throw new IllegalStateException("Could not create tmp file at " + prefix + XML_SUFFIX + ". ", e);
}
}
I changed from
return Files.createTempFile(prefix, XML_SUFFIX);
to
return File.createTempFile(prefix, XML_SUFFIX, "/tmp/in");
and I get following error:
java: incompatible types: java.lang.String cannot be converted to java.io.File.
If I change the logic here then its affecting other method that are calling createTmpXmlFile method.
I really don't understand how to resolve this issue. Below is my code:
#Slf4j
public class InputCS implements Runnable {
public static final String XML_SUFFIX = ".xml";
#Value("${gleifdataimporter.file.dir}")
private String gleifZipFile;
private void processleifZipFile() {
final AtomicBoolean isInsideLeiRecord = new AtomicBoolean();
isInsideLeiRecord.set(false);
final StringBuilder currentLeiRecordXml = new StringBuilder();
try (FileSystem zipFs = FileSystems.newFileSystem(jobRunner.getInputZipPath(), null)) {
Path tmpXMLPath = xmlFileFromLeiZipFile(zipFs);
try (Stream<String> lines = Files.lines(tmpXMLPath)) {
AtomicInteger processedLinesCounter = new AtomicInteger();
AtomicInteger currentLineNumber = new AtomicInteger();
lines.sequential().forEach(handleLineAndIncrementLineNumber(isInsideLeiRecord, currentLeiRecordXml, processedLinesCounter, currentLineNumber));
log.info("{} lines of XML file inside LEIF input ZIP file {} processed.", processedLinesCounter.get(), jobRunner.getInputZipPath());
}catch (IOException e) {
throw new IllegalStateException("Problem reading input file at " + jobRunner.getInputZipPath() + ".", e);
} finally {
Files.delete(tmpXMLPath);
}
} catch (IOException e) {
throw new IllegalStateException("Problem reading input file at " + jobRunner.getInputZipPath() + ".", e);
}
}
private Path xmlFileFromLeiZipFile(FileSystem zipFs) { //extracts the xml file from zip file
log.info("Input file {} exists: {}", jobRunner.getInputZipPath(), Files.exists(jobRunner.getInputZipPath()));
Path tmpXmlPath = createTmpXmlFile("leif__" + System.currentTimeMillis());
for (Path rootDir : zipFs.getRootDirectories()) {
try (Stream<Path> files = treeAt(rootDir)) {
log.info("Trying to extract LEIF XML file from ZIP file into {}.", tmpXmlPath);
final Path xmlFileInsideZip = files
.filter(isNotADir())
.filter(Files::isRegularFile)
.findFirst()
.orElseThrow(() -> new IllegalStateException("No file found in LEI ZIP file."));
log.info("Path to LEIF XML file inside ZIP file: {}.", xmlFileInsideZip);
return copyReplacing(xmlFileInsideZip, tmpXmlPath);
}
}
throw new IllegalStateException("No file found in LEI ZIP file " + jobRunner.getInputZipPath() + ".");
}
private static Path createTmpXmlFile(final String prefix) {
try {
log.info("Creating temporary file {}{}", prefix, XML_SUFFIX);
return Files.createTempFile(Paths.get(gleifZipFile), prefix, XML_SUFFIX);
} catch (IOException e) {
throw new IllegalStateException("Could not create tmp file at " + prefix + XML_SUFFIX + ". ", e);
}
}
#NotNull
private static Path copyReplacing(Path from, Path to) {
requireNonNull(from, "Trying to copy from a path, which is null to path " + to + "."); //trying to copy file where no xml file exist in root directory
requireNonNull(to, "Trying to copy from path " + from + " to a path, which is null.");
try {
return Files.copy(from, to, REPLACE_EXISTING);
} catch (IOException e) {
throw new IllegalStateException("Cannot copy from " + from + " to " + to + ". ", e);
}
}
}
As suggested by Slaw, use Files#createTempFile(Path,String,String,FileAttribute...) to specify the directory to create temp file.
Use Paths#get(String,String...) for java 7 or 8, or Path#of(String,String...) for java 11 or later to convert String to Path. Further reading: Paths.get vs Path.of
private static Path createTmpXmlFile(final String prefix) {
try {
// Java 11 or later
// return Files.createTempFile(Path.of("/tmp/in"), prefix, XML_SUFFIX);
// Java 8
return Files.createTempFile(Paths.get("/tmp/in"), prefix, XML_SUFFIX);
} catch (IOException e) {
throw new IllegalStateException("Could not create tmp file at " + prefix + XML_SUFFIX + ". ", e);
}
}
File.createTempFile is expecting a File object as third parameter. Just wrap your "/tmp/in" into a File
=> return File.createTempFile(prefix, XML_SUFFIX, new File("/tmp/in")); and you should be good to go.
so you can do:
File.createTempFile("prefix", "suffix", new File("/tmp/in"));
Or using NIO (recommended)
Files.createTempFile(Paths.get("/tmp/in"), "prefix", "suffix");
Edit: I recognize that FileSystem.getDefault() will give me what I was looking for in my original question statement. I am attempting to use FileSystem.getFileSystem(URI) to get the FileSystem for any given path.
I am attempting to develop some code that will give me a java.nio.file.FileSystem object for a given path.
Here is some grossly simplified example code to give a better idea of what is being attempted:
public FileSystem getCwdFilesystem()
{
URI cwdUri = null;
String delimiter = "";
try
{
_cwd = System.getProperty("user.dir");
cwdUri = new URI("file", delimiter + _cwd, null);
}
catch (URISyntaxException ue)
{
System.out.println("URI Creation failure on URI: " + _cwd);
ue.printStackTrace();
System.exit(1);
}
System.out.println("Filestore data for CWD: " + cwdUri.toString());
return (FileSystems.getFileSystem(cwdUri));
}
Upon execution, an exception is throw on the last line of code:
Filestore data for CWD: file:/Users/redacted/Documents/Java%20Projects/ExampleCode
Exception in thread "main" java.lang.IllegalArgumentException: Path component should be '/'
at sun.nio.fs.UnixFileSystemProvider.checkUri(UnixFileSystemProvider.java:77)
at sun.nio.fs.UnixFileSystemProvider.getFileSystem(UnixFileSystemProvider.java:92)
at java.nio.file.FileSystems.getFileSystem(FileSystems.java:217)
at examplecode.FilesystemCapacity.getCwdFilesystem(FilesystemCapacity.java:54)
at examplecode.FilesystemCapacity.main(FilesystemCapacity.java:33)
Java Result: 1
When I make a small update to the delimiter variable:
String delimiter = "/";
I get a different error message thrown from the same place:
Filestore data for CWD: file://Users/redacted/Documents/Java%20Projects/ExampleCode
Exception in thread "main" java.lang.IllegalArgumentException: Authority component present
at sun.nio.fs.UnixFileSystemProvider.checkUri(UnixFileSystemProvider.java:73)
at sun.nio.fs.UnixFileSystemProvider.getFileSystem(UnixFileSystemProvider.java:92)
at java.nio.file.FileSystems.getFileSystem(FileSystems.java:217)
at examplecode.FilesystemCapacity.getCwdFilesystem(FilesystemCapacity.java:54)
at examplecode.FilesystemCapacity.main(FilesystemCapacity.java:33)
Java Result: 1
Adding additional "/" characters to the delimiter simply gets me the first error message again.
What am I doing wrong?
I found a reference I had previously missed on the last page of the NIO.2 document trail.
I wrote up some test code that gave me exactly what I needed:
public void getPathFilesystem(String path)
{
try
{
URI rootURI = new URI("file:///");
Path rootPath = Paths.get(rootURI);
Path dirPath = rootPath.resolve(path);
FileStore dirFileStore = Files.getFileStore(dirPath);
printFileStore(dirFileStore, path);
}
catch (IOException | URISyntaxException e)
{
e.printStackTrace();
}
}
public void printFileStore(FileStore filestore, String path)
{
try
{
System.out.println("Name: " + filestore.name());
System.out.println("\tPath: " + path);
System.out.println("\tSize: " + filestore.getTotalSpace());
System.out.println("\tUnallocated: " + filestore.getUnallocatedSpace());
System.out.println("\tUsable: " + filestore.getUsableSpace());
System.out.println("\tType: " + filestore.type());
}
catch (IOException ioe)
{
ioe.printStackTrace();
}
}
The following code works like a charm in eclipse under windows:
public static void main(String[] args)
{
try
{
String filePath = "\\\\myserver\\dir";
String fileName = "myFile.txt";
FileWriter myFileWriter = new FileWriter(filePath + File.separator + fileName);
BufferedWriter myBufferedWriter = new BufferedWriter(myFileWriter);
myBufferedWriter.write("test");
myBufferedWriter.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
Now I want to run this code from a unix machine in the same network. The program runs, but does not write my file or throws an exception. Any ides ?
Cheers
If that destination unix machine has Samba installed you might want to try the following library:
http://jcifs.samba.org/
You would need a username and password though.
try {
String filePath = "myserver/dir";
String fileName = "myFile.txt";
String user = "username";
String password = "password";
// URL: smb://user:passwd#host/share/filname
SmbFileOutputStream out = new SmbFileOutputStream("smb://" + user + ":" + password + "#" + filePath
+ File.separator + fileName);
out.write("test".getBytes());
out.close();
} catch (Exception e) {
e.printStackTrace();
}
This would also work with a windows machine as the destination if the server is configured as an SMB server.
Because in Unix/Linux this is not the right path
String filePath = "\\\\myserver\\dir";
I suggest to check such path exist, and 99% chances you will not have permission to create them. It would be more or less
String filePath = "/usr/xx/";
Creating folder:
File temp = new File("temp");
boolean test = temp.mkDir();
I am having problems calling classes at run time in java
Im basically making a plugin framework
it starts off by opening plugin/Plugins.cfg and parses the test into a map..
EX text in cfg file
1 = myplugin
2 = plugin2
(each plugins main class is: plugin.(plugin name).main.class)
as you can see it loads each value from the map and trys to run its main class
public static void loadPlugins()
{
int x = hackers.core.startup.InitializeGame.map.size();
for (int i = 1; i<=x;i++)
{
String className = hackers.core.startup.InitializeGame.map.get(i + "");
File file = new File(System.getProperty("user.dir") + File.separator + "plugins" + File.separator + className);
URL url = null;
try {
url = file.toURI().toURL();
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
URL[] urls = new URL[]{url};
ClassLoader cl = new URLClassLoader(urls);
try {
Class cls = cl.loadClass("plugin." + className + ".main");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(className);
}
}
Class cls = cl.loadClass("plugin." + className + ".main");
^line gives me the error: java.lang.ClassNotFoundException: plugin.myplugin.main
anyone know whats wrong here?, or any suggestions, I have looked at an API for it but it was confusing to me and lacks documentation.
Your file doesn't point to a valid class or jar file.
Debug the following line; you will notice it's path isn't an existing path in your file system.
File file = new File(System.getProperty("user.dir") + File.separator + "plugins" + File.separator + className);
I would assume that you've forgotten to include .class in the className.
I am trying to get this JTextArea, called textArea, to update while it is copying these photos but I can't quite seem to get it to work. I was using this code:
String name = "";
int numberOfPicturesCopied = 0;
while (pictures.isEmpty() == f) {
try {
File tmp = pictures.firstElement();
name = tmp.getName();
String filename = destination + Meta.date(tmp) + tmp.getName();
Path source = tmp.toPath();
File destFile = new File(filename);
Path destination = destFile.toPath();
Files.copy(source, destination,
StandardCopyOption.COPY_ATTRIBUTES);
textArea.append("Copied " + name + "\n");
pictures.removeElementAt(0);
numberOfPicturesCopied++;
} catch (FileAlreadyExistsException faee) {
textArea.append("Skipped " + name
+ ": Picture Already In Computer\n");
} catch (NoSuchFileException ncfe) {
File tmp = pictures.firstElement();
String filename = destination + Meta.date(tmp);
File newDir = new File(filename);
newDir.mkdir();
} catch (IOException ee) {
// TODO Auto-generated catch block
ee.printStackTrace();
}
}
and then I changed it to this:
public void copyPictures(){
SwingUtilities.invokeLater(new Thread(){
public void run(){
String name = "";
while(pictures.isEmpty() == f){
try {
File tmp = pictures.firstElement();
name = tmp.getName();
String filename = destination + Meta.date(tmp) + tmp.getName();
Path source = tmp.toPath();
File destFile = new File(filename);
Path destination = destFile.toPath();
Files.copy(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
textArea.append("Copied " + name + "\n");
pictures.removeElementAt(0);
numberOfPicturesCopied++;
} catch(FileAlreadyExistsException faee){
textArea.append("Skipped " + name +": Picture Already In Computer\n");
} catch (NoSuchFileException ncfe){
File tmp = pictures.firstElement();
String filename = destination + Meta.date(tmp);
File newDir = new File(filename);
newDir.mkdir();
} catch (IOException ee) {
// TODO Auto-generated catch block
ee.printStackTrace();
}
}
}
});
}
with the same outcome. Any suggestions?
Also, is there any way to get the text to come in at the top of text area?
How to insert your text at the start is already answered. The other part of your question is the same as always ... you are performing heavy work on the Event Dispatch Thread, which is no longer able to perform repaints.
What you should do is perform the heavy work on a worker thread, and only update the UI on the EDT. You can for example use a SwingWorker, which is designed for this. Or even simpler, take your current code and with a few simple modifications
public void copyPictures(){
new Thread(){
public void run(){
while(pictures.isEmpty() == f){
try {
File tmp = pictures.firstElement();
final String name = tmp.getName();
String filename = destination + Meta.date(tmp) + tmp.getName();
Path source = tmp.toPath();
File destFile = new File(filename);
Path destination = destFile.toPath();
Files.copy(source, destination, StandardCopyOption.COPY_ATTRIBUTES);
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
textArea.append("Copied " + name + "\n");
}
}
);
pictures.removeElementAt(0);
numberOfPicturesCopied++;
} catch(FileAlreadyExistsException faee){
textArea.append("Skipped " + name +": Picture Already In Computer\n");
} catch (NoSuchFileException ncfe){
File tmp = pictures.firstElement();
String filename = destination + Meta.date(tmp);
File newDir = new File(filename);
newDir.mkdir();
} catch (IOException ee) {
// TODO Auto-generated catch block
ee.printStackTrace();
}
}
}
}.run();
}
See how the work is done on a separate Thread yet the UI is updated on the EDT. More information can be found in the Swing Concurrency tutorial or on SO (keyword for your search is SwingWorker, which will results in a heap of examples as this is a daily question)
Not sure what you are asking, the title seems to be saying that the text isnt updating, but your question seems to indicate that is isnt being inserted where you want it to be...
If its the latter, use the insert method instead
textArea.insert("Copied " + name + "\n",0);
to put it at the top of the text area.