ServiceStack Client multiple GET arguments (not comma separated) - web-services

I am writing a client wrapper over a RESTful API which can take more than one value for an argument.
Take for example this endpoint
/rest/bug?product=Foo&product=Bar
My class for this is
public class SearchBugRequest : IReturn<BugResponse>
{
[DataMember(Name = "product")]
public string[] Product { get; set; }
}
When I use ToUri it shows that the ServiceStack is constructing the URI as
/rest/bug?product=Foo%2CBar%2CBlah
ServiceStack is ending up creating a URL which is comma-seperated and URL encoded
How do I force ServiceStack to create the URL which the service expects?

You should only be using ServiceStack's Typed Clients to talk to ServiceStack Services not an external 3rd Party REST API as they're primarily designed to generate HTTP Requests that are natively understood by ServiceStack Services.
If you want to consume 3rd Party Services it's recommended to use the more flexible and customizable HTTP Utils API's instead.
Having said that you can customize the generated Url to generate the url you want using an IUrlFilter with something like:
public class SearchBugRequest : IReturn<BugResponse>, IUrlFilter
{
[IgnoreDataMember]
public string[] Product { get; set; }
public string ToUrl(string absoluteUrl)
{
Product.Each(p => absoluteUrl = absoluteUrl.AddQueryParam("product",p));
return absoluteUrl;
}
}

Related

How to open JSF page using JAX-RS web service?

I would like other web application (in .net or any other) to call my JAX-RS web service to set and open my JSF page with some passed values.
E.g.
Another web application just pass the userId and a token to open an entry page.
User will complete the entry and service will return the uniqueId for created entry.
I am confused in how I can set JSF context parameters and open that JSF page using JAX-RS. Can anyone give idea about how to set value of JSF session scoped managed bean using web service?
First of all, this question indicates a misunderstanding of purpose of "REST web services" in general. The question concretely asks to perform two rather unusual tasks with a REST web service:
Manipulating the HTTP session associated with the request.
Redirecting to a HTML page managed by a stateful MVC framework as response.
Both squarely contradict the stateless nature of REST. Those tasks aren't supposed to be performed by a REST web service. Moreover, REST web services are primarily intented to be used by programmatic clients (e.g. JavaScript or Java code), not by webbrowsers which consume HTML pages. You normally don't enter the URL of a REST webservice in browser's address bar in order to see a HTML page. You normally enter the URL of a HTML page in browser's address bar. That HTML page can in turn be produced by a HTML form based MVC framework such as JSF.
In your specific case, after the programmatic client has retrieved the unique
ID from the REST web service, then the programmatic client should in turn all by itself fire a new request to the JSF web application. E.g. as follows in Java based client (below example assumes it's a plain servlet, but it can be anything else as you said yourself):
String uniqueId = restClient.getUniqueId(userId, token);
String url = "http://example.com/context/login.xhtml?uniqueId=" + URLEncoder.encode(uniqueId, "UTF-8");
response.sendRedirect(url);
In the target JSF web application, just use <f:viewParam>/<f:viewAction> the usual way in order to grab the unique ID and perform business actions based on that. E.g. as below in login.xhtml:
<f:metadata>
<f:viewParam name="uniqueId" value="#{authenticator.uniqueId}" />
<f:viewAction action="#{authenticator.check}" />
</f:metadata>
#ManagedBean
#RequestScoped
public class Authenticator {
private String uniqueId;
#EJB
private UserService service;
public String check() {
FacesContext context = FacesContext.getCurrentInstance();
User user = service.authenticate(uniqueId);
if (user != null) {
context.getExternalContext().getSessionMap().put("user", user);
return "/somehome.xhtml?faces-redirect=true";
}
else {
context.addMessage(null, new FacesMessage("Invalid token"));
return null; // Or some error page.
}
}
// Getter/setter.
}
Perhaps the REST webservice could for convenience even return the full URL including the unique ID so that the client doesn't need to worry about the target URL.
String uniqueIdURL = restClient.getUniqueIdURL(userId, token);
response.sendRedirect(uniqueIdURL);
On the other hand, there's a reasonable chance that you just misunderstood the functional requirement and you can just directly process the user ID and token in the JSF web application, the more likely if it runs at the same server as the REST web service and also uses HTTPS. Just add an extra <f:viewParam> and do the same business service logic as the JAX-RS resource in the <f:viewAction> method.
<f:metadata>
<f:viewParam name="userId" value="#{authenticator.userId}" />
<f:viewParam name="token" value="#{authenticator.token}" />
<f:viewAction action="#{authenticator.check}" />
</f:metadata>
See also:
What can <f:metadata>, <f:viewParam> and <f:viewAction> be used for?
How to implement JAX-RS RESTful service in JSF framework
Try this in your code,
return new Viewable("/index", "FOO");
Or,
RequestDispatcher rd = request.getRequestDispatcher("{url}");
rd.forward(request, response);
Or,
return Response.status(myCode).entity(new Viewable("/index", "FOO")).build();
try these example working in using jersey,
#GET
public Response get() {
URI uri=new URI("http://nohost/context");
Viewable viewable=new Viewable("/index", "FOO");
return Response.ok(viewable).build();
}
to return something different use this approach:
#GET
public Response get() {
int statusCode=204;
Viewable myViewable=new Viewable("/index","FOO");
return Response.status(statusCode).entity(myViewable).build();
}
Hope that helpe

Setting MTOM-enabled property dynamically in Apache CXF

I'm developing SOAP web service using Apache CXF framework. My web-method returns either binary data or plain XML depending on request parameters. Most of requests return binary data, so I configured CXF to use MTOM in service responses.
But this is not always useful: when XML is returned, caller side expects to get plain text/xml document rather than multipart one. So I'd like my web service to dynamically change its binding.
CXF documentation has following example:
Endpoint ep = ...; // example does not explain how to get it
SOAPBinding binding = (SOAPBinding)ep.getBinding();
binding.setMTOMEnabled(true); // or false
Question: how can I get Endpoint instance?
I'm using Spring annotation #Endpoint for web-service and #PayloadRoot for web-method.
You can use the following code if you are using on server,
you need to add import javax.xml.ws.Endpoint;
HelloWorldImpl implementor = new HelloWorldImpl();
String address = "http://localhost:9000/helloWorld";
Endpoint.publish(address, implementor);
From client side
TestMtomService tms = new TestMtomService(wsdlURL, SERVICE_NAME);
TestMtomPortType port = (TestMtomPortType)tms.getPort(PORT_NAME,TestMtomPortType.class);
Binding binding = ((BindingProvider)port).getBinding();
((SOAPBinding)binding).setMTOMEnabled(true);
Refer
If you are downloaded the cxf bundle, code samples for MTOM Server/Client available on following path
apache-cxf-2.7.2\samples\mtom
I created my own marshalled class extended from org.springframework.oxm.jaxb.Jaxb2Marshaller. Only single method is overriden:
public class Marshaller extends Jaxb2Marshaller {
#Override
public void marshal(Object graph, Result result, MimeContainer mimeContainer) throws XmlMappingException {
if ( disableMtom() ) {
super.marshal(graph, result, null);
} else {
super.marshal(graph, result, mimeContainer);
}
}
private boolean disableMtom() {
return ... // depends on response context
}
}
The disableMtom detects if MTOM is disabled from response context. Web service endpoint takes care to pass this context to marshaller somehow.
By default MTOM is enabled.

Create Web Service from struts2 Web Application

First, I'm new to Web Services. I have a didactical task at university about developing web application and web service for something like managing distribuited drug stores.
I've developed a working Web Application using struts2 framework, but now I'd like to extend it to a Web Service. I found that I could implement a class (named for example WSManager) which is a wrapper of the various Web App Controllers.
It would have to make calls to static methods of those Controllers. Web Application is designed to provide a Controller for each use case.
for example a Controller is like this:
public class AdminLocaleController extends AbstractController {
private static final long serialVersionUID = -6266455088438602574L;
private static Logger logger = Logger.getLogger(AdminLocaleController.class);
private List<Prodotto> prodotti;
#Override
public String execute() {
prodotti = initializeAdminLocaleView();
return "success";
}
public List<Prodotto> getProdotti() {
return prodotti;
}
public void setProdotti(List<Prodotto> prodotti) {
this.prodotti = prodotti;
}
public static List<Prodotto> initializeAdminLocaleView() {
logger.info("Recupero lista di prodotti da ordinare");
DBController dbController = new DBControllerImpl();
return dbController.getProdottiDaOrdinare();
}
}
and the WSManager class makes a call to the initializeAdminLocaleView(), just like this:
/* AdminLocaleController */
public List<Prodotto> initializeAdminLocaleView(){
return AdminLocaleController.initializeAdminLocaleView();
}
I would create a Web Service in Eclipse providing that service class.
If I'm doing something wrong I ask you the proper way to extend the web application to a web service.
Otherwise, my matter is if I have to (and how to) manage parameters and attributes between Views (jsp) and Controllers.
Finally I have some Controllers (each of these implement SessionAware) which process data and store returned object in Session (for example a LoginController which saves a User bean in request session). Deeper, my question is how I should manage Web App's session stored attributes in case of a Web Service. If I have method calls in WSManager which passes a User bean as parameters, how could I obtain it from a session. Or simply, do I have necessity of obtaining something from a session from a Web Service perspective?
I'm sure I've written a confusionary question, but confusionary is my state of mind at this point too.

Dynamic Web Service URL with MonoTouch

I have an app written using MonoTouch that relies on a Web Services URL backend. I need the ability to set the URL of this backend dynamically at run time from within the app (or from within it's settings).
I've read this article on CodeProject that describes setting URL dynamically:
http://www.codeproject.com/Articles/12317/How-to-make-your-Web-Reference-proxy-URL-dynamic#_rating
But I can't find this option in MonoDevelop.
I've tried altering the Url property of my service, but it appears there is more to it than that. (Specifically the "references.cs" file added by the web service seems to also have the URL hard coded in various attributes).
Any help much appreciated.
Thanks!
--scotru
When Mono generates C# wrapper for SOAP web-service to you, it creates 2 constructors of wrapper. Second one contains URL parameter, which you can use to set proper URL and so switch between web-services.
Example from project, which is in production (file Reference.cs):
public partial class ServicesInfoImplService : System.Web.Services.Protocols.SoapHttpClientProtocol
...
public ServicesInfoImplService() {
this.Url = "<DEFAULT_URL>";
}
public ServicesInfoImplService(string url) {
this.Url = url;
}
...

Unable to deploy ejb-based WSDL web-service in Glassfish 3

I'm trying to deploy a weeb-service, generated from an EJB into glassfish, but, for some reason, my web service is never visible in Glassfish. The web-service is defined from an EJB interface as follows :
#Remote
#WebService
public interface TemplateEJBRemote {
public abstract #WebResult(name="found") Template find(#WebParam(name="templateId", mode=Mode.IN) Long id);
}
This EJB interface has a Local implementation :
#Local
#Stateless
public class TemplateEJBImpl implements TemplateEJBRemote {
#PersistenceContext(unitName=NamingConstants.PERSISTENCE_CONTEXT)
private EntityManager entityManager;
#Override
public Template find(Long id) {
return entityManager.find(Template.class, id);
}
}
And they're both defined in a war module, which an ear module sends to Glassfish.
Those module produce correctly looking artefacts, including an ear with the correct application.xml :
<application xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/application_6.xsd"
version="6">
<description>This is the project that will deliver a full usable
EAR including all delivered components. All the project
dependencies here will be included in this</description>
<display-name>my-ear</display-name>
<module>
<web>
<web-uri>my-war-0.0.1-SNAPSHOT.war</web-uri>
<context-root>/my-war</context-root>
</web>
</module>
</application>
When deployed in Glassfish, all infos I can get is
E:\java-ext\glassfish3>bin\asadmin list-components --subcomponents
my-ear-0.0.1-SNAPSHOT <ear, ejb, webservices, web>
my-war-0.0.1-SNAPSHOT.war <WebModule>
Command list-components executed successfully.
it seems to me that, were my web-service really deployed, it would appear below my war submodule, no ?
If not, what can I do to ensure my web-service is correctly defined and deployed ?
[UPDATE 1] In order to give some more informations, i created a smaller web-service endpoint, the infamous Hello world, coded as such :
#WebService
public class Hello {
public String hello(String world) {
return "Salut, "+world+" !";
}
}
using this definition, it is a perfect Glassfiosh web-service :
But, as soon as I make it a bean, as such :
#WebService
#Stateless
public class Hello {
public String hello(String world) {
return "Salut, "+world+" !";
}
}
Things become a little different :
However, as log files told me, HelloService is still present :
[#|2011-03-31T17:55:55.059+0200|INFO|glassfish3.1|javax.enterprise.webservices.org.glassfish.webservices|_ThreadID=339;_ThreadName=Thread-1;|WS00019: EJB Endpoint deployed
autocat-ear-0.0.1-SNAPSHOT listening at address at http://perigee-567125f:8080/HelloService/Hello|#]
I tried to apply the same logic to my initial bean, but with an infortunate result (a 404 error, of course). So I guess there is another issue hidden beneath. But which on ? I can't have any idea.
[UPDATE 2] To make things clear, the EJb I try to deploy is not visible as a web-service in Glassfish console, and its URL can't be pinged by any web client.
I'm looking at my copy of "EJB 3 In Action" and it says:
"A careful look at the code reveals that the #WebService endpoint interface looks similar to the remote interface. You might be tempted to mark the same interface as both a web service and a remote interface, like this:
#WebService
#Remote
public interface PlaceBid {
public Long addBid(String bidderID, Long itemID, Double dibPrice);
}
Unfortunately, although some vendors allow this as an extension, this is not part of the specification, and code that uses this particular attribute combination won't be portable."
You're going to have to remove the #Remote
You need to do some more troubleshooting. Have a look at the logs in glassfish3/glassfish/domains/domain1/logs. Or if you have standalone or cluster nodes look in glassfish3/glassfish/nodes/<nodename>/<instancename>/logs.
Also, log into the admin page "http://localhost:4848", default username is admin, default password is adminadmin. On the left there is a tree, find Applications, then your Ear should be listed there. Click it and you'll see a list of modules and components. If your web service is listed there you can click View Endpoint. There is a built-in tester, and you can get the wsdl URL there too.
update 1:
You don't have any #WebMethod(operationName = "blah) on your hello(). Maybe if there are no WebMethods GlassFish decides it's not worth making your web service available.
update 2: More complete example of how my web service is put together inside the ear. I'm pretty sure you don't have to separate the #WebService and #Stateless classes, but I like it that way because it feels cleaner and seems to separate the concerns.
war:
SomePojo.java:
#WebService(targetNamespace="blah.com")
public class SomePojo {
#EJB
private BlahSessionLocal blahSession;
#WebMethod(operationName = "hello")
public String hello(#WebParam(name = "user_id") Integer userId) throws Exception {
return blahSession.hello(userId);
}
}
ejb jar:
BlahSessionLocal.java
#Local
public interface BlahSessionLocal {
String hello(Integer userId);
}
BlahSessionBean.java
#Stateless(mappedName = "BlahSession")
public class BlahSessionBean implements BlahSessionLocal {
public String hello(Integer userId) {
return "hello user " + userId);
}
}