/**
   * Creates a new registration in the server. If it exists, updates its information
   *
   * @param registration The registration to create
   * @return The created registration
   * @throws Exception
   */
  private Registration registerInternal(Registration registration) throws Exception {

    if (mIsRefreshNeeded) {
      String pNSHandle = mSharedPreferences.getString(STORAGE_PREFIX + PNS_HANDLE_KEY, "");

      if (isNullOrWhiteSpace(pNSHandle)) {
        pNSHandle = registration.getPNSHandle();
      }

      refreshRegistrationInformation(pNSHandle);
    }

    String registrationId = retrieveRegistrationId(registration.getName());
    if (isNullOrWhiteSpace(registrationId)) {
      registrationId = createRegistrationId();
    }

    registration.setRegistrationId(registrationId);

    try {
      return upsertRegistrationInternal(registration);
    } catch (RegistrationGoneException e) {
      // if we get an RegistrationGoneException (410) from service, we will recreate registration id
      // and will try to do upsert one more time.
    }

    registrationId = createRegistrationId();
    registration.setRegistrationId(registrationId);
    return upsertRegistrationInternal(registration);
  }
  /**
   * Registers the client for native notifications with the specified tags
   *
   * @param pnsHandle PNS specific identifier
   * @param tags Tags to use in the registration
   * @return The created registration
   * @throws Exception
   */
  public Registration register(String pnsHandle, String... tags) throws Exception {
    if (isNullOrWhiteSpace(pnsHandle)) {
      throw new IllegalArgumentException("pnsHandle");
    }

    Registration registration =
        PnsSpecificRegistrationFactory.getInstance().createNativeRegistration(mNotificationHubPath);
    registration.setPNSHandle(pnsHandle);
    registration.setName(Registration.DEFAULT_REGISTRATION_NAME);
    registration.addTags(tags);

    return registerInternal(registration);
  }
  /**
   * Updates a registration
   *
   * @param registration The registration to update
   * @return The updated registration
   * @throws Exception
   */
  private Registration upsertRegistrationInternal(Registration registration) throws Exception {
    Connection conn = new Connection(mConnectionString);

    String resource = registration.getURI();
    String content = registration.toXml();

    String response = conn.executeRequest(resource, content, XML_CONTENT_TYPE, "PUT");

    Registration result;
    if (PnsSpecificRegistrationFactory.getInstance().isTemplateRegistration(response)) {
      result =
          PnsSpecificRegistrationFactory.getInstance()
              .createTemplateRegistration(mNotificationHubPath);
    } else {
      result =
          PnsSpecificRegistrationFactory.getInstance()
              .createNativeRegistration(mNotificationHubPath);
    }

    result.loadXml(response, mNotificationHubPath);

    storeRegistrationId(result.getName(), result.getRegistrationId(), registration.getPNSHandle());

    return result;
  }
  private void refreshRegistrationInformation(String pnsHandle) throws Exception {
    if (isNullOrWhiteSpace(pnsHandle)) {
      throw new IllegalArgumentException("pnsHandle");
    }

    // delete old registration information
    Editor editor = mSharedPreferences.edit();
    Set<String> keys = mSharedPreferences.getAll().keySet();
    for (String key : keys) {
      if (key.startsWith(STORAGE_PREFIX + REGISTRATION_NAME_STORAGE_KEY)) {
        editor.remove(key);
      }
    }

    editor.commit();

    // get existing registrations
    Connection conn = new Connection(mConnectionString);

    String filter =
        PnsSpecificRegistrationFactory.getInstance().getPNSHandleFieldName()
            + " eq '"
            + pnsHandle
            + "'";

    String resource =
        mNotificationHubPath + "/Registrations/?$filter=" + URLEncoder.encode(filter, "UTF-8");
    String content = null;
    String response = conn.executeRequest(resource, content, XML_CONTENT_TYPE, "GET");

    DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
    builder.setEntityResolver(
        new EntityResolver() {
          @Override
          public InputSource resolveEntity(String publicId, String systemId)
              throws SAXException, IOException {
            return null;
          }
        });

    Document doc = builder.parse(new InputSource(new StringReader(response)));

    doc.getDocumentElement().normalize();
    Element root = doc.getDocumentElement();

    // for each registration, parse it
    NodeList entries = root.getElementsByTagName("entry");
    for (int i = 0; i < entries.getLength(); i++) {
      Registration registration;
      Element entry = (Element) entries.item(i);
      String xml = getXmlString(entry);
      if (PnsSpecificRegistrationFactory.getInstance().isTemplateRegistration(xml)) {
        registration =
            PnsSpecificRegistrationFactory.getInstance()
                .createTemplateRegistration(mNotificationHubPath);
      } else {
        registration =
            PnsSpecificRegistrationFactory.getInstance()
                .createNativeRegistration(mNotificationHubPath);
      }

      registration.loadXml(xml, mNotificationHubPath);

      storeRegistrationId(
          registration.getName(), registration.getRegistrationId(), registration.getPNSHandle());
    }

    mIsRefreshNeeded = false;
  }