How would I go about this? Different projects communicating? C# - java

Okay, I'm not sure how to go about explaining this, nor how to do it, but I will try to explain what I want step-by-step.
I want to make an API that contains, for example an EntitySpawnEvent object. It might look something like this:
namespace ExampleAPI
{
class EntitySpawnEvent
{
private bool cancelled;
private Entity entity;
public EntitySpawnEvent(Entity entity)
{
this.entity = entity;
this.cancelled = false;
}
public void SetCancelled(bool cancelled)
{
this.cancelled = cancelled;
}
public bool IsCancelled()
{
return this.cancelled;
}
}
}
Then I have I will have a server that uses this API. This server will also load plugins that also uses the API. The server might be something like this:
using System.Generics;
using ExampleAPI;
namespace ExampleServer
{
class Server
{
private List<Plugin> plugins;
public OnEnable()
{
LoadPlugins();
}
private void LoadPlugins()
{
// Loop through all "plugins" in the "/plugins" folder.
// Add them all to the list of plugins.
}
}
}
Then later when the server wants to spawn an entity, it throws the event to all plugins, the plugins can manipulate the event's information. For example, whether or not to cancel the event. The plugin's event listener could look something like this:
using ExampleAPI;
namespace ExamplePlugin
{
class Plugin : EventListener
{
public void onEntitySpawn(EntitySpawnEvent event)
{
event.SetCancelled(true);
}
}
}
And the server would throw it something like this:
using ExampleAPI;
namespace ExampleServer
{
class ExampleEventThrower
{
private Server server;
public ExampleEventThrower(Server server)
{
this.server = server;
SpawnEntity();
}
void SpawnEntity()
{
EntitySpawnEvent event = new EntitySpawnEvent(new Entity()); // Entity would also be part of the API
foreach (Plugin plugin in server.GetPlugins())
{
plugin.onEntitySpawn(event); // Here the plugin could manipulate the values of the EntitySpawnEvent
}
if (!event.IsCancelled())
{
// Spawn entity
}
}
}
}
Of course these are just extremely basic code examples, but they should help explain what I want.
Basically, what I want to know and do is the following:
I have an exported Server.
The Server have a /plugins folder
The user can make their own plugins using the API, export them and put them in the /plugins folder
The Server would load the plugin and let it modify all the events and such.
My key question is, how should the plugins be exported and loaded, so they can manipulate the events and such? Do I export them as DDLs? I have no idea.
I guess it's sort of similar to the way Bukkit works, but there everything's in Java and you just export it is a .jar file.
Any help would be greatly appreciated. Thanks!

So few things to take a look at...
It sounds like you want to have plugins run off of an interface that you know about, and load the plugins at runtime.
This should help you build the DLLs:
http://msdn.microsoft.com/en-us/library/3707x96z.aspx
This should help load the DLL dynamically at runtime:
Can I load a .NET assembly at runtime and instantiate a type knowing only the name?

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.

What are the ways to manage Android resource ids without using R.java?

I am new to Android . . .Till now i was thinking that all the resource's ids are in android app are managed and mapped using R.java file. But i got an application in market to work on,in which i did not found R.java/R.class file in it, after decompiling it using dex2jar utility
my issue is that till now my work was dependant on R.java/ R.class file , I was accessing all ids in an app using this file and reflection concept. But since this app does not contain R.class file my work is stuckked for now.
Interesting thing for me is that, when i create dex file from this jar and replace it in app and sign app using one_click_signer ,the app works fine on mobile.
So ,
i want to know how they could have managed ids without R.java?
Is it possible to have an application without R.java, or i may have
made mistake while decompiling app?
how can i find ids in the application?
They used R but it was optimized away.
Let's say the app had this code:
public class R {
public static class id {
public static final int something = 123456;
}
}
public class Main {
public void doSomething() {
doSomethingWith(R.id.something);
}
}
When compiling Java, the compiler "inlines" static final fields - replacing the field access with the value, since the compiler already knows the value. That means the compiler translates the code to this:
public class R {
public static class id {
public static final int something = 123456;
}
}
public class Main {
public void doSomething() {
doSomethingWith(123456);
}
}
If the application is optimized/obfuscated with Proguard - which is common with Android applications - then Proguard would then detect that the class "R" is not used and delete it, resulting in this:
public class Main {
public void doSomething() {
doSomethingWith(123456);
}
}

How can I exclude annotated definition from build in java?

I am building an Android app. Now, I have a source code for API #1, I should get it adapted for API #2. Then I will publish the both versions for API #1 and API #2 in different packages. I can't use something like values-en, because both versions can be used worldwide. Also, the user may not have choice.
As the new version will use same UI and DB logic, (and because now the code is erroneous,) I don't want to separate the code. If i were coding in c or c++, I must use #ifdef and Makefile. However, I'm in Java. It's possible to run the API-dependent code by determining the package name in runtime, but it's somewhat weird.
I think I can use annotations. What I expect is:
package foo.app;
public class API {
public boolean prepare() { ... }
#TargetPlatform(1)
public void open() { ... }
#TargetPlatform(2)
public void open() { ... }
}
and use only one of them. Also, this is good:
package foo.app;
public class R {
#TargetPlatform(1) com.example.foo.app.R R;
#TargetPlatform(2) net.example.foo.app.R R;
}
Just defining an annotation is simple. What I don't know is, how can I exclude unused duplicates from build or execution, or so on? If the work can be done in this way, I can do anything.
You cannot use annotations for that.
It would be better to hide the implementation specific classes behind an interface.
public interface Api {
boolean prepare();
void open();
}
To create a Api instance use a factory class:
public class ApiFactory {
public static Api createApi() {
if(isTargetPlatform1())
return new com.example.foo.app.Api();
else
return new net.example.foo.app.Api();
}
private boolean isTargetPlatform1() {
// determine the current platform, e.g. by reading a configuration file
}
}
In all other places you only refer to the Api interface and ApiFactory class.
Use it like that:
Api api = ApiFactory.createApi();
api.open();
// ...
A more advanced solution would be to use dependency injection.

Is it possible to make web app proactive rather than reactive?

Web applications traditionally follow the request/response cycle, where a request is made by a user or another web app. However, I'm curious if it is possible to make a web app automatically initiate certain tasks upon it's deployment to a app server. For example, let's say we have a web app that retrieves and processes data. Is it possible to configure this app to automatically retrieve and process data when certain criteria are met, rather than needing a request from a user/another web app?
Yes it is using task schedulers like cron for example. Although one might argue, that such tasks no longer are a web application, but local applications unning on the server instead.
Have a look at Quartz Scheduler
If the data in your example are in files, then you can use a FileWatcher to monitor the folder and initiate some action when a new file lands there.
Here is one example of a very simple one, just to give you an idea of how it works:
package pilrcedit;
import java.io.*;
import java.util.*;
public class FileWatcher implements ChangeListener
{
private static final int FILE_MODIFIED=MODIFIED;
Hashtable files=new Hashtable();
ChangeListeners listeners=new ChangeListeners();
public FileWatcher()
{
Preferences.addChangeListener(this);
}
public void objectChanged(Object source,int id,Object data)
{
checkFiles();
}
private void checkFiles()
{
for(Enumeration e=files.keys();e.hasMoreElements();)
{
File f=(File)e.nextElement();
if (f.lastModified()!=((Long)files.get(f)).longValue())
{
files.put(f,new Long(f.lastModified()));
notifyListeners(f);
}
}
}
public void addFile(File f,ChangeListener listener)
{
files.put(f,new Long(f.lastModified()));
listeners.add(f,listener);
}
public void removeFile(File f,ChangeListener listener)
{
listeners.remove(f,listener);
}
public void notifyListeners(File f)
{
listeners.fireObjectChanged(f,this,FILE_MODIFIED,f);
}
}
You can include that in the deploy process itself. Or include that initial request to the webpage in the deploy process.
Since you mentioned you want to do certain things during the deployment I think you can use spring here to perform certain tasks or load something in memory (cache) during deployment. For example in the application context xml you can have this:-
<bean id="someCache" class="com.my.company.MyCache"
init-method="load">
<!-- <property> as needed -->
</bean>
MyCache class could be something like below:-
class MyCache{
public void load() {
//do your deployment work
}
}

Categories