Camel route logic / Output expectations - java

Background:
I'm trying to unmarshal an xml file using jaxb and camel. I think I'm having a hard time with it because I don't know exactly what to expect filewise.
For example, I have:
from("file://C:/test.xml").unmarshal(jaxb).to("file://C:/testEnd.java");
With that, I'm expecting to see the result of the unmarshalling in the .java file (i.e. parameters and values from the xml file elements). However, when I run the program, nothing shows up in the .java file, but I don't receive any errors.
The same thing happens with marshalling. When I have a .java file as the from function and a .xml file in the to function, nothing happens.
For example, I have:
from("file://C:/test.java").marshal(jaxb).to("file://C:/testEnd.xml");
From this, I would expect to see values from my annotated java file appear in the xml file.
Question:
Is my expectation in both of these cases correct? Or is there something wrong with that logic?

Please try this:
If in your code you want to save java object in the form of an xml and then again use that xml to retrieve the state of the java object saved earlier, we do marshalling and unmarshalling
1) Marshalling: convert java object to xml based and save it to file
Create a producerTemplate sending java object to the producerendpoint, marshal it against jaxb dataformat and it would be converted to xml using the pojo bean marked with XmlRootElement and referred as contextPath in jaxb tag.
public class ClientEight {
#Produce(uri="direct:invoice")
ProducerTemplate template;
public static void main(String rgs[]) throws InterruptedException{
AbstractApplicationContext ctx= new ClassPathXmlApplicationContext("resources/camel-configTen.xml");
InvoiceXml invoice= new InvoiceXml("fdf3443",3454, 435345.44f, "hfhfddfdg"); //any java object we are passing
ClientEight client = (ClientEight) ctx.getBean("client");
Object xmlObj= client.template.requestBody(invoice);
System.out.println(xmlObj);
}
Above is a client code which u are using to send java object to a producer endpoint and since u are using template.requestBody, u are getting back the object returned.
<camel:camelContext>
<camel:dataFormats>
<!-- path to jaxb annotated class -->
<camel:jaxb id="invoiceJaxb" contextPath="com.java.bean"
prettyPrint="true" />
</camel:dataFormats>
<camel:route>
<camel:from uri="direct:invoice" />
<camel:marshal ref="invoiceJaxb" />
<camel:log message=" ${body}" />
<camel:to uri="file://src/resources?fileName=One.xml"/>
</camel:route>
</camel:camelContext>
This would be your camel config file. Hope this helps

The file component take a directory, and process all files in this directory. it doesn't handle file by default, you have to use options, or the stream component.
see http://camel.apache.org/file2.html
Only directories
Camel supports only endpoints configured with a
starting directory. So the directoryName must be a directory. If you
want to consume a single file only, you can use the fileName option,
e.g. by setting fileName=thefilename. Also, the starting directory
must not contain dynamic expressions with ${ } placeholders. Again use
the fileName option to specify the dynamic part of the filename.

Related

Changing single parameters in XML file wrapped as Java Object

I am getting a config.xml file via a REST API which has a specific structure. I am adapting this config.xml via Java and pushing it again via PUT command to the REST endpoint to update it.
This XML structure contains the same amount of properties (let's say 'name' and 'description') but might be enhanced by some more properties (e.g. 'category'), which I am not aware of.
<config>
<name>myName</name>
<description>myDescription<description>
<category>myCategory<category>
</config>
My goal is to adapt this config file via Java Code while wrapping it into an Object. So I built a Class 'Config' containing 'String name' and 'String description'.
I can easily parse the config.xml to my Config object with JAXB and adapt name and description, but when marshalling it to XML the category would be missing, although it was returned by the REST API. Is there a way (maybe ValueChangeListener?) to adapt only the changed values in an existing xml file?
public class Config { String name; String description; }
So I don't event want to be able to change 'category' at all, I just don't want to lose the data.
Info: In my scenario the Config class is very complex and has alot of subclasses (it's a representing a Jenkins Job). So the example above is very simplified.
I got the idea to create a second config file, only having the changed parameters. Afterwards merging the to config files. But I had no idea how to be aware what exactly has changed and how to implement it.
Example:
I want to change description to "newDescription", so my expected XML would be:
<config>
<name>myName</name>
<description>newDescription<description>
<category>myCategory<category>
</config>
unfortuntately it is:
<config>
<name>myName</name>
<description>newDescription<description>
</config>
Means category parameter is lost, as I am not aware of it and therefore didnt add it to the Config class. Summarized, there might be parameters in the XML file which I am not aware, which I also do not want to change - but don't want to lose when pushing an updated config.

xstream is not parsing root element

I am using 'com.thoughtworks.xstream:xstream:1.4.10' library and trying to parse xml files.
Broker is the root element and there are other tags inside
<broker>
<othertags/>
</broker>
The problem is when I am generating an xml file it is generating properly but it is not able read a file.
#XStreamAlias("broker")
public static class Broker {
While file generation it is able to convert Broker class to but not the other way around. All other classes and list are getting correctly mapped but the root #XStreamAlias is not working while reading.
Any pointers as to why will be very helpful.
The exception I am getting:
com.thoughtworks.xstream.mapper.CannotResolveClassException: broker
One more question: while calling xStream.fromXML(responseString) how does xStream know which class to use? Say I have two classes with same alias
XStream does not process annotations by default.
Add the following before the deserialization of your xml content.
XStream xstream = new XStream();
xstream.processAnnotations(Broker.class);

Copying multiple files from various sources to various destinations via Spring Integration

I am presented with the following use case.
I am receiving a Message<Foo> object on my input channel, where Foo object has 2 properties
public class Foo {
...
public String getSourcePathString();
public String getTargetPathString();
...
}
sourcePathString is a String which denotes where the source file is located, while targetPathString is a place where the file should be copied to.
Now, I do know how to use file:outbound-channel-adapter to copy the file to a custom target location via FileNameGenerator, however, I am not sure how I can provide the location where to read the file from in file:inbound-channel-adapter and how to activate the reading when the message is received only.
What I have so far is a custom service activator where I perform copying in my own bean, however, I'd like to try and use Spring Integration for it.
So, is there a way to implement triggerable file copying in Spring Integration with already present components?
You cannot currently change the input directory dynamically on the inbound channel adapter.
The upcoming 4.2 release has dynamic pollers which would allow this.
However, it seems the adapter is not really suitable for your use case - it is a polled adapter, whereas you want to fetch the file on demand.
You could minimize your user code by configuring a FileReadingMessageSource, set the directory and call receive() to get the file.

xstream: only parsing child element

I have following xml
<root>
<child-1>
</child-1>
<child-2>
<subchild-21>
</subchild-22>
</child-2>
</root>
My requirement is such that I only want to parse child-2. I am unaware of root and child-1.
Is it possible with xstream because I couldn't find a way to ignore root.
There are several ways to go, depending on your requirements.
If you know the name of the class to parse (child-2 here), you could look for the <child-2> and </child-2> entry in the XML, copy them along with the content in-between to a new temporary XML file (you can create temporary files using createTempFile() from the standard File class). This is the way I would suggest.
If you want to take out the child-2 instance without knowing its name, but you know the names of the surrounding classes, you could mock their classes, that is create classes of the same name, but without their specific content. In your example there is no content (might have been ignored at export time), but it's important to have the same member data in the mock classes for the import to succeed. (unless you use ignoreUnknownElements() as stated by Philipi Willemann)
Of course, if you're the one creating the XML, you should be able to export only the child-2 instance in the first place.
If you know the root name you can create a simple class has an attribute of the class you have mapped to child-2:
#XStreamAlias("root")
class Root {
#XStreamAlias("child-2")
private Child2 child;
//get and set
}
Then when you are processing the XML you can set XStream to ignore unknown elements with xstream.ignoreUnknownElements();

Generate Spring bean definition from a Java object

Let's suggest that I have a bean defined in Spring:
<bean id="neatBean" class="com..." abstract="true">...</bean>
Then we have many clients, each of which have slightly different configuration for their 'neatBean'. The old way we would do it was to have a new file for each client (e.g., clientX_NeatFeature.xml) that contained a bunch of beans for this client (these are hand-edited and part of the code base):
<bean id="clientXNeatBean" parent="neatBean">
<property id="whatever" value="something"/>
</bean>
Now, I want to have a UI where we can edit and redefine a client's neatBean on the fly.
My question is: given a neatBean, and a UI that can 'override' properties of this bean, what would be a straightforward way to serialize this to an XML file as we do [manually] today?
For example, if the user set property whatever to be "17" for client Y, I'd want to generate:
<bean id="clientYNeatBean" parent="neatBean">
<property id="whatever" value="17"/>
</bean>
Note that moving this configuration to a different format (e.g., database, other-schema'd-xml) is an option, but not really an answer to the question at hand.
You can download the Spring-beans 2.5 xsd from here and run xjc on it to generate the Java classes with JAXB bindings. Then you can create the Spring-beans object hierarchy on runtime (and manipulate it as you wish) and then serialize it to an XML string using the JAXB Marshaller as shown in Pablojim's answer.
I'd use Jax-b to do this. You'de create a bean object with a list of property objects inside.
#XmlRootElement(name = "bean")
#XmlAccessorType(XmlAccessType.FIELD)
public class Bean {
#XmlAttribute
private String id;
#XmlAttribute
private String parent;
#XmlElement(name="property")
private List<BeanProperty> properties
Then You'd need to also add annotations to BeanProperty. Then when you have a populated object simply marshal it to xml using jaxb:
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal( myBean, System.out );
For full code examples see: http://java.sun.com/webservices/docs/2.0/tutorial/doc/JAXBUsing.html
Alternatively you could use Groovy - you can drop it in place and creating this xml would be very simple... : http://www.ibm.com/developerworks/java/library/j-pg05199/index.html
If you want a simple to implement, no work solution, you can look at the IDE support provided in IntelliJ and Eclipse (The Spring Tool Suite).
They parse all the bean files (you can configure which set) and inspect the java code so it knows which classes there are, which properties are in those classes. Everywhere you can use Ctrl-Space to help with the options, etc...
I imagine you could setup 'projects' w/o Java code and only the spring config files in order to reduce the learning curve of front line personnel who must make these changes.
What you need is obviously a factory for your neatBeans.
In Spring, instead of declaring a bean, you can declare a FactoryBean whose role is to actually create and configure your final bean.
The NeatBeanFactoryBean could read a property file (or xml configuration) to determine how to configure the produced neatBeans, depending on some runtime parameter (the current clientID for example) or compile-time parameter (environment variable).
To add to the other two questions, I believe Spring already has a working model for bean definitions (see org.springframework.beans.factory.config.BeanDefinition); you could base your work on that.
I'd suggest using
<context:property-placeholder location="classpath*:clientX.properties"/>
and then in your bean def:
<bean id="${clientYNeatBeanId}" parent="neatBean">
<property id="whatever" value="${whateverValue}"/>
</bean>
Then for each client you can have a clientX.properties containing
whateverValue=17
whateverAnotherValue=SomeText
.properties files are easier to edit both manually, and programaticalyl via java.util.Properties store(..) / save(..) methods

Categories