I am running a tool that runs an external Java program several times in its operation. The external tool starts with opening a JOptionPane inside a JFrame.
Here is a test script I wrote to try to solve my issue.
import java.io.File;
public class Test {
public static void main(String[] args) throws Exception {
for(int i=0; i<6; i++) {
//Thread.sleep(1000);
String toRun = "java -jar \"" + "C:\\Folder\\File.jar" + "\" " + i;
Runtime.getRuntime().exec(toRun, null, new File("C:\\Folder"));
}
}
}
When this runs, only the final run's JOptionPane (i=5) appears, but it seems that others are "trying" to appear as panes seem to be opening and immediately closing.
When I uncomment the Thread.sleep however, all of the panes open separately. If i set the sleep to 300 (0.3 seconds) about half of the panes appear, usually the first and last ones.
I would like to find a way to run all instances of the external program fully without needing to use Thread.sleep() at all, if possible.
Edit: As per requirement's I've minimalised my external program as well.
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
public class File {
static JFrame frame = new JFrame("Frame");
private static String doc1Address = "C:\\Folder\\doc1.csv";
private static String doc2Address = "C:\\Folder\\doc2.csv";
public static void main(String[] args) throws Exception {
if(args.length == 1) {
SimpleDateFormat form = new SimpleDateFormat("yyyy-MM-dd hh-mm-ss");
Date date = new Date();
String currentDate = form.format(date);
//Save Backup of doc1
String doc1BackAddress = doc1Log.substring(0, doc1Log.length()-15) + "doc1Back " + currentDate + ".csv";
Path todoc1 = Paths.get(doc1Address);
Path todoc1Back = Paths.get(doc1BackAddress);
Files.copy(todoc1, todoc1Back);
Files.setAttribute(todoc1Back, "dos:readonly", true);
//Save Backup of doc2
String doc2BackAddress = doc2Log.substring(0, doc2Log.length()-16) + "doc2Back " + currentDate + ".csv";
Path todoc2 = Paths.get(doc2Address);
Path todoc2Back = Paths.get(doc2BackAddress);
Files.copy(todoc2, todoc2Back);
Files.setAttribute(todoc2Back, "dos:readonly", true);
//Format JFrame
frame.pack();
frame.setLodoc1ionRelativeTo(null);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JOptionPane.showMessageDialog(frame, args[0]);
frame.dispose();
}
}
}
Found my own issue; since the backup files use the format yyyy-MM-dd hh-mm-ss, and files saved during the same second result in a FileAlreadyExists Exception, meaning only the first file to finish saving allows the program to continue running.
Having a 1 second pause results in the files having different save names, so no error occurs.
Having a sub-1 second pause results in some file name overlap, but some different names too, hence some files appear.
Solution: either change the name format (i.e. include milliseconds), or include the backup functions in an if-statement, that is ignored if the file with the same time already exists.
(also; thank you #ErwinBolwidt, in being encouraged to format my question properly I realised that the issue in my code was not where I assumed it to be).
Related
I wrote a simple test to capture timing metrics using the SPF4J (Simple Profiler Framework For Java) MeasurementRecorder. I'm running a simple for loop and capturing time of a random sleep from 100-200 ms as shown in the complete code sample below.
When I run the test, the Time-Series DataBase (TSDB) files are created successfully, but they're empty while the test is running (around 2 mins). The buffered data are written to files when the application completes, but samples at the end are missing and the last one is truncated, like the buffer is not getting flushed properly.
If the application never terminates (e.g. web service), when will the buffered metrics be written to file - on a timer, or when a certain amount of data is buffered? Is this configurable and, if so, how?
package com.examples.spf4j;
import org.spf4j.perf.MeasurementRecorder;
import org.spf4j.perf.impl.RecorderFactory;
import java.io.File;
import java.util.Random;
import org.junit.Test;
public class TestMeasurementRecorder {
#Test
public void testMeasurementRecorder() throws InterruptedException {
initialize();
MeasurementRecorder measurementRecorder = getMeasurementRecorder();
Random random = new Random();
for (int i=0; i<=1000; i++) {
long startTime = System.currentTimeMillis();
Thread.sleep(100 + random.nextInt(100));
measurementRecorder.record(System.currentTimeMillis() - startTime);
}
}
public static void initialize() {
String tsDbFile = System.getProperty("user.dir") + File.separator + "spf4j-performance-monitor.tsdb2";
String tsTextFile = System.getProperty("user.dir") + File.separator + "spf4j-performance-monitor.txt";
System.setProperty("spf4j.perf.ms.config", "TSDB#" + tsDbFile + "," + "TSDB_TXT#" + tsTextFile);
}
public static MeasurementRecorder getMeasurementRecorder() {
int sampleTimeMillis = 1000;
return RecorderFactory.createScalableQuantizedRecorder("response time", "ms", sampleTimeMillis, 10, 0, 40, 10);
}
}
You will need to set the system property: spf4j.perf.ms.periodicFlush=true
to enable the periodic flush.
The image below shows the format of my settings file for a web bot I'm developing. If you look at line 31 in the image you will see it says chromeVersion. This is so the program knows which version of the chromedriver to use. If the user enters an invalid response or leaves the field blank the program will detect that and determine the version itself and save the version it determines to a string called chromeVersion. After this is done I want to replace line 31 of that file with
"(31) chromeVersion(76/77/78), if you don't know this field will be filled automatically upon the first run of the bot): " + chromeVersion
To be clear I do not want to rewrite the whole file I just want to either change the value assigned to chromeVersion in the text file or rewrite that line with the version included.
Any suggestions or ways to do this would be much appreciated.
image
You will need to rewrite the whole file, except the byte length of the file remains the same after your modification. Since this is not guaranteed to be the case or to find out is too cumbersome here is a simple procedure:
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class Lab1 {
public static void main(String[] args) {
String chromVersion = "myChromeVersion";
try {
Path path = Paths.get("C:\\whatever\\path\\toYourFile.txt");
List<String> lines = Files.readAllLines(path, StandardCharsets.UTF_8);
int lineToModify = 31;
lines.set(lineToModify, lines.get(lineToModify)+ chromVersion);
Files.write(path, lines, StandardCharsets.UTF_8);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
Note that this is not the best way to go for very large files. But for the small file you have it is not an issue.
i am developing an simple blackberry application in BlackBerry - Java Plug-in for Eclipse. In that, i want to read data from an external text file. I had searched for this, and tried for some tips, like. But failed at last. I will describe my application...
my main file...
package com.nuc;
import net.rim.device.api.ui.UiApplication;
public class Launcher extends UiApplication
{
public static void main(String[] args)
{
Launcher theApp = new Launcher();
theApp.enterEventDispatcher();
}
public Launcher()
{
pushScreen(new MyScreen());
}
}
And then my app class is like....
package com.nuc;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.component.BasicEditField;
import net.rim.device.api.ui.component.Dialog;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.container.GridFieldManager;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FieldChangeListener;
public final class MyScreen extends MainScreen implements FieldChangeListener
{
// declared variables...
public MyScreen()
{
//rest codes...
I want to show some details from a text file before my app starts, like the End User License Agreement.. ie, something which cames as the first line..
my first question is, where i need to put that text file... i got lots of guidance from net, but nothing worked for eclipse..
Secondly, then how can i read the file and put its content in a dialog.
So plz guide me how i can achieve it.. sample code will be appreciable, for i am new to this environment...
To add a file to your Eclipe project
right click on the res folder of your project structure, click on New, click on Untitled Text File and then enter some text and save the file.
To read from a file and display on a dialog try something like the following code snippet:
try {
InputStream is = (InputStream) getClass().getResourceAsStream("/Text");
String str = "";
int ch;
while ((ch = is.read()) != -1) {
str += (char)ch;
}
synchronized (UiApplication.getEventLock()) {
Dialog.alert(str == null ? "Failed to read." : str);
}
} catch (Exception e) {
synchronized (UiApplication.getEventLock()) {
Dialog.alert(e.getMessage() + " + " + e.toString());
}
}
in the above code "/Text" is the file name. And if you got a NullPointerException then check the file name and path.
Rupak's answer is mostly correct, but there's a few problems with it. You definitely don't want to add immutable strings together in a situation like this. When you add 2 strings together (myString += "Another String") Java basically creates a new String object with the values of the two other Strings, because it cannot change the contents of the other strings. Usually this is fine if you just need to add two strings together, but in this case if you have a large file then you're creating a new String object for EVERY character in the file (each object bigger than the last). There's a lot of overhead associated with this object creation AND the garbage collector (very slow) will have to intervene more often because of all these objects that need to be destroyed.
StringBuffer to the rescue! Using a StringBuffer in place of the String concatenation will only require 1 object to be created and will be much faster.
try {
InputStream is = (InputStream) getClass().getResourceAsStream("/Text");
StringBuffer str = new StringBuffer();
int ch;
while ((ch = is.read()) != -1) {
str.append((char)ch);
}
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run(){
Dialog.alert(str.toString() == null ? "Failed to read." : str.toString());
}
}
} catch (Exception e) {
UiApplication.getUiApplication().invokeLater(new Runnable(){
public void run(){
Dialog.alert(e.getMessage() + " + " + e.toString());
}
}
}
Also several developers on the Blackberry support forums recommend against using UiApplication.getEventLock() because it can be "dangerous". They recommend using invokeLater() instead. See Blackberry Support Forums
I want to be able to execute the .Jar file, and if the heap space isn't set big enough, it should launch a new JVM with the same .Jar file, but set with a bigger heap space, and then close the first JVM and .Jar.
I've tried using the ProcessBuilder, but I can't get it to work.
It has to work cross platform.
-ONi
I have found the solution, and it works cross platform. To restart the JVM from code, use the following. This answer is taken from another question I found after hours of search in here. If you want, you can follow it with an System.exit(0), to terminate the JVM that started the new process, after a call to this method.
public static void startSecondJVM() throws Exception {
String separator = System.getProperty("file.separator");
String classpath = System.getProperty("java.class.path");
String path = System.getProperty("java.home")
+ separator + "bin" + separator + "java";
ProcessBuilder processBuilder =
new ProcessBuilder(path, "-Xmx1024m", "-cp",
classpath,
Main.class.getName());
Process process = processBuilder.start();
}
You can launch java with an initial heap size, and also specify a maximum heap size which will be only be used as required. I'm not sure what you're trying to do but it might emulate the behaviour you want?
java -Xms256m -Xmx1g -jar myapp.jar
In this example you start with 256M, if the app needs more memory it will take it, incrementally, up until 1G.
You might try combining these two sources.
MemoryRecoveryTest.java
Makes attempts to recover from an OutOfMemoryError.
/*License - LGPL
<h3>Recovery from an OutOfMemory Error</h3>
<p>The JavaDocs for Error state, in the first sentence..
<blockquote>"An Error is a subclass of Throwable that indicates
serious problems that a reasonable application should
not try to catch."</blockquote>
<p>This advice has led to the fallacy that an OutOfMemoryError
should not be caught and dealt with.But this demo. shows
that it is quite easy to recover to the point of providing
the user with meaningful information, and advice on how to
proceed.
<p>I aim to make my applications 'unreasonable'.;-)
*/
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JProgressBar;
import javax.swing.JOptionPane;
import javax.swing.JDialog;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;
import java.util.ArrayList;
/** A demo. showing recovery from an OutOfMemoryError.
Our options once an OOME is encountered are relatively
few, but we can still warn the end user and provide
advice on how to correct the problem.
#author Andrew Thompson */
public class MemoryRecoveryTest {
public static void main(String[] args) {
// reserve a buffer of memory
byte[] buffer = new byte[2^10];
ArrayList<Object> list = new ArrayList<Object>();
final JProgressBar memory = new JProgressBar(
0,
(int)Runtime.getRuntime().totalMemory());
ActionListener listener = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
memory.setValue(
(int)Runtime.getRuntime().freeMemory() );
}
};
Timer timer = new Timer(500, listener);
timer.start();
JDialog dialog = new JDialog();
dialog.setTitle("Available Memory");
JPanel memoryPanel = new JPanel();
memoryPanel.add(memory);
memoryPanel.setBorder(new EmptyBorder(25,25,25,25));
dialog.add( memoryPanel );
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
dialog.addWindowListener( new WindowAdapter(){
#Override
public void windowClosing(WindowEvent we) {
System.exit(0);
}
} );
// prepare a memory warning panel in advance
JPanel memoryWarning = new JPanel();
memoryWarning.add( new JLabel(
"<HTML><BODY>There is not enough memory to" +
" complete the task!<BR> Use a variant " +
" of the application that assigns more memory.") );
try {
// do our 'memory intensive' task
while(true) {
list.add( new Object() );
}
} catch(OutOfMemoryError oome) {
// provide the VM with some memory 'breathing space'
// by clearing the buffer
buffer = null;
// tell the user what went wrong, and how to fix it
JOptionPane.showMessageDialog(
dialog,
memoryWarning,
"Out of Memory!",
JOptionPane.ERROR_MESSAGE);
}
}
}
IWantToBeBig.java
Ensures a Process is started with a memory size specified.
import java.awt.EventQueue;
import javax.swing.JOptionPane;
import java.io.File;
class IWantToBeBig {
public static void main(String[] args) throws Exception {
if (args.length==0) {
ProcessBuilder pb = new ProcessBuilder(
"java",
"-jar",
"-Xmx512m",
"big.jar",
"anArgument"
);
pb.directory(new File("."));
Process process = pb.start();
process.waitFor();
System.out.println("Exit value: " + process.exitValue());
} else {
Runnable r = new Runnable() {
public void run() {
JOptionPane.showMessageDialog(
null,
"Max Memory: " +
Runtime.getRuntime().maxMemory() +
" bytes.");
}
};
EventQueue.invokeLater(r);
}
}
}
I'd do this kind of work in an outer script file - in pseudo code:
$heap := 128
$ok := true
do {
exitCode = java -Xmx$heapM -jar myApp.jar
if (exitCode = OOME) {
heap += 128
$ok := false
}
while(!$ok)
Catch OOME and exiting with a custom code should always be possible. There's one problem with this approach - if the $heap value exceeds the maximum heap space that is possible for the target system (example: ~1.4GByte on Win32 systems) then it will not terminate.
Note: this is just an answer to the question - usually one would assign a high amount of memory and/or fight the memory leaks - but I don't know the actual requirments/restrictions
I have a bunch of strings in a properties file which i want to 'un-externalize', ie inline into my code.
I see that both Eclipse and Intellij have great support to 'externalize' strings from within code, however do any of them support inlining strings from a properties file back into code?
For example if I have code like -
My.java
System.out.println(myResourceBundle.getString("key"));
My.properties
key=a whole bunch of text
I want my java code to be replaced as -
My.java
System.out.println("a whole bunch of text");
I wrote a simple java program that you can use to do this.
Dexternalize.java
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
public class Deexternalize {
public static final Logger logger = Logger.getLogger(Deexternalize.class.toString());
public static void main(String[] args) throws IOException {
if(args.length != 2) {
System.out.println("Deexternalize props_file java_file_to_create");
return;
}
Properties defaultProps = new Properties();
FileInputStream in = new FileInputStream(args[0]);
defaultProps.load(in);
in.close();
File javaFile = new File(args[1]);
List<String> data = process(defaultProps,javaFile);
buildFile(javaFile,data);
}
public static List<String> process(Properties propsFile, File javaFile) {
List<String> data = new ArrayList<String>();
Set<Entry<Object,Object>> setOfProps = propsFile.entrySet();
int indexOf = javaFile.getName().indexOf(".");
String javaClassName = javaFile.getName().substring(0,indexOf);
data.add("public class " + javaClassName + " {\n");
StringBuilder sb = null;
// for some reason it's adding them in reverse order so putting htem on a stack
Stack<String> aStack = new Stack<String>();
for(Entry<Object,Object> anEntry : setOfProps) {
sb = new StringBuilder("\tpublic static final String ");
sb.append(anEntry.getKey().toString());
sb.append(" = \"");
sb.append(anEntry.getValue().toString());
sb.append("\";\n");
aStack.push(sb.toString());
}
while(!aStack.empty()) {
data.add(aStack.pop());
}
if(sb != null) {
data.add("}");
}
return data;
}
public static final void buildFile(File fileToBuild, List<String> lines) {
BufferedWriter theWriter = null;
try {
// Check to make sure if the file exists already.
if(!fileToBuild.exists()) {
fileToBuild.createNewFile();
}
theWriter = new BufferedWriter(new FileWriter(fileToBuild));
// Write the lines to the file.
for(String theLine : lines) {
// DO NOT ADD windows carriage return.
if(theLine.endsWith("\r\n")){
theWriter.write(theLine.substring(0, theLine.length()-2));
theWriter.write("\n");
} else if(theLine.endsWith("\n")) {
// This case is UNIX format already since we checked for
// the carriage return already.
theWriter.write(theLine);
} else {
theWriter.write(theLine);
theWriter.write("\n");
}
}
} catch(IOException ex) {
logger.log(Level.SEVERE, null, ex);
} finally {
try {
theWriter.close();
} catch(IOException ex) {
logger.log(Level.SEVERE, null, ex);
}
}
}
}
Basically, all you need to do is call this java program with the location of the property file and the name of the java file you want to create that will contain the properties.
For instance this property file:
test.properties
TEST_1=test test test
TEST_2=test 2456
TEST_3=123456
will become:
java_test.java
public class java_test {
public static final String TEST_1 = "test test test";
public static final String TEST_2 = "test 2456";
public static final String TEST_3 = "123456";
}
Hope this is what you need!
EDIT:
I understand what you requested now. You can use my code to do what you want if you sprinkle a bit of regex magic. Lets say you have the java_test file from above. Copy the inlined properties into the file you want to replace the myResourceBundle code with.
For example,
TestFile.java
public class TestFile {
public static final String TEST_1 = "test test test";
public static final String TEST_2 = "test 2456";
public static final String TEST_3 = "123456";
public static void regexTest() {
System.out.println(myResourceBundle.getString("TEST_1"));
System.out.println(myResourceBundle.getString("TEST_1"));
System.out.println(myResourceBundle.getString("TEST_3"));
}
}
Ok, now if you are using eclipse (any modern IDE should be able to do this) go to the Edit Menu -> Find/Replace. In the window, you should see a "Regular Expressions" checkbox, check that. Now input the following text into the Find text area:
myResourceBundle\.getString\(\"(.+)\"\)
And the back reference
\1
into the replace.
Now click "Replace all" and voila! The code should have been inlined to your needs.
Now TestFile.java will become:
TestFile.java
public class TestFile {
public static final String TEST_1 = "test test test";
public static final String TEST_2 = "test 2456";
public static final String TEST_3 = "123456";
public static void regexTest() {
System.out.println(TEST_1);
System.out.println(TEST_1);
System.out.println(TEST_3);
}
}
You may use Eclipse "Externalize Strings" widget. It can also be used for un-externalization. Select required string(s) and press "Internalize" button. If the string was externalized before, it'll be put back and removed from messages.properties file.
May be if you can explain on how you need to do this, then you could get the correct answer.
The Short answer to your question is no, especially in Intellij (I do not know enough about eclipse). Of course the slightly longer but still not very useful answer is to write a plugin. ( That will take a list of property files and read the key and values in a map and then does a regular expression replace of ResourceBundle.getValue("Key") with the value from Map (for the key). I will write this plugin myself, if you can convince me that, there are more people like you, who have this requirement.)
The more elaborate answer is this.
1_ First I will re-factor all the code that performs property file reading to a single class (or module called PropertyFileReader).
2_ I will create a property file reader module, that iterates across all the keys in property file(s) and then stores those information in a map.
4_ I can either create a static map objects with the populated values or create a constant class out of it. Then I will replace the logic in the property file reader module to use a get on the map or static class rather than the property file reading.
5_ Once I am sure that the application performs ok.(By checking if all my Unit Testing passes), then I will remove my property files.
Note: If you are using spring, then there is a easy way to split out all property key-value pairs from a list of property files. Let me know if you use spring.
I would recommend something else: split externalized strings into localizable and non-localizable properties files. It would be probably easier to move some strings to another file than moving it back to source code (which will hurt maintainability by the way).
Of course you can write simple (to some extent) Perl (or whatever) script which will search for calls to resource bundles and introduce constant in this place...
In other words, I haven't heard about de-externalizing mechanism, you need to do it by hand (or write some automated script yourself).
An awesome oneliner from #potong sed 's|^\([^=]*\)=\(.*\)|s#Messages.getString("\1")#"\2"#g|;s/\\/\\\\/g' messages.properties |
sed -i -f - *.java run this inside your src dir, and see the magic.