I am trying to define a static method in the service interface to make an rpc call. But it doesn't allow me to do so. here I am pasting my code
Client class
public void sendDomesticData(String product,String dma,String yrmnths,String dist,String metrics) {
String url = GWT.getModuleBaseURL() + "domesticservice";
domesticServiceAsync = (DomesticServiceAsync) GWT.create(DomesticService.class);
ServiceDefTarget endpoint = (ServiceDefTarget) domesticServiceAsync;
endpoint.setServiceEntryPoint(url);
domesticServiceAsync.sendDomesticData(product,dma,yrmnths,dist,metrics,new Domestichandler<Void>() );
}
public class Domestichandler<Void> implements AsyncCallback<Void> {
#Override
public void onFailure(Throwable caught) {
String error = caught.getMessage();
System.out.println(error);
}
public void onSuccess(Void result) {
System.out.println("perfect");
}
}
Service
public interface DomesticService extends RemoteService {
public void sendDomesticData(String product,String dma,String yrmnths,String dist,String metrics);
}
public interface DomesticServiceAsync {
void sendDomesticData(String product,String dma,String yrmnths,String dist,String metrics,AsyncCallback<Void> callback);
}
Server side -
public void sendDomesticData(String product, String dma, String yrmnths, String dist, String metrics) {
System.out.println(product);
}
Basically I am trying to send the values from the front interface to the server side and I don't want any return value. But the values passed to the server side should be stored globally in the server class so i can access those values in different method. I tried changing all the senddomestic values to static but it won't allow me to do so? why?
Because RemoteServiceServlet needs to invoke your service methods somehow and the implementation expects instance methods. But this shouldn't prevent you from assigning the method data to static fields. Just be aware of multi threading.
GWT always uses instance methods for RPC calls, static methods are not possible in this case.
What is important to understand about GWT is that any RemoteServiceServlet instances are created and maintained by the servlet container (e.g. Tomcat). The servlet container might create a number of servlet instances on startup (Tomcat creates 6 RemoteServiceServlet instances by default) and then uses load balancing to determine which servlet handles an RPC request at a particular point in time. Depending on settings of course, you have little control over which RemoteServiceServlet instance exactly will handle a specific RPC request.
Therefore, if you want to store information on the server side globally using RPC calls, the idea proposed by YuPPie to use static fields of your RemoteServiceServlet implementation is a BAD idea. You will have no idea which of the RemoteServiceServlet instances maintained by the server contains your static data, and any subsequent calls to retrieve the data will give erratic results.
You have a few options, though. Storing the information in a database (or something similar) is the most straightforward option, but from your post I'm guessing you want something simpler. A singleton class which holds your data is probably the way to go. A thread-safe example:
public class DataContainer
{
private static DataContainer _singleton;
private String _dataField1;
public static synchronized DataContainer getInstance()
{
if (_singleton == null)
_singleton = new DataContainer();
return _singleton;
}
public synchronized String getDataField1()
{
return _dataField1;
}
public synchronized void setDataField1(String dataField1)
{
_dataField1 = dataField1;
}
}
Then in the server side implementation of your RPC call you could do something like:
public void sendDomesticData(String product, String dma, String yrmnths, String dist, String metrics)
{
DataContainer.getInstance().setDataField1(product);
}
This way, if there are multiple servlet instances they will all share the singleton instance of DataContainer, thus giving you a place to store your data globally. I hope this will help you.
Related
I have created a CN1 web service which some custom objects that I want to externalize in order to send over the network. I read through several articles on how to create the web service and how to work with the CN1 Externalizable interface.
This works well for web service methods that return a custom externalizable object, however the only indicator that I have is that a method which takes an externalizable object as an argument, I get the following error:
SCHWERWIEGEND: Servlet.service() for servlet [CN1WebServiceServlet]
in context with path [/<myPath>] threw exception
java.io.IOException: Object type not supported: Post
The object is properly registered with the Util class, as changing either the object ID or commenting out the register call will cause a null pointer instead of the IO exception.
The Post class looks like this (simplified to the minimum which already fails):
public class Post implements Externalizable {
public int postid;
public int userid;
// default constructor needed for web service marshalling
public Post() {
}
#Override
public int getVersion() {
return 1;
}
#Override
public void externalize(DataOutputStream out) throws IOException {
Util.writeUTF("" + postid, out);
Util.writeUTF("" + userid, out);
}
#Override
public void internalize(int version, DataInputStream in) throws IOException {
this.postid = Integer.parseInt(Util.readUTF(in));
this.userid = Integer.parseInt(Util.readUTF(in));
}
#Override
public String getObjectId() {
return "Post";
}
Note that this Post object works well when I call a web service method which returns a post object, but not when I send a Post object to the web service:
// works
public static com.codename1.io.Externalizable getPostDetails(int postid) {
return getPostDetails(postid);
}
// fails
public static void sendPost(com.codename1.io.Externalizable post) {
sendPost(post);
}
I am at a loss of what I missed here.
Thanks and best regards
In your Servlet code call Util.register("Post", Post.class); which should hopefully resolve this.
Thanks a lot Shai! My mistake was to assume that registering the externalizable object on one side only. But of course it needs to be registered wherever it is going to be internalized, so in this case on my server.
Solution:
Within the "CN1WebServiceServlet" (not the ProxyServer class where the rest of the code has to be completed), call Util.register("Post", Post.class);
if(methodName.equals("sendPost")) {
Util.register("Post", Post.class); // this is a my insertedline, rest is generated
Object[] args = ProxyServerHelper.readMethodArguments(di, def_sendPost);
WebServiceProxyServer.sendPost((com.codename1.io.Externalizable)args[0]);
ProxyServerHelper.writeResponse(response, def_sendPost);
return;
}
I wanted to make a little "log" on what the user is doing. I have different panels and all of these have Ajax functions such as "onclick", "onevent" and "onchange". What I planned was to define an Application wide ArrayList of Strings to log all the things.
I wrote following into WicketApplication.java
public class WicketApplication extends WebApplication {
private List<String> log = new ArrayList<String>();
#Override
public Class<? extends WebPage> getHomePage() {
//code
}
#Override
public void init() {
//code
}
public List<String> getLog() {
return log;
}
public void setLog(List<String> log) {
this.log = log;
}}
Then in one of my panels:
public class Foo extends Panel{
private static final long serialVersionUID = 1L;
private WicketApplication wapp = (WicketApplication) Application.get();
public Foo(String id){
super(id);
}
public void bar(){
List<String> protocol = wapp.getLog();
protocol.add(foo.getBarName() + " has been added to " + selectedKontakt.getObject().getName());
wapp.setLog(protocol);
}
}
In a next panel I tried to create a new reference to WicketApplication. But it seems not to be the same.
Now I have these questions:
Isn't WicketApplication unique and therefore usable for this kind of manipulation?
Do I have to take a session for this?
Can I even parse Applcation to WebApplication? Because I have this error in the console
wapp <----- field that is causing the problem
Is there any other way to create an Application wide variable?
I think you are doing it wrong (on multiple levels).
Firstly: if you want to log, use a Logging framework. E.g. LogBack, preferably accessed through SLF4J
Secondly: if you don't want to use a log framework, create a log service (a dedicated object, not the Wicket Application), use Dependency Injection to inject the log service into all components where you need it. Wicket Supports both Spring and Guice
Third: Static access to the WebApplication as suggested by the accepted answer sounds like a very bad idea (but it is apparently suggested by Wicket, to be fair).
Normal way of use is (static) method. Its typical, don't be afraid.
MyApllication m = MyApllication.get();
So is genrally easy in every wicket object.
Usually "statically overrided" to return correct type, (and can give additional control).
public static MyApllication getMyApplication() {
return (MyApllication) get();
}
or
public static MyApllication get() {
return (MyApllication ) WebApplication.get();
}
When this static method returns correct type, Your problem is resolved.
Analyse how is build AuthenticatedWebApplication over WebApplication (or WebApplication over Application) , its from Wicket team and seems be canonical
BTW I You will have idea access / execute actions dependent on user / session similar idea exist : WebSession override in MySession
Look at the following use case.
I have a client (Java) application, which wants to get/set the state of another, remote application (C). The communication between them is done via SIP, which is run in another thread.
The SIP interface can do the following:
sendMessage
onRequest
I have two ideas for the architecture:
RPC (JSON-RPC)
Define a class which does the marshalling/unmarshalling for JSONRPCRequests and JSONRPCResponse (http://software.dzhuvinov.com/json-rpc-2.0-base.html)
Define a Invoker class, which has something like a call(server, name, arguments) method.
In the Invoker class, the name and arguments are put into a JSONRPCRequest and sent via the SIP layer sendMessage
Now comes my problem. How do i actually get the right back to the caller? The control flow is now:
The onRequest method is called, but I do now know whether it is the answer to my previous call. What i do is putting all responses reaching my server into a Map, and just poll that list in the Invoker.
A rough sketch might be;
Invoker (provides API to client)
class Invoker {
private Channel channel;
public Invoker(Channel channel) { this.channel = channel; }
public Object call(String server, String name, Object .. args) {
JSONRPCRequest req = ...;
channel.sendMessage(server, req.toString());
while( ! channel.hasResponse(req.id()) {
Thread.sleep(42);
}
return channel.getResponse(req.id()).result();
}
}
Channel (interface to messenger):
class Channel {
private Map<Object, JSONRPCResponse> responses = new //;
private Sip sip = new Sip() {
public void onRequest(String msg) {
JSONRPCResponse response = JSONRPCResponse.parse(msg);
responses.put(msg.id(), response);
}
};
public void sendMessage(String server, String message) {
sip.sendMessage();
}
public boolean hasResponse onRequest(Object id) {
responses.hasKey(id);
}
public JSONRPCResponse getResponse(Object id) {
responses.get(id);
responses.delete(id);
}
}
SIP (messenger itself):
abstract class Sip {
public void sendMessage(String msg) {
// SIP magic
}
public abstract void onRequest(String msg);
}
Is there a better way to do that? My biggest problems/code smells are:
the blocking in Invoker
the protocol is in Invoker, maybe I want to switch marshalling to something else
the map as mean to get the correct response for a request
the SIP abstract method looks strange
No error handling
No timeout
Message Passing
Is there an easy way to get rid of RPC, and implement something like RPC with just message passing? Any hints for pattern are welcome. I do not need the code itself, I am totally fine with just architecture. I tried to google for message passing implementations, and how they actually change state with it, but I did not find anything useful. How to implement timeout/ error handling?
Any good books/literature on that topic is also welcome, as I never programmed such distributed stuff.
Any other ideas on which protocol to use inside SIP to change state is welcome, too, as RPC was my initial thought, and I did not find anything other useful.
The code will not compile, I guess, it was just to visualize my idea.
Define a service interface that has meaningful (for the us case) methods. Instead of using blocking calls, have the client supply a ResponseHandler that will be invoked when the operation is complete:
interface ResponseHandler {
void onComplete(Response response);
void onError(Throwable error);
}
interface SomeService {
void set(String attribute, Object value, ResponsHandler responseHandler);
void get(String attribute, ResponseHandler responseHandler);
}
The implementation of the Service interface can use any suitable protocol, but it has to correlate requests with responses in order to invoke the correct callbacks.
Say I've got a logging service deployed to some (jaxrs-compliant) container.
#Path("/logger")
public class LogService
{
#GET
#Path("/log")
public Response log(final String #QueryParam("msg") msg)
{
System.out.println(msg);
// ...
}
}
If I make the following request to the container hosting this service, I expect to see the output of my message to the container's stdout log:
GET <host>:<port>/logger/log?msg=foo
Now I'd like to change the implementation of this log message at runtime with behavior specified by some arbitrary client.
For example, say we had an interface:
public interface LoggerApi
{
void logMessage(final String msg);
}
and the service was redefined to use an implementation of this interface:
#Path("/logger")
public class LogService
{
public static LoggerApi LOGGER = new LoggerApi()
{
void logMessage(final String msg)
{
System.out.println(msg);
}
}
#GET
#Path("/log")
public Response log(final String #QueryParam("msg") msg)
{
LOGGER.logMessage(msg);
// ...
}
}
The question thus becomes, how can I hot swap the implementation of logger with a new implementation defined by some client external to the server.
My first instinct was that RMI and/or dynamic proxies could get me where I wanted to be, but I'm not soo sure with all the security policy madness.
Essentially what I want is the ability to do the following:
#Path("/config")
public class ConfigService
{
#POST
#Path("/loggerApi")
public Response setLoggerApi(final LoggerApi clientSuppliedLogger)
{
LogService.LOGGER = clientSuppliedLogger;
// ...
}
}
Thoughts?
(Oh and I know this poses a severe security risk and such a pattern ought never be used in production environments. My interest is in designing a mock service where the service's behavior and side effects can be defined by the integration tests calling the mock service)
I think the short answer may be no, but I'm hoping I can get alternative suggestions. Assume I have a data object and a data service. The data service is an interface and has the following method.
public Data getData();
I'm creating a proxy for the service using the following invocation handler plus Netty to do what I'd call asynchronous rpc. The proxy is on the client side.
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Convert the call into an async request that returns a ListenableFuture
APCRequest request = new APCRequest(serviceType, method, args);
ListenableFuture future = apcClient.asyncMessage(request);
// This blocks until the future finishes
return future.get();
}
This works fine. However, if my client is a UI, I end up wrapping the service call in something like a SwingWorker. I'd prefer to come up with a way of returning the ListenableFuture that I already have sitting there. Is there any way I can accomplish that without creating a separate, asynchronous service API. For example:
public ListenableFuture<Data> getData();
If I could have my InvocationHandler return the wrong type, I could use something like this.
public abstract class AsyncServiceCall<S, D> { // S = service type, D = expected doCall return type
protected final S service;
protected AsyncServiceCall(Class<S> serviceType, APCClient client) {
ProxyFactory proxyFactory = new ProxyFactory(client);
// The true tells the proxyFactory we're expecting a ListenableFuture<D>
// rather than the real return type.
service = proxyFactory.createProxy(serviceType, true);
}
// Sub-classes would make a normal method call using this. For
// example, service.getData()
public abstract Object doCall();
#SuppressWarnings("unchecked")
public ListenableFuture<D> execute() {
return (ListenableFuture<D>) doCall();
}
Is there another way of accomplishing what I want? Performance isn't an issue for me, so blocking until the proxy can get the return value from the future is still an option if there's no simple way of doing what I want. It just seems like a waste since I want an asynchronous call in the UI anyway.
Keeping my service API simple is more of a priority than anything. I want to be able to prototype using a simple service provider that instantiates service implementations directly and plug in my remoting protocol / server that's using dynamic proxies / Netty late in the development cycle.
If you want to keep your API simple then I would suggest providing only the async API in the interface - it's much easier to wrap up a synchronous implementation in an asynchronous API than vice-versa.
public interface DataService {
public ListenableFuture<Data> getData();
}
public abstract class LocalDataService implements DataService {
public ListenableFuture<Data> getData() {
SettableFuture<Data> result = SettableFuture.create();
try {
Data theData = computeData();
result.set(theData);
} catch(Throwable t) {
result.setException(e);
}
return result;
}
protected abstract Data computeData() throws Throwable;
}