So i'm trying to get my Apache xmlrpc client/server implementation to play ball. Everything works fine except for one crucial issue:
my handler class (mapped through the properties file org.apache.xmlrpc.webserver.XmlRpcServlet.properties) reacts as it should but it's constructor is called at every method invocation. It would seem that the handler class is instantiated at each call which is bad because I have data stored in instance variables that I need to save between calls.
How do I save a reference to the instantiated handler so that I can access it's instance variables?
So, for anyone else who still wants to use XMLRPC here's how I fixed this issue:
http://xmlrpc.sourceforge.net/
far superior to apache xmlrpc, in my opinion.
This is standard behaviour of Apache XMLRPC 3.x. http://ws.apache.org/xmlrpc/handlerCreation.html:
By default, Apache XML-RPC creates a new object for processing each
request received at the server side.
However, you can emulate the behaviour of XMLRPC 2.x, where you registered handler objects instead of handler classes, using a RequestProcessorFactoryFactory. I have written a custom RequestProcessorFactoryFactory that you can use:
public class CustomHandler implements RequestProcessorFactoryFactory {
Map<Class<?>, RequestProcessorFactory> handlers =
Collections.synchronizedMap(
new HashMap<Class<?>, RequestProcessorFactory>());
#Override
public RequestProcessorFactory getRequestProcessorFactory(Class pClass)
throws XmlRpcException {
return handlers.get(pClass);
}
public void addHandler(final Object handler) {
handlers.put(handler.getClass(), new RequestProcessorFactory() {
#Override
public Object getRequestProcessor(XmlRpcRequest pRequest)
throws XmlRpcException {
return handler;
}
});
}
}
This can then be used with e.g. a XMLRPC WebServer like this
WebServer server = ...
PropertyHandlerMapping phm = new PropertyHandlerMapping();
server.getXmlRpcServer().setHandlerMapping(phm);
Custom sh = new CustomHandler();
phm.setRequestProcessorFactoryFactory(sh);
Object handler = ... /** The object you want to expose via XMLRPC */
sh.addHandler(handler);
phm.addHandler(serverName, handler.getClass());
Maybe something to do with javax.xml.rpc.session.maintain set to true?
I know this is a really old post but I managed to solve the problem with Apache's Java XML-RPC.
First, I thought this could be solved with singleton class in Java but it doesn't work and throws "illegal access exception".
These are what I have done:
public class XmlRpcServer {
private static JFrame frame = new JFrame();
private static JPanel pane = new JPanel();
public static XmlRpcServer singleton_inst = new XmlRpcServer();
public XmlRpcServer() {
// I kept the constructor empty.
}
public static void main(String[] args) throws XmlRpcException, IOException {
// In my case, I put the constructor code here.
// Then stuff for XML-RPC server
// Server Part
WebServer ws = new WebServer(8741);
PropertyHandlerMapping mapping = new PropertyHandlerMapping();
mapping.addHandler("SERVER", singleton_inst.getClass());
ws.getXmlRpcServer().setHandlerMapping(mapping);
ws.start();
////
}
// I called doTheJob() from python via XML-RPC
public String doTheJob(String s) throws XmlRpcException {
loop();
return s;
}
// It executed loop() forever
private static void loop() throws XmlRpcException {
// Actual work is here
}
But metaspace increases gradually:
I worked too much on this metaspace issue when looping forever in Java but I couldn't figure out a solution.
Related
I decided to split the last part of that question here into a new question here: https://softwareengineering.stackexchange.com/questions/411738/extension-of-classes-where-to-put-behaviour-how-much-direct-access-is-allowe
If i have a lib and i want to use it, i wrote mostly a own class. This class has one method. In that there is the code how to instantiate the lib/framework. Sometimes there are a few more methods, with them i not only instantiate the class but use it. For example if i want to start a http-server i have there a start-method.
class Container
{
TheLib theLib;
public void init() //or a constructor
{
//some init of the theLib
}
public void start() //
{
theLib.doSomething(...)
theLib.doSomethingmore(...);
theLib.start(...);
}
//important!
public TheLib getTheLib()
{
return this.theLib; //after i started configured it and so on, i want of course use all methods,
which the lib have in some other parts in my application
}
}
But it seems not to be the best solution.
Are there any better solutions, that OO is?
Often i also use only one method, a own class for this seems to be here a big overhead?
Exposing the lib breaks encapsulation? Tell-Dont-Ask is also violated?
Everything depend on what you actually need or how you have access to your 'the lib' instance.
public class Container {
private TheLib theLib;
/* #1: Do you already created the instance before? */
public Container(TheLib theLib) {
this.theLib = theLib;
}
/* #2: Do you need to created the instance each time? */
public Container() {
this.theLib = new TheLib();
}
public void start() {
theLib.doSomething(...)
theLib.doSomethingmore(...);
theLib.start(...);
}
public TheLib getTheLib() {
return this.theLib;
}
public static void main(String[] args) {
/* #1 */
TheLib theLib = ...;
Container container = new Container(theLib);
/* #2 */
Container container = new Container();
/* Continue the flow of your program */
container.start();
container.getTheLib().doSomethingEvenMore();
}
}
Or maybe you actually need only one instance of your 'Container' class. In this case, you should look on how to make a singleton: Java Singleton and Synchronization
Anwser: Often i also use only one method, a own class for this seems to be here a big overhead?
Well, in Java, you cannot do formal programming like in C, so everything line of code that you write, or will be using, has to be in a class of some sort.
If your piece of code is small and don't really need an object, static function might do the work.
I have a MATLAB script running on a Java Eclipse project via the matlabcontrol.jar package.
I have the following set-up
MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
.setUsePreviouslyControlledSession(true)
.setHidden(true)
.setMatlabLocation(null).build();
MatlabProxyFactory factory = new MatlabProxyFactory(options);
MatlabProxy proxy = factory.getProxy();
//some code invoking the proxy.eval() method
The problem is that I have the MATLAB script running several times over the course of the runtime of the simulation. How can I make it so that Java doesn't have to reconnect with MATLAB every single time I want to use the MATLAB function?
Any help would be appreciated.
Thanks!
I'm not expert on JAVA, so I will give my solution in simple words that you can translate to JAVA world. :)
Create a JAVA singleton class which is responsible for handling connections.
Provide a public static read-only property pointing to singleton object.
Now use singleton object to call MATLAB functions.
E.g.:
public class MATLABConnector
{
private MATLABConnector con=new MATLABConnector();
MatlabProxyFactoryOptions options = new MatlabProxyFactoryOptions.Builder()
.setUsePreviouslyControlledSession(true)
.setHidden(true)
.setMatlabLocation(null).build();
MatlabProxyFactory factory = new MatlabProxyFactory(options);
private MATLABConnector()
{
// Do basic initializations.
}
private boolean checkConnecionStatus();
private boolean establishConnection();
public static MATLABProxy getProxy()
{
if(!con.checkConnectionStatus())
con.establishConnection();
return con.factory.getProxy();
}
}
I have a java class:
public class httpd implements Runnable
{
public void createHttpdStatistics
{
httpdStatistics stats = new httpdStastics(this);
}
}
Now I would get in another class the object stats created inside httpd. When httpd object starts, it execute in the jvm. I tought to build get method inside httpd class but when I'm in the other class how I get the exact httpd object to call get method to retrieve stats object?
EDIT
public class httpd implements Runnable
{
public static void main(String[] args)
{
httpd server = new httpd();
OtherClass oc = new OtherClass(server);
}
{
MY OWN MAIN
public class myownmain
{
public static void main(String[] args)
{
//Here I need OtherClass object created in httpd class
}
}
What's the problem in passing the passing the stats object to the other class you need inside a CTOR, by providing a getter to the stats object in class httpd -
this is only of course if the createHttpdStatistics method is not executed in the code of the run method (I suggest your pvovide it).
If the createHttpdStatistics method is executed within the run method (in a different thread) you should consider having a shared data structure between the threads (for example - shared Singletone that can be used as a shared data structure), if you want to create the HttpdStatistics object within a thread.
In this case the code will look like:
public class httpd implements Runnable
{
public void createHttpdStatistics()
{
httpdStatistics stats = new httpdStastics(this);
StatsManager.getInstance().putStats(stats);
}
public void run() {
//I assume the creation is done at the run method. Maybe I'm wrong here.
createHttpdStatistics();
}
}
And then use this somewhere in your code -
HttpdStatistics stats = StatsManager.getInstance().getStats();
MyClass stats = new MyClass(stats); //passing stats to another object.
You should of course make sure that getStats either blocks under the stats object is set to the singletone, or to check if getStats() returns null.
Given the code posted here:
In your other class, say OtherClass for example, you should have setter for httpd object or provide the httpd instance in the OtherClass constructor. This way OtherClass will have a reference to httpd
public class OtherClass{
httpd httpd_ = null;
public OtherClass(httpd httpd_){
this.httpd_ = httpd_;
}
// Access and use stats from httpd
public void useStats(){
httpdStatistics stats = httpd_.getStatistics()
if(stats != null){
// Do something here
}else{
// stats not set yet, the thread did probably not start yet
}
}
}
In your application's main you can have the following:
httpd h = new httpd();
OtherClass otherClass = new OtherClass(h);
EDIT As mentioned in one of the comments, the stats variable is shared among two threads so you will have to synchronize on it and make sure it is updated in a exclusive way.
I've been looking around and I only found one answer which wasn't clear enough, to me at least.
I am building a very basic chat application with a GUI and I have separated the GUI from the connection stuff. Now I need to call one method from GUI in server class and vice versa. But I don't quite understand how to do it (even with "this"). Here's what a part of code looks like (this is a class named server_frame):
textField.addActionListener(
new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
try {
srv.sendData(arg0.getActionCommand());
} catch (Exception e) {
e.printStackTrace();
}
textField.setText("");
}
}
);
This is a code from server_frame, srv is an object from the other class (server) which contains sendData method, and I probably didn't define it correctly so hopefully someone could make a definition of it.
On the other side class server from which object srv was made contains method using JTextArea displayArea from server_frame in this code:
private void displayMessage(final String message){
sf = new server_frame();
SwingUtilities.invokeLater(new Runnable(){
public void run(){
sf.displayArea.append(message);
}
}
);
}
Yet again sf is an object made of server_frame and yet again probably missdefined :)
Hopefully that was clear enough, sadly I tried the searching but it just didn't give me the results I was looking for, if you need any more info I will gladly add it!
Thanks for reading,
Mr.P.
P.S. Please don't mind if I made terminology mishaps, I am still quite new to java and open to any corrections!
Some class must be building both of these objects--the GUI and the server--and it should make each aware of the other. For example, say the main class is ServerApplication. I'll use standard Java convention of starting class names with an uppercase letter for clarity.
class ServerApplication {
Server server;
ServerFrame gui;
public static void main(String []) {
server = new Server(...);
gui = new ServerFrame(server);
server.setGui(gui);
}
}
Each class should store the reference to the other as well.
class Server {
ServerFrame gui;
public void setGui(ServerFrame gui) {
this.gui = gui;
}
...
}
class ServerFrame extends JFrame {
Server server;
public ServerFrame(Server server) {
this.server = server;
}
...
}
I think you may be looking for the ClassName.this.methodName syntax. this in those actionlisteners refer to the anonymous class you created. If you used the above syntax you would be referencing the class that contains the anonymous class.
Or if you are looking for a private field in the class, you would do ClassName.this.privateField
I'm trying to return a normal class via a RMI call. My server holds a instance of a class called GameState that i want to perform actions on via it's methods, from a client application. So the RMI works fine if a just return a int or something, but when a try to return GameState, which is a class defined inside the GameServer java file, the following error occurs (game state is declared neither public, protected or private):
Exception in thread "main" java.lang.IllegalAccessError: tried to access class GameState from class $Proxy0
at $Proxy0.getGameState(Unknown Source)
at GameClient.login(GameClient.java:204)
at GameClient.main(GameClient.java:168)
So, i guess the client application knows how GameState looks, but dont have any access to it?
I have tried to make GameState a public class in it's own file, but then the different connecting client applications get each their own GameState, so it's seems like that dont get it from the server.
Here are some code that i think is relevant:
The remote interface:
import java.rmi.*;
public interface ServerInterface extends Remote
{
public GameState getGameState() throws RemoteException;
}
Some if the server code:
public class GameServer extends UnicastRemoteObject implements ServerInterface {
/**
*
*/
private static final long serialVersionUID = -6633456258968168102L;
private final static int DEFAULT_NAMING_PORT = 9955; // TODO: IMPORTANT - change this to a group-specific number,
// e.g., 2000 + group number. The number should be the same
// as in GameClient.java.
private final GameState m_state;
public static void main(String[] args) {
//the variables: port and host etc it configurated here, but has nothing to do with the RMI problem.
try {
GameServer instance = new GameServer(players);
System.out.print("Setting up registry on "+host+":"+port+" ... ");
//Set up an unrestricted security manager.
if (System.getSecurityManager() == null) {
// Set security manager to an instance of a dynamically created
// subclass of RMISecurityManager with the checkPermission() method overloaded
System.setSecurityManager(
new RMISecurityManager() {
#Override
public void checkPermission(Permission permission) {
}
}
);
}
// Create a registry for binding names (name server)
Registry naming = LocateRegistry.createRegistry(port);
System.out.println("done.");
String rmiObjectName = "GeschenktServer";
System.out.print("Binding name "+rmiObjectName+" ... ");
naming.rebind(rmiObjectName, instance);
System.out.println("done.");
} catch(RemoteException e) {
System.err.println("Could not start server: "+e);
System.exit(-1);
}
}
//the rest of the server code....
//the GameState declared in the same file
class GameState implements java.io.Serializable {
private static final long serialVersionUID = 545671487061859760L;
//the rest of the Game state code.
Here is some of the client code:
private void login() {
try {
System.out.println("Connecting to server on host "+m_host+".");
// Set up an unrestricted security manager. In the server we trust.
// See GameServer.java for code explanation.
if (System.getSecurityManager() == null) {
System.setSecurityManager(
new RMISecurityManager() {
#Override
public void checkPermission(Permission permission) {
}
}
);
}
System.out.print("Locating registry on "+m_host+":"+m_port+" ... ");
Registry naming = LocateRegistry.getRegistry(m_host, m_port);
System.out.println("done.");
String name = "GeschenktServer";
System.out.print("Looking up name "+name+" ... ");
m_server = (ServerInterface) naming.lookup(name);
System.out.println("done.");
// TODO: Connect the player, i.e., register the player with the server.
// Make sure that the player cannot register if there are already enough players.
m_Id = m_server.getGameState().loginPlayer(m_name); //this line is causing the error...
if(m_Id < 0)
System.exit(0);
System.out.println("Server connection successful.");
m_window = new GameWindow(m_server, m_name, m_Id);
m_window.run();
} catch (Exception e) {
System.out.println("Connection failed - "+e);
System.exit(1);
}
}
}
I am using eclipse to do all this, and based on what i have red about RMI in eclipse, rmic and that stuff is not needed anymore, i'm i right?
So anyone with any idea?
Thanks in advance!
I don't think this is a permission problem. I cannot tell for sure from the code above, but I would assume it is a codebase problem. Did you configure the codebase also on client-side?
To deserialize the GameState class, the client needs to be able to load the class definition. This definition is located in the Server implementation and not the interface. Normally, the Server implementation should not be compiled to the client's classpath, only the interface should. I am not entirely sure, as in your solution the interface seems to have a dependency on the implementation due to the GameState which is not a good idea btw. Anyways, try adding a codebase configuration to your VM-args. Assuming you execute everything on localhost, it should look like this:
-Djava.rmi.server.codebase=file:${workspace_loc}/PROJECT-NAME/bin/
Where ${workspace_loc} is the absolute path to your workspace and PROJECT-NAME is the name of the server project. Eclipse will resolve ${workspace_loc} automatically, so you only need to set your PROJECT-NAME
As a side note: If you implement it that way, the GameState object is transmitted to the client-side and is executed on the client, having no effect whatsoever on the execution of the server. Is this really what you want? If you want the GameState instance to execute on the server-side, GameState also needs to implement Remote, not Serializable, and you need to export it when transmitting its stub to the client.
Finally, as you correctly stated, you do not need to use rmic since Java 1.5
try to return GameState, which is a class defined inside the
GameServer java file, the following error occurs (game state is
declared neither public, protected or private)
This is the problem. Only the GameServer class and classes in the same package can create instances of GameState. Your RMI proxy object (stub) Make it a public class in its own file.
I have tried to make GameState a public class in it's own file, but
then the different connecting client applications get each their own
GameState, so it's seems like that dont get it from the server
That's correct. It is serialized to each client. If you want to share a single GameState and have it remain at the server, it has to be an exported remote object itself, with a remote interface called GameState.
The IllegalAccessError reason is simple: GameState is NOT public
However, there is a larger issue:
you do understand that loginPlayer will not do what you like it to... The GameState is a copy of the original state. You want GameState to be Remote not serializable, so you can execute the operation on the server, not each client to get a useless copy of.