Java XmlRpc Client POST issue with TCL XMLRPC Server - apache

I am having a simple problem, my Java XMLRPC Client cant seem to properly speak to the XMLRPC Server that is written in TCL
(Using TCL XMLRPC SERVER OPEN SOURCE implementation)
Summary: XMLRPC Clients in TCL/Python etc, can/do send/receive messages to the TCL XMLRPC Server, but my Java XMLRPC client doenst seem to work.
Java Client Side Code:
/*
* try's, catches, comments removed to show code-flow w/ out mess.
* host/port/target all same as whats set in Python
*/
//show imports / package used, this is using apache's xmlrpc v3.1.3
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
//... host and port are the same as whats used in working tcl/python clients. (remoteHostName / 5555)
//... method is the same as well, 'fooBar123', and args is just 1 string passed to it.
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
target = "RPC2";
String targetUrl = "http://"+host+":"+port+"/" + target;
TestNgUtil.ReportInfo("config.SetServerUrl("+targetUrl+")");
config.setServerURL(new URL(targetUrl));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
String result = null;
/*
* This Result Never Returns from TCL XMLRPC Server
*/
result = (String) client.execute(command, params);
TCL Server's Debug ERROR Response to Java:
//(notice unlike Python example below, no proper Header, Content-Type, etc)
TCL Server Side of the Java Error
in serveOnce: addr: 10.21.69.13
in serveOnce: port: 64522
Unknown type: fooBar123</value></param></params>
bgerror failed to handle background error.
Original error:
Error in bgerror: can't read "xmlcall": no such variable**
Python example works, however, also note I print out the XML-debug to look at successful requests:
However, If I attempt to use the TCL client, or even a simple Python XMLRPC client, it works.
I even use Python to print out the XMLRPC request:
(from Python client, nothing fancy, )
import xmlrpclib
server_url = "http://remoteHostName:5555";
server = xmlrpclib.Server(server_url, verbose=True);
result = server.hello('hello world')
## DEBUG INFO PRINTED FROM REQUEST POST ##
send: "POST /RPC2 HTTP/1.1\r\nHost: remoteHostName:5555\r\nAccept-Encoding: gzip\r\nUser-Agent: xmlrpclib.py/1.0.1 (by www.pythonware.com)\r\nContent-Type: text/xml\r\nContent-Length: 160\r\n\r\n<?xml version='1.0'?>\n<methodCall>\n<methodName>hello</methodName>\n<params>\n<param>\n<value><string>hello world</string></value>\n</param>\n</params>\n</methodCall>\n"
reply: 'HTTP/1.1 200 OK\n'
header: Content-Type: text/xml
header: Content-length: 162
body: '<?xml version="1.0"?>\n<methodResponse>\n\t<params>\n\t\t<param>\n\t\t\t<value> <string>hello(hello world) yaaaah?!</string></value>\n\t\t</param>\n\t</params>\n</methodResponse>\n'
TCL Server's Debug/Response to Python, before pushing back proper response:
send: "POST /RPC2 HTTP/1.1
Host: remoteHostName:5555
Accept-Encoding: gzip
User-Agent: xmlrpclib.py/1.0.1 (by www.pythonware.com)
Content-Type: text/xml
Content-Length: 156
here's the TCL XMLRPC Server code for hello( arg ), works for tcl, python, not java. (java client configuration issue probably)
#using the TCL XMLRPC Server ( http://sourceforge.net/projects/xmlrpctcl/ )
package require xmlrpc
xmlrpc::serv 5555
proc hello { world } {
puts "IN HELLO WORLD!"
set res "hello(${world}) yaaaah?!"
return [list string $res]
}
vwait forever
I appreciate any pointers, I've gone so far to attempt to use Java or Python with embedded TCL interpretters to avoid this, but because of the large amount of TCL that this application has to use, source, and share, I have to get a TCL XMLRPC server up and working.
I've also attempted to use the webservices httpd with XMLRPC, but did not have much sucess even with getting it to work with tcl/python clients.
Killed a whole weekend on this already.
Thanks for reading, and any pointers/help.
SOLUTION FOUND (POSTED HERE)
the problem boils down to the XML of the old tcl xmlrpc server not including on the data types. They're implied, so in order to get apache's XMLRPC client to send the implied data types around strings, just implement the 'custom data type' to put the tag back.
CODE IS HERE:
import java.net.URL;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.common.TypeFactoryImpl;
import org.apache.xmlrpc.common.XmlRpcController;
import org.apache.xmlrpc.common.XmlRpcStreamConfig;
import org.apache.xmlrpc.serializer.StringSerializer;
import org.apache.xmlrpc.serializer.TypeSerializer;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
public class XMLRPCClient {
public static void main(String[] argv) throws Exception {
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://127.0.0.1:6800/rpc"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
client.setTypeFactory(new MyTypeFactoryImpl(client));
Object[] params = new Object[] {
new String[] { "http://www.google.com" }
};
String result = (String)client.execute("aria2.addUri", params);
}
static private class MyStringSerializer extends StringSerializer {
public void write(ContentHandler pHandler, Object pObject)
throws SAXException {
// Write <string> tag explicitly
write(pHandler, STRING_TAG, pObject.toString());
}
}
static private class MyTypeFactoryImpl extends TypeFactoryImpl {
public MyTypeFactoryImpl(XmlRpcController pController) {
super(pController);
}
public TypeSerializer getSerializer(XmlRpcStreamConfig pConfig, Object pObject) throws SAXException {
if(pObject instanceof String) {
return new MyStringSerializer();
} else {
return super.getSerializer(pConfig, pObject);
}
}
}
}

The problem boils down to the XML of the old tcl XMLRPC server not including on the data types. They're implied, so in order to get Apache's XMLRPC client to send the implied data types around strings just implement the 'custom data type' to put the tag back.
import java.net.URL;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
import org.apache.xmlrpc.common.TypeFactoryImpl;
import org.apache.xmlrpc.common.XmlRpcController;
import org.apache.xmlrpc.common.XmlRpcStreamConfig;
import org.apache.xmlrpc.serializer.StringSerializer;
import org.apache.xmlrpc.serializer.TypeSerializer;
import org.xml.sax.ContentHandler;
import org.xml.sax.SAXException;
public class XMLRPCClient {
public static void main(String[] argv) throws Exception {
XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
config.setServerURL(new URL("http://127.0.0.1:6800/rpc"));
XmlRpcClient client = new XmlRpcClient();
client.setConfig(config);
client.setTypeFactory(new MyTypeFactoryImpl(client));
Object[] params = new Object[] {
new String[] { "http://www.google.com" }
};
String result = (String)client.execute("aria2.addUri", params);
}
static private class MyStringSerializer extends StringSerializer {
public void write(ContentHandler pHandler, Object pObject)
throws SAXException {
// Write <string> tag explicitly
write(pHandler, STRING_TAG, pObject.toString());
}
}
static private class MyTypeFactoryImpl extends TypeFactoryImpl {
public MyTypeFactoryImpl(XmlRpcController pController) {
super(pController);
}
public TypeSerializer getSerializer(XmlRpcStreamConfig pConfig, Object pObject) throws SAXException {
if(pObject instanceof String) {
return new MyStringSerializer();
} else {
return super.getSerializer(pConfig, pObject);
}
}
}
}

Related

How to use Google translate for free? Maybe you have some analogs [duplicate]

If I pass a string (either in English or Arabic) as an input to the Google Translate API, it should translate it into the corresponding other language and give the translated string to me.
I read the same case in a forum but it was very hard to implement for me.
I need the translator without any buttons and if I give the input string it should automatically translate the value and give the output.
Can you help out?
You can use google script which has FREE translate API. All you need is a common google account and do these THREE EASY STEPS.
1) Create new script with such code on google script:
var mock = {
parameter:{
q:'hello',
source:'en',
target:'fr'
}
};
function doGet(e) {
e = e || mock;
var sourceText = ''
if (e.parameter.q){
sourceText = e.parameter.q;
}
var sourceLang = '';
if (e.parameter.source){
sourceLang = e.parameter.source;
}
var targetLang = 'en';
if (e.parameter.target){
targetLang = e.parameter.target;
}
var translatedText = LanguageApp.translate(sourceText, sourceLang, targetLang, {contentType: 'html'});
return ContentService.createTextOutput(translatedText).setMimeType(ContentService.MimeType.JSON);
}
2) Click Publish -> Deploy as webapp -> Who has access to the app: Anyone even anonymous -> Deploy. And then copy your web app url, you will need it for calling translate API.
3) Use this java code for testing your API:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
public class Translator {
public static void main(String[] args) throws IOException {
String text = "Hello world!";
//Translated text: Hallo Welt!
System.out.println("Translated text: " + translate("en", "de", text));
}
private static String translate(String langFrom, String langTo, String text) throws IOException {
// INSERT YOU URL HERE
String urlStr = "https://your.google.script.url" +
"?q=" + URLEncoder.encode(text, "UTF-8") +
"&target=" + langTo +
"&source=" + langFrom;
URL url = new URL(urlStr);
StringBuilder response = new StringBuilder();
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setRequestProperty("User-Agent", "Mozilla/5.0");
BufferedReader in = new BufferedReader(new InputStreamReader(con.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
response.append(inputLine);
}
in.close();
return response.toString();
}
}
As it is free, there are QUATA LIMITS: https://docs.google.com/macros/dashboard
Use java-google-translate-text-to-speech instead of Google Translate API v2 Java.
About java-google-translate-text-to-speech
Api unofficial with the main features of Google Translate in Java.
Easy to use!
It also provide text to speech api. If you want to translate the text "Hello!" in Romanian just write:
Translator translate = Translator.getInstance();
String text = translate.translate("Hello!", Language.ENGLISH, Language.ROMANIAN);
System.out.println(text); // "Bună ziua!"
It's free!
As #r0ast3d correctly said:
Important: Google Translate API v2 is now available as a paid service. The courtesy limit for existing Translate API v2 projects created prior to August 24, 2011 will be reduced to zero on December 1, 2011. In addition, the number of requests your application can make per day will be limited.
This is correct: just see the official page:
Google Translate API is available as a paid service. See the Pricing and FAQ pages for details.
BUT, java-google-translate-text-to-speech is FREE!
Example!
I've created a sample application that demonstrates that this works. Try it here: https://github.com/IonicaBizau/text-to-speech
Generate your own API key here. Check out the documentation here.
You may need to set up a billing account when you try to enable the Google Cloud Translation API in your account.
Below is a quick start example which translates two English strings to Spanish:
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.translate.Translate;
import com.google.api.services.translate.model.TranslationsListResponse;
import com.google.api.services.translate.model.TranslationsResource;
public class QuickstartSample
{
public static void main(String[] arguments) throws IOException, GeneralSecurityException
{
Translate t = new Translate.Builder(
GoogleNetHttpTransport.newTrustedTransport()
, GsonFactory.getDefaultInstance(), null)
// Set your application name
.setApplicationName("Stackoverflow-Example")
.build();
Translate.Translations.List list = t.new Translations().list(
Arrays.asList(
// Pass in list of strings to be translated
"Hello World",
"How to use Google Translate from Java"),
// Target language
"ES");
// TODO: Set your API-Key from https://console.developers.google.com/
list.setKey("your-api-key");
TranslationsListResponse response = list.execute();
for (TranslationsResource translationsResource : response.getTranslations())
{
System.out.println(translationsResource.getTranslatedText());
}
}
}
Required maven dependencies for the code snippet:
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-translate</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-gson</artifactId>
<version>LATEST</version>
</dependency>
I’m tired of looking for free translators and the best option for me was Selenium (more precisely selenide and webdrivermanager) and https://translate.google.com
import io.github.bonigarcia.wdm.ChromeDriverManager;
import com.codeborne.selenide.Configuration;
import io.github.bonigarcia.wdm.DriverManagerType;
import static com.codeborne.selenide.Selenide.*;
public class Main {
public static void main(String[] args) throws IOException, ParseException {
ChromeDriverManager.getInstance(DriverManagerType.CHROME).version("76.0.3809.126").setup();
Configuration.startMaximized = true;
open("https://translate.google.com/?hl=ru#view=home&op=translate&sl=en&tl=ru");
String[] strings = /some strings to translate
for (String data: strings) {
$x("//textarea[#id='source']").clear();
$x("//textarea[#id='source']").sendKeys(data);
String translation = $x("//span[#class='tlid-translation translation']").getText();
}
}
}
You can use Google Translate API v2 Java. It has a core module that you can call from your Java code and also a command line interface module.

Netty client server login, how to have channelRead return a boolean

I'm writing client server applications on top of netty.
I'm starting with a simple client login server that validates info sent from the client with the database. This all works fine.
On the client-side, I want to use If statements once the response is received from the server if the login credentials validate or not. which also works fine. My problem is the ChannelRead method does not return anything. I can not change this. I need it to return a boolean which allows login attempt to succeed or fail.
Once the channelRead() returns, I lose the content of the data.
I tried adding the msg to a List but, for some reason, the message data is not stored in the List.
Any suggestions are welcome. I'm new... This is the only way I've figured out to do this. I have also tried using boolean statements inside channelRead() but these methods are void so once it closes the boolean variables are cleared.
Following is the last attempt I tried to insert the message data into the list I created...
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class LoginClientHandler extends ChannelInboundHandlerAdapter {
Player player = new Player();
String response;
public volatile boolean loginSuccess;
// Object message = new Object();
private Object msg;
public static final List<Object> incomingMessage = new List<Object>() {
#Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// incomingMessage.clear();
response = (String) msg;
System.out.println("channel read response = " + response);
incomingMessage.add(0, msg);
System.out.println("incoming message = " + incomingMessage.get(0));
}
How can I get the message data "out" of the channelRead() method or use this method to create a change in my business logic? I want it to either display a message to tell the client login failed and try again or to succeed and load the next scene. I have the business logic working fine but I can't get it to work with netty because none of the methods return anything I can use to affect my business logic.
ChannelInitializer
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.Delimiters;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
public class LoginClientInitializer extends ChannelInitializer <SocketChannel> {
#Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast("framer", new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));
pipeline.addLast("decoder", new StringDecoder());
pipeline.addLast("encoder", new StringEncoder());
pipeline.addLast("handler", new LoginClientHandler());
}
}
To get the server to write data to the client, call ctx.write here is a basic echo server and client example from the Netty in Action book. https://github.com/normanmaurer/netty-in-action/blob/2.0-SNAPSHOT/chapter2/Server/src/main/java/nia/chapter2/echoserver/EchoServerHandler.java
There are several other good examples in that repo.
I highly recommend reading the "netty in action" book if you're starting out with netty. It will give you a solid foundational understanding of the framework and how it's intended to be used.

Wiremock tests always getting a 404 on a simple request

I'm trying to get wiremock to return a 200 status with a simple request in my unit tests however, this unit test is always returning a 404 error.
How can this be solved?
import static com.github.tomakehurst.wiremock.client.WireMock.*;
import static org.junit.Assert.assertTrue;
import com.github.tomakehurst.wiremock.junit.WireMockRule;
import org.junit.Rule;
import org.junit.Test;
import java.net.HttpURLConnection;
import java.net.URL;
public class WiremockTest {
#Rule
public WireMockRule wireMockRule = new WireMockRule(8089); // No-args constructor defaults to port 8080
#Test
public void exampleTest() throws Exception {
stubFor(get(urlPathMatching("/my/resource[0-9]+"))
.willReturn(aResponse()
.withStatus(200)
.withHeader("Content-Type", "text/xml")
.withBody("<response>Some content</response>")));
int result = sendGet("http://localhost/my/resource/121");
assertTrue(200 == result);
//verify(getRequestedFor(urlMatching("/my/resource/[a-z0-9]+")));
}
private int sendGet(String url) throws Exception {
URL obj = new URL(url);
HttpURLConnection con = (HttpURLConnection) obj.openConnection();
// optional default is GET
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
return responseCode;
}
}
}
Using your provided code, I first had to handle the java.net.ConnectionException that was being thrown. Your test's url needs the port on localhost.
sendGet("http://localhost:8089/my/resource/121")
After that, I think that the reason you're getting a 404 is that your regex does not match your test url.
urlPathMatching("/my/resource[0-9]+")
should be
urlPathMatching("/my/resource/[0-9]+")
note the additional path separator between 'resource' and '[0-9]+'
Online tools for regex testing like regex101 can be used to test out pattern matching behaviors. (Remember to escape your forward slashes)
Pattern :\/my\/resource\/[0-9]+
Test String: http://localhost:8089/my/resource/121
Hope that helps!

How to find port of Spring Boot container when running a spock test using property server.port=0

Given this entry in application.properties:
server.port=0
which causes Spring Boot to chose a random available port, and testing a spring boot web application using spock, how can the spock code know which port to hit?
Normal injection like this:
#Value("${local.server.port}")
int port;
doesn't work with spock.
You can find the port using this code:
int port = context.embeddedServletContainer.port
Which for those interested in the java equivalent is:
int port = ((TomcatEmbeddedServletContainer)((AnnotationConfigEmbeddedWebApplicationContext)context).getEmbeddedServletContainer()).getPort();
Here's an abstract class that you can extends which wraps up this initialization of the spring boot application and determines the port:
abstract class SpringBootSpecification extends Specification {
#Shared
#AutoCleanup
ConfigurableApplicationContext context
int port = context.embeddedServletContainer.port
void launch(Class clazz) {
Future future = Executors.newSingleThreadExecutor().submit(
new Callable() {
#Override
public ConfigurableApplicationContext call() throws Exception {
return (ConfigurableApplicationContext) SpringApplication.run(clazz)
}
})
context = future.get(20, TimeUnit.SECONDS);
}
}
Which you can use like this:
class MySpecification extends SpringBootSpecification {
void setupSpec() {
launch(MyLauncher.class)
}
String getBody(someParam) {
ResponseEntity entity = new RestTemplate().getForEntity("http://localhost:${port}/somePath/${someParam}", String.class)
return entity.body;
}
}
The injection will work with Spock, as long as you've configured your spec class correctly and have spock-spring on the classpath. There's a limitation in Spock Spring which means it won't bootstrap your Boot application if you use #SpringApplicationConfiguration. You need to use #ContextConfiguration and configure it manually instead. See this answer for the details.
The second part of the problem is that you can't use a GString for the #Value. You could escape the $, but it's easier to use single quotes:
#Value('${local.server.port}')
private int port;
Putting this together, you get a spec that looks something like this:
#ContextConfiguration(loader = SpringApplicationContextLoader, classes = SampleSpockTestingApplication.class)
#WebAppConfiguration
#IntegrationTest("server.port=0")
class SampleSpockTestingApplicationSpec extends Specification {
#Value("\${local.server.port}")
private int port;
def "The index page has the expected body"() {
when: "the index page is accessed"
def response = new TestRestTemplate().getForEntity(
"http://localhost:$port", String.class);
then: "the response is OK and the body is welcome"
response.statusCode == HttpStatus.OK
response.body == 'welcome'
}
}
Also note the use of #IntegrationTest("server.port=0") to request a random port be used. It's a nice alternative to configuring it in application.properties.
You could do this too:
#Autowired
private org.springframework.core.env.Environment springEnv;
...
springEnv.getProperty("server.port");

How To Use Groovy HTTPBuilder To Get Stories from AgileZen?

I would like to pull stories from Agile Zen using their REST API.
I read:
http://help.agilezen.com/kb/api/overview
http://help.agilezen.com/kb/api/security
Also, I got this to work: http://groovy.codehaus.org/HTTP+Builder
How would one combine the above in order to get Groovy client code to access AgileZen stories?
Here is the code sample which makes one story with id of 1 show up for a specific project whose id is 16854:
import groovyx.net.http.HTTPBuilder
import static groovyx.net.http.Method.GET
import static groovyx.net.http.ContentType.JSON
public class StoryGetter {
public static void main(String[] args) {
new StoryGetter().getStories()
}
void getStories() {
// http://agilezen.com/project/16854/story/4
// /api/v1/project/16854/story/2
def http = new HTTPBuilder( 'http://agilezen.com' )
http.request( GET, JSON ) {
uri.path = '/api/v1/project/16854/story/1'
headers.'X-Zen-ApiKey' = 'PUT YOUR OWN API KEY HERE'
response.success = { resp, json ->
println "json size is " + json.size()
println json.toString()
}
}
}
}
I had to put in a fake API key in this post since I should not share my API key.
(By the way, this is not using SSL. A follow up question in regards to doing this for a SSL enabled project may come soon.)