Persisting my state between uses - java

Newbie at netbeans-platform.
How can I save my state from one execution to the next.
The netbeans platform elegantly remembers the state and position of all my windows. How can I add to that state some of my own data? Very much like Netbeans saves what projects are open and reopens them when it starts up, along with their state.
Ass suggested here I added the following to my TopComponent but it doesn't work. getPersistenceType is called but neither writeExternal n'or readExternal are called.
#Override
public int getPersistenceType() {
return TopComponent.PERSISTENCE_ALWAYS;
}
#Override
public void writeExternal(ObjectOutput oo) throws IOException {
super.writeExternal(oo);
}
#Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException {
super.readExternal(oi);
}
Comments here suggest tapping into readProperties and writeProperties but that doesn't feel right to me. I am not wanting to store Properties, I want to store State.

Some years ago I blogged about this, using the Session Storage feature of the Swing Application Framework in a NetBeans Platform application:
http://puces-blog.blogspot.ch/2009/04/netbeans-platform-meets-swing.html
The following 3 classes should provide the integration into the NetBeans Platform:
ModuleApplicationContext.java
ModuleLocalStorage.java
Modules.java
The referenced XProperties and JXTable you only need if you want support for SwingX classes such as JXTable.
To use this feature in your own module you need to initialize the context in your ModuleInstall class:
public class Installer extends ModuleInstall {
private static ModuleApplicationContext applicationContext;
#Override
public void restored() {
applicationContext = new ModuleApplicationContext(Modules.getModuleInfo(
Installer.class));
}
public static ModuleApplicationContext getApplicationContext() {
return applicationContext;
}
}
For a given contentPane you can then store the GUI session state using:
Installer.getApplicationContext().getSessionStorage().save(
getContentPanel(), SESSION_STORAGE_XML);
and restore the state using:
Installer.getApplicationContext().getSessionStorage().
restore(getContentPanel(), SESSION_STORAGE_XML);
Note: you need to set the component names of the relevant components
You can find the complete sample here: http://sourceforge.net/p/puces-samples/code/HEAD/tree/tags/sessionstate-1.0/
Also note however that development of the Swing Application Framework (JSR-296) has been withdrawn.
There is a fork called Better Swing Application Framework, but I haven't used it yet.

I also had some problems with this but finally I could fix it.
Annotate Your topcomponent class with #TopComponent.Description and set the right persistence type inside the annotation.
Your topcomponent class has to be serializable so,
every fields inside the topcompent have to be serializable or transient.
You can implement Your custom serialization with readExtern/writeExternal but it is not necessary, You can remove them.
If it still does not work check the log after You closed Your netbeans app and You will see why the platform could not serialize Your topComponent.

Related

Listening to class reload in Java

For performance reasons, I have a class that stores a Map whose key is a Class<?> and its value is function of that class's fields. The map is populated during code execution according to the type of the calling object. The above is a generalization/simplification
public class Cache {
private static final Map<Class<?>, String> fieldsList = ...;
//Synchronization omitted for brevity
public String getHqlFor(Class<?> entity){
if (!fieldsList.containsKey(entity))
fieldsList.put(entity,createHql(entity));
return fieldsList.get(entity);
}
}
During development, thanks to the help of Jrebel, I often make modifications to classes by changing entire properties or just their names. I can continue development just fine. However, if I already put a value into the cache it will be stale forever.
What I am asking here is if it is possible to intercept the event that a class in the classpath has changed. Very broad... But my specific problem is very simple: since I have such a need only during development, I just want to wipe that cache in case any class in my classpath changes.
How can I accomplish this? I don't need to do anything special than intercepting the event and simply wiping the cache
JRebel has a plugin API that you can use to trigger code on class reloads. The tutorial complete with example application and plugin available here: https://manuals.zeroturnaround.com/jrebel/advanced/custom.html
The JRebel plugin is a self-contained jar built against the JRebel SDK, which is attached to the running application via the JVM argument -Drebel.plugins=/path/to/my-plugin.jar. The JRebel agent attached to the application will load and start plugins from this argument.
If the application is not started with the JRebel agent, the plugin is simply not loaded.
In your example you want to register a ClassEventListener that will clear the Cache.fieldsList map. As it is a private field, you need to access it via reflection or add a get/clear method via a ClassBytecodeProcessor
public class MyPlugin implements Plugin {
void preinit() {
ReloaderFactory.getInstance().addClassReloadListener(new ClassEventListenerAdapter(0) {
#Override
public void onClassEvent(int eventType, Class<?> klass) throws Exception {
Cache.clear();
}
});
}
// ... other methods ...
}
And to clear the map
public class CacheCBP extends JavassistClassBytecodeProcessor {
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) {
ctClass.addMethod(CtMethod.make("public static void clear() { fieldsList.clear(); }", ctClass));
}
}
However a better option is to only clear/recalculate the single class entry on class reload if possible. The example didn't display whether the info computed from one class depended on superclass infos, but if this is true, the JRebel SDK has methods to register a reload listener on the class hierarchy as well.
There is an existing class ClassValue which already does the job for you:
public class Cache {
private final ClassValue<String> backend = new ClassValue<String>() {
#Override
protected String computeValue(Class<?> entity) {
return createHql(entity);
}
};
public String getHqlFor(Class<?> entity){
return backend.get(entity);
}
}
When you call get, it will call computeValue if this is the first call for this specific Class argument or return the already existing value otherwise. It does already care thread safety and for allowing classes to get garbage collected. You don’t need to know when class unloading actually happens.

Starting Instrumentation Agent after VM Startup

I was hoping for someone to explain this item since I might be getting this wrong:
I was reading about Java Agent Instrumentation which says that the agent can start after VM startup. So if I want to dynamically replace some class (without brining down the app) is this what I am going to go for using agent-main? Or do I need to do something more here?
I know people might ask "Are you talking about JRebel" - not really because I want to do something simple and JRebel is an overkill.
instrument docs - Java docs for Instrumentation
I understand all the instrumentation overrides, but I am slightly confused how I can hook this agent with -agent argument after the app has started.
First your agent class needs to specify an agentmain method like:
public class MyAgent {
public static void agentmain(final String args, final Instrumentation inst) {
try {
System.out.println("Agent loaded.");
} catch (Exception e) {
// Catch and handle every exception as they would
// otherwise be ignored in an agentmain method
e.printStackTrace();
}
}
}
Compile it and pack it inside a jar-file for example. If you choose the jar-variant then it must specify the Agent-Class key in its manifest-file (MANIFEST.MF). It points to the class implementing the agentmain method. It could look like:
Manifest-Version: 1.0
Agent-Class: package1.package2.MyAgent
If it is located inside those packages, as an example.
After that you can load the agent via the VirtualMachine#loadAgent method (documentation). Note that the mechanism used by those classes are part of the Attach library of Java. They decided, as most users don't need it, to not directly add it to the systems path but you can just add it. It is located at
pathToYourJDKInstallation\jre\bin\attach.dll
And it needs to be somewhere where the system property java.library.path is pointing at. You could for example just copy it to your .../Windows/System32 folder or adjust the property or stuff like that.
As an example, if you want to inject an agent-jar inside another currently running jar, you could use a method like this:
public void injectJarIntoJar(final String processIdOfTargetJar,
final String pathToAgentJar, final String[] argumentsToPass) {
try {
final VirtualMachine vm = VirtualMachine.attach(processIdOfTargetJar);
vm.loadAgent(pathToAgentJar, argumentsToPass.toString());
vm.detach();
} catch (AttachNotSupportedException | AgentLoadException
| AgentInitializationException | IOException e) {
System.err.println("Unable to inject jar into target jar.");
}
}
With the same technique you can inject dll-libraries (if they implement the corresponding agent-methods via the native agent interface) into jars.
Actually, if that helps you, I have written some small library for that kind of stuff some time ago. See Mem-Eater-Bug, the corresponding class is Injector.java and the whole project has a small Wiki.
It has an example showing how to use that technique to manipulate a SpaceInvaders game written as Java application.
So apparently you want to reload classes at runtime. Such that your project can react to changes of the code without restarting.
To achieve this you need to prepare your project and write a very clean architecture, it involves using interfaces, factory-patterns, proxy-patterns and a routine that checks for updates and then destroys and rebuilds all current objects.
Unfortunately this might not be an easy task, but it is doable, depending on the size of your project and the amount of code that should react dynamically to changes.
I found this article helpful, let me explain how it works. You can easily load a class with ClassLoader.loadClass(...) and you can also use that to reload a class, very easy. However at the time you have compiled your code classes are some kind of hardwired already. So your old code will continue to create instances of the old classes although you have reloaded the class.
This is the reason why we need some kind of architecture that allows exchanging the old class with the new class. Also it is pretty obvious that current instances of the old class can not automatically be transferred to the new version as everything could have changed. So you will also need a custom method that collects and rebuilds those instances.
The approach described in the article uses an Interface instead of an actual class in the first place. This allows to easily exchange the class behind that interface without breaking the code that uses the interface.
Then you need a factory where you ask for instances of that Interface. The factory can now check if the underlying class-file has changed, if so it reloads it and obtains a reference to the new class version. It can now always create an instance of the interface which uses the up-to-date class.
The factory, by that, is also able to collect all created instances in order to exchange them later, if the code base has changed. But the factory should reference them using WeakReference (documentation), else you have a big memory leak because the Garbage Collector would not be able to delete instances because the factory holds references to them.
Okay, now we are able to always obtain up-to-date implementations of an Interface. But how can we easily exchange existing instances. The answer is by using a proxy-pattern (explanation).
It is simple, you have a proxy class which is the actual object you are working with. It has all the methods of the Interface and upon calling methods it simply forwards to the real class.
Your factory, as it has a list of all current instances using WeakReference, can now iterate the list of proxies and exchange their real class with a new up-to-date version of the object.
Existing proxies that are used all around your project will now automatically use the new real version as the proxy itself has not changed, only its internal reference to the real target has changed.
Now some sample code to give you a rough idea.
The interface for the objects you want to monitor:
public interface IExample {
void example();
}
The real class, which you want to rebuild:
public class RealExample implements IExample {
#Override
public void example() {
System.out.println("Hi there.");
}
}
The proxy class that you will actually use:
public class ProxyExample implements IExample {
private IExample mTarget;
public ProxyExample(final IExample target) {
this.mTarget = target;
}
#Override
public void example() {
// Forward to the real implementation
this.mRealExample.example();
}
public void exchangeTarget(final IExample target) {
this.mTarget = target;
}
}
The factory you will mainly use:
public class ExampleFactory {
private static final String CLASS_NAME_TO_MONITOR = "somePackage.RealExample";
private final List<WeakReference<ProxyExample>> mInstances;
private final URLClassLoader mClassLoader;
public ExampleFactory() {
mInstances = new LinkedList<>();
// Classloader that will always load the up-to-date version of the class to monitor
mClassLoader = new URLClassLoader(new URL[] {getClassPath()}) {
public Class loadClass(final String name) {
if (CLASS_NAME_TO_MONITOR.equals(name)) {
return findClass(name);
}
return super.loadClass(name);
}
};
}
private IExample createRealInstance() {
return (IExample) this.mClassLoader.loadClass(CLASS_NAME_TO_MONITOR).newInstance();
}
public IExample createInstance() {
// Create an up-to-date instance
final IExample instance = createRealInstance();
// Create a proxy around it
final ProxyExample proxy = new ProxyExample(instance);
// Add the proxy to the monitor
this.mInstances.add(proxy);
return proxy;
}
public void updateAllInstances() {
// Iterate the proxies and update their references
// Use a ListIterator to easily remove instances that have been cleared
final ListIterator<WeakReference<ProxyExample>> instanceIter =
this.mInstances.listIterator();
while (instanceIter.hasNext()) {
final WeakReference<ProxyExample> reference = instanceIter.next();
final ProxyExample proxy = reference.get();
// Remove the instance if it was already cleared,
// for example by the garbage collector
if (proxy == null) {
instanceIter.remove();
continue;
}
// Create an up-to-date instance for exchange
final IExample instance = createRealInstance();
// Update the target of the proxy instance
proxy.exchangeTarget(instance);
}
}
}
And finally how to use it:
public static void main(final String[] args) {
final ExampleFactory factory = new ExampleFactory();
// Get some instances using the factory
final IExample example1 = factory.createInstance();
final IExample example2 = factory.createInstance();
// Prints "Hi there."
example1.example();
// Update all instances
factory.updateAllInstances();
// Prints whatever the class now contains
example1.example();
}
Attaching an agent at runtime requires use of the attach API which is contained in the tools.jar until Java 8 and is contained in its own module starting from Java 9. The location of the tools.jar and the name of its classes is system-dependent (OS, version, vendor) and as of Java 9 it does not exist at all but must be resolved via its module.
If you are looking for an easy way to access this functionality, try out Byte Buddy which has a subproject byte-buddy-agent for this. Create a Java agent as you are used to it but add anAgent-Main entry where you would put your Pre-Main in the manifest. Also, name the entry method agentmain, not premain.
Using byte-buddy-agent, you can write a program:
class AgentLoader {
public static void main(String[] args) {
String processId = ...
File agentJar = ...
ByteBuddyAgent.attach(processId, agentJar);
}
}
and you are done.

libgdx (Ashley Framework ECS) - What is the proper way of talking system to another system?

System to System
Currently I'm developing CharacterSystem, GunSystem, BulletSystem using ashley framework. My problem is I dont know if this is the proper way of talking system to other system.
My CharacterSystem method onProcessEntity when the character attack is triggered I used getEngine().getSystem(GunSystem.class).trigger(true) and inside the GunSystem I have a method the Generate entity of a Bullet. While the BulletSystem handles the freeing of bodies, when outside the camera.
sub-question What is the proper way of creating Bullet class with ECS framework?
I use the Ashley ECS quite a lot for games and in a recent project (https://github.com/basimkhajwal/LSD) I ran into a similar situation. My method probably isn't standard and it may have issues which would occur in a different project setup but using an event queue has been a good solution for me.
In essence, you have an enum (in my case GameEvent) which handles all the different events needing to be passed around like PLAYER_DIED, LAUNCH_PLAYER and so on. I used Ashley's signals interface to create a simple queued store of events that a system can poll on each tick. As follows:
public class EventQueue implements Listener<GameEvent> {
private PriorityQueue<GameEvent> eventQueue;
public EventQueue() {
eventQueue = new PriorityQueue<GameEvent>();
}
public GameEvent[] getEvents() {
GameEvent[] events = eventQueue.toArray(new GameEvent[0]);
eventQueue.clear();
return events;
}
public GameEvent poll() {
return eventQueue.poll();
}
#Override
public void receive(Signal<GameEvent> signal, GameEvent event) {
eventQueue.add(event);
}
}
Next, in my GameWorld class, the one which loads the Ashley Engine and populates it with systems, I have a single Signal<GameEvent> which is the main backbone for my event queue. Here, like Listener<T>, Signal<T> is already part of Ashley.
Some systems then need to be able to fire into this signal / receive events from it so they take this Signal class in the constructor. The EntitySystem can then bind a listener or fire events which would then be passed on to other listeners. E.g. my LaserSystem class (simplified):
public class LaserSystem extends IteratingSystem implements Disposable, ContactListener {
...
private Signal<GameEvent> gameEventSignal;
private EventQueue eventQueue;
public LaserSystem(Signal<GameEvent> gameEventSignal) {
super(Family.all(LaserComponent.class).get(), Constants.SYSTEM_PRIORITIES.LASER);
this.gameEventSignal = gameEventSignal;
eventQueue = new EventQueue();
gameEventSignal.add(eventQueue);
}
...
#Override
public void beginContact(Contact contact) {
....
LaserComponent laserComponent = laserMapper.get(laser);
laserComponent.updateLaser = true;
if (other.getComponent(PlayerComponent.class) != null) {
gameEventSignal.dispatch(GameEvent.LASER_COLLISION);
}
}
}
Hopefully this makes sense, also feel free to read my project code for more example usage.
I never used Ashley as ECS but usually Systems should not communicate with each other.
Reason: When Systems would communicate they would not be independent of each other. Independent Systems allow you to freely add and remove them without having to worry the code breaks. The game logic probably breaks of course when a important Systems are missing.
Have a Factory (class) which does create the bullet entity. Then use the Factory in each System which can built new bullet entity.

Spring - Passing Listener via RMI

Basis
I have several projects, which implement a caching service - each its own, and each one is almost the same as the others. I have coompressed and shortened the existing cacheservices into a single project containing two different cache services - one for basic objects, and one for complex objects (which extends the basic service). I have created 2 projects - one to deploy as a .war-file and the API-project for this.
The entire application runs on a JBoss AS 7.1 "Thunder" with the latest JDK 7.
Problem
One class in particular requires to be notified whenever an old cache entry is deleted. For this, I implemented a notification procedure using CleanupListeners.
CleanupListener.java
public interface CleanupListener extends Remote {
public abstract boolean supports(Class<?> clazz) throws RemoteException;
public abstract void notify(Object removedObject) throws RemoteException;
}
necessary implementations in the cache service
public void registerCleanupListener(CleanupListener listener) {
listeners.add(listener);
}
private void fireCleanupEvent(Object removedObject) {
for (CleanupListener cleanupListener : listeners) {
try {
if (cleanupListener.supports(removedObject.getClass())) {
cleanupListener.notify(removedObject);
}
} catch (RemoteException re) {
LOGGER.error("Remote Listener not available", re);
}
}
}
The listeners are managed via a private final HashSet<CleanupListener>
The project which needs to be notified uses this implementation of the interface:
#Component
public class CleanupEventListener extends UnicastRemoteObject implements CleanupListener {
protected CleanupEventListener() throws RemoteException {
super();
}
#Resource
private ClassRequiresNotification notifyMe;
public boolean supports(Class<?> clazz) {
return SupportedObject.class.isAssignableFrom(clazz);
}
public void notify(Object removedObject) {
notifyMe.someMethod((SupportedObject) removedObject);
}
}
and a registration bean:
#Component
public class CleanupEventListenerRegistrator {
#Resource
private CleanupEventListener cleanupEventListener;
#Resource
private BasicCacheService cacheService;
#PostConstruct
public void init() {
cacheService.registerCleanupListener(cleanupEventListener);
}
}
The remote services are exported via SpringBean:
#Bean
public RmiServiceExporter basicCacheServiceExporter(BasicCacheService basicCacheService) {
RmiServiceExporter cacheService = new RmiServiceExporter();
cacheService.setService(basicCacheService);
cacheService.setServiceName(BASIC_CACHE_SERVICE_NAME);
cacheService.setServiceInterface(some.package.BasicCacheService.class);
return cacheService;
}
and registered via XML-Config:
<bean id="basicCacheService" class="org.springframework.remoting.rmi.RmiProxyFactoryBean">
<property name="lookupStubOnStartup" value="false"/>
<property name="serviceUrl" value="basicCacheService" />
<property name="serviceInterface" value="some.package.BasicCacheService" />
<property name="refreshStubOnConnectFailure" value="true"/>
</bean>
Exception
So, whenever I try to call the expected methods, I get one of two Exceptions:
Either I get a NoSuchObjectException (rare) or, much more common a ClassNotFoundException wrapped in an UnmarshalException
What I did
I already consulted the JavaDocs, googled massively and have sifted through several questions here, however to no avail. I found a bit of info that the standard property rmi.codebase is set to true, and this might require some rewriting of code, however we are already using RMI at another place in the projects, and it does work fine there. Adding a SecurityManager breaks the rest of our Application (due to external prerequisites) and calls the NoSuchObjectException.
Answers within StackOverflow so far have yielded "this is a problem with the codebase", "you need to install a securityManager", "the classes have to have the same name and be in the same package" and of course "it's the codebase". I am mentioning this one twice, since it does appear quite often yet not a single mention as to how to deal with a codebase problem accompanies it.
Additional Info
I am not sure if this is important, but here's some more info:
The cacheservice-project is configured in java code, the projects which use the service are configured in XML.
The Listener-Interface is not exported vie Annotations or XML-Beans, since several Posts (including at least one here) hinted that this will export the class, but keep listening only on server-side, which is not what I want.
I have also tried to make the CleanupListeneran abstract class, which in itselt extends UnicastRemoteObject but that did not work out either - in fact, it was worse than what I have now.
I am writing and testing the application in eclipse.
Assembling and publishing to server is done by gradle in the command line.
Question
Does anyone know what the problem here is, and how to actually solve it? It is getting quite aggravating when everything I do is either running into an exception or is "yeah that's a codebase error", since both do not help at all.
Any help would be appreciated.
Actual answer
Okay, this is simultaneously embarrassing and relieving. First of all...
The good news
The Listener-Interface as described above works. It is registered on the server-side, and when called, fires a notification to the client, which then may act accordingly. So, if you have been looking for an answer to the whole "passing a listener"-problem, there you have it.
The bad news
however is that I have been quite ignorant to certain facts. Among other things, what the term codebase actually covers. In my particular case, the problem was that the cacheservice itself had no dependencies on the other projects, which (custom) classes it should preserve. So technically, the codebase actually was the problem - due to lacking dependencies in the build.gradle.
I hope I dodn't waste anyone's time on this, if so, please accept my apologies, and hopefully, this question helps someone else sometime.

JIRA custom plugin develpment - creating custom field returns null

I'm currently developing a custom JIRA plugin and I'm having some trouble integrating my plugin to the JIRA project/issue management system. I have only been using the JIRA SDK for about 4 months now so I'm no expert.
Some notes:
I have a class called PluginListener which implements InitializingBean. In my class I'm overwriting the afterPropertiesSet method and I've placed my custom field code there.
In the same method, I'm also creating a custom issue type and I know that works because I can create issue with that issue type inside JIRA.
I've basically be following this guide here: http://www.j-tricks.com/tutorials/plugin-lifecycle-events
I'm using ATLAS Version: 4.2.18
Now, what currently happening with my code is that is appears the createCustomField method is returning null. When I run the atlas-debug command, I can see (in cmd) that there is null pointer exception thrown because of that method. The plugin is not installed because of that.
Here is my code:
public class PluginListener implements InitializingBean, DisposableBean {
private final IssueTypeManager issueTypeManager;
private final CustomFieldManager customFieldManager;
private final FieldScreenManager fieldScreenManager;
public PluginListener(IssueTypeManager issueTypeManager, CustomFieldManager customFieldManager, FieldScreenManager fieldScreenManager) {
this.issueTypeManager = issueTypeManager;
this.customFieldManager = customFieldManager;
this.fieldScreenManager = fieldScreenManager;
}
#Override
public void destroy() throws Exception {
// Handle plugin disabling or un-installation here
}
#Override
public void afterPropertiesSet() throws Exception {
// Handle plugin enabling or installation here
// Create issue type:
IssueType issueType = this.issueTypeManager.createIssueType("TheType", "TheDescription", "/images/icons/issuetypes/genericissue.png");
// Create custom field:
// Create a list of issue types for which the custom field needs to be available
List<GenericValue> issueTypes = new ArrayList<GenericValue>();
issueTypes.add(null);
// Create a list of project contexts for which the custom field needs to be available
List<JiraContextNode> contexts = new ArrayList<JiraContextNode>();
contexts.add(GlobalIssueContext.getInstance());
CustomFieldType fieldType = this.customFieldManager.getCustomFieldType("com.atlassian.jira.plugin.system.customfieldtypes:textfield");
CustomFieldSearcher fieldSearcher = this.customFieldManager.getCustomFieldSearcher("com.atlassian.jira.plugin.system.customfieldtypes:textsearcher");
// Add custom field
final CustomField cField = this.customFieldManager.createCustomField("FOO", "BAR", fieldType, fieldSearcher, contexts, issueTypes);
// Add field to default Screen
FieldScreen defaultScreen = fieldScreenManager.getFieldScreen(FieldScreen.DEFAULT_SCREEN_ID);
if (!defaultScreen.containsField(cField.getId())) {
FieldScreenTab firstTab = defaultScreen.getTab(0);
firstTab.addFieldScreenLayoutItem(cField.getId());
}
}
}
Running atlas-debug is effectively installing your plugin from a JIRA cold start; the likely issue is that JIRA plugins are installed (and their OSGi bundles activated) before JIRA is fully ready to operate and process certain types of requests.
To debug this, after your atlas-debug run fails, I would try manually navigating to Toolgear->Add-ons->Manage add-ons and try to re-upload your plugin .JAR again (find it in the target directory). If it works that time, it suggests that JIRA was simply not ready for your plugin at the time of initial system startup, so you will need to move the field creation step elsewhere.
You might try the onStart event. If that does not work for you, the most reliable method will probably be lazy initialization, so long as you can ensure that this step gets performed the first time your plugin is ever accessed by a user.

Categories