I need to wash some testdata and want to write to a file only when I get HTTP 500 in response. I also get 504 and 502 when running the washing job.
I tried this but it does not write to the file:
val writer4: PrintWriter = {
val fos = new java.io.FileOutputStream("pasienter_feiler.txt")
new java.io.PrintWriter(fos, true)}
.exec((session: io.gatling.core.session.Session) => {
if (session.status == 500) {
writer4.println(session.attributes("identifier"))
}
session
})
First need separated all != 500 .check(status.not(500))
And add FileAppender to your logback-test.xml
<appender name="FILE" class="ch.qos.logback.core.FileAppender">
<file> logs.txt </file>
<append>true</append>
<encoder>
<pattern>%-4relative [%thread] %-5level %logger{35} - %msg%n</pattern>
</encoder>
</appender>
<root level="debug">
<appender-ref ref="FILE" />
</root>
Related
I have an ASP.NET WebAPI (v2) controller action that has the following general structure:
[HttpPost]
public HttpResponseMessage Post(UserDTO model)
{
try {
// do something
}
catch (Exception ex)
{
var error = new {
errorMessage = ex.Message,
userId = 123,
// some other simple data
};
return Request.CreateResponse(HttpStatusCode.BadRequest, error);
}
return Request.CreateResponse(HttpStatusCode.OK, model);
}
When I run this on my local development server (IIS Express) and an error is thrown, I get the expected JSON payload back.
{
config: {...},
data: {
errorMessage: "User invalid",
userId: 123,
...
},
status: 400,
statusText: "Bad Request"
}
When I run the same code/data on the remote/production server (IIS 8.5), all I get back is:
{
config: {...},
data: "Bad Request,
status: 400,
statusText: "Bad Request"
}
The custom data payload is lost/stripped away from the response. This appears to be related to the HttpStatusCode used in the Request.CreateResponse() call as if I change HttpStatusCode.BadRequest to HttpStatusCode.OK then the custom data payload is downloaded.
As I test, I tried changing the return to Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState); but the results were the same, i.e. the data was returned as a simple "Bad Request" string.
For reference, the API is being called by an AngularJS $http.post() call.
Why is the change in HttpStatusCode changing the response payload on the production server but not locally? Any help would be much appreciated.
It turns out this was down to the following section in Web.config
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="403" />
<error statusCode="403" responseMode="ExecuteURL"
path="/Error/AccessDenied" />
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL"
path="/Error/NotFound" />
<remove statusCode="500" />
<error statusCode="500" responseMode="ExecuteURL"
path="/Error/ApplicationError" />
</httpErrors>
</system.webServer>
It was 'odd' because these pages were not being returned by the API call, but with their removal, the API call returned the correct payload - presumably the HttpStatusCode.BadRequest was being intercepted by an error handler somewhere hence losing the original response data?
With these handlers I removed, I resorted to using the Application_Error handler in Global.asax as described by ubik404 here.
There may well be a better/alternative way to achieve the same result, but this seems to work.
You need to remove existingResponse="Replace", I just had the same issue and that solved it for me. The default value is Auto.
Your answer lead me to find the real problem, so thanks! :)
Documentation
I have a Single Page Application with a webClient and a webAPI. When I go to a view which has a table, my table is not being updated. Actually the API is only being called once upon startup of application even though it is suppose to be called each time, or what I expected to happen.
Service Code -
function getPagedResource(baseResource, pageIndex, pageSize) {
var resource = baseResource;
resource += (arguments.length == 3) ? buildPagingUri(pageIndex, pageSize) : '';
return $http.get(serviceBase + resource).then(function (response) {
var accounts = response.data;
extendAccounts(accounts);
return {
totalRecords: parseInt(response.headers('X-InlineCount')),
results: accounts
};
});
}
factory.getAccountsSummary = function (pageIndex, pageSize) {
return getPagedResource('getAccounts', pageIndex, pageSize);
};
API Controller -
[Route("getAccounts")]
[EnableQuery]
public HttpResponseMessage GetAccounts()
{
int totalRecords;
var accountsSummary = AccountRepository.GetAllAccounts(out totalRecords);
HttpContext.Current.Response.Headers.Add("X-InlineCount", totalRecords.ToString());
return Request.CreateResponse(HttpStatusCode.OK, accountsSummary);
}
I can trace it to the service, but it will not hit a break point in the controller.
I added this to my web.config file for the REST API project and now it works as I need it -
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Cache-Control" value="no-cache, no-store, must-revalidate" />
<!-- HTTP 1.1. -->
<add name="Pragma" value="no-cache" />
<!-- HTTP 1.0. -->
<add name="Expires" value="0" />
<!-- Proxies. -->
</customHeaders>
</httpProtocol>
</system.webServer>
Thanks everybody for pointing me in the right direction!
I suspect the REST service response is getting cached in your browser on first call. So on REST service side add headers in response not to cache it or in your request add some additional changeable parameter(like time stamp) to ensure browser will not pick up the response form cache.
I'm trying to create a response to a REST web service call in a CXFRS Camel route, but no matter what I do the response to the client is always the same 200, not 201. Here's my route:
<route id="front-end">
<from uri="cxfrs:bean:myService" />
<setBody>
<constant>Will do...</constant>
</setBody>
<setHeader headerName="CamelHttpResponseCode">
<constant>201</constant>
</setHeader>
<setHeader headerName="Content-Type">
<constant>more/blah</constant>
</setHeader>
</route>
The body is returned but the response code and content type are ignored. What am I doing wrong?
Thanks,
Matt
Basically camel-cxfrs overwrites any headers set in exchange when it converts the exchange to actual HTTP response
See here:
exchange.getOut().setHeaders(binding.bindResponseHeadersToCamelHeaders(response, exchange));
And this happens because DefaultCxfRsBinding expects a jaxrs Response as a parameter.
So to fix the issue you either override DefaultCxfRsBinding with custom one in order to copy headers from exchange.getIn().
<cxf:rsServer id="MyService" address="/myAddress">
<cxf:binding><bean class="MyCustomCxfRsBinding" /></cxf:binding>
<cxf:serviceBeans>
<ref bean="myResourceWithJSR311Annotations" />
</cxf:serviceBeans>
</cxf:rsServer>
Or make your camel route to return a jaxrs Response with headers instead of setting headers in the rout or in camel processors. Something
class HttpHeaderProcessor implements Processor
{
#Override
public void process(Exchange exchange) throws Exception
{
Message message = exchange.getIn();
Response response = convertToJaxRs(message);
exchange.getIn().setBody(response);
exchange.getIn().setHeader("Test", "Won't work unless DefaultCxfRsBinding is not replaced with a custom one");
}
private Response convertToJaxRs(Message message)
{
ResponseBuilder jaxrsResponseBuilder = Response.ok(message.getBody(), MediaType.APPLICATION_XML);
jaxrsResponseBuilder.header("header1", "you'll see this");
Response response = jaxrsResponseBuilder.build();
return response;
}
}
For your sample:
<route id="front-end">
<from uri="cxfrs:bean:myService" />
<setBody>
set it to Response.ok(your message).header(x, y).build()
</setBody>
You can also use a Service bean returning a jaxrs.Response with headders
<route id="front-end">
<from uri="cxfrs:bean:myService" />
<bean ref="myServiceImpl">
I am having trouble getting my Camel route to successfully POST a message to an existing RESTful web service. I have tried all the examples in the camel cxf package but none of them produce a web service call (they are consumers). I would love to find a working example for this so I can step through the CxfRsProducer execution to hopefully discover why my route is not posting correctly to the web service.
Here is my RouteBuilder's configuration:
public void configure()
{
//errorHandler(deadLetterChannel(String.format("file:%s/../errors", sourceFolder)).useOriginalMessage().retriesExhaustedLogLevel(LoggingLevel.DEBUG));
errorHandler(loggingErrorHandler());
/*
* JMS to WS route for some of the events broadcast to the jms topic
*/
Endpoint eventTopic = getContext().getEndpoint(String.format("activemq:topic:%s?clientId=%s&durableSubscriptionName=%s", eventTopicName, durableClientId, durableSubscriptionName));
from(eventTopic) // listening on the jms topic
.process(eventProcessor) // translate event into a Notifications object (JAX-RS annotated class)
.choice() // gracefully end the route if there is no translator for the event type
.when(header("hasTranslator").isEqualTo(false)).stop() // no translator stops the route
.otherwise() // send the notification to the web service
.to("cxfrs:bean:rsClient");
}
Here is the rsClientBean:
<cxf:rsClient id="rsClient"
address="http://localhost/ws"
serviceClass="com.foo.notifications.NotificationsResource"
loggingFeatureEnabled="true" />
I'm pretty new to REST and I don't really understand what the serviceClass does for the rsClient because it looks to me like the definition of the exposed web service on the server.
The NotificationsResource class:
#Path("/notifications/")
public class NotificationManagerResource
{
// NOTE: The instance member variables will not be available to the
// Camel Exchange. They must be used as method parameters for them to
// be made available
#Context
private UriInfo uriInfo;
public NotificationManagerResource()
{
}
#POST
public Response postNotification(Notifications notifications)
{
return null;
}
}
The processor creates a Notifications object to put in the exechange message body:
private class EventProcessor implements Processor
{
#Override
public void process(Exchange exchange) throws Exception
{
Message in = exchange.getIn();
IEvent event = (IEvent) in.getBody();
Notifications notifications = null;
in.setHeader("hasTranslator", false);
in.setHeader("Content-Type", "application/xml");
in.setHeader(CxfConstants.CAMEL_CXF_RS_USING_HTTP_API, false);
// I've tried using the HTTP API as 'true', and that results in a 405 error instead of the null ptr.
INotificationTranslator translator = findTranslator(event);
if (translator != null)
{
notifications = translator.build(event);
in.setHeader("hasTranslator", true);
}
// replace the IEvent in the body with the translation
in.setBody(notifications);
exchange.setOut(in);
}
}
The Notifications class is annotated with JAXB for serialization
#XmlRootElement(name = "ArrayOfnotification")
#XmlType
public class Notifications
{
private List<Notification> notifications = new ArrayList<>();
#XmlElement(name="notification")
public List<Notification> getNotifications()
{
return notifications;
}
public void setNotifications(List<Notification> notifications)
{
this.notifications = notifications;
}
public void addNotification(Notification notification)
{
this.notifications.add(notification);
}
}
The error that is returned from the web service:
Exchange
---------------------------------------------------------------------------------------------------------------------------------------
Exchange[
Id ID-PWY-EHANSEN-01-62376-1407805689371-0-50
ExchangePattern InOnly
Headers {breadcrumbId=ID:EHANSEN-01-62388-1407805714469-3:1:1:1:47, CamelCxfRsUsingHttpAPI=false, CamelRedelivered=false, CamelRedeliveryCounter=0, Content-Type=application/xml, hasTranslator=true, JMSCorrelationID=null, JMSDeliveryMode=2, JMSDestination=topic://SysManEvents, JMSExpiration=1407805812574, JMSMessageID=ID:EHANSEN-01-62388-1407805714469-3:1:1:1:47, JMSPriority=4, JMSRedelivered=false, JMSReplyTo=null, JMSTimestamp=1407805782574, JMSType=null, JMSXGroupID=null, JMSXUserID=null}
BodyType com.ehansen.notification.types.v2.Notifications
Body <?xml version="1.0" encoding="UTF-8"?><ArrayOfnotification xmlns="http://schemas.datacontract.org/2004/07/ehansen.Notifications.Dto"> <notification> <causeType>EVENT_NAME</causeType> <causeValue>DeviceEvent</causeValue> <details> <notificationDetail> <name>BUSY</name> <value>false</value> <unit>boolean</unit> </notificationDetail> <notificationDetail> <name>DESCRIPTION</name> <value>Software Computer UPS Unit</value> <unit>name</unit> </notificationDetail> <notificationDetail> <name>DEVICE_NUMBER</name> <value>1</value> <unit>number</unit> </notificationDetail> <notificationDetail> <name>DEVICE_SUB_TYPE</name> <value>1</value> <unit>type</unit> </notificationDetail> <notificationDetail> <name>DEVICE_TYPE</name> <value>UPS</value> <unit>type</unit> </notificationDetail> <notificationDetail> <name>FAULTED</name> <value>false</value> <unit>boolean</unit> </notificationDetail> <notificationDetail> <name>RESPONDING</name> <value>true</value> <unit>boolean</unit> </notificationDetail> <notificationDetail> <name>STORAGE_UNIT_NUMBER</name> <value>1</value> <unit>number</unit> </notificationDetail> </details> <sourceType>DEVICE_ID</sourceType> <sourceValue>1:UPS:1</sourceValue> <time>2014-08-11T18:09:42.571-07:00</time> </notification></ArrayOfnotification>
]
Stacktrace
---------------------------------------------------------------------------------------------------------------------------------------
java.lang.NullPointerException
at java.lang.Class.searchMethods(Class.java:2670)
at java.lang.Class.getMethod0(Class.java:2694)
at java.lang.Class.getMethod(Class.java:1622)
at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.findRightMethod(CxfRsProducer.java:266)
at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.invokeProxyClient(CxfRsProducer.java:222)
at org.apache.camel.component.cxf.jaxrs.CxfRsProducer.process(CxfRsProducer.java:90)
at org.apache.camel.util.AsyncProcessorConverterHelper$ProcessorToAsyncProcessorBridge.process(AsyncProcessorConverterHelper.java:61)
at org.apache.camel.processor.SendProcessor$2.doInAsyncProducer(SendProcessor.java:143)
at org.apache.camel.impl.ProducerCache.doInAsyncProducer(ProducerCache.java:307)
at org.apache.camel.processor.SendProcessor.process(SendProcessor.java:138)
It is the methodName parameter in the following method from CxfRsProducer class that is null... so I assume there is something about my rsClient that is not configured correctly.
private Method findRightMethod(List<Class<?>> resourceClasses, String methodName, Class<?>[] parameterTypes) throws NoSuchMethodException {
Method answer = null;
for (Class<?> clazz : resourceClasses) {
try {
answer = clazz.getMethod(methodName, parameterTypes);
} catch (NoSuchMethodException ex) {
// keep looking
} catch (SecurityException ex) {
// keep looking
}
if (answer != null) {
return answer;
}
}
throw new NoSuchMethodException("Cannot find method with name: " + methodName + " having parameters: " + arrayToString(parameterTypes));
}
Thanks for any help anyone can provide!
The serviceClass is a JAX-RS annotated Java class that defines the operations of a REST web service.
When configuring a CXF REST client, you must specify and address and a serviceClass. By inspecting the annotations found on the serviceClass, the CXF client proxy knows which REST operations are supposed to be available on the REST service published on the specified address.
So in your case, you need to add in.setHeader.setHeader(CxfConstants.OPERATION_NAME, "postNotification"); to the EventProcessor to tell camel which method of the service class you want to call.
Alright then. Here is the camel configuration xml file.
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://w3.org/2001/XMLSchema-instance"
xmlns:cxf="http://camel.apache.org/schema/cxf"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/cxf
http://camel.apache.org/schema/cxf/camel-cxf.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
>
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<bean id="helloBean" class="com.examples.camel.cxf.rest.resource.HelloWorldResource" />
<cxf:rsServer id="helloServer" address="/helloapp" loggingFeatureEnabled="true">
<cxf:serviceBeans>
<ref bean="helloBean" />
</cxf:serviceBeans>
<cxf:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider" />
</cxf:providers>
</cxf:rsServer>
<camelContext id="context" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="cxfrs:bean:helloServer />
<log message="Processing CXF route....http method ${header.CamelHttpMethod}" />
<log message="Processing CXF route....path is ${header.CamelHttpPath}" />
<log message="Processing CXF route....body is ${body}" />
<choice>
<when>
<simple>${header.operationName} == 'sayHello'</simple>
<to uri="direct:invokeSayHello" />
</when>
<when>
<simple>${header.operationName} == 'greet'</simple>
<to uri="direct:invokeGreet" />
</when>
</choice>
</route>
<route id="invokeSayHello">
<from uri="direct:invokeSayHello" />
<bean ref="helloBean" method="sayHello" />
</route>
<route id="invokeGreet">
<from uri="direct:invokeGreet" />
<bean ref="helloBean" method="greet" />
</route>
</camelContext>
</beans>
The actual resource implementation class looks like below.
package com.examples.camel.cxf.rest.resource;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
public class HelloWorldResource implements HelloWorldIntf
{
public Response greet() {
return Response.status(Status.OK).
entity("Hi There!!").
build();
}
public Response sayHello(String input) {
Hello hello = new Hello();
hello.setHello("Hello");
hello.setName("Default User");
if(input != null)
hello.setName(input);
return Response.
status(Status.OK).
entity(hello).
build();
}
}
class Hello {
private String hello;
private String name;
public String getHello() { return hello; }
public void setHello(String hello) { this.hello = hello; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
You don't need , and cxf:rsServer> to be provided.
The tag alone will suffice to handle a web service request and invoke a route.
In case you have both and the then invoking the former will not help you in executing a route. For a route to get invoked, the request must reach to the address published by .
Hope this helps.
I am trying to do "SAML 2.0 Bearer Assertion for SalesForce"
I am getting {"error":"invalid_grant","error_description":"invalid assertion"}
Is there any way to validate bearer assertion at salesforce?
I did following in my code
String environment = "https://login.salesforce.com/services/oauth2/token?saml=MgoTx78aEPRbRaz0CkRqjaqrhP3sCa7w7.Y5wbrpGMNT07zKRYwcNWf0zs";
Map<String, String> map = new HashMap<String, String>();
HttpClient httpclient = new HttpClient();
PostMethod post = new PostMethod(environment);
post.addParameter("grant_type", "urn:ietf:params:oauth:grant-type:saml2-bearer");
post.addParameter("client_assertion", Base64.encode(samlResponse.getBytes()));
post.addParameter("client_assertion_type","urn:ietf:params:oauth:client_assertion_type:saml2-bearer");
post.addParameter("format", "json");
String accessToken= null;
String instanceUrl = null;
try {
httpclient.executeMethod(post);
JSONObject authResponse = new JSONObject(new JSONTokener(new InputStreamReader(post.getResponseBodyAsStream())));
System.out.println(authResponse.toString());
} catch (Exception e) {
e.printStackTrace();
} finally {
post.releaseConnection();
}
I have generated following assertion
<saml:Assertion xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
ID="s2d3a451cf30560ca819118cf5785e722ea6da7b64" IssueInstant="2012-03-06T12:34:13Z"
Version="2.0">
<saml:Issuer>http://localhost:8080/opensso
</saml:Issuer>
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:SignedInfo>
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
<ds:SignatureMethod Algorithm="http://www.w3.org/2000/09/xmldsig#rsa-sha1" />
<ds:Reference URI="#s2d3a451cf30560ca819118cf5785e722ea6da7b64">
<ds:Transforms>
<ds:Transform
Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature" />
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#" />
</ds:Transforms>
<ds:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha1" />
<ds:DigestValue>seHyxsFzsHCs0GaY7usF0DfMV58=
</ds:DigestValue>
</ds:Reference>
</ds:SignedInfo>
<ds:SignatureValue> signature.....</ds:SignatureValue>
<ds:KeyInfo>
<ds:X509Data>
<ds:X509Certificate> certificate.....</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</ds:Signature>
<saml:Subject>
<saml:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:transient"
NameQualifier="http://localhost:8080/opensso" SPNameQualifier="https://saml.salesforce.com">deepakmule</saml:NameID>
<saml:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
<saml:SubjectConfirmationData
NotOnOrAfter="2012-03-06T12:44:13Z"
Recipient="https://login.salesforce.com/?saml=MgoTx78aEPRbRaz0CkRqjaqrhP3sCa7w7.Y5wbrpGMNT07zKRYwcNWf0zs" />
</saml:SubjectConfirmation>
</saml:Subject>
<saml:Conditions NotBefore="2012-03-06T12:34:13Z"
NotOnOrAfter="2012-03-06T12:44:13Z">
<saml:AudienceRestriction>
<saml:Audience>https://saml.salesforce.com</saml:Audience>
</saml:AudienceRestriction>
</saml:Conditions>
<saml:AuthnStatement AuthnInstant="2012-03-06T12:34:13Z"
SessionIndex="s27fb03a2b73bd8dc6846851bed7885b85e1d9ed6f">
<saml:AuthnContext>
<saml:AuthnContextClassRef> urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport
</saml:AuthnContextClassRef>
</saml:AuthnContext>
</saml:AuthnStatement>
<saml:AttributeStatement>
<saml:Attribute Name="userid">
<saml:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">deepakmule</saml:AttributeValue>
</saml:Attribute>
</saml:AttributeStatement>
</saml:Assertion>
Are you trying to use the same IDP as you have configured for SSO for your Org, or are you trying to use the certificate added to a Remote Access application?
If you're trying to use your SSO configuration, then this looks pretty good - I'd check the SAML assertion validator
If you're trying to use the Bearer flow with a Remote Access application, then I'd look at the following
1) The Issuer should be the your Consumer Key from the remote access app ( the oauth client_id )
2) Post to our regular token endpoint
3) Use the salesforce username as the subject
4) Shorten the lifetime of your assertion to a minute