Is it possible to return a text/plain from Google Cloud Endpoints? - google-app-engine

I want to return just a simple blob of text from Google Cloud Endpoints that would be interpreted by the client as nothing but a text file. Is this possible?
I know it is not possible to return primitives, but can I return an HttpServletResponse and set the content myself or something?

Disclaimer: Not tested, just a braindump.
Cloud Endpoints uses ProtoRPC as the underlying transport, which encodes messages as JSON over the wire. You can't change this behavior. The simplest way to return a text file is to just define a simple message class with one String member for the text file:
public class TextFile {
private String text;
// getText, setText methods ...
}
Then your Endpoints method would look something like this:
#Api(name = "my_api", ...)
public class MyAPI {
#ApiMethod(name = "myapi.returntext", httpMethod = "get)
public TextFile returnText() {
TextFile response = new TextFile;
response.setText(read_text_from_some_source());
return response;
}
}
You'll get a trivial JSON response from this method which should be easy enough to parse the text data out of:
{ "text": "<contents_of_text_dump>" }
The response may have some extra fields such as 'kind' and 'etag' which you can ignore.
Of course the simplest method if you just want to dump out some text is to forget about Endpoints altogether and just set up a GET handler:
public class ReturnText extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");
response.getWriter().write(read_text_from_some_source());
}
}
You can then map this to whatever endpoint url you wish in your web.xml.

Related

Camel - Enrich CSV from FTP with CSV from local disk using Camel Bindy

The goal is to produce a report every hour by comparing two CSV files with
use of Camel 3.0.0. One is located on a FTP server, the other on disk. How to use poll enrich pattern in combination with unmarshalling the CSV on disk with Bindy Dataformat?
Example code (for simplicity the FTP endpoint is replaced by a file endpoint):
#Component
public class EnricherRoute extends RouteBuilder {
#Override
public void configure() {
from("file://data?fileName=part_1.csv&scheduler=quartz2&scheduler.cron=0+0+0/1+*+*+?")
.unmarshal().bindy(BindyType.Csv, Record.class)
.pollEnrich("file://data?fileName=part_2.csv", new ReportAggregationStrategy())
.marshal().bindy(BindyType.Csv, Record.class)
.to("file://reports?fileName=report_${date:now:yyyyMMdd}.csv");
}
}
The problem in this example is that in the ReportAggregationStrategy the resource (coming from data/part_2.csv, see below) is not unmarshalled. How to unmarshal data/part_2.csv as well?
public class ReportAggregationStrategy implements AggregationStrategy {
#Override
public Exchange aggregate(Exchange original, Exchange resource) {
final List<Record> originalRecords = original.getIn().getBody(List.class);
final List<Record> resourceRecords = resource.getIn().getBody(List.class); // Results in errors!
...
}
}
You can wrap enrichment with direct endpoint and do unmarshaling there.
from("file://data?fileName=part_1.csv&scheduler=quartz2&scheduler.cron=0+0+0/1+*+*+?")
.unmarshal().bindy(BindyType.Csv, Record.class)
.enrich("direct:enrich_record", new ReportAggregationStrategy())
.marshal().bindy(BindyType.Csv, Record.class)
.to("file://reports?fileName=report_${date:now:yyyyMMdd}.csv");
from("direct:enrich_record")
.pollEnrich("file://data?fileName=part_2.csv")
.unmarshal().bindy(BindyType.Csv, Record.class);

send a form parameter from Chrome Advanced REST Client

I want to send a form parameter from Chrome Advanced REST Client, however, it comes as null. This my resource class
IKeywordResource.java
#Path("")
public interface IKeywordResource {
#POST
#Path("/upload")
#Consumes("multipart/form-data")
public List<Keyword> uploadKeywords(MultipartFormDataInput uploadFile,
#FormParam("list_format") String listFormat) throws IOException;
}
KeywordResource
public class KeywordResource implements IKeywordResource {
#Inject
public KeywordService keywordService;
#Override
public List<Keyword> uploadKeywords(MultipartFormDataInput uploadFile,
#FormParam("list_format") String listFormat) throws IOException {
return keywordService.upload(uploadFile, listFormat);
}
}
And this is how I send the POST request and define the form parameter.
However, as I said list_format comes as null that I dont know why. I will appreciate for any kind of help
You are trying to map the request payload twice. You can either map all parameters to a MultipartFormDataInput object and retrieve your parameter with uploadFile.getFormDataMap().get("list_format"); or you map each parameter with #FormParam.

How to define correct MediaTypes for ResponseBuilder in ExceptionMapper

I'm facing following problem:
I'm using CXF for REST services. For exception handling I'm using javax.ws.rs.ext.ExceptionMapper and in public Response toResponse(T ex) I want to return some object, for example
class MyObject {
String detail;
}
example implementation of method is similar to
public Response toResponse(T ex) {
MyObject o = new MyObject();
o.detail = "...";
return Response.status(400).entity(o).build();
}
but I'm having problem
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor writeResponseErrorMessage
WARNING: No message body writer has been found for response class RequestError.
Somehow I found that when I specify MediaType
return Response.status(400).entity(o).type("application/json").build();
everything is ok, but I do not know which type client accepts...
Of course I can somewhere store which types client accepts and later use the correct one, but this smells. I'd like to use something nicer.
For example in my CXF endpoint I can specify, using #Produces, what kind of MediaTypes my controller method produces and CXF/Spring select the correct one. I tried it in my ExceptionMapper too, but it doesn't work.
u can do it like this
#Context HttpHeaders headers;
public Response toResponse(Exception e) {
ExceptionEntity ee = new ExceptionEntity(e);
ResponseBuilder rb = Response.status(Response.Status.INTERNAL_SERVER_ERROR);
rb.type(headers.getMediaType());
rb.entity(ee);
Response r = rb.build();
return r;
}
i'm using cxf-rs 2.7.5

How can I add HTTP Request Header to Silverlight RIA Requests

I have a need to pass an HTTP header for each an every RIA Service request being made from a Silverlight app. The value of the header needs to come from the app instance, and not from a cookie. I know this can be accomplished by putting it in the DTOs, but it's not an option because a lot of our service calls use Entities and change sets, so there's no base class to tie into for all requests. So I'm looking for a centralized and safe means to pass something back with each request so the developers do not have to worry with it. A custom HTTP header would work fine, but I don't know how to intercept the outbound request to set it.
Anyone have any ideas I can try?
On the lower level you can add HTTP headers with the help of an IClientMessageInspector. Try starting from this post on SL forum.
The next step depends on your use cases.
If the value of the header must be the same for any method called by the DomainContext, then you may just extend the context using partial class, add a property for the header value and use that property in the inspector.
If you need to pass a different value for each method call, you'd probably need to wrap your DomainContext into another class and add an argument to each method of the context that will accept the header value and pass it to the inspector somehow. Needless to say, without a code-generator this would be hard.
Here's an adapted sample from the SL forum for the first case:
public sealed partial class MyDomainContext
{
public string HeaderValue { get; set; }
partial void OnCreated()
{
WebDomainClient<IMyDomainServiceContract> webDomainClient = (WebDomainClient<IMyDomainServiceContract>)DomainClient;
CustomHeaderEndpointBehavior customHeaderEndpointBehavior = new CustomHeaderEndpointBehavior(this);
webDomainClient.ChannelFactory.Endpoint.Behaviors.Add(customHeaderEndpointBehavior);
}
}
public class CustomHeaderEndpointBehavior : IEndpointBehavior
{
MyDomainContext _Ctx;
public CustomHeaderEndpointBehavior(MyDomainContext ctx)
{
this._Ctx = ctx;
}
public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }
public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime)
{
clientRuntime.MessageInspectors.Add(new CustomHeaderMessageInspector(this._Ctx));
}
public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) { }
public void Validate(ServiceEndpoint endpoint) { }
}
public class CustomHeaderMessageInspector : IClientMessageInspector
{
MyDomainContext _Ctx;
public CustomHeaderMessageInspector(MyDomainContext ctx)
{
this._Ctx = ctx;
}
public void AfterReceiveReply(ref System.ServiceModel.Channels.Message reply, object correlationState) {}
public object BeforeSendRequest(ref System.ServiceModel.Channels.Message request, IClientChannel channel)
{
string myHeaderName = "X-Foo-Bar";
string myheaderValue = this._Ctx.HeaderValue;
HttpRequestMessageProperty property = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name];
property.Headers[myHeaderName] = myheaderValue;
return null;
}
}

how to store these two values(s1&s2) in data store of AppEngine?

I have a Servlet in my AppEngine Application (I am using Eclipse):
public class ServletCheckServlet extends HttpServlet {
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
resp.setContentType("text/plain");
PrintWriter pw=resp.getWriter();
String s1=req.getParameter("username");
String s2=req.getParameter("password");
}
}
My question is, how do I store these two values(s1&s2) in data store of AppEngine?
Entity user = new Entity("User"); // define the entity type
user.setProperty("username", s1); // add some properties
user.setProperty("password", s2);
DatastoreServiceFactory.getDatastoreService().put(user); //save it
Though i would recommend calling these variables something better than s1 & s2 And not saving the password as plain text in favor of users logging into user app. Moreover, GAE has nice User Api to play with.

Resources