public Element getInvitationElemenByOwnerAndPath(String owner, String currentPath) {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return null;
    }

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String userid = XmlUtil.getChildText(invitationElement, "user");

      if ((userid != null) && userid.equals(owner)) {
        String path = XmlUtil.getChildText(invitationElement, "path");

        if ((path != null) && path.equals(currentPath)) {
          return invitationElement;
        }
      }
    }

    return (null);
  }
  public String getInvitationPath(String code) {
    Element invitationElement = getInvitationElement(code);

    if (invitationElement == null) {
      return (null);
    }

    String path = XmlUtil.getChildText(invitationElement, "path");

    if (path == null) {
      return (null);
    }

    String expirationString = XmlUtil.getChildText(invitationElement, "expires");

    if (expirationString == null) {
      return (null);
    }

    long expiration = 0L;

    try {
      expiration = Long.parseLong(expirationString);
    } catch (NumberFormatException nfe) {
    }

    if (System.currentTimeMillis() > expiration) {
      return (null);
    }

    return (path);
  }
  public void removeExpired() {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return;
    }

    Vector expiredList = new Vector();

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String expirationString = XmlUtil.getChildText(invitationElement, "expires");

      if (expirationString != null) {
        long expiration = 0L;

        try {
          expiration = Long.parseLong(expirationString);
        } catch (NumberFormatException nfe) {
        }

        if (System.currentTimeMillis() > expiration) {
          expiredList.add(invitationElement);
        }
      }
    }

    int expiredNum = expiredList.size();

    for (int i = expiredList.size() - 1; i >= 0; i--) {
      Element expiredElement = (Element) expiredList.elementAt(i);

      String type = XmlUtil.getChildText(expiredElement, "type");

      if ((type != null) && type.equals(INVITATION_TYPE_TREE)) {
        String virtualUser = XmlUtil.getChildText(expiredElement, "virtualUser");

        if ((virtualUser != null) && (virtualUser.trim().length() > 0)) {
          WebFileSys.getInstance().getUserMgr().removeUser(virtualUser);
          Logger.getLogger(getClass()).debug("expired virtual user " + virtualUser + " removed");
        }
      }

      invitationRoot.removeChild(expiredElement);
    }

    if (expiredNum > 0) {
      changed = true;
    }

    Logger.getLogger(getClass()).info(expiredNum + " expired invitations removed");
    Logger.getLogger(getClass()).info(expiredNum + " expired invitations removed");
  }
  public boolean addSubscriber(String virtualUser, String subscriberEmail) {
    Element watchedInvitation = getInvitationElementByVirtualUser(virtualUser);
    if (watchedInvitation == null) {
      return false;
    }

    Element subscriberListElem = XmlUtil.getChildByTagName(watchedInvitation, "subscriberList");
    if (subscriberListElem == null) {
      subscriberListElem = doc.createElement("subscriberList");
      watchedInvitation.appendChild(subscriberListElem);
    }

    NodeList subscriberList = subscriberListElem.getElementsByTagName("subscriber");

    if (subscriberList != null) {
      int listLength = subscriberList.getLength();
      for (int i = 0; i < listLength; i++) {
        Element subscriberElement = (Element) subscriberList.item(i);
        if (XmlUtil.getChildText(subscriberElement, "email").equals(subscriberEmail)) {
          return false;
        }
      }
    }

    Element subscriberElem = doc.createElement("subscriber");
    XmlUtil.setChildText(subscriberElem, "email", subscriberEmail);
    XmlUtil.setChildText(subscriberElem, "code", generateAccessCode());
    subscriberListElem.appendChild(subscriberElem);
    changed = true;
    return true;
  }
  public ArrayList<String> listSubscribers(String owner, String path) {

    ArrayList<String> subscribers = new ArrayList<String>();

    Element watchedInvitation = getInvitationElemenByOwnerAndPath(owner, path);
    if (watchedInvitation == null) {
      return subscribers;
    }

    Element subscriberListElem = XmlUtil.getChildByTagName(watchedInvitation, "subscriberList");
    if (subscriberListElem == null) {
      return subscribers;
    }

    NodeList subscriberList = subscriberListElem.getElementsByTagName("subscriber");

    if (subscriberList != null) {
      int listLength = subscriberList.getLength();

      for (int i = 0; i < listLength; i++) {
        Element subscriberElement = (Element) subscriberList.item(i);
        subscribers.add(XmlUtil.getChildText(subscriberElement, "email"));
      }
    }

    if (subscribers.size() > 1) {
      Collections.sort(subscribers);
    }

    return subscribers;
  }
  /** Get the list of access codes owned by the user. */
  public ArrayList<String> getInvitationsByOwner(String userid) {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return (null);
    }

    ArrayList<String> ownerList = new ArrayList<String>();

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String owner = XmlUtil.getChildText(invitationElement, "user");

      if ((owner != null) && owner.equals(userid)) {
        String accessCode = invitationElement.getAttribute("accessCode");

        if (accessCode != null) {
          ownerList.add(accessCode);
        }
      }
    }

    return ownerList;
  }
  public String getInvitationType(String code) {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return (null);
    }

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String accessCode = invitationElement.getAttribute("accessCode");

      if ((accessCode != null) && accessCode.equals(code)) {
        String type = XmlUtil.getChildText(invitationElement, "type");

        if ((type == null) || (type.length() == 0)) {
          return (INVITATION_TYPE_COMMON);
        }

        return (type);
      }
    }

    return (INVITATION_TYPE_COMMON);
  }
  public String getInvitationOwner(String code) {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return (null);
    }

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String accessCode = invitationElement.getAttribute("accessCode");

      if ((accessCode != null) && accessCode.equals(code)) {
        String owner = XmlUtil.getChildText(invitationElement, "user");

        if ((owner == null) || (owner.length() == 0)) {
          return (null);
        }

        return (owner);
      }
    }

    return (null);
  }
  public boolean unsubscribe(String virtualUser, String subscriberEmail, String code) {
    Element watchedInvitation = getInvitationElementByVirtualUser(virtualUser);
    if (watchedInvitation == null) {
      return false;
    }

    Element subscriberListElem = XmlUtil.getChildByTagName(watchedInvitation, "subscriberList");
    if (subscriberListElem == null) {
      return false;
    }

    NodeList subscriberList = subscriberListElem.getElementsByTagName("subscriber");

    if (subscriberList != null) {
      int listLength = subscriberList.getLength();
      for (int i = 0; i < listLength; i++) {
        Element subscriberElement = (Element) subscriberList.item(i);
        String email = XmlUtil.getChildText(subscriberElement, "email");
        if ((email != null) && email.equals(subscriberEmail)) {
          String subscriptionCode = XmlUtil.getChildText(subscriberElement, "code");
          if ((subscriptionCode != null) && subscriptionCode.equals(code)) {
            subscriberListElem.removeChild(subscriberElement);
            if (listLength == 1) {
              watchedInvitation.removeChild(subscriberListElem);
            }
            changed = true;
            return true;
          } else {
            Logger.getLogger(getClass())
                .warn(
                    "unsubscribe attempt with invalid code, virtualUser="******" email="
                        + subscriberEmail
                        + " code="
                        + code);
          }
        }
      }
    }
    return false;
  }
  public boolean commentsEnabled(String code) {
    Element invitationElement = getInvitationElement(code);

    if (invitationElement == null) {
      return (false);
    }

    String allowComments = XmlUtil.getChildText(invitationElement, "allowComments");

    return ((allowComments != null) && allowComments.equalsIgnoreCase("true"));
  }
  public boolean commentsAllowed(String virtualUser) {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return (false);
    }

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String tmp = XmlUtil.getChildText(invitationElement, "virtualUser");

      if ((tmp != null) && tmp.equals(virtualUser)) {
        tmp = XmlUtil.getChildText(invitationElement, "allowComments");

        return ((tmp != null) && tmp.equalsIgnoreCase("true"));
      }
    }

    return (false);
  }
  public String getVirtualUser(String code) {
    Element invitationElement = getInvitationElement(code);

    if (invitationElement == null) {
      return (null);
    }

    String virtualUser = XmlUtil.getChildText(invitationElement, "virtualUser");

    if ((virtualUser == null) || (virtualUser.length() == 0)) {
      return (null);
    }

    return (virtualUser);
  }
  public Date getExpirationTime(String code) {
    Element invitationElement = getInvitationElement(code);

    if (invitationElement == null) {
      return (null);
    }

    long expiration = 0L;

    String expirationString = XmlUtil.getChildText(invitationElement, "expires");

    if (expirationString != null) {
      try {
        expiration = Long.parseLong(expirationString);
      } catch (NumberFormatException nfe) {
      }
    }

    return (new Date(expiration));
  }
  public Element getInvitationElementByVirtualUser(String virtualUser) {
    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return (null);
    }

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElement = (Element) invitationList.item(i);

      String vUser = XmlUtil.getChildText(invitationElement, "virtualUser");

      if ((vUser != null) && vUser.equals(virtualUser)) {
        return (invitationElement);
      }
    }

    return (null);
  }
  private void checkSubscriberNotifications() {
    if (Logger.getLogger(getClass()).isDebugEnabled()) {
      Logger.getLogger(getClass()).debug("checking subscriber notifications");
    }

    NodeList invitationList = invitationRoot.getElementsByTagName("invitation");

    if (invitationList == null) {
      return;
    }

    int listLength = invitationList.getLength();

    for (int i = 0; i < listLength; i++) {
      Element invitationElem = (Element) invitationList.item(i);

      Element notifyElem = XmlUtil.getChildByTagName(invitationElem, "notifySubscribers");
      if (notifyElem != null) {
        Element changedElem = XmlUtil.getChildByTagName(notifyElem, "changed");

        if (changedElem != null) {
          long lastChangeTime = 0;
          try {
            lastChangeTime = Long.parseLong(XmlUtil.getElementText(changedElem));
          } catch (NumberFormatException numEx) {
            Logger.getLogger(getClass()).error("invalid change time", numEx);
          }

          if (System.currentTimeMillis() - lastChangeTime > NOTIFIY_DELAY_AFTER_CHANGE) {
            // wait some time after blog change until subscribers are notified, in case more entries
            // will be created soon
            long lastNotified = 0;
            String lastNotificationTime = XmlUtil.getChildText(notifyElem, "lastNotified");
            if (!CommonUtils.isEmpty(lastNotificationTime)) {
              try {
                lastNotified = Long.parseLong(lastNotificationTime);
              } catch (NumberFormatException numEx) {
                Logger.getLogger(getClass())
                    .error("invalid lastNotified time: " + lastNotificationTime);
              }
            }

            if (System.currentTimeMillis() - lastNotified > MIN_SUBSCRIBER_NOTIFICATION_INTERVAL) {
              Element subscriberListElem =
                  XmlUtil.getChildByTagName(invitationElem, "subscriberList");
              if (subscriberListElem != null) {
                NodeList subscriberList = subscriberListElem.getElementsByTagName("subscriber");

                if (subscriberList != null) {
                  String blogPath = XmlUtil.getChildText(invitationElem, "path");

                  String virtualUser = XmlUtil.getChildText(invitationElem, "virtualUser");

                  String blogTitle = MetaInfManager.getInstance().getDescription(blogPath, ".");
                  if (CommonUtils.isEmpty(blogTitle)) {
                    blogTitle = virtualUser;
                  }

                  String blogAccessCode = invitationElem.getAttribute("accessCode");

                  int subscriberListLength = subscriberList.getLength();

                  for (int k = 0; k < subscriberListLength; k++) {
                    Element subscriberElement = (Element) subscriberList.item(k);
                    String email = XmlUtil.getChildText(subscriberElement, "email");
                    String code = XmlUtil.getChildText(subscriberElement, "code");
                    sendSubscriberNotification(email, code, blogTitle, virtualUser, blogAccessCode);
                  }
                }
              }

              notifyElem.removeChild(changedElem);
              XmlUtil.setChildText(
                  notifyElem, "lastNotified", Long.toString(System.currentTimeMillis()));

              changed = true;
            }
          }
        }
      }
    }
  }