* Calculates the connectionState resulting from the message in the current connection state.
  * Checks if the specified message is allowed in the connection's state and throws an exception if
  * not.
  * @param con
  * @param msg
  * @return
  * @throws won.protocol.exception.IllegalMessageForConnectionStateException if the message is not
  *     allowed in the connection's current state
 private ConnectionState performStateTransit(Connection con, ConnectionEventType msg)
     throws IllegalMessageForConnectionStateException {
   if (!msg.isMessageAllowed(con.getState())) {
     throw new IllegalMessageForConnectionStateException(
         con.getConnectionURI(), msg.name(), con.getState());
   return con.getState().transit(msg);
   * Creates a new Connection object. Expects <> won:hasFacet [FACET] in the RDF content, will throw
   * exception if it's not there.
   * @param needURI
   * @param otherNeedURI
   * @param otherConnectionURI
   * @param content
   * @param connectionState
   * @param connectionEventType
   * @return
   * @throws NoSuchNeedException
   * @throws IllegalMessageForNeedStateException
   * @throws ConnectionAlreadyExistsException
  public Connection createConnection(
      final URI needURI,
      final URI otherNeedURI,
      final URI otherConnectionURI,
      final Model content,
      final ConnectionState connectionState,
      final ConnectionEventType connectionEventType)
      throws NoSuchNeedException, IllegalMessageForNeedStateException,
          ConnectionAlreadyExistsException {

    if (needURI == null) throw new IllegalArgumentException("needURI is not set");
    if (otherNeedURI == null) throw new IllegalArgumentException("otherNeedURI is not set");
    if (needURI.equals(otherNeedURI))
      throw new IllegalArgumentException("needURI and otherNeedURI are the same");

    // Load need (throws exception if not found)
    Need need = DataAccessUtils.loadNeed(needRepository, needURI);
    if (!isNeedActive(need))
      throw new IllegalMessageForNeedStateException(
          needURI, connectionEventType.name(), need.getState());

    URI facetURI = getFacet(content);
    if (facetURI == null)
      throw new IllegalArgumentException(
          "at least one RDF node must be of type won:" + WON.HAS_FACET.getLocalName());
    // TODO: create a proper exception if a facet is not supported by a need
    if (facetRepository.findByNeedURIAndTypeURI(needURI, facetURI).isEmpty())
      throw new RuntimeException("Facet is not supported by Need: " + facetURI);

    List<Connection> connections =
        connectionRepository.findByNeedURIAndRemoteNeedURI(needURI, otherNeedURI);
    Connection con = getConnection(connections, facetURI, connectionEventType);

    if (con == null) {
      /* Create connection */
      con = new Connection();
      // save connection (this creates a new id)
      con = connectionRepository.saveAndFlush(con);
      // create and set new uri
      con = connectionRepository.saveAndFlush(con);

      // TODO: do we save the connection content? where? as a chat content?

    return con;