private @Nullable VPN toVPN(@Nonnull ProviderContext ctx, @Nullable Node node)
      throws CloudException, InternalException {
    if (node == null) {
      return null;
    }

    NodeList attributes = node.getChildNodes();
    String name = null, description = null;
    VPN vpn = new VPN();

    vpn.setCurrentState(VPNState.PENDING);
    vpn.setProviderRegionId(ctx.getRegionId());
    for (int i = 0; i < attributes.getLength(); i++) {
      Node attr = attributes.item(i);
      String nodeName = attr.getNodeName();

      if (nodeName.equalsIgnoreCase("vpnGatewayId") && attr.hasChildNodes()) {
        vpn.setProviderVpnId(attr.getFirstChild().getNodeValue().trim());
      } else if (nodeName.equalsIgnoreCase("state")) {
        vpn.setCurrentState(toVPNState(attr.getFirstChild().getNodeValue().trim()));
      } else if (nodeName.equalsIgnoreCase("type") && attr.hasChildNodes()) {
        String t = attr.getFirstChild().getNodeValue().trim();

        if (t.equalsIgnoreCase("ipsec.1")) {
          vpn.setProtocol(VPNProtocol.IPSEC1);
        } else if (t.equalsIgnoreCase("openvpn")) {
          vpn.setProtocol(VPNProtocol.OPEN_VPN);
        } else {
          logger.warn("DEBUG: Unknown VPN gateway type: " + t);
          vpn.setProtocol(VPNProtocol.IPSEC1);
        }
      } else if (nodeName.equalsIgnoreCase("attachments") && attr.hasChildNodes()) {
        TreeSet<String> vlans = new TreeSet<String>();
        NodeList list = attr.getChildNodes();

        for (int j = 0; j < list.getLength(); j++) {
          Node att = list.item(j);

          if (att.getNodeName().equalsIgnoreCase("item") && att.hasChildNodes()) {
            NodeList aaList = attr.getChildNodes();
            String id = null;

            for (int k = 0; k < aaList.getLength(); k++) {
              Node aa = aaList.item(k);

              if (aa.getNodeName().equalsIgnoreCase("vpcId") && aa.hasChildNodes()) {
                id = aa.getFirstChild().getNodeValue().trim();
                break;
              }
            }
            if (id != null) {
              vlans.add(id);
            }
          }
        }
        vpn.setProviderVlanIds(vlans.toArray(new String[vlans.size()]));
      } else if (nodeName.equalsIgnoreCase("tagSet") && attr.hasChildNodes()) {
        provider.setTags(attr, vpn);
        if (vpn.getTags().get("name") != null) {
          name = vpn.getTags().get("name");
        }
        if (vpn.getTags().get("description") != null) {
          description = vpn.getTags().get("description");
        }
      }
    }
    if (vpn.getProviderVpnId() == null) {
      return null;
    }
    if (vpn.getName() == null) {
      vpn.setName(name == null ? vpn.getProviderVpnId() : name);
    }
    if (vpn.getDescription() == null) {
      vpn.setDescription(description == null ? vpn.getName() : description);
    }
    return vpn;
  }
  private @Nullable VPNGateway toGateway(@Nonnull ProviderContext ctx, @Nullable Node node)
      throws CloudException, InternalException {
    if (node == null) {
      return null;
    }

    NodeList attributes = node.getChildNodes();
    VPNGateway gateway = new VPNGateway();

    gateway.setProviderOwnerId(ctx.getAccountNumber());
    gateway.setProviderRegionId(ctx.getRegionId());
    gateway.setCurrentState(VPNGatewayState.PENDING);
    for (int i = 0; i < attributes.getLength(); i++) {
      Node attr = attributes.item(i);
      String nodeName = attr.getNodeName();

      if (nodeName.equalsIgnoreCase("customerGatewayId") && attr.hasChildNodes()) {
        gateway.setProviderVpnGatewayId(attr.getFirstChild().getNodeValue().trim());
      } else if (nodeName.equalsIgnoreCase("state") && attr.hasChildNodes()) {
        String state = attr.getFirstChild().getNodeValue().trim();

        if (state.equalsIgnoreCase("available")) {
          gateway.setCurrentState(VPNGatewayState.AVAILABLE);
        } else if (state.equalsIgnoreCase("deleting")) {
          gateway.setCurrentState(VPNGatewayState.DELETING);
        } else if (state.equalsIgnoreCase("deleted")) {
          gateway.setCurrentState(VPNGatewayState.DELETED);
        } else if (state.equalsIgnoreCase("pending")) {
          gateway.setCurrentState(VPNGatewayState.PENDING);
        } else {
          logger.warn("DEBUG: Unknown VPN gateway state: " + state);
        }
      } else if (nodeName.equalsIgnoreCase("type") && attr.hasChildNodes()) {
        String t = attr.getFirstChild().getNodeValue().trim();

        if (t.equalsIgnoreCase("ipsec.1")) {
          gateway.setProtocol(VPNProtocol.IPSEC1);
        } else if (t.equalsIgnoreCase("openvpn")) {
          gateway.setProtocol(VPNProtocol.OPEN_VPN);
        } else {
          logger.warn("DEBUG: Unknown VPN gateway type: " + t);
          gateway.setProtocol(VPNProtocol.IPSEC1);
        }
      } else if (nodeName.equalsIgnoreCase("ipAddress") && attr.hasChildNodes()) {
        gateway.setEndpoint(attr.getFirstChild().getNodeValue().trim());
      } else if (nodeName.equalsIgnoreCase("bgpAsn") && attr.hasChildNodes()) {
        gateway.setBgpAsn(attr.getFirstChild().getNodeValue().trim());
      } else if (nodeName.equalsIgnoreCase("tagSet") && attr.hasChildNodes()) {
        provider.setTags(attr, gateway);
      }
    }
    if (gateway.getProviderVpnGatewayId() == null) {
      return null;
    }
    if (gateway.getName() == null) {
      gateway.setName(gateway.getProviderVpnGatewayId() + " [" + gateway.getEndpoint() + "]");
    }
    if (gateway.getDescription() == null) {
      gateway.setDescription(gateway.getName());
    }
    return gateway;
  }