our project runs on GWT and Java App Engine and we use the standard GWT RPC mechanism.
App engine adds log trace for each RPC call, but it just logs the servlet URL and not the called method.
We would like to add the method name to the log URL.
We have tried extending RpcRequestBuilder class, overriding doCreate and adding the method name to the URL, but the problem is that at this point the method name is unknown - it's known later at doSetRequestData (as part of the data string).
Thanks
Itzik
In each rpc implementation you can override one of readContent and processCall and add logging.
#Override
public String processCall(String payload) throws SerializationException {
// TODO Auto-generated method stub
String processCall = super.processCall(payload);
Logger.getLogger("").info(processCall);
return processCall;
}
#Override
protected String readContent(HttpServletRequest request)
throws ServletException, IOException {
// TODO Auto-generated method stub
String readContent = super.readContent(request);
Logger.getLogger("").info(readContent);
return readContent;
}
Log Line
6|0|4|http://127.0.0.1:8888/_4021625/|35C4974968FC8F8A9A7EA4881FD49F57|com.bitdual.client.LogMeService|logmemethod|1|2|3|4|0|
Related
I have a GlobalExceptionHandler class which contain multiple methods annotated with #ExceptionHandler.
#ExceptionHandler({ AccessDeniedException.class })
public final ResponseEntity<Object> handleAccessDeniedException(
Exception ex, WebRequest request) {
return new ResponseEntity<Object>(
"Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
I have a AOP which is suppose to be triggered after the exception handler returns response.
#AfterReturning(value="#annotation(exceptionHandler)",returning="response")
public void afterReturningAdvice(JoinPoint joinPoint, Object response) {
//do something
}
But the #AfterReturning is not triggered after the handler returns a valid response.
Tried full qualified name but not working
#AfterReturning(value = "#annotation(org.springframework.web.bind.annotation.ExceptionHandler)", returning = "response"){
public void afterReturningAdvice(JoinPoint joinPoint, Object response) {
//do something
}
Please go through the documentation to understand the proxying mechanisms in Spring framework.
Assuming the ExceptionHandler code written was of the following format
#ControllerAdvice
public class TestControllerAdvice {
#ExceptionHandler({ AccessDeniedException.class })
final public ResponseEntity<Object> handleAccessDeniedException(
Exception ex, WebRequest request) {
return new ResponseEntity<Object>(
"Access denied message here", new HttpHeaders(), HttpStatus.FORBIDDEN);
}
}
key points from the documentation pertaining to the question are
Spring AOP uses either JDK dynamic proxies or CGLIB to create the
proxy for a given target object.
If the target object to be proxied implements at least one
interface, a JDK dynamic proxy is used. All of the interfaces
implemented by the target type are proxied. If the target object
does not implement any interfaces, a CGLIB proxy is created.
With CGLIB, final methods cannot be advised, as they cannot be overridden in runtime-generated subclasses.
OP identified the issue based on the comments and hints , this answer is for any future references.
I have written a camel route which polls a folder and sends it to Azure Blob Container
I followed the example mentioned in the Azure document page
https://github.com/apache/camel/blob/master/components/camel-azure/src/main/docs/azure-blob-component.adoc
I am reversing the route. Instead of a consumer, I am using the Azure Blob Producer.
This is my route. I have used Java DSL.
from("file://C:/camel/source1").to("azure-blob://datastorage/container1/BLOB1?credentials=#credentials&operation=updateBlockBlob")
When I placed a file, I got the following error.
**java.lang.IllegalArgumentException: Unsupported blob type:org.apache.camel.component.file.GenericFile
at org.apache.camel.component.azure.blob.BlobServiceProducer.getInputStreamFromExchange(BlobServiceProducer.java:474) ~[camel-azure-2.19.2.jar:2.19.2]
at org.apache.camel.component.azure.blob.BlobServiceProducer.updateBlockBlob(BlobServiceProducer.java:143) ~[camel-azure-2.19.2.jar:2.19.2]
at org.apache.camel.component.azure.blob.BlobServiceProducer.process(BlobServiceProducer.java:79) ~[camel-azure-2.19.2.jar:2.19.2]**
I was able to fix this. I rewrote my route as.
from("file://C:/camel/source1")
.process(new Processor() {
#Override
public void process(Exchange exchange) throws Exception {
Object file = exchange.getIn().getMandatoryBody();
exchange.getOut().setBody(
GenericFileConverter.genericFileToInputStream(
(GenericFile<?>) file, exchange));
}
})
.to("azure-blob://datastorage/container1/BLOB1?credentials=#credentials&operation=updateBlockBlob")
.to("mock:Result");
My Question is, do I need to really write the processor? Shouldn't the camel component be receiving a stream or a File Object?
Yeah this is a little bug. I have logged a ticket: https://issues.apache.org/jira/browse/CAMEL-11844
You can do the workaround you did, or you can add a .convertBodyTo and convert to a FileInputStream, String etc.
from("file://C:/camel/source1")
.convertBodyTo(String.class)
...
I'm having trouble following the second step here.
I really don't understand how this sample does anything other than return a simple toast message. How does it utilize the API to display that message?
class EndpointsAsyncTask extends AsyncTask<Pair<Context, String>, Void, String> {
private static MyApi myApiService = null;
private Context context;
#Override
protected String doInBackground(Pair<Context, String>... params) {
if(myApiService == null) { // Only do this once
MyApi.Builder builder = new MyApi.Builder(AndroidHttp.newCompatibleTransport(),
new AndroidJsonFactory(), null)
// options for running against local devappserver
// - 10.0.2.2 is localhost's IP address in Android emulator
// - turn off compression when running against local devappserver
.setRootUrl("http://10.0.2.2:8080/_ah/api/")
.setGoogleClientRequestInitializer(new GoogleClientRequestInitializer() {
#Override
public void initialize(AbstractGoogleClientRequest<?> abstractGoogleClientRequest) throws IOException {
abstractGoogleClientRequest.setDisableGZipContent(true);
}
});
// end options for devappserver
myApiService = builder.build();
}
context = params[0].first;
String name = params[0].second;
try {
return myApiService.sayHi(name).execute().getData();
} catch (IOException e) {
return e.getMessage();
}
}
#Override
protected void onPostExecute(String result) {
Toast.makeText(context, result, Toast.LENGTH_LONG).show();
}
I'm afraid my this sample is too complex for my limited knowledge. How exactly do I "talk" to the Google Endpoints Module when running an app? Specifically, What is EndpointsAsyncTask();?
Are there any resources listing all the methods available to me? Is there a simpler example of an app communicating with a Google Cloud Endpoint?
The service methods available to you are defined by the backend source in section 1.
In the example you posted, this line: myApiService.sayHi(name).execute()
is an actual invocation call to the backend that you defined by annotating #ApiMethod("sayHi") on the method in the MyEndpoint.java class of your backend module.
The reason your Android app defines an EndpointsAsyncTask is because slow operations such as calls that hit the network need to happen off of the UI thread to avoid locking the UI. The demo simply puts the returned value into a Toast but you could modify onPostExecute() to do whatever you'd like with the result.
For more info on Google Endpoints check out:
https://cloud.google.com/appengine/docs/java/endpoints/
And for info about using an Android AsyncTask look here:
http://developer.android.com/reference/android/os/AsyncTask.html
I have a route using a customized load balancer as,
from("timer://myTimer?period=2000")
.loadBalance(new MyCustomLoadBalancer())
.to("mock:em1").to("mock:em2").to("mock:em3")
.end();
In the customized balancer class, it seems only processors can be gotten.
public class MyCustomLoadBalancer extends SimpleLoadBalancerSupport {
public void process(Exchange exchange) throws Exception {
List<Processor> pList = getProcessors();
.......
//It is wanted to log which endpoint is finally targeted.
foo.process(exchange);
}
}
But here, I want to log actually which endpoint is targeted when using this load balancer.
In product environment, Jetty or HTTP endpoints will be used instead of these mock endpoints.
Is there a way to realized this?
===================================================================
Based on the suggestion from Ibsen, I used the Jetty endpoint to do test.
from("jetty:http://0.0.0.0:8043?matchOnUriPrefix=true")
.loadBalance(new MyCustomLoadBalancer())
.to("jetty:http://localhost:80?bridgeEndpoint=true&throwExceptionOnFailure=false")
.to("jetty:http://www.google.com?bridgeEndpoint=true&throwExceptionOnFailure=false")
.end();
But the Processors are not class of SendProcessor("foo instanceof SendProcessor" returns false), so I can't get the endpoint by getDestination.
I believe there should be some relationship between the endpoint and processor.
Could you give me more help?
Thanks.
The Processor is a SendProcessor where you can get the endpoint it will send the exchange to.
if (foo instanceof SendProcessor) {
SendProcessor send = (SendProcessor) foo;
Endpoint dest = send.getDestination();
...
}
Im trying to implement google's Cloud Connection Server with Google App Engine following this tutorial -
Implementing an XMPP-based App Server. I copied latest smack jars from http://www.igniterealtime.org/projects/smack/ (smack.jar and smackx.jar), put them in WEB-INF/lib and added them to the classpath (im using eclipse).
In the code sample in the first link i posted, the XMPPConnection is initiated in a 'main' method. Since this is not really suitable to GAE i created a ServletContextListener and added it to web.xml.
public class GCMContextListener implements ServletContextListener {
private static final String GCM_SENDER_ID = "*GCM_SENDER_ID*";
private static final String API_KEY = "*API_KEY*";
private SmackCcsClient ccsClient;
public GCMContextListener() {
}
#Override
public void contextInitialized(ServletContextEvent arg0) {
final String userName = GCM_SENDER_ID + "#gcm.googleapis.com";
final String password = API_KEY;
ccsClient = new SmackCcsClient();
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
}
#Override
public void contextDestroyed(ServletContextEvent arg0) {
try {
ccsClient.disconnect();
} catch (XMPPException e) {
e.printStackTrace();
}
}
}
web.xml
<web-app>
<listener>
<listener-class>com.myserver.bootstrap.GCMContextListener</listener-class>
</listener>
</web-app>
Now, when i start the GAE server i get the following exception :
java.lang.NoClassDefFoundError: javax.naming.directory.InitialDirContext is a restricted class. Please see the Google App Engine developer's guide for more details.
i searched the "Google App Engine developer's guide for more details" but couldnt find anything about this. can you please help me ?
Google App Engine restricts access to certain JRE classes. In fact they published a whitelist that shows you which classes are useable. It seems to me that the Smack library might require some reference to a directory context (maybe to create the XMPP messages?) and that is why your servlet causes this exception. The javax.naming.directory is not in the whitelist.
I'm currently working on setting up a GCM Server as well. It seems to me that you need to read through the example and see what that main method is doing. What I see is a connection to the GCM server:
try {
ccsClient.connect(userName, password);
} catch (XMPPException e) {
e.printStackTrace();
}
Then a downstream message being sent to a device:
// Send a sample hello downstream message to a device.
String toRegId = "RegistrationIdOfTheTargetDevice";
String messageId = ccsClient.getRandomMessageId();
Map<String, String> payload = new HashMap<String, String>();
payload.put("Hello", "World");
payload.put("CCS", "Dummy Message");
payload.put("EmbeddedMessageId", messageId);
String collapseKey = "sample";
Long timeToLive = 10000L;
Boolean delayWhileIdle = true;
ccsClient.send(createJsonMessage(toRegId, messageId, payload, collapseKey,
timeToLive, delayWhileIdle));
}
These operations would be completed at some point during your application's lifecycle, so your servlet should support them by providing the methods the example is implementing, such as the connect method that appears in the first piece of code that I pasted here. It's implementation is in the example at line 235 if I'm not mistaken.
As the documentation says, the 3rd party application server, which is what you're trying to implement using GAE, should be:
Able to communicate with your client.
Able to fire off properly formatted requests to the GCM server.
Able to handle requests and resend them as needed, using exponential back-off.
Able to store the API key and client registration IDs. The API key is included in the header of POST requests that send messages.
Able to store the API key and client registration IDs.
Able to generate message IDs to uniquely identify each message it sends.