package org.activityinfo.server.endpoint.odk.xform; import com.google.common.base.Optional; import org.activityinfo.model.resource.ResourceId; import org.activityinfo.server.endpoint.odk.build.XPathBuilder; import org.activityinfo.server.endpoint.odk.OdkHelper; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import javax.mail.MessagingException; import javax.mail.internet.MimeMultipart; import javax.mail.util.ByteArrayDataSource; import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import java.io.InputStream; import java.util.logging.Level; import java.util.logging.Logger; import static javax.ws.rs.core.Response.Status.BAD_REQUEST; /** * After {@link LegacyXFormInstance} is eliminated, this class can be merged with {@link XFormInstance} again */ public class XFormInstanceImpl implements XFormInstance { private static final Logger LOGGER = Logger.getLogger(XFormInstanceImpl.class.getName()); private Document document; private MimeMultipart mimeMultipart; private Element data; private Element meta; private String instanceId; private ResourceId formClassId; private String userId; public XFormInstanceImpl(byte[] bytes) { ByteArrayDataSource byteArrayDataSource = new ByteArrayDataSource(bytes, MediaType.MULTIPART_FORM_DATA); parseDocument(byteArrayDataSource); parseHeader(); } private void parseDocument(ByteArrayDataSource byteArrayDataSource) { try { mimeMultipart = new MimeMultipart(byteArrayDataSource); InputStream inputStream = mimeMultipart.getBodyPart(0).getInputStream(); DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); document = documentBuilder.parse(inputStream); } catch (Exception e) { LOGGER.log(Level.SEVERE, "Unable to parse input", e); throw new WebApplicationException(Response.status(BAD_REQUEST).build()); } document.normalizeDocument(); } private void parseHeader() { data = document.getDocumentElement(); formClassId = ResourceId.valueOf(data.getAttribute("id")); meta = findElement(data, "meta"); instanceId = extractText(findElement(meta, "instanceID")).replace("-", ""); userId = extractText(findElement(meta, "userID")); } private String extractText(Element element) { return OdkHelper.extractText(element); } @Override public String getAuthenticationToken() { return userId; } @Override public String getId() { return instanceId; } @Override public Optional<Element> getFieldContent(ResourceId fieldId) { String tagName = XPathBuilder.fieldTagName(fieldId); NodeList nodeList = document.getElementsByTagName(tagName); if (nodeList.getLength() > 0) { return Optional.of((Element) nodeList.item(0)); } else { return Optional.absent(); } } public javax.mail.BodyPart findBodyPartByFilename(String filename) throws MessagingException { for (int i = 0; i < mimeMultipart.getCount(); i++) { javax.mail.BodyPart bodyPart = mimeMultipart.getBodyPart(i); if (filename.equals(bodyPart.getFileName())) { return bodyPart; } } LOGGER.log(Level.SEVERE, "Could not find the specified filename"); throw new WebApplicationException(Response.status(BAD_REQUEST).build()); } static Element findElement(Element parent, String tagName) { NodeList children = parent.getChildNodes(); for(int i=0;i!=children.getLength();++i) { Node child = children.item(i); if(child instanceof Element) { if(((Element) child).getTagName().equals(tagName)) { return (Element) child; } } } throw new IllegalStateException("Cannot find element " + tagName); } @Override public ResourceId getFormClassId() { return formClassId; } }