MQTT / Camel / Custom header parameters - java

So, the problem:
i need to send some custom value in the header via Apache Camel/MQTT.
Code example:
import java.util.Map;
import org.apache.camel.CamelContext;
import org.apache.camel.Message;
import org.apache.camel.impl.DefaultCamelContext;
public class MQTTEntryPoint {
private static final String BASE = "mqtt:test?host=tcp://ip_address&";
private static final String SUBSCRIBER = BASE + "subscribeTopicName=test2";
private static final String PUBLISHER = BASE + "publishTopicName=test2";
public static void main(String[] args) {
CamelContext camelContext = new DefaultCamelContext();
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
Message message = camelContext.createConsumerTemplate().receive(SUBSCRIBER).getIn();
String body = message.getBody(String.class);
System.out.println(body);
Map<String, Object> headers = message.getHeaders();
for (String key : headers.keySet()) {
System.out.println("Header key: " + key + ", Header value: " + headers.get(key));
}
}
});
thread.start();
camelContext.createProducerTemplate().sendBodyAndHeader(PUBLISHER, "some body value", "headerKey",
"some header value");
}
}
In system out i can see only:
some body value
Header key: CamelMQTTSubscribeTopic, Header value: test2
As you can see, sending of custom header value does not works. What is wrong?

The MQTT protocol AFAIR only supports a single payload without any additional headers.

Related

HP ALM Rest API QCSession 411 Authentication

I am using HP-ALM 12.01 which seems to be stock full of issues. I cannot update to another version at this time.
I am trying to get access to the rest api to upload test results automatically from JUnit. I am using the infrastructure shown here (example application -> Infrastructure). From which, my connection scripts passes base64 encoded login info to authentication-point/authenticate and I am retrieving a valid LWSSO cookie. However, when I use this cookie to connect to rest/site-session to receive my QCSession cookies, I am receiving a 411 Length Required error. I have attempted to hard code the Content-Length into the headers as shown here
public void GetQCSession(){
String qcsessionurl = con.buildUrl("rest/site-session");
Map<String, String> requestHeaders = new HashMap<String, String>();
requestHeaders.put("Content-Type", "application/xml");
requestHeaders.put("Accept", "application/xml");
requestHeaders.put("Content-Length", "0");
try {
Response resp = con.httpPost(qcsessionurl, null, requestHeaders);
con.updateCookies(resp);
System.out.println(resp.getStatusCode());
} catch (Exception e) {
e.printStackTrace();
}
}
This did not work. I have also tried modifying the infrastructure to automatically inject the Content-Length header, as shown here
private void prepareHttpRequest(
HttpURLConnection con,
Map<String, String> headers,
byte[] bytes,
String cookieString) throws IOException {
String contentType = null;
//attach cookie information if such exists
if ((cookieString != null) && !cookieString.isEmpty()) {
con.setRequestProperty("Cookie", cookieString);
}
//send data from headers
if (headers != null) {
//Skip the content-type header - should only be sent
//if you actually have any content to send. see below.
contentType = headers.remove("Content-Type");
Iterator<Entry<String, String>>
headersIterator = headers.entrySet().iterator();
while (headersIterator.hasNext()) {
Entry<String, String> header = headersIterator.next();
con.setRequestProperty(header.getKey(), header.getValue());
}
}
// If there's data to attach to the request, it's handled here.
// Note that if data exists, we take into account previously removed
// content-type.
if ((bytes != null) && (bytes.length > 0)) {
con.setDoOutput(true);
//warning: if you add content-type header then you MUST send
// information or receive error.
//so only do so if you're writing information...
if (contentType != null) {
con.setRequestProperty("Content-Type", contentType);
}
OutputStream out = con.getOutputStream();
out.write(bytes);
out.flush();
out.close();
con.setRequestProperty("Content-Length", Integer.toString(bytes.length));
} else {
con.setRequestProperty("Content-Length", "0");
}
}
which also does not work.
note that setRequestProperty simply does a .set(key, value) to a MessageHeader
Has anyone dealt with this issue before or know how to resolve it?
Note that none of these issues occurs with postman. All 4 cookies are generated after a site-session post.
The code Example from Barney was slightly expanded since it was not adapted for ALM 12.5 setting.
Main difference is, that there are more cookies and cookies are attached to header
Config config = new Config(dataService);
String almURL = "https://" + config.host() + "/qcbin";
client = ClientBuilder.newBuilder().build();
target = client.target(almURL).path("api/authentication/sign-in");
invocationBuilder = target
.request(new String[] {"application/xml"})
.accept(new String[] {"application/xml"});
invocationBuilder.header("Authorization", getEncodedAuthString(config.username(), config.password()));
res = invocationBuilder.post(null);
String qcsessioncookie = res.getCookies().get("QCSession").getValue();
String almusercookie = res.getCookies().get("ALM_USER").getValue();
String xsrftokencookie = res.getCookies().get("XSRF-TOKEN").getValue();
String lswoocookie = res.getCookies().get("LWSSO_COOKIE_KEY").getValue();
/* Get the test-Set Data defect */
String midPoint = "rest/domains/" + config.domain() + "/projects/" + config.project();
target = client.target(almURL).path(midPoint).path("test-sets/1");
invocationBuilder = target
.request(new String[] {"application/xml"})
.accept(new String[] {"application/xml"});
concatenatedHeaderCookieString = "QCSession=" + qcsessioncookie + ";" + "ALM_USER=" + ";" + almusercookie + ";" + "XSRF-TOKEN=" + xsrftokencookie + ";"
+ "LWSSO_COOKIE_KEY=" + lswoocookie;
invocationBuilder.header("Cookie", concatenatedHeaderCookieString);
res = invocationBuilder.get();
The issue is that Java's HttpURLConnection ignores certain properties when manually set. One of these is Content-Length. This is because it automatically sets it itself. However, if you're not sending any data it simply doesn't send it, which ALM is not accepting due its outdated http protocols, as it expects to receive a Content-Length of 0.
To work around this you have to tell java to allow restrticted headers. This is done by running
System.setProperty("sun.net.http.allowRestrictedHeaders", "true");
for more information, look here Why does Content-Length HTTP header field use a value other than the one given in Java code?
POM.xml Dependency
<dependency>
<groupId>org.glassfish.jersey.bundles</groupId>
<artifactId>jaxrs-ri</artifactId>
<version>2.0</version>
</dependency>
Java Code: Login, Get the first defect, Logout
import java.util.Base64;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.client.Invocation;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Cookie;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
public class App {
private static final String almURL = "https://abc.hp.com/qcbin";
private static final String isAuthenticatedPath = "authentication-point/authenticate";
private static final String qcSiteSession = "rest/site-session";
private static final String logoutPath = "authentication-point/logout";
private static String lswoocookie;
private static String qcsessioncookie;
public static String strDomain = "domain";
public static String strProject = "project";
public static String strUserName = "username";
public static String strPassword = "password";
public static Client client;
public static WebTarget target;
public static Invocation.Builder invocationBuilder;
public static Response res;
private static String getEncodedAuthString() {
String auth = strUserName + ":" + strPassword;
byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes());
String authHeader = "Basic " + new String(encodedAuth);
return authHeader;
}
public static void main(String args[]){
client = ClientBuilder.newBuilder().build();
/* Get LWSSO Cookie */
target = client.target(almURL).path(
isAuthenticatedPath);
invocationBuilder = target.request(new String[] { "application/xml" });
invocationBuilder.header("Authorization", getEncodedAuthString());
res = invocationBuilder.get();
lswoocookie = res.getCookies().get("LWSSO_COOKIE_KEY").getValue();
/* Get QCSession Cookie */
target = client.target(almURL).path(qcSiteSession);
invocationBuilder = target
.request();
invocationBuilder.cookie("LWSSO_COOKIE_KEY", lswoocookie);
res = invocationBuilder.post(null);
qcsessioncookie = res.getCookies().get("QCSession").getValue();
/* Get the first defect */
String midPoint = "rest/domains/" + strDomain + "/projects/" + strProject;
target = client.target(almURL).path(midPoint).path("defects/1");
invocationBuilder = target
.request(new String[] { "application/json" });
invocationBuilder.cookie("LWSSO_COOKIE_KEY", lswoocookie);
invocationBuilder.cookie("QCSession", qcsessioncookie);
res = invocationBuilder.get();
/* Logout */
target = client.target(almURL).path(logoutPath);
invocationBuilder = target
.request();
invocationBuilder.cookie("LWSSO_COOKIE_KEY", lswoocookie);
invocationBuilder.cookie("QCSession", qcsessioncookie);
res = invocationBuilder.post(null);
}
}

How to Mock HttpResponse for the Web Service (Using JavaHttpClient)?

I have WebService Call using Java Http Client. Need to do Junit testing using Mockito for the Response of WebService (HttpResponse).
Gson gson = new Gson();
HttpResponse httpResponse= JavaHttpClient.callWebService("URL",object);
String json = EntityUtils.toString(httpResponse.getEntity());
response = gson.fromJson(json, ClassName.class);
log.info("Response: " + new Gson().toJson(response));
How to set the mock values for httpResponse.getEntity() ? and this should be convert to JSON as above
Thanks
Nithyanandan K
Here is some sample MockServer. Modify it for your requirement.
import static org.mockserver.integration.ClientAndServer.startClientAndServer;
import static org.mockserver.model.HttpRequest.request;
import static org.mockserver.model.HttpResponse.response;
import org.mockserver.client.server.MockServerClient;
import org.mockserver.initialize.ExpectationInitializer;
import org.mockserver.model.Header;
import org.mockserver.model.HttpStatusCode;
public class MockServerInitializer implements ExpectationInitializer {
/**
* Standalone mock server
*
* #param args
*/
public static void main(String[] args) {
MockServerClient mockServerClient = startClientAndServer(9999);
defineMockServerBehaviour(mockServerClient);
}
#Override
public void initializeExpectations(MockServerClient mockServerClient) {
defineMockServerBehaviour(mockServerClient);
}
public static void defineMockServerBehaviour(MockServerClient mockServer) {
mockServer.when(
request()
.withMethod("POST")
.withPath("/Sample")
).respond(
response()
.withStatusCode(HttpStatusCode.OK_200.code())
.withHeader(Header.header("Content-Type", "application/xml"))
.withBody("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n" +
"<Response>\n" +
" <responseStatus>OK</responseStatus>\n" +
"</Response>"));
}
}

Woocommerce REST API with scribes-java library returns consumer key param missing error message

Hi guys I am trying to use scribe-java library to access the REST api via http.code looks
package org.scribe.examples;
import java.util.*;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class WooCommerceOauth1Example {
private static final String RESOURCE_URL = "http://WEBSITE.COM/wc-api/v1/orders";
public static void main(String[] args) {
OAuthService service = new ServiceBuilder().provider(OneLeggedApi10.class)
.apiKey("ck_SOME_NUMBER")
.apiSecret("cs_SOME_NUMBER")
.build();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, RESOURCE_URL);
//Since it is a one legged protocol, access token is empty.Right?
service.signRequest(new Token("", ""), request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getCode());
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
}
}
Throws the following error
{"errors":[{"code":"woocommerce_api_authentication_error","message":"oauth_consumer_key parameter is missing"}]}
. Any Ideas why my code is throwing the above error? Note that I have checked the v1 endpoint with http and it returns sensible message back.so basically it is working.
Removing '&' + OAuthEncoder.encode(tokenSecret) from https://github.com/fernandezpablo85/scribe-java/blob/master/src/main/java/org/scribe/services/HMACSha1SignatureService.java#L32 and adding and changed signature type to QueryString and it works now.
I will propose a PR after cleaning.Thanks Pablo. Below is the full code
package org.scribe.builder.api;
import org.scribe.model.Token;
import org.scribe.model.Verb;
public class OneLeggedApi10 extends DefaultApi10a {
#Override
public String getAccessTokenEndpoint() {
return null;
}
#Override
public String getRequestTokenEndpoint() {
return null;
}
#Override
public String getAuthorizationUrl(Token requestToken) {
return null;
}
#Override
public Verb getAccessTokenVerb() {
return Verb.GET;
}
#Override
public Verb getRequestTokenVerb() {
return Verb.GET;
}
}
And the example class
package org.scribe.examples;
import org.scribe.builder.*;
import org.scribe.builder.api.*;
import org.scribe.model.*;
import org.scribe.oauth.*;
public class WooCommerceOauth1Example {
private static final String NETWORK_NAME = "Woocommerce";
private static final String RESOURCE_URL = "http://YOUR_DOMAIN/wc-api/v1/orders/count";
private static final String SCOPE = "*"; //all permissions
public static void main(String[] args) {
OAuthService service = new ServiceBuilder().provider(OneLeggedApi10.class)
.apiKey("API_KEY")
.apiSecret("SECRET_KEY")
.debugStream(System.out)
.signatureType(SignatureType.QueryString)
/*.scope(SCOPE).*/
.build();
System.out.println("=== " + NETWORK_NAME + "'s OAuth Workflow ===");
System.out.println();
// Now let's go and ask for a protected resource!
System.out.println("Now we're going to access a protected resource...");
OAuthRequest request = new OAuthRequest(Verb.GET, RESOURCE_URL);
service.signRequest(new Token("", ""), request);
Response response = request.send();
System.out.println("Got it! Lets see what we found...");
System.out.println();
System.out.println(response.getCode());
System.out.println(response.getBody());
System.out.println();
System.out.println("Thats it man! Go and build something awesome with Scribe! :)");
}
}

Camel does not delete camelLock file after finishing route test

I'm learning Apache camel from the "Camel in Action" book and currently I'm on data transformation. More particularly Content Enricher EIP. I noticed that when I run the code below from the book Camel creates fileName + .camelLock file but it doesn't remove it after finishing route.
Is there something wrong from the code side ? Or it should work like that ?
import java.io.File;
import org.apache.camel.Exchange;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.processor.aggregate.AggregationStrategy;
import org.apache.camel.test.junit4.CamelTestSupport;
import org.junit.Test;
public class OrderToCsvProcessorTest extends CamelTestSupport {
#Test
public void testOrderToCsvProcessor() throws Exception {
// this is the inhouse format we want to transform to CSV
String inhouse = "0000004444000001212320091208 1217#1478#2132";
template.sendBodyAndHeader("direct:start", inhouse, "Date", "20091208");
File file = new File("target/orders/received/report-20091208.csv");
assertTrue("File should exist", file.exists());
// compare the expected file content
String body = context.getTypeConverter().convertTo(String.class, file);
assertEquals("000000444,20091208,000001212,1217,1478,2132\nthis,is,sample,string", body);
}
#Override
protected RouteBuilder createRouteBuilder() throws Exception {
return new RouteBuilder() {
#Override
public void configure() throws Exception {
from("direct:start")
.process(new OrderToCsvProcessor())
.pollEnrich("file://target/input?noop=true",
new AggregationStrategy() {
#Override
public Exchange aggregate( Exchange oldExchange, Exchange newExchange) {
if (newExchange == null) {
return oldExchange;
}
String http = oldExchange.getIn().getBody(String.class);
String ftp = newExchange.getIn().getBody(String.class);
String body = http + "\n" + ftp;
oldExchange.getIn().setBody(body);
return oldExchange;
}
})
.to("file://target/orders/received?fileName=report-${header.Date}.csv");
}
};
}
}
Processor which is used in code:
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
public class OrderToCsvProcessor implements Processor {
public void process(Exchange exchange) throws Exception {
String custom = exchange.getIn().getBody(String.class);
String id = custom.substring(0, 9);
String customerId = custom.substring(10, 19);
String date = custom.substring(20, 29);
String items = custom.substring(30);
String[] itemIds = items.split("#");
StringBuilder csv = new StringBuilder();
csv.append(id.trim());
csv.append(",").append(date.trim());
csv.append(",").append(customerId.trim());
for (String item : itemIds) {
csv.append(",").append(item.trim());
}
exchange.getIn().setBody(csv.toString());
}
}
GenericFileOnCompletion is in charge of deleting the lock file. You need to handoverCompletions in AggregationStrategy just like this.
new AggregationStrategy() {
#Override
public Exchange aggregate( Exchange oldExchange, Exchange newExchange) { if (newExchange == null) {
return oldExchange; }
String http = oldExchange.getIn().getBody(String.class); String ftp = newExchange.getIn().getBody(String.class);
String body = http + "\n" + ftp;
oldExchange.getIn().setBody(body);
newExchange.handoverCompletions(oldExchange);
return oldExchange; } })
The issue is due to the fact that you are pulling a file using pollEnrich with a custom AggregationStrategy.
When using a custom AggregationStrategy in this use case, then certain properties of the aggregated Exchange need to be copied over to the original Exchange for the Camel markerFile to be deleted correctly
So, at the end of your AggregationStrategy you can do :
oldExchange.getProperties().putAll(newExchange.getProperties());
Source : https://access.redhat.com/solutions/2189891

2-legged OAuth and the Gmail atom feed

We're trying to get 2-legged OAuth to work with the Gmail atom feed. We're using the Java library contributed by John Kristian, Praveen Alavilli and Dirk Balfanz. [http://oauth.net/code/] instead of the GData library.
We know we have the correct CONSUMER_KEY and CONSUMER_SECRET, etc. becuase it works with the Contacts feed (http://www.google.com/m8/feeds/contacts/default/full) and have no problems. However with Gmail atom feed it always returns: HTTP/1.1 401 Unauthorized
Any ideas? Should we try a different OAuth framework or does the problem lie on the Google side?
We think we got it working with the OAuth libraries but not with the GData library.
Snippet of code is:
import static net.oauth.OAuth.HMAC_SHA1;
import static net.oauth.OAuth.OAUTH_SIGNATURE_METHOD;
import java.net.URL;
import java.util.List;
import java.util.Map;
import net.oauth.OAuthAccessor;
import net.oauth.OAuthConsumer;
import net.oauth.OAuthMessage;
import net.oauth.ParameterStyle;
import net.oauth.SimpleOAuthValidator;
import net.oauth.client.OAuthClient;
import net.oauth.client.httpclient4.HttpClient4;
/**
* Sample application demonstrating how to do 2-Legged OAuth in the Google Data
* Java Client. See the comments below to learn about the details.
*
*/
public class GmailAtomFeed2LeggedOauth {
public static String CONSUMER_KEY = "test-1001.com";
public static String CONSUMER_SECRET = "zN0ttehR3#lSecr3+";
public static String SCOPE = "https://mail.google.com/mail/feed/atom";
public static String RESOURCE_URL = "https://mail.google.com/mail/feed/atom";
public static String SERVICE_NAME = "mail";
public static String username = "username";
public static boolean debug = true;
public static void main(String[] args) throws Exception {
// This should be passed in as a parameter
String user = username + "#" + CONSUMER_KEY;
OAuthConsumer consumer = new OAuthConsumer(null, CONSUMER_KEY, CONSUMER_SECRET, null);
OAuthAccessor accessor = new OAuthAccessor(consumer);
// HMAC uses the access token secret as a factor,
// and it's a little less compute-intensive than RSA.
accessor.consumer.setProperty(OAUTH_SIGNATURE_METHOD, HMAC_SHA1);
// Gmail only supports an atom feed
URL atomFeedUrl = new URL(SCOPE +"?xoauth_requestor_id=" + user);
System.out.println("=====================================================");
System.out.println("Building new request message...");
OAuthMessage request = accessor.newRequestMessage(OAuthMessage.GET, atomFeedUrl.toString(),null);
if (debug) {
List<Map.Entry<String, String>> params = request.getParameters();
for (Map.Entry<String, String> p : params) {
System.out.println("'" + p.getKey() + "' = <" + p.getValue() + ">");
}
System.out.println("Validating message...");
SimpleOAuthValidator validator=new SimpleOAuthValidator();
validator.validateMessage(request,accessor);
}
OAuthClient client = new OAuthClient(new HttpClient4());
System.out.println("Client invoking request message...");
System.out.println(" request: " + request);
OAuthMessage message = client.invoke(request, ParameterStyle.AUTHORIZATION_HEADER);
System.out.println("=====================================================");
System.out.println(" message: " + message.readBodyAsString());
System.out.println("=====================================================");
}
}
Put the OAuth data in the Authorization header, not on the URI.

Categories

Resources