docs: public Channel joinPeer(Orderer orderer, Peer peer, PeerOptions peerOptions) throws ProposalException {
  
          logger.debug(format("Channel %s joining peer %s, url: %s", name, peer.getName(), peer.getUrl()));
  
          if (shutdown) {
              throw new ProposalException(format("Channel %s has been shutdown.", name));
          }
  
          Channel peerChannel = peer.getChannel();
          if (null != peerChannel && peerChannel != this) {
              throw new ProposalException(format("Can not add peer %s to channel %s because it already belongs to channel %s.", peer.getName(), name, peerChannel.getName()));
  
          }
  
          logger.info(format("%s joining %s.", toString(), peer));
  
          if (genesisBlock == null && orderers.isEmpty()) {
              ProposalException e = new ProposalException("Channel missing genesis block and no orderers configured");
              logger.error(e.getMessage(), e);
          }
          try {
  
              genesisBlock = getGenesisBlock(orderer);
              logger.debug(format("Channel %s got genesis block", name));
  
              final Channel systemChannel = newSystemChannel(client); //channel is not really created and this is targeted to system channel
  
              TransactionContext transactionContext = systemChannel.getTransactionContext();
  
              FabricProposal.Proposal joinProposal = JoinPeerProposalBuilder.newBuilder()
                      .context(transactionContext)
                      .genesisBlock(genesisBlock)
                      .build();
  
              logger.debug("Getting signed proposal.");
              SignedProposal signedProposal = getSignedProposal(transactionContext, joinProposal);
              logger.debug("Got signed proposal.");
  
              addPeer(peer, peerOptions); //need to add peer.
  
              Collection<ProposalResponse> resp = sendProposalToPeers(new ArrayList<>(Collections.singletonList(peer)),
                      signedProposal, transactionContext);
  
              ProposalResponse pro = resp.iterator().next();
  
              if (pro.getStatus() == ProposalResponse.Status.SUCCESS) {
                  logger.info(format("Peer %s joined into channel %s", peer, toString()));
              } else {
                  removePeerInternal(peer);
                  throw new ProposalException(format("Join peer to channel %s failed.  Status %s, details: %s",
                          name, pro.getStatus().toString(), pro.getMessage()));
  
              }
          } catch (ProposalException e) {
              logger.error(format("%s removing peer %s due to exception %s", toString(), peer, e.getMessage()));
              removePeerInternal(peer);
              logger.error(e);
              throw e;
          } catch (Exception e) {
              logger.error(format("%s removing peer %s due to exception %s", toString(), peer, e.getMessage()));
              peers.remove(peer);
              logger.error(e);
              throw new ProposalException(e.getMessage(), e);
          }
  
          return this;
      }