JAIN-SIP support for RFC 7339 - java

Is there any way to add custom via header in jain-sip? Adding the oc-parametrs from RFC 7339.
From enter link description hereplace I got the following example, but not sure if it will work. The quote from link:
This could be easily achieved by adding some code to implementation of
javax.sip.message.Message.addHeader(Header header) function.
void addHeader(Header header) {
if(!(header instanceof InternalHeaderObject)
&& header instanceof ExtensionHeader) {
ExtensionHeader extensionHeader = (ExtensionHeader) header;
header = headerFactory.createHeader(extensionHeader.getName(), extensionHeader.getValue());
}
...
}

I will start by saying you can absolutely handle custom via headers in terms of SIP as long as it is valid SIP. For this RFC you just need to use viaHeader.set/getParameter if I am not missing something.
The blog post talks about creating your own header classes, which is not relevant to your needs as far as I can imagine. Custom header classes are tricky and inefficient. For example JAIN SIP will automatically construct it's own ViaHeader instance for inbound messages when parsing them. Plugging a custom header to override the default Via internally will break a lot of validation promises and cause overhead..
If you have a showstopper case for custom header classes I will gladly listen though.

Related

Simplifying REST URL with JSON Parameters

I have been assigned a task and I really don't know how to even begin solving it, so any help would be appreciated. Consider the following example:
#Path("/v1/{server}:{port}/instance")
public class WSInstance {
private static final Log log = LogFactory.getLog(WSInstance.class);
private final String PLANNING_PROPNAME = "**PLNG_NAME**";
private final String PLANNING_PROPVAL = "**CALENDAR_NAME**";
#GET
#Path("/{instanceName}")
#Produces("text/plain")
public String getInstanceStatus(#Context HttpHeaders headers,
#PathParam("server")String server,
#PathParam("port")int port,
#PathParam("instanceName") String instName,
#DefaultValue("") #QueryParam("date") String date,
#DefaultValue("") #QueryParam("instnum") String numexec)
{
return getInstanceStatus(Utils.extractUserInfo(headers), server, port, instName, numexec, date);
}
An example of a call to the aforementioned method is going to look like this:
/v1/serverName:portNumber/instance/toto?date=21090207&instnum=0000
What the task is asking is to replace all the variables in that url (serverName, portNumber, toto, date and instnum) with json parameters. This is meant to simplify the REST URL.
Any idea where to begin?
** EDIT: Thanks to everyone for their answers, you've certainly helped me a lot. Here's what I have done so far:
I decided to take a "simpler" class and method to familiarize myself with the procedure. So I took this one:
#Path("/v2/{server}:{port}/admin/")
public class WSAdmin {
private static final Log log = LogFactory.getLog(WSAdmin.class);
#PUT
#Path("/device")
#Produces("text/plain")
#Consumes("application/json")
public String putDevice(String jsonObject, #Context HttpHeaders headers,
#PathParam("server")String server,
#PathParam("port")int port)
{
ObjectMapper mapper = new ObjectMapper();
try
{
return updateDevice(mapper.readTree(jsonObject), Utils.extractUserInfo(headers), server, port);
}
catch (JsonProcessingException e)
{
return e.getMessage();
}
catch (IOException e)
{
return e.getMessage();
}
}
I changed it like this:
#Path("/v2/admin/")
public class WSAdmin {
private static final Log log = LogFactory.getLog(WSAdmin.class);
#POST
#Path("/device")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response putDevice(Admin admin)
{
String output = admin.toString();
return Response.status(200).entity(output).build();
}
Then I created the corresponding POJO:
#XmlRootElement
public class Admin {
private String server;
private int port;
private Date date;
private String instnum;
// Constructors + getters + setters
#Override
public String toString() {
return new StringBuffer("Server: ").append(this.server)
.append("Port: ").append(this.port).append("Date: ")
.append(this.date).append("InstNum: ")
.append(this.instnum).toString();
}
}
Then I edited the web.xml file to be able marshal and unmarshal Java Objets:
<init-param>
<param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
But for some reason, i'm getting the following error when I make the call from postman:
GRAVE [http-nio-8080-exec-5] com.sun.jersey.spi.container.ContainerRequest.getEntity A message body reader for Java class com.ws.v3.models.Admin, and Java type class com.ws.v3.models.Admin, and MIME media type application/json was not found.
The registered message body readers compatible with the MIME media type are:
application/json ->
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$App
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$App
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$App
*/* ->
com.sun.jersey.core.impl.provider.entity.FormProvider
com.sun.jersey.core.impl.provider.entity.StringProvider
com.sun.jersey.core.impl.provider.entity.ByteArrayProvider
com.sun.jersey.core.impl.provider.entity.FileProvider
com.sun.jersey.core.impl.provider.entity.InputStreamProvider
com.sun.jersey.core.impl.provider.entity.DataSourceProvider
com.sun.jersey.core.impl.provider.entity.XMLJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.ReaderProvider
com.sun.jersey.core.impl.provider.entity.DocumentProvider
com.sun.jersey.core.impl.provider.entity.SourceProvider$StreamSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader
com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader
com.sun.jersey.json.impl.provider.entity.JSONJAXBElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLListElementProvider$General
com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General
com.sun.jersey.core.impl.provider.entity.EntityHolderReader
com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider$General
com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General
Those who had a similar error got it to disappear by adding either gerson or jersey-jsonin pom.xml. I've added them but the problem didn't get fixed.
Any idea?
Probably you have to change the method type to POST and pass the data as json in the body of the request.
The GET request
GET /v1/yourServerName:8080/instance/toto?date=21090207&instnum=0000
can become the following POST request
POST /v1/instance
{
"serverName":"yourServerName",
"portNumber":8080,
"date":21090207,
"instnum":"0000"
}
Note that instnum is not a numeric field because you passed the string 0000 that can't be represented as a numeric value. Instead portNumber and date can be numeric values.
Consider using Jackson. Jackson maps JSON <-> objects. Read about how you can use it with Jersey (REST) here:
https://www.mkyong.com/webservices/jax-rs/json-example-with-jersey-jackson/
Per specification the payload of a GET request is undefined. You should, therfore, refrain from sending a body with a GET request. As Davide already suggested you should switch to POST here instead, as here the semantics of a payload received are defined by you, the server/API maintainer.
However, as you've tagged your post with rest you should probably consider copying the concepts used in the Web for over 2 decades now and translate it to your API design. First, REST architecture don't care about the structure of your URI. The URI itself is just a pointer to a resource and clients shouldn't need to interpret it nor hack it. All the information needed for a client to make distinctive choices should be provided by the server to start with. As clients shouldn't parse and interpret URIs how do they determine whether a URI is of use for the client or not?
Well, how do we humans interact with URIs in web-pages? Usually they are annotated with human readable text that summarizes the content of that link (as with the specification i.e. above). Such short but meaningful names are usually called link-relation names and should be "attachted" to each URI. A client reading such link-relation names and just invoke the accompanying URI will be able to continue its task if the server ever has the need to change its URI structure. This is one important step towards decoupling clients from servers. Such link relation names should be standardized but may also be specified in common knowlege or specified in media-types itself.
A common mistake many so called "REST APIs" do is to support either application/xml and/or application/json only. Those are very poor media types in a REST architecture as they only define the syntax to use but not the semantics of the respective elements. It is thus hard for a client to determine the intent of such a document and to easy to fall into the typed resource trap and assume that a certain resource has a certain type. If such a (non-standardized) representation changes, chances are high that a client will break to interoperate with that service/API further.
Media types are more or less standardized processing-rules for a certain received payload that should help give the receiver some meaning of the content and what it might do with it. One probably well known media type is HTML which defines when certain elements are feasible and the constraint each element has. It also defines how certain elements are rendered and how it is backward compatible with former versions. It is the defacto standard when it comes to support for links and link-relations. While HAL, Collection+JSON, ... are steps into the right direction in terms of support of links and relation names, they are far from providing the same semantics as HTML does, though they should be preferable to plain JSON as they not only specify a syntax but also semantics of certain elements such as _links i.e. which help the client to differentiate links from content.
Media types are especially important in terms of content-type negotiation where a client requests a server to return a representation format a client understands. If the server is not able to produce such a representation it will inform the client with an expressive enough error code (406). If the server is not able to process the media type provided by the client (on a POST, PUT, PATCH, ... operation) it will also inform the client that it does not understand such a format (415).
A general advice on designing REST APIs would be to think of the API in terms of a Web server and also desing the whole interaction with it like that. I.e. if a client has to perform certian input it should not send just a playin JSON document with some random fields (specified in some external documentation) to the server, but the server should teach the client on how to send such a request to start with. Similar to Web forms where humans should enter text and stuff, REST APIs should return a media-type representing a formular that teaches a client what fields the server expects, which operation to use and the target to send the payload to.
In regards to the actual question, I'm not sure why your employee is so keen on removing parameters from the URI. As mentioned in my first paragraph on sending a payload you'd need to switch to POST and therefore automatically loose the guaranteed safe and idempotent features of the GET operation, besides not being cacheable by default.
What you can do i.e. is allow users or your coworkers to preconfigure certain queries and create short/tiny URLs for these preconfigured URIs. Here you should provide a form-like media type to the client where it can select the options to choose from and enter further necessary data. Once you received such a request you store such a preconfiguration and return a short/tiny URL for that preconfiguration in the Location header of the response. You should also add the preconfigured links in the regular response so that a client is able to invoke it if it didn't store it right after persistence. By doing so you still have the benefits of the GET operation while having the flexibility to add new or customize existing queries on the fly. As mentioned before, a client won't be able to make much use of such links in a plain application/json representation. If the client supports application/hal+json it might at least know what link-relation and links are and therefore be able to lookup and invoke the URI via its accompanying link relation name. This basically gives you the freedom to later on change the URI structure if needed without affecting the client.

Sending dynamic custom headers in swagger UI try outs

I am using swagger in java.
I am reading a header called callerId through requestAttributes in the code. I am not using the header through the annotation #HeaderParam.
because of this reason, the header section is not showing up in the swagger UI for try outs.
How can I make this header show up in the try out form.
Is there any way I can achieve this without hard coding the header value.
Thanks in advance.
You can add parameters to an operation using #ApiImplicitParams and #ApiImplicitParam.
The following wiki documentation should provide you with an explanation on how to use these annotations - https://github.com/swagger-api/swagger-core/wiki/Annotations#apiimplicitparam-apiimplicitparams
Keep in mind I assume here that this is not a security header but actually part of the API (at least based on the description you gave). If you're looking for a security header, there's an alternative method. Please leave a comment and I'll edit this response.

Adding soap header authentication to wsdl2java generated code

I'm in the process of creating a Java web services client from a wsdl. I used Eclipses's Dynamic Web Project and new Web Services Client to generate the code with wsdl2java with Apache Axis 1.4. I need to add SOAP authentication to this code in order for it to work with the service. I couldn't find a place to do that in the generated code. After copious research I found this, which I've used as the backbone for my code so far.
Adding ws-security to wsdl2java generated classes
Before I was getting a "Error occurred while processing security for the message" or something along those lines. Now I am getting
"Exception: Did not understand "MustUnderstand" header(s):{http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd}Security Message: null"
I've tried many things to get past this exception. This is the code I've arrived at now.
javax.xml.namespace.QName headerName = new javax.xml.namespace.QName(
"http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", "Security");
org.apache.axis.message.SOAPHeaderElement header = new org.apache.axis.message.SOAPHeaderElement(headerName);
header.setActor(null);
header.setMustUnderstand(true);
// Add the UsernameToken element to the WS-Security header
javax.xml.soap.SOAPElement utElem = header.addChildElement("UsernameToken");
utElem.setAttribute("Id", "uuid-3453f017-d595-4a5b-bc16-da53e5831cd1-1");
javax.xml.soap.SOAPElement userNameElem = utElem.addChildElement("Username");
userNameElem.setValue("username");
javax.xml.soap.SOAPElement passwordElem = utElem.addChildElement("Password");
passwordElem.setAttribute("Type", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
passwordElem.setValue("password");
header.setProcessed(true);
// Finally, attach the header to the binding.
setHeader(header)
This code is located in my Binding_ServiceStub class (in its' createCall method).
We have created clients in both C# and VB with this wsdl, and there it's as easy as just changing the ClientCredentials variable which is an extension of the proxy class generated. I was hoping for something similar here.
Here's the security policy from the wsdl code as well.
<wsp:Policy><sp:UsernameToken sp:IncludeToken="http://schemas.xmlsoap.org/ws/2005/07/securitypolicy/IncludeToken/AlwaysToRecipient"><wsp:Policy><sp:WssUsernameToken10/></wsp:Policy></sp:UsernameToken></wsp:Policy>
Does anyone know what else I can do here? Why this exception is happening? I've tried many different combinations of prefixes and setProcesses and setMustUnderstand values all in vain (and based on my research of this exception).
And if anyone knows a way in which to add Soap header authentication to wsdl2java code I would take that too. Just need this to work and you would think something like this would be a little more straightforward or at least have more examples out there.
Update-
Confirmed that the same header passed using SOAPUI works fine. Must be something with the framework? I created a custom handler to process the SOAP Message but that didn't help. Is Axis 1.4 and JAX-RPC the problem? (I know they're outdated but still...)
Cool. I decided to just use Apache CXF as my framework and using this it's as easy as adding
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider) port;
bp.getRequestContext().put("ws-security.username", username);
bp.getRequestContext().put("ws-security.password", password);
Wow that's much better. Don't use Axis 1.4 lesson learned.

How do I sign an MTOM SOAP message using SOAPHandlers?

Currently, I have two handlers, one for logging and one for signing the SOAP message (which inherently tampers with the SOAP message). Without the handler chain, MTOM works as expected, inserting a reference to the binary content, rather than inlining the base64 binary content.
As soon as I introduce a handler, the MTOM content is now included inline.
Is it possible to use handlers to sign a SOAP message or is there a more appropriate means of doing this?
Update 1
Unable to post the full source. Essentially though, custom SOAPHandler implementation. It performs some basic XMLDsig type operations on a timestamp (in header), custom header and SOAP body. The resultant digest values are then injected into a signature element in the header.
With respect to the logger, it is again a simple SOAPHandler. If either it or the signing handler are used exclusively, the result is the same, an MTOM message with the byte content inlined. The only progress I made was using a MessageHandler for logging. This allowed me to output the SOAP envelope (albeit with the byte content inlined) and still maintain the MTOM separation. So not really a solution but an indication that any modification of the SOAP message needs to occur at a lower level. This is leading me down the path of tubes.
Update 2
The following is an example of the MessageHandler approach. You can see that the raw HTTP dump will contain the multiple part message whereas the actually output inlines the base64. The only difference between this impementation and a SOAPHandler implementation is that the actual HTTP request changes to be a single part inlined MTOM message.
#Override
public boolean handleMessage(MessageHandlerContext context) {
HttpTransportPipe.dump = true;
Boolean isOutgoing = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isOutgoing) {
System.out.println("\nOutbound message:");
XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
try {
context.getMessage().writeTo(writer);
} catch (XMLStreamException e) {
throw new IllegalStateException("Unable to write");
}
} else {
System.out.println("\nInbound message:");
}
return true;
}
I tried to replicate your problem by putting together a simple service that accepts an image transferred by MTOM. I found that if I put the MTOM-enabling code before setting the handler, it encodes the message properly. If I set the handler first, it does not. Here is where I set up the properly functioning client code:
Service service = Service.create(url, qname);
Greeting greeting = service.getPort(Greeting.class);
BindingProvider bp = (BindingProvider) greeting;
SOAPBinding binding = (SOAPBinding) bp.getBinding();
binding.setMTOMEnabled(true);
service.setHandlerResolver(new HandlerResolver() {
#SuppressWarnings("rawtypes")
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerList = new ArrayList<Handler>();
handlerList.add(new RGBSOAPHandler());
return handlerList;
}
});
Where RGBSOAPHandler is just some example code I took from another SO answer.
EDIT: Also, if I try setting the handler on the binding and not the service then I get the same problem that you do. So if it looks like this:
Service service = Service.create(url, qname);
Greeting greeting = service.getPort(Greeting.class);
BindingProvider bp = (BindingProvider) greeting;
SOAPBinding binding = (SOAPBinding) bp.getBinding();
binding.setMTOMEnabled(true);
List<Handler> handlerList = new ArrayList<Handler>();
handlerList.add(new RGBSOAPHandler());
binding.setHandlerChain(handlerList);
Then my file is encoded in-line. I don't know why this is, but I suppose the answer is "don't do that". Set your handlers on the Service object.
Looks like I'm limited by the framework and the way in which the handlers work. I think at this stage, my only option is to go to a lower level. I did take a look at using tubes but the same behaviour exhibited itself so it looks as though any attempt to work with the XML of the request fails. As such, I'm going to have to abandon handlers for the time being and investigate at a lower level whether I can make use of codecs to do what I'm after. An MTOM implementation sounds like it may do what I'm after at the byte level:
http://jax-ws.java.net/nonav/jax-ws-20-fcs/arch/com/sun/xml/ws/encoding/MtomCodec.html
I imagined this would be a lot less complex to get working but will update with my progress on the codec front.
#David: Thanks for your help on the handler front but looks as though there is no solution at that level.
Update 1
Came up with an alternate solution that works for my purposes.
I sign the necessary parts of the SOAP message using my SOAPHandler.
Wrote a new SOAPHandler that then takes resultant message and manually extracts the incorrectly inlined binary content.
I then create an AttachmentPart and inject the content from Step 2 into that. It takes Base64 encoded text too which is handy. That AttachmentPart then has a reference UUID assigned to it for Content-Id.
I then create a new element in place of the Base64 content in the SOAP body that reference the UUID, along the lines of the following:
<xop:Include xmlns:xop="http://www.w3.org/2004/08/xop/include" href="cid:UUID!!!"></xop:Include>
Will probably write a blog post on this as it's been a bit of an epic journey to this point. It was not the best solution but it was certainly easier than going down the tubes/codec path.

Google Protocol Buffers and HTTP

I'm refactoring legacy C++ system to SOA using gSoap. We have some performance issues (very big XMLs) so my lead asked me to take a look at protocol buffers. I did, and it looks very cool (We need C++ and Java support). However protocol buffers are solution just for serialization and now I need to send it to Java front-end. What should I use from C++ and Java perspective to send those serialized stuff over HTTP (just internal network)?
PS. Another guy tries to speed-up our gSoap solution, I'm interested in protocol buffers only.
You can certainly send even a binary payload with an HTTP request, or in an HTTP response. Just write the bytes of the protocol buffer directly into the request/response, and make sure to set the content type to "application/octet-stream". The client, and server, should be able to take care of the rest easily. I don't think you need anything more special than that on either end.
ProtoBuf is a binary protocol. It doesn't mix well with SOAP. I suggest you either stick with gSOAP or convert to ProtoBuf entirely.
With protoBuf, you define your protocol in a special format like this,
message Product {
required string id = 1;
required string description = 2;
required int32 quantity = 3;
optional bool discontinued = 4;
}
The protoc tool can generate code in C++/Java/Python so you can serialize it on one end and deserialize on another.
As you can see, ProtoBuf is designed to serialize individual object. It doesn't provide all the facilities provided by SOAP, like headers. To get around this issue, we use ProtoBuf inside ProtoBuf. We define an Envelope like this,
message Envelope {
enum Type {
SEARCH = 1;
SEARCH_RESPONSE = 2;
RETRIEVE = 3;
RETRIEVE_RESPONSE = 4;
}
required Type type = 1;
required bytes encodedMessage = 2;
message Header {
required string key = 1;
required bytes value = 2;
}
repeated Header headers = 3;
}
The encodedMessage is another serialized ProtoBuf message. All the stuff in SOAP header now goes to headers.
Google frontends prefer application/protobuf.
The ProtocolBufferModel of the Google API client uses application/x-protobuf.
You can serialize/de-serialize protobuf encoded data to/from strings. Send the serialized string as the body of an HTTP POST to Java and de-serialize it. That is one approach. Another way is to make use of the protobuf Service interface. Protobuf allows you to define a service interface in a .proto file and the protocol buffer compiler will generate service interface code and stubs in your chosen language. You only need to implement the protobuf::RpcChannel and protobuf::RpcController classes to get a complete RPC framework. Probably you can write an HTTP wrapper for these classes. See the following links for more information:
http://code.google.com/apis/protocolbuffers/docs/proto.html#services
http://code.google.com/apis/protocolbuffers/docs/reference/cpp-generated.html#service
http://code.google.com/apis/protocolbuffers/docs/reference/cpp/google.protobuf.service.html
To my knowledge protocol buffers support is available in both C++ and Java, you should be able to exchange protocol buffer serialized data between both systems.
That said, it seems your real question is "How do I send stuff over HTTP between a C++ backend and Java client"
It sound like you need to learn how to use gSOAP, read the docs.
Alternatively you could host a RESTful web server from your C++ app: Look at this: https://stackoverflow.com/questions/298113/how-can-i-implement-a-restful-webservice-using-c++
Next you would need to access the data hosted on your new C++ RESTful server: Look at this: Rest clients for Java?

Categories