Java parse and update xml value in thread - java

I written a multiple thread program, each thread need to parse a xml file and update new value. The problem: assuming i have a xml contents of ABC, now thread A parse the xml and update it become ABCA, at the same time thread B also parse the xml (which the content is ABC) and update it become ABCB. thread B update the xml after thread A updated, so the result of the xml is ABCB, what i want is the xml result should be ABCAB. Any idea to control the way of parsing and update in the thread?
here's my code:
WSthread.java
public class WSthread extends Thread {
public String WSname;
Process proc= null;
WebServicesXML xml;
WSthread(String name){
WSname=name;
}
public void run() {
try {
//my code
// Run a java app in a separate system process
String cmd = (WSname);
proc = Runtime.getRuntime().exec("java -jar "+cmd);
xml = new WebServicesXML();
//Process proc = Runtime.getRuntime().exec("java -jar .jar");
// Then retreive the process output
//InputStream in = proc.getInputStream();
//InputStream err = proc.getErrorStream();
BufferedReader is = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line;
String regex = "\\bhttp\\b";
Pattern pattern = Pattern.compile(regex);
String WSaddress = "";
while ((line = is.readLine()) != null){
Matcher matcher = pattern.matcher(line);
if(matcher.find()){
WSaddress = line;
System.out.println("Updating WS address..."+WSaddress);
xml.create(WSname, WSaddress);
}
System.out.println(line);
}
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public void close(){
proc.destroy();
}
WebServicesXML.java
public class WebServicesXML{
public int totalWebServices;
public String WSnamelist[];
public synchronized void create(String WSname, String WSaddress) throws OException, TransformerConfigurationException, TransformerException, ParserConfigurationException{
try {
DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
DocumentBuilder docBuilder = dbfac.newDocumentBuilder();
Document readdoc = docBuilder.parse("webservices.xml");
// normalize text representation
readdoc.getDocumentElement ().normalize ();
Node rootList = readdoc.getDocumentElement();
Element rootElement = (Element)rootList;
Element webservice = readdoc.createElement("WebService");
Element name = readdoc.createElement("name");
Element address = readdoc.createElement("address");
name.setTextContent(WSname);
address.setTextContent(WSaddress);
webservice.appendChild(name);
webservice.appendChild(address);
rootElement.appendChild(webservice);
/////////////////
//Output the XML
//set up a transformer
TransformerFactory transfac = TransformerFactory.newInstance();
Transformer trans = transfac.newTransformer();
trans.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
trans.setOutputProperty(OutputKeys.INDENT, "yes");
//create string from xml tree
File file = new File("webservices.xml");
StringWriter sw = new StringWriter();
StreamResult result = new StreamResult(file);
DOMSource source = new DOMSource(readdoc);
trans.transform(source, result);
}
catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

The basic problem is a seperate DOM is built in every thread for a single transform to be applied. This means that the last thread to run 'wins' in terms of writing its content back to the XML file.
On the one hand you are using threads, I assume for performance, but on the other hand you parse and serialize the XML multiple times. And the threading implementation is unsafe.
My recommendation is to remove the threading and do the changes in loop. When it's working you can measure the performance and THEN choose to look at an implementation using threads.
Remember, premature optimization is the root of all evil.

You need to make sure that only one thread is accessing the file at any time. You can use the native synchronization tools available for that (such as the synchronized keyword and the wait()/notify() mechanism) or you can look into higher-level synchronization tools such as Semaphore or FileLock.

When you synchronize a method the lock is taken on the object (for non-static methods) so because each thread gets its own instance of WebServicesXML each can obtain a lock and no blocking occurs.
The easiest way to deal with this would be to only create a single instance of WebServicesXML and pass that single instance to each thread when it is created.
Alternatively create a semaphore object in WebServicesXML like this:
private static final Object FILE_SEMAPHORE = new Object();
And then add a synchronized block round the lines that update the file like this:
synchronized (FILE_SEMAPHORE) {
//File update code goes here.
}

Related

Convert an XML String to CSV file (Java) -> CSV Result is empty

I need help understanding why the XML String does not convert into a CSV file. Why is the CSV Resut always empty?
Here is an example of a Java Code
public class transformCSV_1 {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
try {
String xmlData = new String(
"<?xml version=\"1.0\"?><PurchaseOrder xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://localhost:8080/source/schemas/poSource/xsd/purchaseOrder.xsd\"><Reference>SBELL-2002100912333601PDT</Reference><Actions><Action><User>SVOLLMAN</User></Action></Actions><Requestor>Sarah J. Bell</Requestor><User>SBELL</User><CostCenter>S30</CostCenter><ShippingInstructions><name>Sarah J. Bell</name><address>400 Oracle Parkway Redwood Shores CA 94065 USA</address><telephone>650 506 7400</telephone></ShippingInstructions><SpecialInstructions>Air Mail</SpecialInstructions><LineItems><LineItem ItemNumber=\"1\"><Description>A Night to Remember</Description><Part Id=\"715515009058\" UnitPrice=\"39.95\" Quantity=\"2\"/></LineItem><LineItem ItemNumber=\"2\"><Description>The Unbearable Lightness Of Being</Description><Part Id=\"37429140222\" UnitPrice=\"29.95\" Quantity=\"2\"/></LineItem><LineItem ItemNumber=\"3\"><Description>Sisters</Description><Part Id=\"715515011020\" UnitPrice=\"29.95\" Quantity=\"4\"/></LineItem></LineItems></PurchaseOrder>");
String stylesheet = new String(
"<?xml version=\"1.0\" encoding=\"utf-8\"?><xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\"><xsl:output method=\"text\" /><xsl:variable name=\"delimiter\" select=\"','\" /><!-- define an array containing the fields we are interested in --><xsl:variable name=\"fieldArray\"><field>Reference</field><field>User</field><field>Reject</field><field>Requestor</field></xsl:variable><xsl:param name=\"fields\" select=\"document('')/*/xsl:variable[#name='fieldArray']/*\" /><xsl:template match=\"/\"><!-- output the header row --><xsl:for-each select=\"$fields\"><xsl:if test=\"position() != 1\"><xsl:value-of select=\"$delimiter\"/></xsl:if><xsl:value-of select=\".\" /></xsl:for-each><!-- output newline --><xsl:text>
</xsl:text><xsl:apply-templates select=\"PurchaseOrder\"/></xsl:template><xsl:template match=\"PurchaseOrder\"><xsl:variable name=\"currNode\" select=\".\" /><!-- output the data row --><!-- loop over the field names and find the value of each one in the xml --><xsl:for-each select=\"$fields\"><xsl:if test=\"position() != 1\"><xsl:value-of select=\"$delimiter\"/></xsl:if><xsl:value-of select=\"$currNode/*[name() = current()]\" /></xsl:for-each><!-- output newline --><xsl:text>
</xsl:text></xsl:template></xsl:stylesheet>");
InputStream xmlSource = new ByteArrayInputStream(
xmlData.getBytes("UTF-8"));
InputStream styleSource = new ByteArrayInputStream(
stylesheet.getBytes("UTF-8"));
DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
DocumentBuilder builder = factory.newDocumentBuilder();
Document document = builder.parse(xmlSource);
StreamSource stylesource = new StreamSource(styleSource);
Transformer transformer = TransformerFactory.newInstance()
.newTransformer(stylesource);
Source source = new DOMSource(document);
Result outputTarget = new StreamResult(new File("src/resultI.csv"));
transformer.transform(source, outputTarget);
} catch (TransformerConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerFactoryConfigurationError e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (TransformerException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Best way is to use XSLT to "transform" the XML to CSV --> Can someone give me hint?
Consider to load the XSLT code from a file or URI (instead of from a string) as otherwise your approach of doing <xsl:param name="fields" select="document('')/*/xsl:variable[#name='fieldArray']/*" /> where document('') tries to pull in the XSLT code again is likely to fail, unless you set up a special resolver.

Java parse XML string

I have an string which I am attempting to extract values from, for convenience I thought that converting the string to a Document and then parsing the xml would be the best way to do this but I am running into all sorts of problems! The string looks like:
<Messagexxx>
<Unit>
<contact>0</contact>
<text>Test Content</text>
<date>09-Sep-14 13:56</date>
<subject>Test Title</subject>
</Unit>
</Messagexxx>
Can someone point me in the correct way to achieve my goal of reading the values from the tags .
I have attempted using the following snippet but I all the values in the array are
null! Document xml = null; Node T = null; try { xml = stringToDom(message); T = xml.getLastChild(); } catch (SAXException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ParserConfigurationException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } if(xml.getFirstChild() != null){ }
When you write your string to a text file, you can first parse it:
private Document parse(String filename){
Document doc = null;
try {
DOMParser parser = new DOMParser();
parser.parse(filename);
doc = parser.getDocument();
} catch (SAXException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return doc;
}
and then you read all text elements out of this document:
public void extract (Document doc){
Node root = doc.getDocumentElement();
for (int i = 0; i< root .getChildNodes().getLength(); i++){
Node child = root.getChildNodes().item(i);
System.out.println(child.getTextContent());
}
}
Use JAXB lib : https://jaxb.java.net/
Create your model from your XML and to read :
JAXBContext jaxbContext = JAXBContext.newInstance(YourModel.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader("xml string here");
YourModel yourModel= (Person) unmarshaller.unmarshal(reader);
After your can use the object "YourModel" to read your value.
This is a very simple way to get node values when you know the node names, and they don't repeat:
String getXmlNodeValue(String xmlString, String nodeName){
int start = xmlString.indexOf("<"+nodeName+">") + nodeName.length() + 2;
int end = xmlString.indexOf("</"+nodeName+">");
return xmlString.substring(start, end);
}

XML output Print in Browser using JAVA

Here I try to access two third party API.
I got two xml response, I merge them in one single file and store it in local system.
If i print the output in console I got the output in xml format, but I want to print it in the browser.
My solution won't work please help me.
Here's my code:
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/xml");
PrintWriter out=response.getWriter();
String btn1=request.getParameter("btn1");
String btn2=request.getParameter("btn2");
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setIgnoringComments(true);
DocumentBuilder builder = null;
try {
builder = domFactory.newDocumentBuilder();
} catch (ParserConfigurationException e2) {
e2.printStackTrace();
}
Document doc = null;
try {
doc = builder.parse(new URL("valid url in my program").openStream());
response.setContentType("text/xml");
Object con=doc.getDoctype();
} catch (SAXException e2) {
e2.printStackTrace();
}
Document doc1 = null;
try {
doc1 = builder.parse(new URL(valid url).openStream());
} catch (SAXException e2) {
e2.printStackTrace();
}
NodeList nodes = doc.getElementsByTagName("events");
NodeList node1=doc.getElementsByTagName("events");
Element root=doc.getDocumentElement();
Element root1 = doc.createElement("ObjectId");
doc.getDocumentElement().appendChild(root1);
root.getElementsByTagName("ObjectId").item(0).setTextContent("1");
node1.item(0).getParentNode().insertBefore(root1,node1.item(0));
NodeList nodes1 = doc1.getElementsByTagName("events");
NodeList node2=doc1.getElementsByTagName("event");
Element root2=doc1.getDocumentElement();
Element root3= doc1.createElement("ObjectId");
doc1.getDocumentElement().appendChild(root3);
root2.getElementsByTagName("ObjectId").item(0).setTextContent("2");
node2.item(0).getParentNode().insertBefore(root3,node2.item(0));
for(int i=0;i<nodes1.getLength();i=i+1){
Node n= (Node) doc.importNode(nodes1.item(i), true);
nodes.item(i).getParentNode().appendChild(n);
}
Transformer transformer = null;
try {
transformer = TransformerFactory.newInstance().newTransformer();
} catch (TransformerConfigurationException e1) {
e1.printStackTrace();
} catch (TransformerFactoryConfigurationError e1) {
e1.printStackTrace();
}
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
StreamResult result = new StreamResult(new StringWriter());
DOMSource source = new DOMSource(doc);
try {
transformer.transform(source,result);
} catch (TransformerException e) {
e.printStackTrace();
}
Writer output = null;
output = new BufferedWriter(new FileWriter("merge.xml"));
String xmlout = result.getWriter().toString();
output.write(xmlout);
response.setContentType("text/xml");
out.write(xmlout);
//out.println(xmlout);
//System.out.println(xmlout);
//I tried many ways but
//it will not print to the browser in xml the format
}
A point of note; you're setting the ContentType three times. It only needs setting once?
You don't appear to be returning the response, but I presume some other part of your program is handling that.
EDITED: the other answer that was here disappeared.
Going to need more information to work out what is going wrong. Please bear in mind that System.out.println() calls will not show up in the browser as they're console-specific.

How to disable prettyPrint xstream xml and still add stylesheet and prolog?

I can remove prettyprint in xml (all newlines/carriage returns) by using CompactWriter() but how to keep my prolog and stylesheets?
Currently I am using Writer class to add prolog and stylesheet using write method.
Below is my function to serialize an object.
private void serializeData(DiagData diagData){
fileinfo=new HashMap<String,String>();
XStream xstream = new XStream();
xstream.processAnnotations(DiagData.class);
FileOutputStream fileOutputStream=null;
Writer writer=null;
//CompactWriter writer=null;
xstream.registerConverter(new MapConverter());
try {
String path = Constants.XML_PATH+File.separator+Constants.DIRECTORY_NAME;
File diagnosticDir = new File(path);
String serialNumber=null;
IDataCollector dataCollector=new DataCollector();
serialNumber=dataCollector.getSerialNumber();
String fileName = new SimpleDateFormat("yyyyMMddhhmmss'.xml'").format(new Date());
if(serialNumber!=null)fileName=serialNumber+Constants.UNDERSCORE+fileName;
fileName=Constants.PHONEHOME+Constants.UNDERSCORE+fileName;
fileOutputStream = new FileOutputStream(path+File.separator+fileName);
writer = new OutputStreamWriter(fileOutputStream);
//writer = new CompactWriter(new OutputStreamWriter(fileOutputStream));
writer.write(Constants.PROLOG);
writer.write(Constants.STYLESHEET);
xstream.toXML(diagData, writer);
//xstream.marshal(diagData, writer);
} catch (FileNotFoundException e1) {
} catch (Exception e) {
} finally {
try {
fileOutputStream.close();
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
}
}
}
If you look at the XStream documentation, they clearly state that you have to add the XML prolog yourself:
Why does XStream not write an XML declaration?
XStream is designed to write XML snippets, so you can embed its output into
an existing stream or string. You can write the XML declaration yourself into
the Writer before using it to call XStream.toXML(writer).
The following code should work. I removed most of your code, so you have to put it back. The purpose is just to give you a rough working example:
private static void serializeData(Object diagData) throws Exception {
XStream xstream = new XStream();
xstream.processAnnotations(DiagData.class);
FileOutputStream fileOutputStream = null;
Writer writer = new PrintWriter(new File(your file));
CompactWriter compactWriter = new CompactWriter(writer);
try {
writer.write(your xml prolog);
writer.write(your stylesheet);
xstream.marshal(diagData, compactWriter);
} catch (FileNotFoundException e1) {
} catch (Exception e) {
} finally {
release resources
}
}

Applying a xalan java transformation to an axis2 object?

I am tying to get the open source OWL-S API http://on.cs.unibas.ch/owls-api/ to use axis2. I have managed to get the requests sent correctly but when it comes to the response I am having trouble applying a transformation to it. In order to make my question easier to answer I am providing some standalone code which should run without having to import the project. To setup the DOMSource:
String xmlString = "<ns1:countResponse xmlns:ns1=\"http://www.test.de/pill-counter\"><ns1:value>0</ns1:value><ns1:value>0</ns1:value><ns1:value>1</ns1:value><ns1:value>0</ns1:value><ns1:value>0</ns1:value><ns1:value>0</ns1:value></ns1:countResponse>";
ByteArrayInputStream xmlStream = new ByteArrayInputStream(xmlString.getBytes());
OMElement test = null;
try {
StAXBuilder builder = new StAXOMBuilder(xmlStream);
test = (OMElement) builder.getDocument().getChildren().next();
} catch (XMLStreamException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
OMElement documentElement = null;
try {
documentElement = AXIOMUtil.stringToOM(DOOMAbstractFactory.getOMFactory(), xmlString);
} catch (XMLStreamException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
SAAJConverterFactory convFactory = (SAAJConverterFactory) FactoryRegistry.getFactory(org.apache.axis2.jaxws.message.factory.SAAJConverterFactory.class);
SAAJConverter conv = convFactory.getSAAJConverter();
//Create soap 1.1 message
SOAPMessage msg = MessageFactory.newInstance().createMessage();
SOAPPart sp = msg.getSOAPPart();
SOAPEnvelope se = sp.getEnvelope();
SOAPBody soapBody = se.getBody();
javax.xml.soap.SOAPFactory soapFactory = javax.xml.soap.SOAPFactory.newInstance();
response = conv.toSAAJ(documentElement, soapBody, soapFactory);
Node root = response;
And now to apply the transformation:
Transformer transformer = null;
try {
transformer = TransformerFactory.newInstance().newTransformer(new StreamSource(new StringReader("<xsl:stylesheet version=\"1.0\" xmlns:xsl=\"http://www.w3.org/1999/XSL/Transform\" xmlns:ns1=\"http://www.test.de/pill-counter\">\n\n\t<xsl:template match=\"/\">\n\t\t<xsl:value-of select=\"sum(*/ns1:value)\" />\n\t</xsl:template>\n</xsl:stylesheet>")));
} catch (TransformerConfigurationException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (TransformerFactoryConfigurationError e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
transformer.transform(new DOMSource(root), new StreamResult(System.out));
} catch (TransformerException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
The result of running this code is a NullPointerException.
SystemId unknown; Line num.0; Column num.0; java.lang.NullPointerException
I have tried searching for a solution to this problem on Google, the Xalan-j mailing list and on this site with no luck. I have also tried with several other coding approaches and no luck. Any ideas from anyone?
I found another way to get this working by generating the Document from scratch:
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setNamespaceAware(true);
dbf.setValidating(false);
DocumentBuilder db = null;
try {
db = dbf.newDocumentBuilder();
} catch (ParserConfigurationException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
InputSource is = new InputSource(new StringReader(documentElement.toString()));
Document document = null;
try{
document=db.parse(is);
} catch (SAXException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
} catch (IOException e3) {
// TODO Auto-generated catch block
e3.printStackTrace();
}
To use the JAXP API on an Axiom tree you don't need to convert it first to SAAJ or DOM. Axiom is able to create a SAXSource that can be passed to JAXP. An example can be found here. That example uses the javax.xml.validation API, but for javax.xml.transform it works the same way.
Note that the example uses some APIs introduced in recent Axiom versions, but the feature already exists for quite some time. Depending on the Axiom version you are using, the code needs to be adapted to the older API. In particular, instead of calling getSAXSource (which was introduced in 1.2.13), you need to construct an org.apache.axiom.om.impl.jaxp.OMSource object and pass that to JAXP.
Have you considered using wsdl2java to construct stubs, rather that using the low-level API directly? This would let you easily manipulate the reponse in java. Using xslt seems like an unusual approach in this case.

Categories