public ServiceExecutionResult<SorRole> updateSorRole(
      final SorPerson sorPerson, final SorRole sorRole) {
    Assert.notNull(sorPerson, "sorPerson cannot be null.");
    Assert.notNull(sorRole, "sorRole cannot be null.");

    final Set validationErrors = this.validator.validate(sorRole);

    if (!validationErrors.isEmpty()) {
      // since because of existing design we cannot raise exception, we can only rollback the
      // transaction through code
      // OR-384
      if (TransactionAspectSupport.currentTransactionStatus() != null) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

      return new GeneralServiceExecutionResult<SorRole>(validationErrors);
    }

    final SorRole savedSorRole = this.personRepository.saveSorRole(sorRole);

    final Person person = this.personRepository.findByInternalId(sorPerson.getPersonId());
    final Role role = person.findRoleBySoRRoleId(savedSorRole.getId());
    if (role != null) {
      // update calculated role only if that role was previously converted to calculated one by
      // sorRoleElector
      role.recalculate(savedSorRole);
      this.personRepository.savePerson(person);
    }
    // else //do nothing i.e. don't update the calculated role if SorRoleElector Previously decided
    // not to convert this sor role to calculated role

    return new GeneralServiceExecutionResult<SorRole>(savedSorRole);
  }
  public ServiceExecutionResult<ReconciliationResult> reconcile(
      final ReconciliationCriteria reconciliationCriteria) throws IllegalArgumentException {
    Assert.notNull(reconciliationCriteria, "reconciliationCriteria cannot be null");
    logger.info("reconcile start");
    final Set validationErrors = this.validator.validate(reconciliationCriteria);

    if (!validationErrors.isEmpty()) {
      Iterator iter = validationErrors.iterator();
      while (iter.hasNext()) {
        logger.info("validation errors: " + iter.next());
      }
      logger.info("reconcile start");
      // since because of existing design we cannot raise exception, we can only rollback the
      // transaction through code
      // OR-384
      if (TransactionAspectSupport.currentTransactionStatus() != null) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

      return new GeneralServiceExecutionResult<ReconciliationResult>(validationErrors);
    }

    final ReconciliationResult result = this.reconciler.reconcile(reconciliationCriteria);
    // (reconciliationCriteria, result);
    return new GeneralServiceExecutionResult<ReconciliationResult>(result);
  }
  /**
   * Persists an SorPerson on update.
   *
   * @param sorPerson the person to update.
   * @return serviceExecutionResult.
   */
  public ServiceExecutionResult<SorPerson> updateSorPerson(final SorPerson sorPerson) {
    final Set validationErrors = this.validator.validate(sorPerson);

    if (!validationErrors.isEmpty()) {
      Iterator iter = validationErrors.iterator();
      while (iter.hasNext()) {
        logger.info("validation errors: " + iter.next());
      }
      // since because of existing design we cannot raise exception, we can only rollback the
      // transaction through code
      // OR-384
      if (TransactionAspectSupport.currentTransactionStatus() != null) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

      return new GeneralServiceExecutionResult<SorPerson>(validationErrors);
    }

    // do reconciliationCheck to make sure that modifications do not cause person to reconcile to a
    // different person
    if (!this.reconciler.reconcilesToSamePerson(sorPerson)) {
      throw new IllegalStateException();
    }

    // Iterate over any sorRoles setting sorid and source id if not specified by SoR.
    for (final SorRole sorRole : sorPerson.getRoles()) {
      setRoleIdAndSource(sorRole, sorPerson.getSourceSor());
    }

    // Save Sor Person
    final SorPerson savedSorPerson = this.personRepository.saveSorPerson(sorPerson);

    Person person = this.findPersonById(savedSorPerson.getPersonId());

    Assert.notNull(person, "person cannot be null.");

    logger.info(
        "Verifying Number of calculated Roles before the calculate: " + person.getRoles().size());

    // Iterate over sorRoles. SorRoles may be new or updated.
    for (final SorRole savedSorRole : savedSorPerson.getRoles()) {
      logger.info(
          "DefaultPersonService: savedSorPersonRole Found, savedSorRoleID: "
              + savedSorRole.getId());
      logger.info("DefaultPersonService: savedSorPersonRole Found, Role Must be newly added.");
      // let sor role elector decide if this new role can be converted to calculated one
      sorRoleElector.addSorRole(savedSorRole, person);
      logger.info(
          "Verifying Number of calculated Roles after calculate: " + person.getRoles().size());
    }

    for (final IdentifierAssigner ia : this.identifierAssigners) {
      ia.addIdentifierTo(sorPerson, person);
    }

    person = recalculatePersonBiodemInfo(person, savedSorPerson, RecalculationType.UPDATE, false);
    person = this.personRepository.savePerson(person);

    return new GeneralServiceExecutionResult<SorPerson>(savedSorPerson);
  }
  @PreAuthorize("hasPermission(#sorRole, 'admin')")
  public ServiceExecutionResult<SorRole> validateAndSaveRoleForSorPerson(
      final SorPerson sorPerson, final SorRole sorRole) {
    logger.info(" validateAndSaveRoleForSorPerson start");
    Assert.notNull(sorPerson, "SorPerson cannot be null.");
    Assert.notNull(sorRole, "SorRole cannot be null.");

    // check if the SoR Role has an ID assigned to it already and assign source sor
    setRoleIdAndSource(sorRole, sorPerson.getSourceSor());

    final Set validationErrors = this.validator.validate(sorRole);

    if (!validationErrors.isEmpty()) {
      // since because of existing design we cannot raise exception, we can only rollback the
      // transaction through code
      // OR-384
      if (TransactionAspectSupport.currentTransactionStatus() != null) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

      return new GeneralServiceExecutionResult<SorRole>(validationErrors);
    }

    final SorPerson newSorPerson = this.personRepository.saveSorPerson(sorPerson);
    Person person = this.personRepository.findByInternalId(newSorPerson.getPersonId());
    final SorRole newSorRole = newSorPerson.findSorRoleBySorRoleId(sorRole.getSorId());
    // let sor role elector decide if this new role can be converted to calculated one
    sorRoleElector.addSorRole(newSorRole, person);
    person = recalculatePersonBiodemInfo(person, newSorPerson, RecalculationType.UPDATE, false);
    this.personRepository.savePerson(person);
    logger.info("validateAndSaveRoleForSorPerson end");
    return new GeneralServiceExecutionResult<SorRole>(newSorRole);
  }
  /**
   * This does not explicitly delete the names because its assumed the recalculation will clean it
   * up.
   */
  public boolean deleteSystemOfRecordPerson(
      final SorPerson sorPerson, final boolean mistake, final String terminationTypes) {
    Assert.notNull(sorPerson, "sorPerson cannot be null.");
    final String terminationTypeToUse =
        terminationTypes != null ? terminationTypes : Type.TerminationTypes.UNSPECIFIED.name();

    final Person person = this.personRepository.findByInternalId(sorPerson.getPersonId());
    Assert.notNull(person, "person cannot be null.");

    if (mistake) {
      Set<Role> rolesToDelete = new HashSet<Role>();

      for (final SorRole sorRole : sorPerson.getRoles()) {
        for (final Role role : person.getRoles()) {
          if (sorRole.getId().equals(role.getSorRoleId())) {
            rolesToDelete.add(role);
          }
        }
      }

      for (final Role role : rolesToDelete) {
        // let sorRoleElector delete the role and add another role if required
        sorRoleElector.removeCalculatedRole(
            person, role, this.personRepository.getSoRRecordsForPerson(person));
      }

      final Number number = this.personRepository.getCountOfSoRRecordsForPerson(person);

      if (number.intValue() == 1) {
        this.personRepository.deletePerson(person);
      }

      this.personRepository.deleteSorPerson(sorPerson);
      return true;
    }

    // we do this explicitly here because once they're gone we can't re-calculate?  We might move to
    // this to the recalculateCalculatedPerson method.
    final Type terminationReason =
        this.referenceRepository.findType(Type.DataTypes.TERMINATION, terminationTypeToUse);

    for (final SorRole sorRole : sorPerson.getRoles()) {
      for (final Role role : person.getRoles()) {
        if (!role.isTerminated() && sorRole.getId().equals(role.getSorRoleId())) {
          role.expireNow(terminationReason, true);
        }
      }
    }

    this.personRepository.deleteSorPerson(sorPerson);
    this.personRepository.savePerson(person);

    Person p = recalculatePersonBiodemInfo(person, sorPerson, RecalculationType.DELETE, mistake);
    this.personRepository.savePerson(p);
    return true;
  }
  public ServiceExecutionResult<Person> addPerson(
      final ReconciliationCriteria reconciliationCriteria)
      throws ReconciliationException, IllegalArgumentException, SorPersonAlreadyExistsException {
    Assert.notNull(reconciliationCriteria, "reconciliationCriteria cannot be null");
    logger.info("addPerson start");
    if (reconciliationCriteria.getSorPerson().getSorId() != null
        && this.findBySorIdentifierAndSource(
                reconciliationCriteria.getSorPerson().getSourceSor(),
                reconciliationCriteria.getSorPerson().getSorId())
            != null) {
      // throw new IllegalStateException("CANNOT ADD SAME SOR RECORD.");
      throw new SorPersonAlreadyExistsException(
          this.findBySorIdentifierAndSource(
              reconciliationCriteria.getSorPerson().getSourceSor(),
              reconciliationCriteria.getSorPerson().getSorId()));
    }

    final Set validationErrors = this.validator.validate(reconciliationCriteria);

    if (!validationErrors.isEmpty()) {
      Iterator iter = validationErrors.iterator();
      while (iter.hasNext()) {
        logger.info("validation errors: " + iter.next());
      }
      // since because of existing design we cannot raise exception, we can only rollback the
      // transaction through code
      // OR-384
      if (TransactionAspectSupport.currentTransactionStatus() != null) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

      return new GeneralServiceExecutionResult<Person>(validationErrors);
    }

    final ReconciliationResult result = this.reconciler.reconcile(reconciliationCriteria);

    switch (result.getReconciliationType()) {
      case NONE:
        return new GeneralServiceExecutionResult<Person>(
            saveSorPersonAndConvertToCalculatedPerson(reconciliationCriteria));

      case EXACT:
        return new GeneralServiceExecutionResult<Person>(
            addNewSorPersonAndLinkWithMatchedCalculatedPerson(reconciliationCriteria, result));
    }

    this.criteriaCache.put(reconciliationCriteria, result);
    logger.info("addPerson start");
    throw new ReconciliationException(result);
  }
  public ServiceExecutionResult<Person> validateAndSavePersonAndRole(
      final ReconciliationCriteria reconciliationCriteria) {
    logger.info(" validateAndSavePersonAndRole start");
    SorPerson sorPerson = reconciliationCriteria.getSorPerson();
    if (sorPerson == null || sorPerson.getRoles() == null)
      throw new IllegalArgumentException("Sor Person not found in provided criteria.");
    SorRole sorRole = reconciliationCriteria.getSorPerson().getRoles().get(0);
    if (sorRole == null)
      throw new IllegalArgumentException("Sor Role not found for provided criteria.");

    setRoleIdAndSource(sorRole, sorPerson.getSourceSor());

    final Set validationErrors = this.validator.validate(sorRole);

    if (!validationErrors.isEmpty()) {
      // since because of existing design we cannot raise exception, we can only rollback the
      // transaction through code
      // OR-384
      if (TransactionAspectSupport.currentTransactionStatus() != null) {
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
      }

      return new GeneralServiceExecutionResult<Person>(validationErrors);
    }

    Long personId = sorPerson.getPersonId();
    if (personId == null) {
      logger.info("calling saveSorPersonAndConvertToCalculatedPerson");
      // add new Sor Person and roles, create calculated person
      return new GeneralServiceExecutionResult<Person>(
          saveSorPersonAndConvertToCalculatedPerson(reconciliationCriteria));
    } else { // Add new Sor Person and role and link to the existing person
      Person thisPerson = this.personRepository.findByInternalId(personId);
      try {
        logger.info("calling addSorPersonAndLink");
        Person savedPerson = this.addSorPersonAndLink(reconciliationCriteria, thisPerson);
        return new GeneralServiceExecutionResult<Person>(savedPerson);
      } catch (SorPersonAlreadyExistsException sorE) {
        throw new IllegalArgumentException(
            "If a sor Person of the same source already exists, should call the other method to add the role only");
      }
    }
  }
  public void init() throws IOException {
    this._logger = LoggerFactory.getLogger(AcquirePort.class);
    selector = Selector.open();
    // 通过open方法来打开一个未绑定的ServerSocketChannel实例
    ServerSocketChannel server = ServerSocketChannel.open();
    InetSocketAddress isa = new InetSocketAddress(_acquirePort);
    // 将该ServerSocketChannel绑定到指定IP地址
    server.socket().bind(isa);
    // 设置ServerSocket以非阻塞方式工作
    server.configureBlocking(false);
    // 将server注册到指定Selector对象
    server.register(selector, SelectionKey.OP_ACCEPT);
    // 定义准备执行读取数据的ByteBuffer
    ByteBuffer buff = ByteBuffer.allocate(1024);
    while (selector.select() > 0) {
      // 依次处理selector上的每个已选择的SelectionKey
      Set<SelectionKey> sks = selector.selectedKeys();
      Iterator keys = sks.iterator();
      while (keys.hasNext()) {
        SelectionKey sk = (SelectionKey) keys.next();
        // 从selector上的已选择Key集中删除正在处理的SelectionKey
        keys.remove();
        // 如果sk对应的通道包含客户端的连接请求
        if (sk.isAcceptable()) {
          // 调用accept方法接受连接,产生服务器端对应的SocketChannel
          SocketChannel sc = server.accept();
          // 设置采用非阻塞模式
          sc.configureBlocking(false);
          // 将该SocketChannel也注册到selector
          sc.register(selector, SelectionKey.OP_READ);
        }
        // 如果sk对应的通道有数据需要读取
        if (sk.isReadable()) {
          // 获取该SelectionKey对应的Channel,该Channel中有可读的数据
          SocketChannel sc = (SocketChannel) sk.channel();
          // 开始读取数据

          try {
            while (sc.read(buff) > 0) {
              buff.flip();
              this._logger.info("content" + buff);
              sc.write(buff);
              if (buff.hasRemaining()) {
                buff.compact();
              } else {
                buff.clear();
              }
            }
            // 打印从该sk对应的Channel里读取到的数据
            this._logger.info("accpect content" + buff);
          }
          // 如果捕捉到该sk对应的Channel出现了异常,即表明该Channel
          // 对应的Client出现了问题,所以从Selector中取消sk的注册
          catch (IOException ex) {
            // 从Selector中删除指定的SelectionKey
            sk.cancel();
            if (sk.channel() != null) {
              sk.channel().close();
            }
          }
        }
      }
    }
  }