public void generateXmlListOfForms(PrintWriter output, CallingContext cc)
      throws IOException, ODKDatastoreException {
    Document d = new Document();
    d.setStandalone(true);
    d.setEncoding(HtmlConsts.UTF8_ENCODE);
    Element e = d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.XFORMS_TAG);
    e.setPrefix(null, XML_TAG_NAMESPACE);
    d.addChild(0, Node.ELEMENT, e);
    int idx = 0;
    e.addChild(idx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);

    // build XML table of form information
    for (IForm form : forms) {
      if (!form.getDownloadEnabled()) continue;

      idx = generateFormXmlEntry(d, e, idx, form, cc);
    }

    KXmlSerializer serializer = new KXmlSerializer();
    serializer.setOutput(output);
    // setting the response content type emits the xml header.
    // just write the body here...
    d.writeChildren(serializer);
    serializer.flush();
  }
  private static void populateRelationshipTypes(Element controlNode) {
    List<RelationshipType> relationshipTypes =
        Context.getPersonService().getAllRelationshipTypes(false);
    for (RelationshipType type : relationshipTypes) {
      Element itemNode;
      // The value is of the form relationTypeId:A
      itemNode = createRelationTypeOptionNode(type, controlNode, true);
      controlNode.addChild(Element.ELEMENT, itemNode);

      // For relationships like sibling/sibling just display one option. Otherwise, we need 2
      // items for each side of the relationship, one for each side of the relationship so that
      // the user can select which side the of the relationship the relative is i.e A Vs B
      if (!type.getbIsToA().equalsIgnoreCase(type.getaIsToB())) {
        itemNode = createRelationTypeOptionNode(type, controlNode, false);
        controlNode.addChild(Element.ELEMENT, itemNode);
      }
    }
  }
  public static void fillRelationships(Patient patient, Element dataNode) throws Exception {
    Element relativeNode = XformBuilder.getElement(dataNode, NODE_RELATIVE);
    if (relativeNode == null) return;

    int index = 0;
    List<Relationship> relationships = Context.getPersonService().getRelationshipsByPerson(patient);
    for (Relationship relationship : relationships) {
      if (++index > 1)
        relativeNode = XformBuilder.createCopy(relativeNode, new ArrayList<String>());

      relativeNode.setAttribute(null, XformBuilder.ATTRIBUTE_UUID, relationship.getUuid());

      String personUuid;
      String relative;
      if (getPersonId(patient).equals(relationship.getPersonA().getPersonId())) {
        relative =
            relationship.getPersonB().getPersonName()
                + " - "
                + getPatientIdentifier(relationship.getPersonB());

        personUuid = relationship.getPersonB().getUuid();
      } else {
        relative =
            relationship.getPersonA().getPersonName()
                + " - "
                + getPatientIdentifier(relationship.getPersonA());

        personUuid = relationship.getPersonA().getUuid();
      }

      Element personNode = XformBuilder.getElement(relativeNode, NODE_PERSON);
      personNode.setAttribute(null, "displayValue", relative);
      personNode.setAttribute(null, "default", "false()");
      XformBuilder.setNodeValue(personNode, personUuid);

      Element relationshipNode = XformBuilder.getElement(relativeNode, NODE_RELATIONSHIP);
      relationshipNode.setAttribute(null, "default", "false()");
      XformBuilder.setNodeValue(
          relationshipNode,
          relationship.getRelationshipType().getRelationshipTypeId()
              + ((relationship.getPersonA().getPersonId().equals(patient.getPersonId()))
                  ? "B"
                  : "A"));
    }
  }
  private static void writeSubmissionManifest(
      EncryptedFormInformation formInfo, File submissionXml, List<File> mediaFiles)
      throws EncryptionException {

    Document d = new Document();
    d.setStandalone(true);
    d.setEncoding(UTF_8);
    Element e = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, DATA);
    e.setPrefix(null, XML_ENCRYPTED_TAG_NAMESPACE);
    e.setAttribute(null, ID, formInfo.formId);
    if (formInfo.formVersion != null) {
      e.setAttribute(null, VERSION, formInfo.formVersion);
    }
    e.setAttribute(null, ENCRYPTED, "yes");
    d.addChild(0, Node.ELEMENT, e);

    int idx = 0;
    Element c;
    c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, BASE64_ENCRYPTED_KEY);
    c.addChild(0, Node.TEXT, formInfo.base64RsaEncryptedSymmetricKey);
    e.addChild(idx++, Node.ELEMENT, c);

    c = d.createElement(XML_OPENROSA_NAMESPACE, META);
    c.setPrefix("orx", XML_OPENROSA_NAMESPACE);
    {
      Element instanceTag = d.createElement(XML_OPENROSA_NAMESPACE, INSTANCE_ID);
      instanceTag.addChild(0, Node.TEXT, formInfo.instanceMetadata.instanceId);
      c.addChild(0, Node.ELEMENT, instanceTag);
    }
    e.addChild(idx++, Node.ELEMENT, c);
    e.addChild(idx++, Node.IGNORABLE_WHITESPACE, NEW_LINE);

    if (mediaFiles != null) {
      for (File file : mediaFiles) {
        c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, MEDIA);
        Element fileTag = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, FILE);
        fileTag.addChild(0, Node.TEXT, file.getName() + ".enc");
        c.addChild(0, Node.ELEMENT, fileTag);
        e.addChild(idx++, Node.ELEMENT, c);
        e.addChild(idx++, Node.IGNORABLE_WHITESPACE, NEW_LINE);
      }
    }

    c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, ENCRYPTED_XML_FILE);
    c.addChild(0, Node.TEXT, submissionXml.getName() + ".enc");
    e.addChild(idx++, Node.ELEMENT, c);

    c = d.createElement(XML_ENCRYPTED_TAG_NAMESPACE, BASE64_ENCRYPTED_ELEMENT_SIGNATURE);
    c.addChild(0, Node.TEXT, formInfo.getBase64EncryptedElementSignature());
    e.addChild(idx++, Node.ELEMENT, c);

    FileOutputStream fout = null;
    OutputStreamWriter writer = null;
    try {
      fout = new FileOutputStream(submissionXml);
      writer = new OutputStreamWriter(fout, UTF_8);

      KXmlSerializer serializer = new KXmlSerializer();
      serializer.setOutput(writer);
      // setting the response content type emits the xml header.
      // just write the body here...
      d.writeChildren(serializer);
      serializer.flush();
      writer.flush();
      fout.getChannel().force(true);
      writer.close();
    } catch (Exception ex) {
      ex.printStackTrace();
      String msg =
          "Error writing submission.xml for encrypted submission: "
              + submissionXml.getParentFile().getName();
      Log.e(t, msg);
      throw new EncryptionException(msg, ex);
    } finally {
      IOUtils.closeQuietly(writer);
      IOUtils.closeQuietly(fout);
    }
  }
  @Override
  protected HashMap<String, FormDetails> doInBackground(Void... values) {
    SharedPreferences settings =
        PreferenceManager.getDefaultSharedPreferences(Collect.getInstance().getBaseContext());
    String downloadListUrl =
        settings.getString(
            PreferencesActivity.KEY_SERVER_URL,
            Collect.getInstance().getString(R.string.default_server_url));
    String downloadPath = settings.getString(PreferencesActivity.KEY_FORMLIST_URL, "/formlist");
    downloadListUrl += downloadPath;
    String auth = settings.getString(PreferencesActivity.KEY_AUTH, "");

    // We populate this with available forms from the specified server.
    // <formname, details>
    HashMap<String, FormDetails> formList = new HashMap<String, FormDetails>();

    // get shared HttpContext so that authentication and cookies are retained.
    HttpContext localContext = Collect.getInstance().getHttpContext();
    HttpClient httpclient = WebUtils.createHttpClient(WebUtils.CONNECTION_TIMEOUT);

    DocumentFetchResult result =
        WebUtils.getXmlDocument(downloadListUrl, localContext, httpclient, auth);

    // If we can't get the document, return the error, cancel the task
    if (result.errorMessage != null) {
      if (result.responseCode == 401) {
        formList.put(DL_AUTH_REQUIRED, new FormDetails(result.errorMessage));
      } else {
        formList.put(DL_ERROR_MSG, new FormDetails(result.errorMessage));
      }
      return formList;
    }

    if (result.isOpenRosaResponse) {
      // Attempt OpenRosa 1.0 parsing
      Element xformsElement = result.doc.getRootElement();
      if (!xformsElement.getName().equals("xforms")) {
        String error = "root element is not <xforms> : " + xformsElement.getName();
        Log.e(t, "Parsing OpenRosa reply -- " + error);
        formList.put(
            DL_ERROR_MSG,
            new FormDetails(
                Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed, error)));
        return formList;
      }
      String namespace = xformsElement.getNamespace();
      if (!isXformsListNamespacedElement(xformsElement)) {
        String error = "root element namespace is incorrect:" + namespace;
        Log.e(t, "Parsing OpenRosa reply -- " + error);
        formList.put(
            DL_ERROR_MSG,
            new FormDetails(
                Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed, error)));
        return formList;
      }
      int nElements = xformsElement.getChildCount();
      for (int i = 0; i < nElements; ++i) {
        if (xformsElement.getType(i) != Element.ELEMENT) {
          // e.g., whitespace (text)
          continue;
        }
        Element xformElement = (Element) xformsElement.getElement(i);
        if (!isXformsListNamespacedElement(xformElement)) {
          // someone else's extension?
          continue;
        }
        String name = xformElement.getName();
        if (!name.equalsIgnoreCase("xform")) {
          // someone else's extension?
          continue;
        }

        // this is something we know how to interpret
        String formId = null;
        String formName = null;
        String majorMinorVersion = null;
        String description = null;
        String downloadUrl = null;
        String manifestUrl = null;
        // don't process descriptionUrl
        int fieldCount = xformElement.getChildCount();
        for (int j = 0; j < fieldCount; ++j) {
          if (xformElement.getType(j) != Element.ELEMENT) {
            // whitespace
            continue;
          }
          Element child = xformElement.getElement(j);
          if (!isXformsListNamespacedElement(child)) {
            // someone else's extension?
            continue;
          }
          String tag = child.getName();
          if (tag.equals("formID")) {
            formId = XFormParser.getXMLText(child, true);
            if (formId != null && formId.length() == 0) {
              formId = null;
            }
          } else if (tag.equals("name")) {
            formName = XFormParser.getXMLText(child, true);
            if (formName != null && formName.length() == 0) {
              formName = null;
            }
          } else if (tag.equals("majorMinorVersion")) {
            majorMinorVersion = XFormParser.getXMLText(child, true);
            if (majorMinorVersion != null && majorMinorVersion.length() == 0) {
              majorMinorVersion = null;
            }
          } else if (tag.equals("descriptionText")) {
            description = XFormParser.getXMLText(child, true);
            if (description != null && description.length() == 0) {
              description = null;
            }
          } else if (tag.equals("downloadUrl")) {
            downloadUrl = XFormParser.getXMLText(child, true);
            if (downloadUrl != null && downloadUrl.length() == 0) {
              downloadUrl = null;
            }
          } else if (tag.equals("manifestUrl")) {
            manifestUrl = XFormParser.getXMLText(child, true);
            if (manifestUrl != null && manifestUrl.length() == 0) {
              manifestUrl = null;
            }
          }
        }
        if (formId == null || downloadUrl == null || formName == null) {
          String error =
              "Forms list entry "
                  + Integer.toString(i)
                  + " is missing one or more tags: formId, name, or downloadUrl";
          Log.e(t, "Parsing OpenRosa reply -- " + error);
          formList.clear();
          formList.put(
              DL_ERROR_MSG,
              new FormDetails(
                  Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed, error)));
          return formList;
        }
        /*
         * TODO: We currently don't care about major/minor version. maybe someday we will.
         */
        // Integer modelVersion = null;
        // Integer uiVersion = null;
        // try {
        // if (majorMinorVersion == null || majorMinorVersion.length() == 0) {
        // modelVersion = null;
        // uiVersion = null;
        // } else {
        // int idx = majorMinorVersion.indexOf(".");
        // if (idx == -1) {
        // modelVersion = Integer.parseInt(majorMinorVersion);
        // uiVersion = null;
        // } else {
        // modelVersion = Integer.parseInt(majorMinorVersion.substring(0, idx));
        // uiVersion =
        // (idx == majorMinorVersion.length() - 1) ? null : Integer
        // .parseInt(majorMinorVersion.substring(idx + 1));
        // }
        // }
        // } catch (Exception e) {
        // e.printStackTrace();
        // String error = "Forms list entry " + Integer.toString(i) +
        // " has an invalid majorMinorVersion: " + majorMinorVersion;
        // Log.e(t, "Parsing OpenRosa reply -- " + error);
        // formList.clear();
        // formList.put(DL_ERROR_MSG, new FormDetails(
        // Collect.getInstance().getString(R.string.parse_openrosa_formlist_failed,
        // error)));
        // return formList;
        // }
        formList.put(formId, new FormDetails(formName, downloadUrl, manifestUrl, formId));
      }
    } else {
      // Aggregate 0.9.x mode...
      // populate HashMap with form names and urls
      Element formsElement = result.doc.getRootElement();
      int formsCount = formsElement.getChildCount();
      for (int i = 0; i < formsCount; ++i) {
        if (formsElement.getType(i) != Element.ELEMENT) {
          // whitespace
          continue;
        }
        Element child = formsElement.getElement(i);
        String tag = child.getName();
        String formId = null;
        if (tag.equals("formID")) {
          formId = XFormParser.getXMLText(child, true);
          if (formId != null && formId.length() == 0) {
            formId = null;
          }
        }
        if (tag.equalsIgnoreCase("form")) {
          String formName = XFormParser.getXMLText(child, true);
          if (formName != null && formName.length() == 0) {
            formName = null;
          }
          String downloadUrl = child.getAttributeValue(null, "url");
          downloadUrl = downloadUrl.trim();
          if (downloadUrl != null && downloadUrl.length() == 0) {
            downloadUrl = null;
          }
          if (downloadUrl == null || formName == null) {
            String error =
                "Forms list entry "
                    + Integer.toString(i)
                    + " is missing form name or url attribute";
            Log.e(t, "Parsing OpenRosa reply -- " + error);
            formList.clear();
            formList.put(
                DL_ERROR_MSG,
                new FormDetails(
                    Collect.getInstance().getString(R.string.parse_legacy_formlist_failed, error)));
            return formList;
          }
          formList.put(formName, new FormDetails(formName, downloadUrl, null, formName));
        }
      }
    }
    return formList;
  }
 private boolean isXformsListNamespacedElement(Element e) {
   return e.getNamespace().equalsIgnoreCase(NAMESPACE_OPENROSA_ORG_XFORMS_XFORMS_LIST);
 }
  public static DecryptOutcome decryptAndValidateSubmission(
      Document doc, PrivateKey rsaPrivateKey, File instanceDir, File unEncryptedDir)
      throws ParsingException, FileSystemException, CryptoException {

    Element rootElement = doc.getRootElement();

    String base64EncryptedSymmetricKey;
    String instanceIdMetadata = null;
    List<String> mediaNames = new ArrayList<String>();
    String encryptedSubmissionFile;
    String base64EncryptedElementSignature;

    {
      Element base64Key = null;
      Element base64Signature = null;
      Element encryptedXml = null;
      for (int i = 0; i < rootElement.getChildCount(); ++i) {
        if (rootElement.getType(i) == Node.ELEMENT) {
          Element child = rootElement.getElement(i);
          String name = child.getName();
          if (name.equals("base64EncryptedKey")) {
            base64Key = child;
          } else if (name.equals("base64EncryptedElementSignature")) {
            base64Signature = child;
          } else if (name.equals("encryptedXmlFile")) {
            encryptedXml = child;
          } else if (name.equals("media")) {
            Element media = child;
            for (int j = 0; j < media.getChildCount(); ++j) {
              if (media.getType(j) == Node.ELEMENT) {
                Element mediaChild = media.getElement(j);
                String mediaFileElementName = mediaChild.getName();
                if (mediaFileElementName.equals("file")) {
                  String mediaName = XFormParser.getXMLText(mediaChild, true);
                  if (mediaName == null || mediaName.length() == 0) {
                    mediaNames.add(null);
                  } else {
                    mediaNames.add(mediaName);
                  }
                }
              }
            }
          }
        }
      }

      // verify base64Key
      if (base64Key == null) {
        throw new ParsingException("Missing base64EncryptedKey element in encrypted form.");
      }
      base64EncryptedSymmetricKey = XFormParser.getXMLText(base64Key, true);

      // get instanceID out of OpenRosa meta block
      instanceIdMetadata = XmlManipulationUtils.getOpenRosaInstanceId(rootElement);
      if (instanceIdMetadata == null) {
        throw new ParsingException("Missing instanceID within meta block of encrypted form.");
      }

      // get submission filename
      if (encryptedXml == null) {
        throw new ParsingException("Missing encryptedXmlFile element in encrypted form.");
      }
      encryptedSubmissionFile = XFormParser.getXMLText(encryptedXml, true);
      if (base64Signature == null) {
        throw new ParsingException(
            "Missing base64EncryptedElementSignature element in encrypted form.");
      }
      base64EncryptedElementSignature = XFormParser.getXMLText(base64Signature, true);
    }

    if (instanceIdMetadata == null
        || base64EncryptedSymmetricKey == null
        || base64EncryptedElementSignature == null
        || encryptedSubmissionFile == null) {
      throw new ParsingException("Missing one or more required elements of encrypted form.");
    }

    FormInstanceMetadata fim;
    try {
      fim = XmlManipulationUtils.getFormInstanceMetadata(rootElement);
    } catch (ParsingException e) {
      e.printStackTrace();
      throw new ParsingException(
          "Unable to extract form instance medatadata from submission manifest. Cause: "
              + e.toString());
    }

    if (!instanceIdMetadata.equals(fim.instanceId)) {
      throw new ParsingException(
          "InstanceID within metadata does not match that on top level element.");
    }

    boolean isValidated =
        FileSystemUtils.decryptSubmissionFiles(
            base64EncryptedSymmetricKey,
            fim,
            mediaNames,
            encryptedSubmissionFile,
            base64EncryptedElementSignature,
            rsaPrivateKey,
            instanceDir,
            unEncryptedDir);

    // and change doc to be the decrypted submission document
    File decryptedSubmission = new File(unEncryptedDir, "submission.xml");
    doc = XmlManipulationUtils.parseXml(decryptedSubmission);
    if (doc == null) {
      return null;
    }

    // verify that the metadata matches between the manifest and the submission
    rootElement = doc.getRootElement();
    FormInstanceMetadata sim = XmlManipulationUtils.getFormInstanceMetadata(rootElement);
    if (!fim.xparam.equals(sim.xparam)) {
      throw new ParsingException(
          "FormId or version in decrypted submission does not match that in manifest!");
    }
    if (!fim.instanceId.equals(sim.instanceId)) {
      throw new ParsingException(
          "InstanceId in decrypted submission does not match that in manifest!");
    }

    return new DecryptOutcome(doc, isValidated);
  }
  private static Element buildRepeatInputNode(Element bodyNode) {
    // Create the parent repeat ui node.
    Element groupNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    groupNode.setName(XformBuilder.NODE_GROUP);
    bodyNode.addChild(Element.ELEMENT, groupNode);

    Element labelNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    labelNode.setName(XformBuilder.NODE_LABEL);
    labelNode.addChild(Element.TEXT, "RELATIONSHIPS");
    groupNode.addChild(Element.ELEMENT, labelNode);

    Element hintNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    hintNode.setName(XformBuilder.NODE_HINT);
    hintNode.addChild(Element.TEXT, "Relationships that this patient has.");
    groupNode.addChild(Element.ELEMENT, hintNode);

    Element repeatNode = bodyNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    repeatNode.setName(XformBuilder.CONTROL_REPEAT);
    repeatNode.setAttribute(null, XformBuilder.ATTRIBUTE_BIND, BIND_RELATIVE);
    groupNode.addChild(Element.ELEMENT, repeatNode);

    return repeatNode;
  }
  private static void buildBindNodes(Element modelElement) {
    // Create bind node for relative.
    Element bindNode = modelElement.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    bindNode.setName(XformBuilder.NODE_BIND);
    bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_ID, BIND_RELATIVE);
    bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_NODESET, "/form/patient/patient_relative");
    modelElement.addChild(Element.ELEMENT, bindNode);

    // Create bind node for person.
    bindNode = modelElement.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    bindNode.setName(XformBuilder.NODE_BIND);
    bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_ID, BIND_PERSON);
    bindNode.setAttribute(
        null,
        XformBuilder.ATTRIBUTE_NODESET,
        "/form/patient/patient_relative/patient_relative.person");
    modelElement.addChild(Element.ELEMENT, bindNode);

    // Create bind node for relationship.
    bindNode = modelElement.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    bindNode.setName(XformBuilder.NODE_BIND);
    bindNode.setAttribute(null, XformBuilder.ATTRIBUTE_ID, BIND_RELATIONSHIP);
    bindNode.setAttribute(
        null,
        XformBuilder.ATTRIBUTE_NODESET,
        "/form/patient/patient_relative/patient_relative.relationship");
    modelElement.addChild(Element.ELEMENT, bindNode);
  }
  /**
   * Creates a node for a select option for the specified relation type
   *
   * @param relationshipType the relationshipType object.
   * @param controlNode the select node
   * @param isA specifies which side of the relationship we are adding the option for
   * @return the Element for the select option
   */
  private static Element createRelationTypeOptionNode(
      RelationshipType relationshipType, Element controlNode, boolean isA) {
    Element itemNode = controlNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    itemNode.setName(XformBuilder.NODE_ITEM);

    Element node = itemNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    node.setName(XformBuilder.NODE_LABEL);
    node.addChild(
        Element.TEXT,
        "is "
            + ((isA) ? relationshipType.getaIsToB() : relationshipType.getbIsToA())
            + " ["
            + relationshipType.getRelationshipTypeId()
            + "]");
    itemNode.addChild(Element.ELEMENT, node);

    node = itemNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    node.setName(XformBuilder.NODE_VALUE);
    node.addChild(Element.TEXT, relationshipType.getRelationshipTypeId() + ((isA) ? "A" : "B"));
    itemNode.addChild(Element.ELEMENT, node);
    return itemNode;
  }
  private static void buildRelationshipInputNode(Element repeatNode) {
    // Create relationship input node.
    Element inputNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    inputNode.setName(XformBuilder.CONTROL_SELECT1);
    inputNode.setAttribute(null, XformBuilder.ATTRIBUTE_BIND, BIND_RELATIONSHIP);

    populateRelationshipTypes(inputNode);

    repeatNode.addChild(Element.ELEMENT, inputNode);

    // Create relationship label.
    Element labelNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    labelNode.setName(XformBuilder.NODE_LABEL);
    labelNode.addChild(Element.TEXT, "RELATIONSHIP");
    inputNode.addChild(Element.ELEMENT, labelNode);

    repeatNode.addChild(Element.ELEMENT, inputNode);
  }
  private static void buildPersonInputNode(Element repeatNode) {
    // Create person input node.
    Element inputNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    inputNode.setName(XformBuilder.CONTROL_INPUT);
    inputNode.setAttribute(null, XformBuilder.ATTRIBUTE_BIND, BIND_PERSON);
    repeatNode.addChild(Element.ELEMENT, inputNode);

    // Create person label.
    Element labelNode = repeatNode.createElement(XformBuilder.NAMESPACE_XFORMS, null);
    labelNode.setName(XformBuilder.NODE_LABEL);
    labelNode.addChild(Element.TEXT, "RELATIVE");
    inputNode.addChild(Element.ELEMENT, labelNode);

    repeatNode.addChild(Element.ELEMENT, inputNode);
  }
 /**
  * Encode.
  *
  * @param method the method
  * @return the element
  */
 public final Element encode(final RPCMethod method) {
   GetRPCMethodsResponse grpc = (GetRPCMethodsResponse) method;
   Element result = new Element();
   result.setName("GetRPCMethodsResponse");
   result.setNamespace(Soap.getCWMPNameSpace());
   Element eMethodList = new Element();
   eMethodList.setName("MethodList");
   result.addChild(Element.ELEMENT, eMethodList);
   StringBuffer value = new StringBuffer("xsd:string[");
   value.append(grpc.getLsRPCMethods().size());
   value.append("]");
   eMethodList.setAttribute(Soap.getSoapEncNameSpace(), "arrayType", value.toString());
   for (String string : grpc.getLsRPCMethods()) {
     Element e = new Element();
     e.setName("string");
     e.addChild(Element.TEXT, string);
     eMethodList.addChild(Element.ELEMENT, e);
   }
   return result;
 }
  public GetTransactionResponseMessage getTransaction(
      String api,
      String safekey,
      additionalInfo additionalInformation,
      List<HeaderProperty> headers,
      String username,
      String password) {
    SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    soapEnvelope.implicitTypes = true;
    soapEnvelope.dotNet = true;
    soapEnvelope.setAddAdornments(true);
    SoapObject soapReq = new SoapObject("", "n1:getTransaction");

    // getTransaction namespace, NB for PAYU
    AttributeInfo attributeInfo = new AttributeInfo();
    attributeInfo.setValue("http://soap.api.controller.web.payjar.com/");
    attributeInfo.setName("xmlns:n1");
    soapReq.addAttribute(attributeInfo);

    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/",
        "AdditionalInformation",
        new additionalInfo().getClass());
    soapReq.addProperty("Api", api);
    soapReq.addProperty("Safekey", safekey);
    additionalInformation.isGetTransaction = true;
    soapReq.addProperty("AdditionalInformation", additionalInformation);
    soapEnvelope.setOutputSoapObject(soapReq);

    // set security header for PAYU
    Element header[] = new Element[1];
    header[0] =
        new Element()
            .createElement(
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                "Security");
    header[0].setAttribute(null, "v:mustUnderstand", "1");

    Element to =
        new Element()
            .createElement(
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                "UsernameToken");

    Element action1 = new Element().createElement(null, "n0:Username");
    action1.setAttribute(
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
        "Id",
        "UsernameToken-9");
    action1.addChild(Node.TEXT, username);
    to.addChild(Node.ELEMENT, action1);

    Element action2 = new Element().createElement(null, "n0:Password");
    action2.setAttribute(
        null,
        "Type",
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
    action2.addChild(Node.TEXT, password);
    to.addChild(Node.ELEMENT, action2);

    header[0].addChild(Node.ELEMENT, to);

    soapEnvelope.headerOut = header;

    HttpTransportSE httpTransport = new HttpTransportSE(url, timeOut);
    httpTransport.debug = true;
    try {
      httpTransport.getServiceConnection().setRequestProperty("Connection", "close");
      System.setProperty("http.keepAlive", "false");
      httpTransport.getServiceConnection().setRequestProperty("Accept-Encoding", "gzip");
      if (headers != null) {
        httpTransport.call(
            "http://soap.api.controller.web.payjar.com/getTransaction", soapEnvelope, headers);
      } else {
        sendgetTransaction(
            "http://soap.api.controller.web.payjar.com/getTransaction", soapEnvelope, 0);
      }
      Object retObj = soapEnvelope.bodyIn;
      if (retObj instanceof SoapFault) {
        SoapFault fault = (SoapFault) retObj;
        Exception ex = new Exception(fault.faultstring);
        if (eventHandler != null) eventHandler.Wsdl2CodeFinishedWithException(ex);
      } else {
        SoapObject result = (SoapObject) retObj;
        if (result.getPropertyCount() > 0) {
          Object obj = result.getProperty(0);
          SoapObject j = (SoapObject) obj;
          GetTransactionResponseMessage resultVariable = new GetTransactionResponseMessage(j);
          return resultVariable;
        }
      }
    } catch (Exception e) {
      if (eventHandler != null) eventHandler.Wsdl2CodeFinishedWithException(e);
      e.printStackTrace();
    }
    return null;
  }
  public SetTransactionResponseMessage setTransaction2(
      String api,
      String safekey,
      transactionType transactionType,
      boolean transactionTypeSpecified,
      boolean stage,
      boolean stageSpecified,
      additionalInfo additionalInformation,
      customer customer,
      basket basket,
      fraud fraud,
      VectorcreditCard creditcard,
      Vectoreft eft,
      VectorloyaltyCard loyalty,
      VectorbankTransfer bankTransfer,
      ebucks ebucks,
      autoPay autopay,
      soulstace soulstace,
      globalpay globalpay,
      VectorcustomField customfield,
      transactionRecord transactionRecord,
      List<HeaderProperty> headers,
      String username,
      String password) {
    SoapSerializationEnvelope soapEnvelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
    soapEnvelope.implicitTypes = false;
    soapEnvelope.dotNet = true;
    soapEnvelope.setAddAdornments(true);
    SoapObject soapReq = new SoapObject("", "n1:setTransaction");

    // settranaction namespace, NB for PAYU
    AttributeInfo attributeInfo = new AttributeInfo();
    attributeInfo.setValue("http://soap.api.controller.web.payjar.com/");
    attributeInfo.setName("xmlns:n1");
    soapReq.addAttribute(attributeInfo);

    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/",
        "AdditionalInformation",
        new additionalInfo().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Customer", new customer().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Basket", new basket().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Fraud", new fraud().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Ebucks", new ebucks().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Autopay", new autoPay().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Soulstace", new soulstace().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/", "Globalpay", new globalpay().getClass());
    soapEnvelope.addMapping(
        "http://soap.api.controller.web.payjar.com/",
        "TransactionRecord",
        new transactionRecord().getClass());

    soapReq.addProperty("Customer", customer);
    soapReq.addProperty("Api", api);
    soapReq.addProperty("Safekey", safekey);
    if (transactionTypeSpecified)
      soapReq.addProperty("TransactionType", transactionType.toString());
    if (stageSpecified) soapReq.addProperty("Stage", stage);
    soapReq.addProperty("AdditionalInformation", additionalInformation);
    soapReq.addProperty("Basket", basket);
    //        soapReq.addProperty("Fraud", fraud);
    //        soapReq.addProperty("Creditcard", creditcard);
    //        soapReq.addProperty("Loyalty", loyalty);
    //        soapReq.addProperty("BankTransfer", bankTransfer);
    //        soapReq.addProperty("Ebucks", ebucks);
    //        soapReq.addProperty("Autopay", autopay);
    //        soapReq.addProperty("Soulstace", soulstace);
    //        soapReq.addProperty("Globalpay", globalpay);
    // soapReq.addProperty("Customfield", customfield);
    soapReq.addProperty("TransactionRecord", transactionRecord);
    soapEnvelope.setOutputSoapObject(soapReq);

    // set security header for PAYU
    Element header[] = new Element[1];
    header[0] =
        new Element()
            .createElement(
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                "Security");
    header[0].setAttribute(null, "v:mustUnderstand", "1");

    Element to =
        new Element()
            .createElement(
                "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd",
                "UsernameToken");

    Element action1 = new Element().createElement(null, "n0:Username");
    action1.setAttribute(
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd",
        "Id",
        "UsernameToken-9");
    action1.addChild(Node.TEXT, username);
    to.addChild(Node.ELEMENT, action1);

    Element action2 = new Element().createElement(null, "n0:Password");
    action2.setAttribute(
        null,
        "Type",
        "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText");
    action2.addChild(Node.TEXT, password);
    to.addChild(Node.ELEMENT, action2);

    header[0].addChild(Node.ELEMENT, to);

    soapEnvelope.headerOut = header;

    HttpTransportSE httpTransport = new HttpTransportSE(url, timeOut);
    httpTransport.debug = true;
    try {
      if (headers != null) {
        httpTransport.call(
            "http://soap.api.controller.web.payjar.com/setTransaction", soapEnvelope, headers);
      } else {
        httpTransport.call(
            "http://soap.api.controller.web.payjar.com/setTransaction", soapEnvelope);
      }
      Object retObj = soapEnvelope.bodyIn;
      String a = soapEnvelope.toString();
      if (retObj instanceof SoapFault) {
        SoapFault fault = (SoapFault) retObj;
        Exception ex = new Exception(fault.faultstring);
        if (eventHandler != null) eventHandler.Wsdl2CodeFinishedWithException(ex);
      } else {
        SoapObject result = (SoapObject) retObj;
        if (result.getPropertyCount() > 0) {
          Object obj = result.getProperty(0);
          SoapObject j = (SoapObject) obj;
          SetTransactionResponseMessage resultVariable = new SetTransactionResponseMessage(j);
          return resultVariable;
        }
      }
    } catch (Exception e) {
      if (eventHandler != null) eventHandler.Wsdl2CodeFinishedWithException(e);
      e.printStackTrace();
    }
    return null;
  }
  private int generateFormXmlEntry(Document d, Element e, int idx, IForm form, CallingContext cc)
      throws ODKDatastoreException {

    int xfIdx = 0;
    Element xformElement = d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.XFORM_TAG);
    e.addChild(idx++, Node.ELEMENT, xformElement);

    Element formIdElement = d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.FORM_ID_TAG);
    xformElement.addChild(xfIdx++, Node.ELEMENT, formIdElement);
    formIdElement.addChild(
        0,
        Node.TEXT,
        form.getFormId()
            .replace(ParserConsts.FORWARD_SLASH_SUBSTITUTION, ParserConsts.FORWARD_SLASH));
    xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);

    Element formNameElement = d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.FORM_NAME_TAG);
    xformElement.addChild(xfIdx++, Node.ELEMENT, formNameElement);
    formNameElement.addChild(0, Node.TEXT, form.getViewableName());
    xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);

    // transitional -- 1.1.6 and 1.1.7
    Element majorMinorVersionElement =
        d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.MAJOR_MINOR_VERSION_TAG);
    xformElement.addChild(xfIdx++, Node.ELEMENT, majorMinorVersionElement);
    majorMinorVersionElement.addChild(0, Node.TEXT, form.getMajorMinorVersionString());
    xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);

    // conforming OpenRosa 1.0
    Element versionElement = d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.VERSION_TAG);
    xformElement.addChild(xfIdx++, Node.ELEMENT, versionElement);
    versionElement.addChild(0, Node.TEXT, form.getOpenRosaVersionString());
    xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);

    Element hashElement = d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.HASH_TAG);
    xformElement.addChild(xfIdx++, Node.ELEMENT, hashElement);
    hashElement.addChild(0, Node.TEXT, form.getXFormFileHash(cc));
    xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);

    String description = form.getDescription();
    if (description != null && verbose) {
      Element descriptionElement =
          d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.DESCRIPTION_TEXT_TAG);
      xformElement.addChild(xfIdx++, Node.ELEMENT, descriptionElement);
      descriptionElement.addChild(0, Node.TEXT, description);
      xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);
    }
    String descriptionUrl = form.getDescriptionUrl();
    if (descriptionUrl != null && verbose) {
      Element descriptionUrlElement =
          d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.DESCRIPTION_URL_TAG);
      xformElement.addChild(xfIdx++, Node.ELEMENT, descriptionUrlElement);
      descriptionUrlElement.addChild(0, Node.TEXT, descriptionUrl);
      xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);
    }

    {
      Map<String, String> properties = new HashMap<String, String>();
      properties.put(ServletConsts.FORM_ID, form.getFormId());
      String urlLink = HtmlUtil.createLinkWithProperties(downloadRequestURL, properties);

      Element downloadUrlElement =
          d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.DOWNLOAD_URL_TAG);
      xformElement.addChild(xfIdx++, Node.ELEMENT, downloadUrlElement);
      downloadUrlElement.addChild(0, Node.TEXT, urlLink);
      xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);
    }

    if (form.hasManifestFileset(cc)) {
      Map<String, String> properties = new HashMap<String, String>();
      properties.put(ServletConsts.FORM_ID, form.getFormId());
      String urlLink = HtmlUtil.createLinkWithProperties(manifestRequestURL, properties);

      Element manifestUrlElement =
          d.createElement(XML_TAG_NAMESPACE, XFormsTableConsts.MANIFEST_URL_TAG);
      xformElement.addChild(xfIdx++, Node.ELEMENT, manifestUrlElement);
      manifestUrlElement.addChild(0, Node.TEXT, urlLink);
      xformElement.addChild(xfIdx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);
    }
    e.addChild(idx++, Node.IGNORABLE_WHITESPACE, BasicConsts.NEW_LINE);
    return idx;
  }