I need to catch exception of business logic and cut down its message (stack trace of exception, I don't want to log a bunch of stack trace, just exception type and its message). According to the examples in internet, I have to override or implement handleFault(Message message) method. I have web method for which I attached Interceptor class implements org.apache.cxf.interceptor.Interceptor. But It doesn't work. There is no sign of its call. I can't find any solution surfing through internet.
My web service :
#Stateless
#WebService(name = "LocationServicesWS", targetNamespace = "http://com.example.apps.sc.ws", serviceName = "locationServices")
#WebContext(contextRoot = "/bb/sc", urlPattern = "/lb", transportGuarantee = "NONE", secureWSDLAccess = false)
#Pool("sl-strict-pool")
public class LbServices implements IServicesLocal, IServicesRemote {
#WebMethod
#Override
#Interceptors(TestFaultInterceptor.class)
public LbLocation getLbsLocationService(#WebParam(name="ms")String ms, #WebParam(name="serID")Long ser) throws ScAccViolation, LbsException {
return serviceProcesses.getLbsLocationForService(ms, ser);
}
}
My custom interceptor:
#Interceptor
#Priority(Interceptor.Priority.APPLICATION)
public class TestFaultInterceptor implements org.apache.cxf.interceptor.Interceptor {
private static Logger logger = Logger.getLogger(String.valueOf(TestFaultInterceptor.class));
#Override
public void handleMessage(Message message) throws Fault {
//this method is not invoked
logger.info("handleMessage");
}
#Override
public void handleFault(Message message) {
//this method is also not invoked
logger.info("handleFault");
}
/*
#AroundInvoke
public Object intercept(InvocationContext invocationContext) throws Exception {
// This method works fine.
return invocationContext.proceed();
}
*/
But in my Interceptor class when I don't implement Interceptor and put annotation #AroundInvoke it works. So what's the problem ? Is there any solution without creating additional *.xml files ?
I have even put annotation
#Priority(Interceptor.Priority.APPLICATION)
But it's to no avail.
Here are links I stumbled in the internet (especially how to not log whole stack trace).
Apache CXF JAX-WS return fault without logging exception
How to get incoming & outgoing soap xml in a simple way using Apache CXF?
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 am trying to implement server side events.
I have very simple resource exposed by a RESTful web service with Jersey/Grizzly. I try to broadcast the events with the SseBroadcaster. An event is created, whenever a data item comes in and is added to an internal list. A client should open a connection to the URL /events to receive the events.
#Path("sensordataelements")
public class SensorDataResource {
private SseBroadcaster broadcaster = new SseBroadcaster();
#GET
#Path("events")
#Produces(SseFeature.SERVER_SENT_EVENTS)
public EventOutput getServerSentEvents() {
final EventOutput eventOutput = new EventOutput();
broadcaster.add(eventOutput);
return eventOutput;
}
#POST
#Path("/addraw")
#Produces(MediaType.APPLICATION_JSON)
public Response addRawSensorData(String elementBody) {
... data processing stuff ...
cList.add(
new SensorDataElement.SensorDataElementBuilder().id()
.sensorReading(tmpValue)
.build()
);
OutboundEvent evt = new OutboundEvent.Builder()
.data(Float.class, Float.valueOf(tmpValue))
.build();
broadcaster.broadcast(evt);
return Response.status(201).build();
}
...
I tried to connect with
curl -v http://localhost:8080/sensordataapp/sensordataelements/events
The connection is fine, but i do not get any events. I looked at some examples, but got the impression that this should work. What did i miss?
Thanks!
By default, a new instance of the resource class is created for each request. This means that a new broadcaster is created for each request, which isn't what you want. If you want to make the resource class a Singleton, you can simply annotate the class with #Singleton
#Singleton
#Path("sensordataelements")
public class SensorDataResource {
...
}
Now, only one instance of the resource class will be created for the entire application, and it will be shared for all requests.
The other option, is if you inject the broadcaster, instead of instantiating it yourself, you can inject it as a Singleton. Whether or not the resource class is a singleton or not, it will still get injected the same broadcaster instance. To do that, you can do something like the following in your ResourceConfig subclass
public class AppConfig extends ResourceConfig {
public AppConfig() {
register(new AbstractBinder() {
#Override
public void configure() {
bind(new SseBroadcaster()).to(SseBroadcaster.class);
}
});
}
}
Then in your resource class, just inject it
#Path("sensordataelements")
public class SensorDataResource {
#Inject
private SseBroadcaster broadcaster;
See also:
Dependency injection with Jersey 2.0
I am trying to implement a simple client in rest easy, but I am getting an error saying "You must use at least one, but no more than one http method annotation". In my server implementation, I have added a http annotation on my method.
#Path("/")
public class TestResource
{
#GET
#Path("/domain/{value}")
public String get(#PathParam("value") final String value) {
return "Hello" + value;
}
}
I debugged it through, the first time it is not hitting the runtime exception, However, it is making a second call to it and failing, not sure why and how.
My client as junit test:
#Test
public void testPerformRestEasy() {
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target("http://localhost:8080/");
TestResource proxy = target.proxy(TestResource.class);
String response = proxy.get("user");
Assert.assertEquals("Hellouser", response);
}
The code where it is failing
private static <T> ClientInvoker createClientInvoker(Class<T> clazz, Method method, ResteasyWebTarget base, ProxyConfig config)
{
Set<String> httpMethods = IsHttpMethod.getHttpMethods(method);
if (httpMethods == null || httpMethods.size() != 1)
{
throw new RuntimeException("You must use at least one, but no more than one http method annotation on: " + method.toString());
}
ClientInvoker invoker = new ClientInvoker(base, clazz, method, config);
invoker.setHttpMethod(httpMethods.iterator().next());
return invoker;
}
Error:
java.lang.RuntimeException: You must use at least one, but no more than one http method annotation on: public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.createClientInvoker(ProxyBuilder.java:76)
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.proxy(ProxyBuilder.java:52)
at org.jboss.resteasy.client.jaxrs.ProxyBuilder.build(ProxyBuilder.java:120)
at org.jboss.resteasy.client.jaxrs.internal.ClientWebTarget.proxy(ClientWebTarget.java:72)
Does anyone know what the issue is here?
The Resteasy JAXRS 2 client does not seem to accept implementation classes directly. To make it work, you have to create a properly annotated interface. It is used by Resteasy to generate a client proxy and your server must implement exactly the same interface.
So in your case, you have to split your code into an interface and a separate implementation class:
#Path("/")
public interface TestResource {
#GET
#Path("/domain/{value}")
String get(#PathParam("value") final String value);
}
public class TestResourceImpl implements TestResource {
#Override String get(final String value) {
return "Hello" + value;
}
}
I'm not sure if this is Resteasy-specific or required by the specification, but solved the same issue for me. You can find the section that gave me the hint here in the documentation.
You have to define the MIME media type resource representation of resource(#Produces/#Consumes) from client. Like -
#Path("/")
public class TestResource
{
#GET
#Produces("text/plain")
#Path("/domain/{value}")
public String get(#PathParam("value") final String value) {
return "Hello" + value;
}
}
The Jboss Client framework Doc will help you more.
In my case the developer of the Rest Client Interface had wrongly extended RestEasyClientProxy. It wasn't the methods in the Rest Interface that were missing the http annotations, but the inherited methods.
Removing extends RestEasyClientProxy from the Rest Client Interface code fixed the issue.
Please look at the code I posted below. FYI, this is from the Oracle website's websocket sample:
https://netbeans.org/kb/docs/javaee/maven-websocketapi.html
My question is, how does this work?! -- especially, the broadcastFigure function of MyWhiteboard. It is not a abstract function that is overridden and it is not "registered" with another class as in the traditional sense. The only way I see it is when the compiler sees the #OnMessage annotation, it goes and inserts the broadcastFigure call into the compiled code for when a new message is received. But before calling this function, it flows through the received data through the FigureDecoder class - based on this decoder being specified in the annotation #ServerEndpoint. Within broadcastFigure, when sendObject is called, the compiler inserts a reference to FigureEncoder - based on what's specified in the annotation #ServerEndpoint. Is this accurate?
If so, why did this implementation do things this way using annotations? Before looking at this, I would have expected there to be an abstract OnMessage function which needs to be overridden and explicit registration functions for Encoder and Decoder. Instead of such a "traditional" approach, why does the websocket implementation do it via annotations?
Thank you.
Mywhiteboard.java:
#ServerEndpoint(value = "/whiteboardendpoint", encoders = {FigureEncoder.class}, decoders = {FigureDecoder.class})
public class MyWhiteboard {
private static Set<Session> peers = Collections.synchronizedSet(new HashSet<Session>());
#OnMessage
public void broadcastFigure(Figure figure, Session session) throws IOException, EncodeException {
System.out.println("broadcastFigure: " + figure);
for (Session peer : peers) {
if (!peer.equals(session)) {
peer.getBasicRemote().sendObject(figure);
}
}
}
#OnError
public void onError(Throwable t) {
}
#OnClose
public void onClose(Session peer) {
peers.remove(peer);
}
#OnOpen
public void onOpen(Session peer) {
peers.add(peer);
}
}
FigureEncoder.java
public class FigureEncoder implements Encoder.Text<Figure> {
#Override
public String encode(Figure figure) throws EncodeException {
return figure.getJson().toString();
}
#Override
public void init(EndpointConfig config) {
System.out.println("init");
}
#Override
public void destroy() {
System.out.println("destroy");
}
}
FigureDecoder.java:
public class FigureDecoder implements Decoder.Text<Figure> {
#Override
public Figure decode(String string) throws DecodeException {
JsonObject jsonObject = Json.createReader(new StringReader(string)).readObject();
return new Figure(jsonObject);
}
#Override
public boolean willDecode(String string) {
try {
Json.createReader(new StringReader(string)).readObject();
return true;
} catch (JsonException ex) {
ex.printStackTrace();
return false;
}
}
#Override
public void init(EndpointConfig config) {
System.out.println("init");
}
#Override
public void destroy() {
System.out.println("destroy");
}
}
Annotations have their advantages and disadvantages, and there is a lot to say about choosing to create an annotation based API versus a (how you say) "traditional" API using interfaces. I won't go into that since you'll find plenty of wars online.
Used correctly, annotations provide better information about what a class/method's responsibility is. Many prefer annotations and as such they have become a trend and they are used everywhere.
With that out of the way, let's get back to your question:
Why did this implementation do things this way using annotations? Before looking at this, I would have expected there to be an abstract OnMessage function which needs to be overridden and explicit registration functions for Encoder and Decoder. Instead of such a "traditional" approach, why does the websocket implementation do it via annotations?
Actually they don't. Annotation is just a provided way of using the API. If you don't like it then you can do it the old way. Here is from the JSR-356 spec:
There are two main means by which an endpoint can be created. The first means is to implement certain of
the API classes from the Java WebSocket API with the required behavior to handle the endpoint lifecycle,
consume and send messages, publish itself, or connect to a peer. Often, this specification will refer to this
kind of endpoint as a programmatic endpoint. The second means is to decorate a Plain Old Java Object
(POJO) with certain of the annotations from the Java WebSocket API. The implementation then takes these
annotated classes and creates the appropriate objects at runtime to deploy the POJO as a websocket endpoint.
Often, this specification will refer to this kind of endpoint as an
annotated endpoint.
Again, people prefer using annotations and that's what you'll find most of tutorials using, but you can do without them if you want it bad enough.
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)