I have a question.
Is it possible to use the hotswap without using breakpoints ?
When notch made prelude of chambered (http://www.youtube.com/user/Nizzotch?feature=playlist-comment#p/u) he used the hotswap without having to :
- add breakpoints
- save
- remove breakpoint
- resume
In this video it's too fast to see that, but i can't find old ones.
Do you have an idea ? eclipse-options, macro, plugins ... ?
Thank you
Depends on your JVM, but hotswap in Eclipse worked for me with no tricks on the Sun's HotSpot JVM back in the times of Java 1.5. Here's a related Sun's bug. Which JVM are you using?
public class Test {
private static int ctr = 0;
public static void main(String[] args) {
while (true) {
method();
try {
Thread.sleep(200);
} catch (InterruptedException e) {
System.err.println("Interrupted");
}
}
}
private static void method() {
System.out.println(ctr);
}
}
I changed System.out.println(ctr); to System.out.println(ctr++);, and my output altered to an increasing sequence.
Related
I created a console application using Java, then exported it as runnable JAR file. but when I run the JAR file the automation is finished but the "Java (TM) Platform SE binary" is still on background, I tried to put System.exit(0) and still not able to terminate the process.
I'm also trying to run this automatically in Task Scheduler in indefinitely repetition every 15 minutes, the problem is it will not run again after 15 minutes since the "Java (TM) Platform SE binary" is still in process and identified its status as running.
I'm pretty sure that all my automation task is all finished without error and not creating another threads.
Here is my code below:
public static void main(String[] args) {
String jarName = new File(Selenium.class.getProtectionDomain().getCodeSource().getLocation().getPath())
.getName();
System.out.println("Running " + jarName + " Automation");
if (args.length >= 1 && args[0].toLowerCase().equals("-run")) {
for (int i = 1; i < args.length; i++) {
String pram = args[i].replace(jarName + "_", "");
if (pram.toLowerCase().equals("all")) {
GFC.execute("Login");
GFC.execute("SwitchIntegration");
GFC.execute("BODActivate");
GFC.execute("Users");
GFC.execute("Settings");
GFC.execute("AccountingEntityRegistration");
GFC.execute("CustomizedData");
GFC.execute("BOD");
GFC.execute("BODAttributesMDM");
GFC.execute("BODAttributesTransactional");
GFC.execute("CMD");
GFC.execute("CMDAttributes");
GFC.execute("CMDDataEntry");
GFC.execute("CMDActivate");
GFC.execute("AccountingEntity");
GFC.execute("AccountingEntityMapping");
GFC.execute("JETemplates");
GFC.execute("Scenarios");
GFC.execute("Rules");
GFC.execute("RulesScript").quit();
} else {
if (!pram.equals("Login")) {
GFC.execute("Login");
}
GFC.execute(pram).quit();
}
}
if (Boolean.parseBoolean(infor.automation.utils.Properties.get("gfc.enableemailer"))) {
sendEmail();
}
}
}
Update: 3/14/2018
Worrying might my automation is creating another threads, so I decide
to create a new project and just a main class and export it as a
runnable Jar file, and it's still the same.
My JDK version is 1.8
I make a workaround or maybe a solution. I found out that the System.exit(0) on main will only close the console application, but the "Java (TM) Platform SE binary" will remain. To terminate this I extended to JFrame class to be able to override the ExitApp(). Inside the ExitApp() I add window listener and in windowClosing() I called the disposed() and System.exit(0) once more. I don't have any idea how this even works. If someone know how this works feel free to update this answer.
public class TestClass extends JFrame {
public void ExitApp() {
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
// Dispose Java (TM) Platform SE binary.
dispose();
// Close the Java.exe I'm not sure.
System.exit(0);
}
});
}
public static void main(String[] args) {
// Close Your Application Trigger ExitApp();
System.exit(0);
}
}
I have create a simple plugin system that allows others upload their plugin's jar, and the plugin system will load it and execute some code in it.
the plugin system will get a subclass of Function<Input, Output> to execute the loaded plugin logic, but I do not want that Function to create new Thread or do some danger action like System.exit. how can I forbid this action?
I have found the AccessController or SecurityManager in Java, how to use it to implement my intent.
Like you said, you can add a security Manager. Something like below: You can put your code in try catch block and catch your custom security exception thrown. This code below runs in loop and keeps on calling System.exit(1);
import java.security.Permission;
public class TestPreventSystemExit {
public static void main(String[] args) {
forbidSystemExitCall();
while (true) {
try {
System.exit(1);
} catch (Exception ex) {
}
}
}
private static class PreventExitException extends SecurityException {
}
private static void forbidSystemExitCall() {
final SecurityManager securityManager = new SecurityManager() {
public void checkPermission(Permission permission) {
if (permission.getName().indexOf("exitVM") >= 0) {
System.out.println("Why you did this to me? :)");
throw new PreventExitException();
}
}
};
System.setSecurityManager(securityManager);
}
}
For System.exit() - see the other answer.
For preventing the starting of threads: possible, but requires to extend the SecurityManager class - see here.
AccessController is more about how a client would write code that is potentially checked. It is not something that you, as the "owner" of the JVM can make usage of (see here). So it doesn't help with your problem.
In Joshua Bloch's Effective Java, Item 66, he exemplifies a lifeness failure by failing to communicate a variable between threads.
// Broken! - How long would you expect this program to run?
public class StopThread {
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException {
Thread backgroundThread = new Thread(new Runnable() {
public void run() {
int i = 0;
while (!stopRequested)
i++;
}
});
backgroundThread.start();
TimeUnit.SECONDS.sleep(1);
stopRequested = true;
}
}
He says on his own machine this never terminates, and gives two reasons. I tried this on my own machine, on Oracle JDK 7u75 (newest 7), and it ALWAYS terminates after one second. I also tried starting the runtime with -XX:+AggressiveOpts without success. Is there any reason why this is not working as intended (edit: i.e. not looping forever)? Is Joshua using another runtime? I have a quad-core ivy bridge.
stopRequested is not volatile. So, there is no guarantee that the changes made to it by the main thread will be seen by the backgroundThread. Changes could be seen, changes might not be seen. There is no guarantee. So (as always), Joshua is right :)
Is there a (pref portable) way to check if
The JVM has been stated with a particular -javaagent?
In particular I'm interested to know if the aspectj load time weaver has loaded or not. (I'm trying to provide a helpful error msg in the case of incorrect startup).
The following code shows
a way to determine any -javaagent:... JVM arguments,
a way to check if the AspectJ weaving agent entry point class (the one mentioned in the manifest entry Premain-Class: of aspectjweaver.jar) is loaded.
The former just proves that the argument was given on the command line, not that the agent was actually found and started.
The latter just proves that the weaver is available on the classpath, not that it was actually started as an agent. The combination of both should give you pretty much confidence that the agent is actually active.
package de.scrum_master.app;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.List;
public class Application {
public static void main(String[] args) {
RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
List<String> arguments = runtimeMxBean.getInputArguments();
for (String argument : arguments) {
if (argument.startsWith("-javaagent:"))
System.out.println(argument);
}
try {
Class.forName("org.aspectj.weaver.loadtime.Agent");
} catch (ClassNotFoundException e) {
System.err.println("WARNING: AspectJ weaving agent not loaded");
}
}
}
You also might find the question Starting a Java agent after program start and some of its answers helpful.
Update:
Okay, here is a combination of my own solution and yours, but one which actually works even if the weaver is unavailable, which is important because this is what you want to check in the first place:
public static boolean isAspectJAgentLoaded() {
try {
Class<?> agentClass = Class.forName("org.aspectj.weaver.loadtime.Agent");
Method method = agentClass.getMethod("getInstrumentation");
method.invoke(null);
} catch (Exception e) {
//System.out.println(e);
return false;
}
return true;
}
Update 2:
After some discussion with the OP bacar I have decided to offer a solution which does not use reflection but catches NoClassDefError instead:
public static boolean isAspectJAgentLoaded() {
try {
org.aspectj.weaver.loadtime.Agent.getInstrumentation();
} catch (NoClassDefFoundError | UnsupportedOperationException e) {
System.out.println(e);
return false;
}
return true;
}
Now both main error types
weaving agent is available on the classpath, but instrumentation has not been initiated because aspectjweaver.jar was not started as a Java agent,
agent aspectjweaver.jar is not on the classpath at all and class org.aspectj.weaver.loadtime.Agent is thus unavailable
are handled gracefully by returning false after warning messages (in this simple examples just the exceptions which say clearly what is wrong) have been printed on the console.
Possible console outputs for the two cases are:
java.lang.UnsupportedOperationException: Java 5 was not started with preMain -javaagent for AspectJ
java.lang.NoClassDefFoundError: org/aspectj/weaver/loadtime/Agent
I've found the following works (tested against 1.8.4), although it relies on undocumented aspectjweaver features so may not work across versions.
public static boolean isAspectJAgentLoaded() {
try {
org.aspectj.weaver.loadtime.Agent.getInstrumentation();
return true;
} catch (UnsupportedOperationException e) {
return false;
}
}
Explanation: when aspectj is loaded as an agent, the org.aspectj.weaver.loadtime.Agent.premain(...) static method is invoked by the JVM. This has a side effect we can test for. Calling getInstrumentation either throws UnsupportedOperationException (if it was not initialised as an agent) or returns successfully if it was.
A program that I've developed is crashing the JVM occasionally due to this bug: http://bugs.java.com/bugdatabase/view_bug.do?bug_id=8029516. Unfortunately the bug has not been resolved by Oracle and the bug report says that there are no known workarounds.
I've tried to modify the example code from the bug report by calling .register(sWatchService, eventKinds) in the KeyWatcher thread instead, by adding all pending register request to a list that I loop through in the KeyWatcher thread but it's still crashing. I'm guessing this just had the same effect as synchronizing on sWatchService (like the submitter of the bug report tried).
Can you think of any way to get around this?
From comments:
It appears that we have an issue with I/O cancellation when there is a pending ReadDirectoryChangesW outstanding.
The statement and example code indicate that the bug is triggered when:
There is a pending event that has not been consumed (it may or may not be visible to WatchService.poll() or WatchService.take())
WatchKey.cancel() is called on the key
This is a nasty bug with no universal workaround. The approach depends on the specifics of your application. Consider pooling watches to a single place so you don't need to call WatchKey.cancel(). If at one point the pool becomes too large, close the entire WatchService and start over. Something similar to.
public class FileWatcerService {
static Kind<?>[] allEvents = new Kind<?>[] {
StandardWatchEventKinds.ENTRY_CREATE,
StandardWatchEventKinds.ENTRY_DELETE,
StandardWatchEventKinds.ENTRY_MODIFY
};
WatchService ws;
// Keep track of paths and registered listeners
Map<String, List<FileChangeListener>> listeners = new ConcurrentHashMap<String, List<FileChangeListener>>();
Map<WatchKey, String> keys = new ConcurrentHashMap<WatchKey, String>();
boolean toStop = false;
public interface FileChangeListener {
void onChange();
}
public void addFileChangeListener(String path, FileChangeListener l) {
if(!listeners.containsKey(path)) {
listeners.put(path, new ArrayList<FileChangeListener>());
keys.put(Paths.get(path).register(ws, allEvents), path);
}
listeners.get(path).add(l);
}
public void removeFileChangeListener(String path, FileChangeListener l) {
if(listeners.containsKey(path))
listeners.get(path).remove(l);
}
public void start() {
ws = FileSystems.getDefault().newWatchService();
new Thread(new Runnable() {
public void run() {
while(!toStop) {
WatchKey key = ws.take();
for(FileChangeListener l: listeners.get(keys.get(key)))
l.onChange();
}
}
}).start();
}
public void stop() {
toStop = true;
ws.close();
}
}
I've managed to create a workaround though it's somewhat ugly.
The bug is in JDK method WindowsWatchKey.invalidate() that releases native buffer while the subsequent calls may still access it. This one-liner fixes the problem by delaying buffer clean-up until GC.
Here is a compiled patch to JDK. In order to apply it add the following Java command-line flag:
-Xbootclasspath/p:jdk-8029516-patch.jar
If patching JDK is not an option in your case, there is still a workaround on the application level. It relies on the knowledge of Windows WatchService internal implementation.
public class JDK_8029516 {
private static final Field bufferField = getField("sun.nio.fs.WindowsWatchService$WindowsWatchKey", "buffer");
private static final Field cleanerField = getField("sun.nio.fs.NativeBuffer", "cleaner");
private static final Cleaner dummyCleaner = Cleaner.create(Thread.class, new Thread());
private static Field getField(String className, String fieldName) {
try {
Field f = Class.forName(className).getDeclaredField(fieldName);
f.setAccessible(true);
return f;
} catch (Exception e) {
throw new IllegalStateException(e);
}
}
public static void patch(WatchKey key) {
try {
cleanerField.set(bufferField.get(key), dummyCleaner);
} catch (IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
}
Call JDK_8029516.patch(watchKey) right after the key is registred, and it will prevent watchKey.cancel() from releasing the native buffer prematurely.
You might not be able to work around the problem itself but you could deal with the error and handle it. I don't know your specific situation but I could imagine the biggest issue is the crash of the whole JVM. Putting all in a try block does not work because you cannot catch a JVM crash.
Not knowing more about your project makes it difficult to suggest a good/acceptable solution, but maybe this could be an option: Do all the file watching stuff in a separate JVM process. From your main process start a new JVM (e.g. using ProcessBuilder.start()). When the process terminates (i.e. the newly started JVM crashes), restart it. Obviously you need to be able to recover, i.e. you need to keep track of what files to watch and you need to keep this data in your main process too.
Now the biggest remaining part is to implement some communication between the main process and the file watching process. This could be done using standard input/output of the file watching process or using a Socket/ServerSocket or some other mechanism.