generate executable jar at runtime - java

I'd like to write a Java app which can create executable jars at runtime. The "hello world" of what I want to do is write a Java app X that when run, generates an executable jar Y that when run, prints hello world (or perhaps another string not known until after Y is run).
How can I accomplish this?

The other answers require starting a new process, this is a method that doesn't. Here are 3 class definitions which produce the hello world scenario described in the question.
When you run XMain.main, it generates /tmp/y.jar. Then, when you run this at the command line:
java -jar /tmp/y.jar cool
It prints:
Hello darling Y!
cool
example/YMain.java
package example;
import java.io.IOException;
import java.io.InputStream;
public class YMain {
public static void main(String[] args) throws IOException {
// Fetch and print message from X
InputStream fromx = YMain.class.getClassLoader().getResourceAsStream("fromx.txt");
System.out.println(new String(Util.toByteArray(fromx)));
// Print first command line argument
System.out.println(args[0]);
}
}
example/XMain.java
package example;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
public class XMain {
public static void main(String[] args) throws IOException {
Manifest manifest = new Manifest();
manifest.getMainAttributes().put(Attributes.Name.MANIFEST_VERSION, "1.0");
manifest.getMainAttributes().put(Attributes.Name.MAIN_CLASS, YMain.class.getName());
JarOutputStream jarOutputStream = new JarOutputStream(new FileOutputStream("/tmp/y.jar"), manifest);
// Add the main class
addClass(YMain.class, jarOutputStream);
// Add the Util class; Y uses it to read our secret message
addClass(Util.class, jarOutputStream);
// Add a secret message
jarOutputStream.putNextEntry(new JarEntry("fromx.txt"));
jarOutputStream.write("Hello darling Y!".getBytes());
jarOutputStream.closeEntry();
jarOutputStream.close();
}
private static void addClass(Class c, JarOutputStream jarOutputStream) throws IOException
{
String path = c.getName().replace('.', '/') + ".class";
jarOutputStream.putNextEntry(new JarEntry(path));
jarOutputStream.write(Util.toByteArray(c.getClassLoader().getResourceAsStream(path)));
jarOutputStream.closeEntry();
}
}
example/Util.java
package example;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class Util {
public static byte[] toByteArray(InputStream in) throws IOException {
ByteArrayOutputStream out = new ByteArrayOutputStream();
byte[] buf = new byte[0x1000];
while (true) {
int r = in.read(buf);
if (r == -1) {
break;
}
out.write(buf, 0, r);
}
return out.toByteArray();
}
}

Do you have to write it in plain old Java? I'd use Gradle (a Groovy based build tool). You can have a custom task to write out the source files for Y (Groovy makes it really easy to write out templated files). Gradle makes it easy to generate an executable jar.
If you really want to roll your own from scratch, you'd need to use ZipOutStream to zip up the compiled files after calling javac via the Process API to compile the source.
Maybe a bit more info about why you want to do this would help get better answers
cheers
Lee

To elaborate on Lee's reply, you need to compile the source first. You can use Process or you can use the code from tools.jar directly as explained here. Then write out a MANIFEST.MF file and put it all together using ZipOutputStream as mentioned.

Step 1: figure out how to do it manually using the command line.
Step 2: automate this by calling the program from within Java.
http://devdaily.com/java/edu/pj/pj010016/
For step 1 I would suggest using ant - IDEs are not always automatable. So, either write out all the files from Java, or have some of the ant configurations included as resources n the project.

Related

Why is StandardOpenOption.CREATE_NEW not creating a file to be read from in Java?

Here is my code:
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.InvalidPathException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
public class ExplicitChannelRead {
public static void main(String[] args) {
int count;
Path filePath = null;
// First, obtain a path to a file.
try {
filePath = Paths.get("test1.txt");
}
catch(InvalidPathException e) {
System.out.println("Path error: "+e);
return;
}
// Next, obtain a channel to that file within a try-with-resources block.
try(SeekableByteChannel fChan =
Files.newByteChannel(filePath, StandardOpenOption.CREATE_NEW)) {
// Allocate a buffer.
ByteBuffer mBuf = ByteBuffer.allocate(128);
while((count=fChan.read(mBuf)) != -1) {
//Rewind the buffer so that it can be read.
mBuf.rewind();
for(int i=0; i<count; i++) System.out.print((char)mBuf.get());
}
System.out.println();
} catch (IOException e) {
e.printStackTrace();
// System.out.println("I/O error: "+e);
}
}
}
On running the above code I get this exception:
java.nio.file.NoSuchFileException: test1.txt
at java.base/sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:85)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:103)
at java.base/sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:108)
at java.base/sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:235)
at java.base/java.nio.file.Files.newByteChannel(Files.java:375)
at java.base/java.nio.file.Files.newByteChannel(Files.java:426)
at fileNIO.ExplicitChannelRead.main(ExplicitChannelRead.java:31)
I don't understand why test1.txt file is not being created as it doesn't exist currently and I am using the StandardOpenOption.CREATE_NEW option?
When I use StandardOpenOption.WRITE option along with StandardOpenOption.CREATE_NEW then I see the file text1.txt being created and at that time I get the exception:
Exception in thread "main" java.nio.channels.NonReadableChannelException
This exception I understand its cause because I have opened the file in write mode and in the code I am performing read operation on the file.
It seems to me that a new file can't be created when the file is opened in read mode.
I have reproduced what you are seeing (on Linux with Java 17).
As I noted in the comments, the behavior seems to contradict what the javadocs say what should happen, but what I discovered is this:
With READ or neither READ or WRITE, a NoSuchFileException is thrown.
With WRITE (and no READ), the file is created but then NonReadableChannelException is thrown.
With both READ and WRITE, it works. At least ... it did for me.
I guess this sort of makes sense. You need READ to read the file and WRITE to create it. And the javadocs state that READ is the default if you don't specify READ, WRITE or APPEND.
But creating an empty file1 with CREATE_NEW and then immediately trying to read it is a use-case that borders on pointless. So it not entirely surprising that they didn't (clearly) document how to achieve this.
1 - As a comment noted, CREATE_NEW is specified to fail if the file already exists. If you want "create it if it doesn't exist", then you should use CREATE instead.

OCR implementation using using java

I have written java code to convert images into text using java.But my code is taking only single image as input . I want that the program should fetch images from a folder and then run the OCR on it.
My code is:
import java.io.FileOutputStream;
import org.bytedeco.javacpp.*;
import org.junit.Test;
import static org.bytedeco.javacpp.lept.*;
import static org.bytedeco.javacpp.tesseract.*;
import static org.junit.Assert.assertTrue;
import java.io.File;
public class BasicTesseractExampleTest {
#Test
public void givenTessBaseApi_whenImageOcrd_thenTextDisplayed() throws Exception {
BytePointer outText;
TessBaseAPI api = new TessBaseAPI();
// Initialize tesseract-ocr with English, without specifying tessdata path
if (api.Init(".", "ENG") != 0) {
System.err.println("Could not initialize tesseract.");
System.exit(1);
}
PIX image = pixRead("IMG_0012 (1).jpg");
api.SetImage(image);
// Get OCR result
outText = api.GetUTF8Text();
String string = outText.getString();
assertTrue(!string.isEmpty())
System.out.println(str);
// Destroy used object and release memory
api.End();
outText.deallocate();
pixDestroy(image);
}
}
To read a list of files out of a given Path use for example:
File f = new File("C:/programs");
File[] fileArray = f.listFiles();
Now you can check every File out of the fileArray if it is a directory and skip that with:
if(fileArray[0].isDirectory()) continue;
To find the images you can check for example the ending of the filename with:
fileArray[0].getName().endsWith(".jpg")
Do this check for all files out ouf the fileArray and call your method with the right files. To check the right file you have to change this line of your code:
PIX image = pixRead("IMG_0012 (1).jpg");
and add the fileArray[?] where the ? must be replaced with the right number.

How to make a folder non-readable in Java?

I am trying to create a folder structure as Test1/gotcha/Test3
I want to make Test1 non-reable. The below code does not work:
new File("D:\\Test1\\gotcha\\Test3").mkdirs();
PrintWriter writer= new PrintWriter("D:\\Test1\\gotcha\\Test3\\testing.txt");
writer.write("Hello");
writer.close();
File f1= new File("D:\\Test1");
f1.setReadable(false,false);
f1.setExecutable(false,false);
I am still able to open the Test1 folder. Any suggestions on how I can fix this?
It is not possible to make folders non-readable in Windows, that is why setReadable() in windows does not work.
That cannot be done.
One way around is to change the file extension of files in that folder to a random name, so that even though the user tries to open it he cannot find an application to do it.
Even though he figures out that it can be opened with a text editor, We will encrypt it. So it becomes non-readable.
This was just a key-substitution cipher. You can use a more complex algorithm like SHA or AES to make it impossible to break.
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
public class Demo
{
public static void main( String[] args )throws IOException
{
File file = new File("C://temp//Hello1.sddf");// a random extension.
// creates the file
file.createNewFile();
// creates a FileWriter Object
FileWriter writer = new FileWriter(file);
String data = "Hello world!";//hello world is the data.
// Writes the content to the file
writer.write(encrypt(data));
writer.flush();
writer.close();
}
private static String encrypt(String data) {// I used a simple cipher I advise to use any other encryption technique.
// TODO Auto-generated method stub
String op = "";
for(int i = 0; i < data.length(); i++)
op += (char)(data.charAt(i) - 5);
return op;
}
}

Using displayLogs() in WLSTInterpreter NameError: displayLogs

I am attempting to get a log output from the displayLogs() command and I have trying to do this within the WLST Interpreter. I get the following error which is "NameError: displayLogs" I am able to perform other commands such as domainRuntime() and a number of others, but this one seems to be outside the realm. Do I need to run it with some sort of classes in the classpath when running it? Any help would be appreciated.
The source code that I am using below:
package wlst;
import weblogic.management.scripting.utils.WLSTInterpreter;
import org.python.util.InteractiveInterpreter;
import org.python.core.PyObject;
public class EmbeddedWLST
{
static InteractiveInterpreter interpreter = null;
EmbeddedWLST() {
interpreter = new WLSTInterpreter();
}
private static void connect() {
StringBuffer buffer = new StringBuffer();
buffer.append("connect('USERNAME','PASSWORD','t3://HOSTANAME:PORT')");
interpreter.exec(buffer.toString());
}
public static void main(String[] args) {
new EmbeddedWLST();
connect();
PyObject cmo = interpreter.get("cmo");
String command = getLogs();
System.out.println("Executing Get Logs");
interpreter.exec(command);
System.out.println("Getting Output Object");
PyObject output = interpreter.get("output");
System.out.println(output.getClass());
System.out.println(output);
}
private static String getLogs() {
StringBuffer buf = new StringBuffer();
buf.append( "output = displayLogs(returnData=1)\n" );
return buf.toString();
}
}
UPDATE
Everything you are looking for lives in:
<install dir>/oracle_common/common/wlst
A simple grep -R displayLogs * returned the python module you need:
<install dir>/oracle_common/common/wlst/oracle-logging.py
You will need to include the jars that script needs on your classpath, specifically the logging jar ojdl.jar found under <install dir>/oracle_common/modules/oracle.odl
The above information was found by comparing the scripts below (I am using 10.3.6):
This script <install dir>/wlserver_10.3/common/bin/wlst.sh fails with:
wls:/offline> listLogs()
Traceback (innermost last):
File "<console>", line 1, in ?
NameError: listLogs
This script <install dir>/oracle_common/common/bin/wlst.sh succeeds (and has many more options than the script above) :
wls:/offline> listLogs()
Not connected to a Weblogic server. Connect to a Weblogic server first.
Make sure you have all the same jars and properties set as the second script does.

Java noob question - how to store a string to a new text file

Here is my scenario:
Selenium grabbed some text on the html page and convert it to a string (String store_txt = selenium.getText("text");) - the text is dynamically generated.
Now I want to store this string into a new text file locally every time I run this test, should I use FileWriter? Or is it as simple as writing a System.out.println("string");?
Do I have to write this as a class or can I write a method instead?
Thanks in advance!!
Use createTempFile to create a new file every time, use FileWriter to write to the file.
import java.io.File;
import java.io.IOException;
import java.io.FileWriter;
public class Main {
public static void main(String[] args) throws IOException {
File f = File.createTempFile("selenium", "txt");
FileWriter writer = new FileWriter(f);
writer.append("text");
}
}
Yes, you need to use a FileWriter to save the text to file.
System.out.println("string");
just prints to the screen in console mode.
Always remember to close the filewriter afterwards using
writer.close()
Otherwise you could end up with a half written file.

Categories