/** * */ package fr.cedrik.inotes; import java.io.IOException; import java.io.InputStream; import java.nio.charset.Charset; import java.text.ParseException; import javax.xml.namespace.QName; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.Location; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLReporter; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.Attribute; import javax.xml.stream.events.StartElement; import javax.xml.stream.events.XMLEvent; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import fr.cedrik.email.MessagesMetaData; import fr.cedrik.util.DateUtils; /** * @author Cédrik LIME */ // StAX event API class MessagesXMLConverter { protected static final Logger logger = LoggerFactory.getLogger(MessagesXMLConverter.class); public MessagesXMLConverter() { } protected XMLEventReader getXMLEventReader(InputStream input, Charset charset) throws FactoryConfigurationError, XMLStreamException { XMLInputFactory factory = XMLInputFactory.newInstance(); if (factory.isPropertySupported(XMLInputFactory.IS_VALIDATING)) { factory.setProperty(XMLInputFactory.IS_VALIDATING, Boolean.FALSE); } if (factory.isPropertySupported(XMLInputFactory.IS_COALESCING)) { factory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE); } factory.setXMLReporter(new XMLReporter() { @Override public void report(String message, String errorType, Object relatedInformation, Location location) throws XMLStreamException { logger.warn("XML error of type: " + errorType + " at ligne: " + location.getLineNumber() + " column: " + location.getColumnNumber() + ", message: " + message); } }); XMLEventReader reader; if (charset != null) { reader = factory.createXMLEventReader(input, charset.name()); } else { reader = factory.createXMLEventReader(input); } return reader; } public MessagesMetaData<MessageMetaData> convertXML(InputStream input, Charset charset) throws IOException, XMLStreamException { XMLEventReader reader = getXMLEventReader(input, charset); MessagesMetaData<MessageMetaData> messages = new MessagesMetaData<MessageMetaData>(); while (reader.hasNext()) { XMLEvent next = reader.nextEvent(); if (next.isStartElement()) { StartElement start = next.asStartElement(); String startName = start.getName().getLocalPart(); if ("viewentry".equals(startName)) { try { MessageMetaData message = new MessageMetaData(); loadViewEntry(message, start, reader); if (StringUtils.isBlank(message.getId())) { logger.error("Error while parsing XML viewentry: empty unid!"); return null; } messages.entries.add(message); } catch (ParseException e) { logger.error("", e); return null; } } else if ("dbquotasize".equals(startName)) { loadDbQuotaSize(messages, reader); } else if ("unreadinfo".equals(startName)) { loadUnreadInfo(messages, reader); } else { logger.debug("Unknown root element: {}", startName); } } } reader.close(); return messages; } protected void loadDbQuotaSize(MessagesMetaData<?> messages, XMLEventReader reader) throws XMLStreamException { while (reader.hasNext()) { XMLEvent next = reader.nextEvent(); if (next.isStartElement()) { StartElement start = next.asStartElement(); String startName = start.getName().getLocalPart(); if ("dbsize".equals(startName)) { messages.dbsize = Integer.parseInt(readElementValue(reader, start)); } else if ("sizelimit".equals(startName)) { messages.sizelimit = Integer.parseInt(readElementValue(reader, start)); } else if ("warning".equals(startName)) { messages.warning = Integer.parseInt(readElementValue(reader, start)); } else if ("ignorequota".equals(startName)) { messages.ignorequota = Integer.parseInt(readElementValue(reader, start)); } else if ("currentusage".equals(startName)) { messages.currentusage = Integer.parseInt(readElementValue(reader, start)); } else { logger.debug("Unknown DbQuotaSize element: {}", startName); } } else if (next.isEndElement()) { if ("dbquotasize".equals(next.asEndElement().getName().getLocalPart())) { return; } } } } protected void loadUnreadInfo(MessagesMetaData<?> messages, XMLEventReader reader) throws XMLStreamException { while (reader.hasNext()) { XMLEvent next = reader.nextEvent(); if (next.isStartElement()) { StartElement start = next.asStartElement(); String startName = start.getName().getLocalPart(); if ("foldername".equals(startName)) { messages.foldername = readElementValue(reader, start); } else if ("unreadcount".equals(startName)) { try { messages.unreadcount = Integer.parseInt(readElementValue(reader, start)); } catch (NumberFormatException ignore) { logger.trace(ignore.toString()); } } else { logger.debug("Unknown UnreadInfo element: {}", startName); } } else if (next.isEndElement()) { if ("unreadinfo".equals(next.asEndElement().getName().getLocalPart())) { return; } } } } protected void loadViewEntry(MessageMetaData message, StartElement viewEntry, XMLEventReader reader) throws XMLStreamException, ParseException { Attribute unid = viewEntry.getAttributeByName(QName.valueOf("unid")); message.unid = unid.getValue(); Attribute noteid = viewEntry.getAttributeByName(QName.valueOf("noteid")); message.noteid = noteid.getValue(); Attribute unread = viewEntry.getAttributeByName(QName.valueOf("unread")); if (unread != null) { message.unread = Boolean.parseBoolean(unread.getValue()); } while (reader.hasNext()) { XMLEvent next = reader.nextEvent(); if (next.isStartElement()) { StartElement start = next.asStartElement(); String startName = start.getName().getLocalPart(); if ("entrydata".equals(startName)) { // read data value String value = readSingleSubElementValue(reader, start); // determine which attribute this is String name = start.getAttributeByName(QName.valueOf("name")).getValue(); if ("$86".equals(name)) { // type if (StringUtils.isNotBlank(value)) { message.type = Integer.parseInt(value); } } else if ("$Importance".equals(name)) { // importance if (StringUtils.isNotBlank(value)) { message.importance = Integer.parseInt(value); } // } else if ("SametimeInfo".equals(name)) { // availability // message.availability = value; } else if ("$93".equals(name)) { // from message.from93 = value; } else if ("$98".equals(name)) { // from message.from98 = value; // } else if ("$ThreadColumn".equals(name)) { // thread // message.thread = value; } else if ("$73".equals(name)) { // subject message.subject = value; } else if ("$70".equals(name)) { // date if (StringUtils.isNotBlank(value)) { message.date = DateUtils.parseLotusXMLDate(value); } } else if ("$106".equals(name)) { // size if (StringUtils.isNotBlank(value)) { message.size = Integer.parseInt(value); } } else if ("$ToStuff".equals(name)) { // recipient if (StringUtils.isNotBlank(value)) { message.recipient = Integer.parseInt(value); } } else if ("$97".equals(name)) { // attachement if (StringUtils.isNotBlank(value)) { message.attachement = Integer.parseInt(value); } } else if ("$109".equals(name)) { // answer flag if (StringUtils.isNotBlank(value)) { message.answerFlag = Integer.parseInt(value); } // } else if ("$UserData".equals(name)) { // user data // message.userData = value; } else { logger.debug("Unknown EntryData attribute value: {}", name); } } else { logger.debug("Unknown ViewEntry element: {}", startName); } } else if (next.isEndElement()) { if ("viewentry".equals(next.asEndElement().getName().getLocalPart())) { return; } } } } protected String readSingleSubElementValue(XMLEventReader reader, StartElement start) throws XMLStreamException { String value = null; boolean inValueElement = false; while (reader.hasNext()) { XMLEvent next = reader.nextEvent(); if (next.isStartElement()) { inValueElement = true; StartElement startData = next.asStartElement(); logger.trace("{} element: {}", start.getName().getLocalPart(), startData.getName().getLocalPart()); } else if (next.isCharacters() && inValueElement) { value = next.asCharacters().getData(); } else if (next.isEndElement()) { inValueElement = false; if (start.getName().getLocalPart().equals(next.asEndElement().getName().getLocalPart())) { return value; } } } return value; } protected String readElementValue(XMLEventReader reader, StartElement start) throws XMLStreamException { String value = null; while (reader.hasNext()) { XMLEvent next = reader.nextEvent(); if (next.isCharacters()) { value = next.asCharacters().getData(); } else if (next.isEndElement()) { if (start.getName().getLocalPart().equals(next.asEndElement().getName().getLocalPart())) { return value; } } } return value; } }