I am developing a restful WS and I want to give the option to the users to take data back from my WS in the form of XML or Json and also to be able to choose a callback function if they want Jsonp. This is what I have until now and the part with the Interceptors is based on CXF - JAX-RS : Data Bindings.
My Rest Service:
#GET
#Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
#Produces({ "application/x-javascript", MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML })
public Response getServers(#Context ServletContext context,
#Context Request request,
#QueryParam("format") String format,
#QueryParam("callback") String callback) {
some code where server object is created....
if(format.equals("json"){
if(callback!= null){
response = Response.status(Status.OK).type("application/x-javascript")
.entity(server).build();
}else{
response = Response.status(Status.OK).type("application/json")
.entity(server).build();
}
} else {
response = Response.status(Status.OK).type("application/xml")
.entity(server).build();
}
return response;
}
My Server object:
#XmlRootElement (name="Server")
public class Server implements Serializable {
private String name=null;
private String hardware = null;
public Server(){
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHardware() {
return hardware;
}
public void setHardware(String hardware) {
this.hardware = hardware;
}
}
My beans.xml in the WEB-INF:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<context:property-placeholder/>
<context:annotation-config/>
<bean class="org.springframework.web.context.support.ServletContextPropertyPlaceholderConfigurer"/>
<bean class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer"/>
<jaxrs:server id="services" address="/">
<jaxrs:serviceBeans>
<bean class="com.ba.serversws_cxf.resources.MyResource" />
</jaxrs:serviceBeans>
<jaxrs:inInterceptors>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpInInterceptor">
<property name="callbackParam" value="callback"/>
</bean>
</jaxrs:inInterceptors>
<jaxrs:outInterceptors>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPreStreamInterceptor">
<property name="mediaType" value="application/x+javascript"/>
</bean>
<bean class="org.apache.cxf.jaxrs.provider.jsonp.JsonpPostStreamInterceptor"/>
</jaxrs:outInterceptors>
<jaxrs:providers>
<bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider"/>
</jaxrs:providers>
</jaxrs:server>
</beans>
The error that I get when I set the query parameter "callback" is:
org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor writeResponseErrorMessage
WARNING: No message body writer has been found for response class Server.
It works fine for other other two cases.
I have searched to find a solution but still nothing.
Any ideas?
Thanks
Here is my class that #Overrides the wrtieTo() method of the org.apache.cxf.jaxrs.provider.json.JSONProvider;
First of all in my beans.xml file I have used the <jaxrs:extensionMappings> and I have declared a jsonp extention.
Here is the code
<jaxrs:server id="services" address="/">
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
<entry key="jsonp" value="application/javascript"/>
</jaxrs:extensionMappings>
</jaxrs:server>
And below is my code of the writeTo() method that I have #Override
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedMap;
import org.apache.cxf.jaxrs.provider.json.JSONProvider;
import org.apache.cxf.jaxrs.utils.HttpUtils;
#SuppressWarnings("rawtypes")
#Produces("application/javascript")
public class JsonpProvider extends JSONProvider {
#SuppressWarnings("unchecked")
#Override
public void writeTo(Object obj, Class cls, Type genericType,
Annotation[] anns, MediaType m, MultivaluedMap headers,
OutputStream os) throws IOException {
String requestURI = getContext().getHttpServletRequest()
.getRequestURI();
if (requestURI.contains(".jsonp")) {
String prefix = getContext().getHttpServletRequest().getParameter(
"_jsonp");
if (prefix != null && !prefix.isEmpty()) {
os.write(prefix.getBytes(HttpUtils.getSetEncoding(m, headers,
"UTF-8")));
} else {
os.write("callback".getBytes(HttpUtils.getSetEncoding(m,
headers, "UTF-8")));
}
os.write('(');
super.writeTo(obj, cls, genericType, anns, m, headers, os);
os.write(')');
} else {
super.writeTo(obj, cls, genericType, anns, m, headers, os);
}
}
}
So what I am doing in the code above is I am checking if the .jsonp extension has been given to the URL. If yes then I know that I have to return the jsopn with a callback function. The last thing is to set the name of the callback function. If the user has set the _jsonp query parameter to the URL then the value of this parameter will be the name of the callback function. If the _jsonp pquery parameter is null then I put a defult name callback.
And off course in the beans.xml file as a json provider you put the JsonpProvider above:
<jaxrs:providers>
<bean class="org.apache.cxf.jaxrs.ext.search.SearchContextProvider"/>
<bean class="com.ba.serversws_cxf.utils.JsonpProvider">
<property name="ignoreNamespaces" value="true" />
<property name="dropRootElement" value="false" />
<property name="supportUnwrapped" value="true" />
</bean>
</jaxrs:providers>
Hope that helps #bhuvan !
Related
I'm new to selenium, can anyone help me on how to run the same test case in 2 different URL which has the same functionality
Two ways you can do it.
1) Passing value from xml in testng file.
Test code you can refer.
public class ParameterTest
{
#Parameters({ "url" })
#Test
public void optionTest(String value) {
System.out.println("This is: " + value);
}
}
<suite name="Optional test Suite" verbose="1">
<test name="Optional Test one">
<parameter name="url" value="https://xy.cm" />
<classes>
<class name="test.parameter.OptionalTest" />
</classes>
</test>
<test name="Optional Test two">
<parameter name="url" value="https://abc.om" />
<classes>
<class name="test.parameter.OptionalTest" />
</classes>
</test>
</suite>
2) You can use data provider in testng to pass url as parameter in your test case.
public class SameClassDataProvider
{
#DataProvider(name = "url")
public Object[][] dataProviderMethod() {
return new Object[][] { { "https://yahoo.com" }, { "https://google.in" } };
}
#Test(dataProvider = "data-provider")
public void testMethod(String url) {
//write your test case
}
}
Hope this help you!
So I am wrapping the Spring Integration TCP client to provide APIs for my application. Previous questions regarding this can be found here and here. The problem with this is that the gateway.send() doesn't end at all and the API response never comes back.
Here is my ServerConnection.java file:
package com.abc.xyz.serverconnection;
import org.springframework.context.support.GenericXmlApplicationContext;
public class ServerConnections {
private SimpleGateway gateway;
public ServerConnections() {
final GenericXmlApplicationContext context = setupContext();
this.setGateway(context.getBean(SimpleGateway.class));
}
public static GenericXmlApplicationContext setupContext() {
final GenericXmlApplicationContext context = new GenericXmlApplicationContext();
context.load("classpath:META-INF/spring/integration/tcpClientServerDemo-context.xml");
context.registerShutdownHook();
context.refresh();
return context;
}
public SimpleGateway getGateway() {
return gateway;
}
public void setGateway(SimpleGateway gateway) {
this.gateway = gateway;
}
public boolean sendData(String input) {
this.gateway.send(input);
return true;
}
public void recieveData(String output) {
System.out.println("Data from server:" + output);
}
}
In my controller, I do something like this:
#RequestMapping(value = "/logon", method = RequestMethod.GET)
#ResponseBody
public String logon() {
// logics go here and the result is stored like below and sent
String message = "0000005401F40000C1E3E304010000000020000000000000000000000000000000000000000000004040404040404040C1E3E300C1C2C3C4C5C6C7C8E8C5E2C8E6C1D540F1F7F24BF0F1F64BF0F0F34BF0F5F200";
if (serverConnections.sendData(message)) {
return "Data sent successfully!";
} else {
return "Data not sent!";
}
}
Here is how my config looks like:
<context:property-placeholder />
<int:channel id="input" />
<int:channel id="toSA" />
<int:service-activator input-channel="toSA"
ref="echoService"
method="recieveData"/>
<bean id="echoService" class="com.abc.xyz.serverconnection.ServerConnection" />
<bean id="CustomSerializerDeserializer" class="com.abc.xyz.serverconnection.CustomSerializerDeserializer" />
<int:object-to-string-transformer id="serverBytes2String"
input-channel="serverBytes2StringChannel"
output-channel="toSA"/>
<int:gateway id="gw"
service-interface="com.abc.xyz.serverconnection.SimpleGateway"
default-request-channel="input"/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="<ip>"
serializer="CustomSerializerDeserializer"
deserializer="CustomSerializerDeserializer"
port="6100"
single-use="false" />
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="input"
reply-channel="serverBytes2StringChannel"
connection-factory="client" />
EDIT: Not able to get the DEBUG log of the application since I am using the TCP client implementation as a Maven Module inside a Maven Project. Another module uses this as a dependency and that is where the REST API end-points reside at.
I think your
<int:service-activator input-channel="toSA"
ref="echoService"
method="recieveData"/>
Doesn't return any result to be sent to the replyChannel header, meanwhile your gateway.send() isn't a void method. That's how it waits for the reply which never comes back.
how can i use org.springframework.beans.propertyeditors.CustomDateEditor if i have 2 date formats in a single line in a flat file.
<bean id="dateEditor1" class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="MMddyyyy" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
<bean id="dateEditor2" class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="java.text.SimpleDateFormat">
<constructor-arg value="MMddyyyyHHmm" />
</bean>
</constructor-arg>
<constructor-arg value="true" />
</bean>
<property name="customEditors">
<map>
<entry key="java.util.Date" value-ref="dateEditor1"/>
<entry key="java.util.Date" value-ref="dateEditor1"/>
</map>
</property>
I am trying the above code. but it doesnt work. i am useing PatternMatchingCompositeLineMapper.
Used the below custom date format:
public class CustomDateFormats extends DateFormat {
private static final long serialVersionUID = 1L;
private static final String[] formats = new String[] { "MMddyyyy", "MMddyyyyHHmm", "MMdd" };
Date result = null;
#Override
public StringBuffer format(final Date date, final StringBuffer toAppendTo, final FieldPosition fieldPosition) {
throw new UnsupportedOperationException("This custom date formatter can only be used to *parse* Dates.");
}
#Override
public Date parse(final String source, final ParsePosition pos) {
Date res = null;
for (String format : formats) {
if (source != null && format.length() == source.length()) {
SimpleDateFormat sdFormat = new SimpleDateFormat(format);
res = sdFormat.parse(source, pos);
break;
}
}
return res;
}
}
<bean id="dateEditor1" class="org.springframework.beans.propertyeditors.CustomDateEditor">
<constructor-arg>
<bean class="com.disney.wdpro.service.transaction.processing.batch.domain.logicalBatchOpen.CustomDateFormats" />
</constructor-arg>
<constructor-arg value="true" />
</bean>
You can't do that. Look at the map where you are trying using java.util.Date as key and then you are expecting it to hold 2 values. map doesn't work that way, it will always override the value if the key is already existing. Thus in your case you have to write a customized bean for to set these fields in your flat file.
According to the Spring doc,only one single registered custom editor per property path is supported.
But you can write a custom dateformat class which will hold a list of different date formats and use this class to autowire to custom editor.
For example one like given below or you create your customized editor and wrap a list of CustomDateEditor , There are multiple use , you can refer to one example like below.
<bean id="customer4" class="org.testSpring.util.DateBeanTest4">
<property name="birthDate">
<bean factory-bean="customDateFormat" factory-method="parse">
<constructor-arg value="31-01-2010" />
<!-- mm/dd/yyyy, dd-MM-yyyy, yyyyMMdd -->
</bean>
</property>
</bean>
<bean id="customDateFormat" class="org.testSpring.util.CustomDateFormats">
</bean>
And your formatter class
public class CustomDateFormats extends DateFormat {
private static final List<? extends DateFormat> DATE_FORMATS = Arrays.asList(
// or inject thorough construction with a list of formats
new SimpleDateFormat("dd-MM-yyyy"),
new SimpleDateFormat("mm/dd/yyyy"),
new SimpleDateFormat("yyyyMMdd"));
#Override
public StringBuffer format(final Date date, final StringBuffer toAppendTo, final FieldPosition fieldPosition)
{
throw new UnsupportedOperationException("This custom date formatter can only be used to *parse* Dates.");
}
#Override
public Date parse(final String source, final ParsePosition pos) {
Date res = null;
for (final DateFormat dateFormat : DATE_FORMATS) {
if ((res = dateFormat.parse(source, pos)) != null) {
return res;
}
}
return null;
}
}
I have been looking at how to simplify some of my rules which are manually written in DRL, becoming difficult to maintain.
Searching through google resulted in "decision tables is the best way to go forawad".
But unfortunately our facts are very complex, So at moment drools spreadsheetconverter, can not handle so much complexity on facts,
So the first question is how do developers normally deal with handling very complex facts in the drools knowledge base?
For example We have facts like
Person->List<Cars>->List<Insurances>->Each insurance Has List<History>
Now i have to write a rule say Person Has bad history for his Insurance claim. Then i find very diffcult to put it in speadsheet, where as its easier to manually write this rule on the drl file.
Thanks for the help. Any help on the above example would be very good too .
For complex rules like this, we use Drools Templates. You write a rule template with parameter expansions for fields to populate and you have much more flexibility in where the actual values come from to populate the skeleton rule.
This capability is built into Drools Guvnor, but writing the complex rule templates through the GUI is somewhat tedious. I have also written standalone Java to populate template drl files from lists of values pulled from properties files, and recently developed a SmartGWT web app that allows the user to populate rule values and generate DRL.
Edit: Adding sample program. DroolsTemplateBuilder creates a list of TestType objects, which have fields that map to the template keys in Test.drl. The generated DRL is printed and also compiled to a pkg which is written out to a file called Test.pkg.
Libraries: antlr-3.3.jar, antlr-runtime-3.3.jar, drools-compiler-5.2.0.Final.jar, drools-core-5.2.0.Final.jar, drools-templates-5.2.0.Final.jar, ecj-4.2.jar, knowledge-api-5.2.0.Final.jar, mvel2-2.1.0.drools.jar (these may not all be necessary).
Note: This example uses 5.2.0 libraries and some functionality may be different in newer releases. build.xml should make it clear how to structure your project.
DroolsTemplateBuilder.java:
package some.test.pkg;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Collection;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.common.DroolsObjectOutputStream;
import org.drools.definitions.impl.KnowledgePackageImp;
import org.drools.io.ResourceFactory;
import org.drools.template.ObjectDataCompiler;
public class DroolsTemplateBuilder {
private String filePath;
private String drl;
public static void main(String[] args) {
DroolsTemplateBuilder test = new DroolsTemplateBuilder();
test.filePath = args[0] + File.separator + "Test.drl";
test.runTest();
}
public void runTest() {
buildPackage();
writeRulePackageToFile();
}
public void buildPackage() {
Collection<Object> templateList = new ArrayList<Object>();
templateList.add(new TestType(1, "John", "Manager"));
templateList.add(new TestType(2, "Peter", "CEO"));
templateList.add(new TestType(3, "Kate", "Engineer"));
try {
ObjectDataCompiler converter = new ObjectDataCompiler();
InputStream templateStream = new FileInputStream(filePath);
String myDrl = inputStreamToString(templateStream, 200);
// I use this ##### replacement instead of just a newline in the
// template
// because of windows/linux issues with newline and carriage return.
// Drools template
// builder, at least in 5.2.0, was very picky about the template
// structure, including
// where newlines are expected.
myDrl = myDrl.replaceAll("#####", "\n");
InputStream tempStream = new ByteArrayInputStream(myDrl.getBytes());
drl = converter.compile(templateList, tempStream);
System.out.println(drl);
} catch (Exception e) {
System.out.println("Exception: " + e.getMessage());
}
}
public void writeRulePackageToFile() {
try {
KnowledgeBuilder kBuilder = KnowledgeBuilderFactory
.newKnowledgeBuilder();
Reader rdr = new StringReader(drl);
kBuilder.add(ResourceFactory.newReaderResource(rdr),
ResourceType.DRL);
if (kBuilder.hasErrors()) {
System.out.println("Drools blew up on");
for (KnowledgeBuilderError err : kBuilder.getErrors()) {
System.out.println(err.getMessage());
}
} else {
String outFile = filePath.replaceFirst("\\.drl", ".pkg");
OutputStream os = new FileOutputStream(outFile);
ObjectOutputStream oos = new DroolsObjectOutputStream(os);
KnowledgePackageImp kPackage = (KnowledgePackageImp) kBuilder
.getKnowledgePackages().iterator().next();
oos.writeObject(kPackage);
oos.close();
}
} catch (Exception e) {
System.out.println("Exception " + e.getMessage());
}
}
public String inputStreamToString(final InputStream is, final int bufferSize) {
final char[] buffer = new char[bufferSize];
final StringBuilder out = new StringBuilder();
try {
final Reader in = new InputStreamReader(is, "UTF-8");
try {
for (;;) {
int rsz = in.read(buffer, 0, buffer.length);
if (rsz < 0)
break;
out.append(buffer, 0, rsz);
}
} finally {
in.close();
}
} catch (Exception ex) {
System.out.println("Something went wrong: " + ex.getMessage());
}
return out.toString();
}
}
Test.drl:
template header
id
name
title
#####
package some.test.pkg;
template "sampleTemplate"
rule "id filter_#{row.rowNumber}"
no-loop true
dialect "java"
when
$t : TestType(id=="#{id}")
then
System.out.println("Doing something special...");
end
end template
template "anotherSample"
rule "another rule_#{row.rowNumber}"
no-loop true
dialect "java"
when
$t : TestType((name=="#{name}") || (title=="#{title}"))
then
System.out.println("Doing something else...");
end
end template
TestType.java:
package some.test.pkg;
public class TestType {
private int id;
private String name;
private String title;
public TestType(int id, String name, String title) {
this.id = id;
this.name = name;
this.title = title;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
build.xml:
<project name="TemplateTest" basedir="." default="jar">
<property name="src.dir" value="src" />
<property name="build.dir" value="build" />
<property name="drl.dir" value="${basedir}/drl" />
<property name="classes.dir" value="${build.dir}/classes" />
<property name="jar.dir" value="${build.dir}/jar" />
<property name="lib.dir" value="${basedir}/lib" />
<path id="compile.classpath">
<fileset dir="${lib.dir}" includes="*.jar" />
</path>
<path id="run.classpath">
<fileset dir="${jar.dir}" includes="*.jar" />
<fileset dir="${lib.dir}" includes="*.jar" />
</path>
<target name="clean">
<delete dir="${classes.dir}" />
<delete dir="${jar.dir}" />
</target>
<target name="compile" depends="clean">
<mkdir dir="${classes.dir}" />
<mkdir dir="${jar.dir}" />
<javac includeantruntime="false" srcdir="${src.dir}" classpathref="compile.classpath" destdir="${classes.dir}" />
</target>
<target name="jar" depends="compile">
<jar destfile="${jar.dir}/${ant.project.name}.jar" basedir="${classes.dir}">
</jar>
</target>
<target name="run" depends="jar" description="run">
<java classpathref="run.classpath" classname="some.test.pkg.DroolsTemplateBuilder" fork="true">
<arg value="${drl.dir}" />
</java>
</target>
</project>
We also use Templates and our facts (and resulting rules) are quite complex. The values in the template table are used in the rules for method calls, setting rule "options," timer values, etc.
Templates help when the rule parameters lend themselves to a tabular format. If access control is of concern you may end up needing multiple templates with the same logic, just different values. (Easy to do in guvnor by just copying the 1st template).
I'm trying to do a progarm small with spring
<bean
id="mybean"
class="com.spr.main.Persona"
p:name="Peter"
p:age="33"
p:address="LA"
p:company="Googel"
p:email="Peter#google.com"
/>
<bean id="logger" class="com.spr.main.Log" />
<aop:config>
<aop:aspect ref="logger">
<aop:pointcut id="testPointcut"
expression="execution(* com.spr.main.Person.toString(..)) and target (bean)" />
<aop:before method="logInfo" pointcut-ref="testPointcut" arg-names="bean"/>
<aop:after-returning method="logWarning" pointcut-ref="testPointcut" arg-names="bean"/>
</aop:aspect>
</aop:config>
the bean work fine, but aop doesn´t show the log messaga, this is the Log class:
public class Log
{
public static void logInfo()
{
Logger.getLogger(Log.class.getName()).log(Level.INFO, "Info Message...");
}
public static void logWarning()
{
Logger.getLogger(Log.class.getName()).log(Level.WARNING, "Warning Message...");
}
}