Weblogic JMS consumer - using XPath in selector with quotes - xpath

I'm trying to subscribe to WebLogic JMS messages using selector containing XPath. In WebLogic, it's achieved using 'JMS_BEA_SELECT' function. Something like this:
session.createConsumer(topic, "JMS_BEA_SELECT('xpath', '/Parent/text()') = '123'");
This seem to work, but what if I need to use quotes in the expression? For example, how do I subscribe when my XPath expression is something like this (which is the only way to have namespace-insensitive query):
"//*[local-name()='Parent']/text()";
How do I specify single quotes of the above expression when I call createConsumer(topic, "WHAT GOES HERE?")?
Note that all the following variants didn't work (throw invalid expression exceptions):
"JMS_BEA_SELECT('xpath', '//*[local-name()=\\\"Parent\\\"]/text()') = '123'"
"JMS_BEA_SELECT('xpath', '//*[local-name()=\\\'Parent\\\']/text()') = '123'"
"JMS_BEA_SELECT('xpath', '//*[local-name()=\"Parent\"]/text()') = '123'"
"JMS_BEA_SELECT('xpath', '//*[local-name()=\'Parent\']/text()') = '123'"
EDIT:
Following the suggestion by #better_use_mkstemp, I tried using " and ' encoding. It doesn't throw exceptions, but it also doesn't select the message.
To be clear on the problem I'm having, below is the actual message I have in the queue:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ServiceResponseNotification xmlns="http://www.mywebsite.com/services/types">
<ServiceResponse>
<IsFailure>true</IsFailure>
</ServiceResponse>
<ServiceRequestId>2642697</ServiceRequestId>
</ServiceResponseNotification>
And here's the code fragment:
Hashtable ht = new Hashtable();
ht.put(Context.INITIAL_CONTEXT_FACTORY, "weblogic.jndi.WLInitialContextFactory");
ht.put(Context.PROVIDER_URL, "...");
Context jndiContext = new InitialContext(ht);
ConnectionFactory connectionFactory = (ConnectionFactory)jndiContext.lookup("jms/TestConnectionFactory");
Destination dest = (Destination) jndiContext.lookup("jms/TestJMSQueue");
Connection connection = connectionFactory.createConnection();
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
String sel = "JMS_BEA_SELECT('xpath', '//*[local-name()=&apos;ServiceResponseNotification&apos;]/*[local-name()=&apos;ServiceRequestId&apos;]/text()') = '2642697'";
MessageConsumer consumer = session.createConsumer(dest, sel);
Message m = consumer.receive(1);
if (m != null) {
System.out.println(((TextMessage)m).getText());
} else {
System.out.println("No messages");
}
The above code returns null, no matter if I'm encoding quotes as " or as &apos;. The XPath above, when applied over this XML using regular XPath testing code - works fine.
Another option I thought of - is to use double single-quotes, which, for example, are suggested when using ApacheMQ (I didn't try it, but this doc says it's OK: http://activemq.apache.org/selectors.html). Both below variants don't throw exceptions, but also don't select the message:
"JMS_BEA_SELECT('xpath', '//*[local-name()=''Parent'']/text()') = '123'"
"JMS_BEA_SELECT('xpath', '//*[local-name()=''Parent'']/text()') = '123'"
Any help will be greatly appreciated.
Thank you.

A few things to note:
First your syntax for the variants you tried doesn't match your example that works... is it = or ==? Is it '123'") or '123')" ?
Second there is a fair amount of info out there about this, from the w3 xpath docs:
"To avoid a quotation mark in an expression being interpreted by the XML
processor as terminating the attribute value the quotation mark can be
entered as a character reference (" or &apos;)"
Reference:
http://www.w3.org/TR/xpath/
http://bytes.com/topic/net/answers/178536-how-do-i-escape-single-tick-marks-xpath-queries
http://userscripts.org/topics/127322
http://kushalm.com/the-perils-of-xpath-expressions-specifically-escaping-quotes

Related

JMeter BeanShell Assertion: Getting error when convert String to Long

Have a need to change the value from String to Long in BeanShell Assertion to do verification.
First Apporach
long balance_after_credit = Long.parseLong(String.valueOf("${balance_after_credit_from_db}"));
Second Approach
long balance_after_credit = Long.parseLong(vars.get("balance_after_credit_from_db"));
For instance, consider am getting a value as '743432545' for the variable balance_after_credit_from_db.
Error
org.apache.jorphan.util.JMeterException: Error invoking bsh method: eval Sourced file: inline evaluation of: ``long token_balance_after_credit = Long.parseLong(vars.get("token_balance_after_c . . . '' : Typed variable declaration : Method Invocation Long.parseLong
Weird thing is sometimes, I didn't get errors and the script is getting passed.
Can anyone please point out where am doing a mistake. TIA.
Inlining JMeter variables into code-based scripts is not something recommended so go for 2nd approach.
How do you know that exactly String is being returned from the database all the time? It easily can be any other object type, in fact any of described in the Mapping SQL and Java Types article. The way more safe approach will be something like:
if (vars.getObject("balance_after_credit_from_db") instanceof String) {
long balance_after_credit = Long.parseLong(vars.get("balance_after_credit_from_db"));
}
else {
log.error("Unexpected \balance_after_credit_from_db\" variable type");
log.error("Expected: String, Actual: " + vars.getObject("balance_after_credit_from_db").getClass().getName());
throw new Exception("Unexpected variable type");
}
So in case of non-String JDBC query result you will be able to see the relevant message in jmeter.log file
See Debugging JDBC Sampler Results in JMeter article for more information on working with the entities coming from databases in JMeter tests
The second option
long balance_after_credit = Long.parseLong(vars.get("balance_after_credit_from_db"));
should work, provided you have a valid numeric variable value. For instance try to run something like this:
vars.put("x", "743432545");
long balance_after_credit = Long.parseLong(vars.get("x"));
It won't return any exception.
The problem is when the variable is not defined, has empty or non-numeric value. Then Long.parseLong will throw a NumberFormatException, which you shold catch and make use of (treat it as assertion failure):
String rawValue = vars.get("balance_after_credit_from_db");
long balance_after_credit = Long.MAX_VALUE; // initialize with some unrealistic value
try {
balance_after_credit = Long.parseLong(rawValue);
}
catch(NumberFormatException e) {
Failure = true;
FailureMessage = "Variable does not contain a valid long. It was " + rawValue + " instead";
}

Disallow DTD's while evaluating xpath

I have below code to evaluate xpath expression.
String inputXml = "<?xml version=\"1.0\"?><!DOCTYPE document SYSTEM \"test.dtd\"><Request><Header><Version>1.0</Version></Header></Request>";
String xpath="/Request/Header/Version";
XPathFactory xpf = new net.sf.saxon.xpath.XPathFactoryImpl();
final InputSource is = new InputSource(new StringReader(inputXml));
String version = xpf.newXPath().evaluate(xpath, is);
xpf.newXPath().evaluate throws error as test.dtd couldn't be found. I want to disallow DTD completely. I have been reading about setting SAXParser feature "http://apache.org/xml/features/disallow-doctype-decl" but not sure how to apply in this case or is there any other way to disallow/ignore DTD's.
I'm not quite sure what you want to achieve. If you want this to fail because there is a DTD referenced, then you already seem to be achieving that.
However, if you want to set a property on the XML parser, there are two ways you could achieve it:
(a) Supply a SAXSource rather than an InputSource; initialize the XMLReader in the SAXSource to the XML parser you want to use, and use the XMLReader's setFeature interface to configure it before you pass it to the XPath engine.
(b) Set the Saxon configuration feature http://saxon.sf.net/feature/parserFeature?uri=http://apache.org/xml/features/disallow-doctype-decl (that's a single string with no spaces or newlines) to the value true. You can do this using
xpf.getConfiguration().setConfigurationProperty(featureName, true);

c# stringbuilder tostring double quote issue

I have an issue when converting a string from stringbuilder to string.
The issue is similar to this issue but slightly different:
This is my code simplified:
StringBuilder sb = new StringBuilder();
sb.Append("\"");
sb.Append("Hello World");
sb.Append("\"");
string test = sb.ToString();
Now in the debugger the sb value is:
"Hello World"
In the debugger the test string value is changed to:
\"Hello World\"
When returning the test string value back to the browser the velue is STILL escaped:
\"Hello World\"
I have tried using the string replace:
test = test.Replace("\"", "");
no luck, I tried appending the ASCII character instead of \" and I have also tried a different append
sb.Append('"');
All these with no luck. Can somebody maybe point me in the right direction of why I'm still getting the escape character and how to get rid of it.
Thanks and appreciate any input.
Ok it seems that in WCF the stringBuilder automatically adds escape quotes. This means you can not get away from that. Also I was going about this all wrong. I was trying to return a string where I was supposed to return a serialised JSON object.
I'm not seeing the behavior you describe. Escaping double quotes with the backslash should work. The following snippet of code
var sb = new StringBuilder();
sb.Append("Ed says, ");
sb.Append("\"");
sb.Append("Hello");
sb.Append("\"");
Console.WriteLine(sb.ToString());
foreach (char c in sb.ToString()) Console.Write(c + "-");
Console.ReadKey();
produces
Ed says, "Hello"
E-d- -s-a-y-s-,- -"-H-e-l-l-o-"-
If you are getting actual backslash characters in your final display of the string, that may be getting added by something after the StringBuilder and ToString code.
You can use a verbatim string literal "#" before the string, then enter the quotes twice. This removes the use to use escapes in the string sequence :)
StringBuilder sb = new StringBuilder();
sb.Append(#"""");
sb.Append("Hello World");
sb.Append(#"""");
string test = sb.ToString();
This question and answer thread kept on coming up when searching for the solution.
The confusion, for me, was that the Debugger escaping looks exactly the same as the JSON serializer behaviour that was being applied later when I returned the string to a client. So the code at the top of the thread (and my code) worked correctly.
Once I realised that, I converted the piece of code I was working on return an array (string[] in this case) and store that rather than the original string object. Later the JSONResult serializer then dealt with converting the array correctly.

DisplayTool installation and usage

I am using Velocity 1.7 to format string and I had some trouble with default values. Velocity by itself has no special syntax for case when value is not set and we want to use some another, default value.
By the means of Velocity it looks like:
#if(!${name})Default John#else${name}#end
which is unconveniant for my case.
After googling I've found DisplayTool, according to documentation it will look like:
$display.alt($name,"Default John")
So I added maven dependency but not sure how to add DisplayTool to my method and it is hard to found instructions for this.
Maybe somebody can help with advice or give useful links?..
My method:
public String testVelocity(String url) throws Exception{
Velocity.init();
VelocityContext context = getVelocityContext();//gets simple VelocityContext object
Writer out = new StringWriter();
Velocity.evaluate(context, out, "testing", url);
logger.info("got first results "+out);
return out.toString();
}
When I send
String url = "http://www.test.com?withDefault=$display.alt(\"not null\",\"exampleDefaults\")&truncate=$display.truncate(\"This is a long string.\", 10)";
String result = testVelocity(url);
I get "http://www.test.com?withDefault=$display.alt(\"not null\",\"exampleDefaults\")&truncate=$display.truncate(\"This is a long string.\", 10)" without changes, but should get
"http://www.test.com?withDefault=not null&truncate=This is...
Please tell me what I am missing. Thanks.
The construction of the URL occurs in your Java code, before you invoke Velocity, so Velocity isn't going to evaluate $display.alt(\"not null\",\"exampleDefaults\"). That syntax will be valid only in a Velocity template (which typically have .vm extensions).
In the Java code, there's no need to use the $ notation, you can just call the DisplayTool methods directly. I've not worked with DisplayTool before, but it's probably something like this:
DisplayTool display = new DisplayTool();
String withDefault = display.alt("not null","exampleDefaults");
String truncate = display.truncate("This is a long string.", 10);
String url = "http://www.test.com?"
+ withDefault=" + withDefault
+ "&truncate=" + truncate;
It might be better, though, to call your DisplayTool methods directly from the Velocity template. That's what is shown in the example usage.

Image tag not closing with HTMLAgilityPack

Using the HTMLAgilityPack to write out a new image node, it seems to remove the closing tag of an image, e.g. should be but when you check outer html, has .
string strIMG = "<img src='" + imgPath + "' height='" + pubImg.Height + "px' width='" + pubImg.Width + "px' />";
HtmlNode newNode = HtmlNode.Create(strIMG);
This breaks xhtml.
Telling it to output XML as Micky suggests works, but if you have other reasons not to want XML, try this:
doc.OptionWriteEmptyNodes = true;
Edit 1:Here is how to fix an HTML Agilty Pack document to correctly display image (img) tags:
if (HtmlNode.ElementsFlags.ContainsKey("img"))
{ HtmlNode.ElementsFlags["img"] = HtmlElementFlag.Closed;}
else
{ HtmlNode.ElementsFlags.Add("img", HtmlElementFlag.Closed);}
replace "img" for any other tag to fix them as well (input, select, and option come up frequently). Repeat as needed. Keep in mind that this will produce rather than , because of the HAP bug preventing the "closed" and "empty" flags from being set simultaneously.
Source: Mike Bridge
Original answer:
Having just labored over solutions to this issue, and not finding any sufficient answers (doctype set properly, using Output as XML, Check Syntax, AutoCloseOnEnd, and Write Empty Node options), I was able to solve this with a dirty hack.
This will certainly not solve the issue outright for everyone, but for anyone returning their generated html/xml as a string (EG via a web service), the simple solution is to use fake tags that the agility pack doesn't know to break.
Once you have finished doing everything you need to do on your document, call the following method once for each tag giving you a headache (notable examples being option, input, and img). Immediately after, render your final string and do a simple replace for each tag prefixed with some string (in this case "Fix_", and return your string.
This is only marginally better in my opinion than the regex solution proposed in another question I cannot locate at the moment (something along the lines of )
private void fixHAPUnclosedTags(ref HtmlDocument doc, string tagName, bool hasInnerText = false)
{
HtmlNode tagReplacement = null;
foreach(var tag in doc.DocumentNode.SelectNodes("//"+tagName))
{
tagReplacement = HtmlTextNode.CreateNode("<fix_"+tagName+"></fix_"+tagName+">");
foreach(var attr in tag.Attributes)
{
tagReplacement.SetAttributeValue(attr.Name, attr.Value);
}
if(hasInnerText)//for option tags and other non-empty nodes, the next (text) node will be its inner HTML
{
tagReplacement.InnerHtml = tag.InnerHtml + tag.NextSibling.InnerHtml;
tag.NextSibling.Remove();
}
tag.ParentNode.ReplaceChild(tagReplacement, tag);
}
}
As a note, if I were a betting man I would guess that MikeBridge's answer above inadvertently identifies the source of this bug in the pack - something is causing the closed and empty flags to be mutually exclusive
Additionally, after a bit more digging, I don't appear to be the only one who has taken this approach:
HtmlAgilityPack Drops Option End Tags
Furthermore, in cases where you ONLY need non-empty elements, there is a very simple fix listed in that same question, as well as the HAP codeplex discussion here: This essentially sets the empty flag option listed in Mike Bridge's answer above permanently everywhere.
There is an option to turn on XML output that makes this issue go away.
var htmlDoc = new HtmlDocument();
htmlDoc.OptionOutputAsXml = true;
htmlDoc.LoadHtml(rawHtml);
This seems to be a bug with HtmlAgilityPack. There are many ways to reproduce this, for example:
Debug.WriteLine(HtmlNode.CreateNode("<img id=\"bla\"></img>").OuterHtml);
Outputs malformed HTML. Using the suggested fixes in the other answers does nothing.
HtmlDocument doc = new HtmlDocument();
doc.OptionOutputAsXml = true;
HtmlNode node = doc.CreateElement("x");
node.InnerHtml = "<img id=\"bla\"></img>";
doc.DocumentNode.AppendChild(node);
Debug.WriteLine(doc.DocumentNode.OuterHtml);
Produces malformed XML / XHTML like <x><img id="bla"></x>
I have created a issue in CodePlex for this.

Resources