1 22 package org.objectweb.petals.engine.csv; 23 24 import java.io.ByteArrayInputStream ; 25 import java.io.ByteArrayOutputStream ; 26 import java.io.InputStream ; 27 import java.io.OutputStream ; 28 import java.nio.charset.Charset ; 29 import java.util.Iterator ; 30 import java.util.Map ; 31 import java.util.Properties ; 32 import java.util.logging.Level ; 33 import java.util.logging.Logger ; 34 35 import javax.activation.DataHandler ; 36 import javax.jbi.messaging.DeliveryChannel; 37 import javax.jbi.messaging.NormalizedMessage; 38 import javax.xml.namespace.QName ; 39 import javax.xml.transform.Source ; 40 41 import org.apache.commons.io.IOUtils; 42 import org.objectweb.petals.component.common.listener.AbstractInternalMEProcessor; 43 import org.objectweb.petals.component.common.util.SourceHelper; 44 import org.objectweb.petals.component.common.util.StringHelper; 45 import org.objectweb.petals.component.common.util.XMLHelper; 46 import org.objectweb.petals.engine.csv.exception.CsvException; 47 import org.w3c.dom.Document ; 48 import org.w3c.dom.Element ; 49 import org.w3c.dom.Node ; 50 import org.w3c.dom.NodeList ; 51 import org.w3c.dom.Text ; 52 53 import com.csvreader.CsvReader; 54 55 99 public class CsvProcessor extends AbstractInternalMEProcessor { 100 101 public static final String CSV_TO_XML_OPERATION = "csvToXml"; 102 public static final String XML_TO_CSV_OPERATION = "xmlToCsv"; 103 104 public static final String CSV_INPUT_MODE_CONTENT = "content"; 105 public static final String CSV_INPUT_MODE_ATTACHMENT = "attachment"; 106 public static final String CSV_INPUT_MODE_GUESS = "guess"; 107 108 public static final String CSV_INPUT_MODE_PROP = "csvInputMode"; 109 public static final String CUSTOM_COLUMN_DELIMITER_CHAR_PROP = "customColumnDelimiterChar"; 110 public static final String USE_CUSTOM_RECORD_DELIMITER_PROP = "useCustomRecordDelimiter"; 111 public static final String CUSTOM_RECORD_DELIMITER_CHAR_PROP = "customRecordDelimiterChar"; 112 public static final String USE_DOUBLE_ESCAPE_MODE_PROP = "useDoubleEscapeMode"; 113 public static final String USE_COMMENT_PROP = "useComment"; 114 public static final String COMMENT_CHAR_PROP = "commentChar"; 115 116 private static final String CONTENT_TAG = "content"; 120 private static final String DATA_TAG = "data"; 121 private static final String ROW_TAG = "row"; 122 private static final String CSVXML_NAMESPACE_URI = "http://petals.objectweb.org/components/csv/csvxml"; 123 private static final String CELL_TAG = "cell"; 124 125 126 127 private Map <String , Properties > mapEndpointCsv; 128 129 130 137 public CsvProcessor(DeliveryChannel c, Logger l, 138 Map <String , Properties > mapEndpointCsv) { 139 super(c, l); 140 this.mapEndpointCsv = mapEndpointCsv; 141 } 142 143 144 @Override 145 protected void sendInMessage(QName service, QName operation, 146 NormalizedMessage in) throws CsvException { 147 throw new CsvException("Only InOut messages are supported"); 149 } 150 151 @Override 152 protected boolean sendInOutMessage(QName service, QName operation, 153 NormalizedMessage in, NormalizedMessage out, boolean optionalOut) 154 throws CsvException { 155 Properties csvProperties = getCsvProperties(service.getLocalPart()); 157 158 159 if (CSV_TO_XML_OPERATION.equals(operation.getLocalPart())) { 160 try { 161 String csvContent = getCsvInputContent(in, csvProperties); 163 164 if (StringHelper.isEmpty(csvContent)) { 165 l.log(Level.WARNING, "Empty message content"); 166 throw new CsvException("operation : message empty"); 168 } 169 170 ByteArrayOutputStream xmlOut = new ByteArrayOutputStream (); 172 transformCsvToXml(new ByteArrayInputStream (csvContent.getBytes()), 173 xmlOut, csvProperties); 174 175 out.setContent(SourceHelper.createSource(new String (xmlOut.toByteArray()))); 177 } catch (CsvException e) { 178 throw e; 179 } catch (Exception e) { 180 String msg = "Error while transforming csv to XML : " + e.getMessage(); 181 l.log(Level.SEVERE, msg, e); 182 throw new CsvException(msg, e); 183 } 184 185 186 } else if (XML_TO_CSV_OPERATION.equals(operation.getLocalPart())) { 187 Node documentNode = getXmlInputDocument(in, csvProperties); 188 189 try { 190 Node xmlTableNode = XMLHelper.getFirstChild(documentNode); 191 StringBuffer csvBuf = new StringBuffer (); 193 transformXmlToCsv(xmlTableNode, csvBuf, csvProperties); 194 195 out.setContent(SourceHelper.createContentSource(csvBuf.toString())); 197 } catch (CsvException e) { 198 throw e; 199 } catch (Exception e) { 200 String msg = "Error while transforming XML to CSV : " + e.getMessage(); 201 l.log(Level.SEVERE, msg, e); 202 throw new CsvException(msg, e); 203 } 204 205 } else { 206 throw new CsvException("Unknown operation " + operation); 207 } 208 209 return true; 210 } 211 212 213 222 private void transformXmlToCsv(Node xmlTableNode, StringBuffer csvBuf, 223 Properties csvProperties) throws CsvException { 224 225 char csvColumnDelimiterChar = csvProperties 227 .getProperty(CUSTOM_COLUMN_DELIMITER_CHAR_PROP, ",").charAt(0); 228 char csvCustomRecordDelimiterChar = csvProperties 229 .getProperty(CUSTOM_RECORD_DELIMITER_CHAR_PROP, "\n").charAt(0); 230 boolean useCustomRecordDelimiter = Boolean.valueOf(csvProperties 231 .getProperty(USE_CUSTOM_RECORD_DELIMITER_PROP, "false")).booleanValue(); 232 String recordDelimiter = (useCustomRecordDelimiter) 233 ? String.valueOf(csvCustomRecordDelimiterChar) : "\r\n"; 234 235 NodeList rowNodes = xmlTableNode.getChildNodes(); 236 int rowNodeNb = rowNodes.getLength(); 237 for (int i = 0; i < rowNodeNb; i++) { 238 Node rowNode = rowNodes.item(i); 239 if (!(rowNode instanceof Element )) { 240 continue; 241 } 242 243 NodeList columnNodes = rowNode.getChildNodes(); 245 int columnNodeNb = columnNodes.getLength(); 246 for (int j = 0; j < columnNodeNb; j++) { 247 Node columnNode = columnNodes.item(j); 248 if (!(columnNode instanceof Element )) { 249 continue; 250 } 251 252 String cellValue = XMLHelper.getTextContent(columnNode); 254 csvBuf.append(cellValue); 255 csvBuf.append(csvColumnDelimiterChar); 256 } 257 if (columnNodeNb != 0) { 258 csvBuf.deleteCharAt(csvBuf.length() - 1); 260 } 261 262 csvBuf.append(recordDelimiter); 264 } 265 266 if (rowNodeNb != 0) { 267 csvBuf.deleteCharAt(csvBuf.length() - recordDelimiter.length()); 269 } 270 } 271 272 273 281 protected Node getXmlInputDocument(NormalizedMessage in, Properties csvProperties) 282 throws CsvException { 283 try { 284 if (isModeAttachment(in, csvProperties)) { 285 String firstAttachmentName = null; 287 for (Iterator nameIt = in.getAttachmentNames().iterator(); nameIt.hasNext();) { 288 firstAttachmentName = (String ) nameIt.next(); 289 break; 290 } 291 if (firstAttachmentName == null) { 292 String msg = "Error while getting XML source content : " 293 + "inputMode is \"attachment\" but there is none given"; 294 l.log(Level.SEVERE, msg); 295 throw new CsvException(msg); 296 } 297 DataHandler firstAttachment = in.getAttachment(firstAttachmentName); 298 String contentString = IOUtils.toString(firstAttachment.getInputStream()); 299 return XMLHelper.createDocumentFromString(contentString); 300 301 } else { 302 Source xmlTableSource = in.getContent(); 303 return XMLHelper.createDOMNodeFromSource(xmlTableSource); 304 } 305 } catch (CsvException e) { 306 throw e; 307 } catch (Exception e) { 308 String msg = "Error while getting XML source content : " + e.getMessage(); 309 l.log(Level.SEVERE, msg, e); 310 throw new CsvException(msg, e); 311 } 312 } 313 314 315 325 protected String getCsvInputContent(NormalizedMessage in, 326 Properties csvProperties) throws Exception { 327 String contentString; 328 if (isModeAttachment(in, csvProperties)) { 329 String firstAttachmentName = null; 331 for (Iterator nameIt = in.getAttachmentNames().iterator(); nameIt.hasNext();) { 332 firstAttachmentName = (String ) nameIt.next(); 333 break; 334 } 335 if (firstAttachmentName == null) { 336 return null; } 338 DataHandler firstAttachment = in.getAttachment(firstAttachmentName); 339 contentString = IOUtils.toString(firstAttachment.getInputStream()); 340 342 } else { 343 Source content = in.getContent(); 345 contentString = createStringFromContent(content); 346 } 348 return contentString; 349 } 350 351 359 protected static String createStringFromContent(Source content) throws Exception { 360 Node contentNode = XMLHelper.getFirstChild(XMLHelper.createDOMNodeFromSource(content)); 361 if (!CONTENT_TAG.equals(contentNode.getLocalName())) { 363 throw new CsvException("Expected <content> encapsulated content " 364 + "but found " + XMLHelper.createStringFromDOMNode(contentNode)); 365 } 366 String contentString = contentNode.getTextContent(); 368 return contentString; 369 } 370 371 378 protected boolean isModeAttachment(NormalizedMessage in, 379 Properties csvProperties) { 380 String csvInputMode = csvProperties.getProperty(CSV_INPUT_MODE_PROP, "guess"); 381 if (CSV_INPUT_MODE_ATTACHMENT.equals(csvInputMode)) { 382 return true; 383 } else if (CSV_INPUT_MODE_CONTENT.equals(csvInputMode)) { 384 return false; 385 } else { if (!in.getAttachmentNames().isEmpty()) { 387 return true; 388 } 389 } 390 return false; 391 } 392 393 394 402 protected void transformCsvToXml(InputStream csvIn, OutputStream xmlOut, 403 Properties csvProperties) throws CsvException { 404 if (csvIn == null) { 405 throw new CsvException("Input stream must not be null"); 406 } 407 CsvReader csvReader = createCsvReader(csvIn, csvProperties); 409 if (csvReader == null) { 410 throw new CsvException("not a CSV file"); 411 } 412 413 try { 414 Document csvDoc = XMLHelper.createDocumentFromString( 417 "<" + DATA_TAG + " xmlns=\"" + CSVXML_NAMESPACE_URI + "\"/>"); 418 Element dataElement = csvDoc.getDocumentElement(); 420 421 while (csvReader.readRecord()) { 422 Element rowElement = csvDoc.createElementNS(CSVXML_NAMESPACE_URI, ROW_TAG); 423 dataElement.appendChild(rowElement); 424 int columnNb = csvReader.getColumnCount(); 425 426 for (int i = 0; i < columnNb; i++) { 427 String value = csvReader.get(i); 428 value = (value == null) ? "" : value; 430 Element cellElement = csvDoc.createElementNS(CSVXML_NAMESPACE_URI, CELL_TAG); 431 rowElement.appendChild(cellElement); 432 Text valueData = csvDoc.createTextNode(value); 435 cellElement.appendChild(valueData); 436 } 437 } 438 String csvDocString = XMLHelper.createStringFromDOMDocument(csvDoc); 439 xmlOut.write(csvDocString.getBytes()); 440 } catch (Exception e) { 441 throw new CsvException("Error while parsing CSV and building output XML : " 442 + e.getMessage()); 443 } 444 } 445 446 447 455 protected CsvReader createCsvReader(InputStream csvIn, 456 Properties csvProperties) throws CsvException { 457 try { 458 char csvColumnDelimiterChar = csvProperties 460 .getProperty(CUSTOM_COLUMN_DELIMITER_CHAR_PROP, ",").charAt(0); 461 char csvCustomRecordDelimiterChar = csvProperties 462 .getProperty(CUSTOM_RECORD_DELIMITER_CHAR_PROP, "\n").charAt(0); 463 boolean useCustomRecordDelimiter = Boolean.valueOf(csvProperties 464 .getProperty(USE_CUSTOM_RECORD_DELIMITER_PROP, "false")).booleanValue(); 465 int escapeMode = (Boolean.valueOf(csvProperties.getProperty( 466 USE_DOUBLE_ESCAPE_MODE_PROP, "true")).booleanValue()) ? 467 CsvReader.ESCAPE_MODE_DOUBLED : CsvReader.ESCAPE_MODE_BACKSLASH; 468 boolean useComment = Boolean.valueOf(csvProperties 469 .getProperty(USE_COMMENT_PROP, "false")).booleanValue(); 470 char commentChar = csvProperties.getProperty(COMMENT_CHAR_PROP, "#").charAt(0); 471 472 CsvReader csvReader = new CsvReader(csvIn, Charset.defaultCharset()); 475 csvReader.setDelimiter(csvColumnDelimiterChar); if (useCustomRecordDelimiter) { 477 csvReader.setRecordDelimiter(csvCustomRecordDelimiterChar); 478 } csvReader.setEscapeMode(escapeMode); csvReader.setUseComments(useComment); 481 csvReader.setComment(commentChar); return csvReader; 485 } catch (Exception e) { 486 throw new CsvException("Error setting CSV reader configuration." 487 + "CSV reader properties are : " + csvProperties); 488 } 489 } 490 491 492 499 protected Properties getCsvProperties(String serviceName) throws CsvException{ 500 Properties csvProperties = this.mapEndpointCsv.get(serviceName); 501 if (csvProperties != null) { 502 return csvProperties; 503 } else { 504 throw new CsvException("CSV properties not found for service " 505 + serviceName); 506 } 507 } 508 509 } 510 | Popular Tags |