Go back to Read free chapters

How to program verified connetions

We look at how to code verified connections that can be used in friend lists, phonebook or match list

We will show you in detail how to program a connecting backend API that can be used to build verified connections between connectables meaning objects that are able to connect using their identification names.

Modelling Connecting pattern to a datamodel

The application is modelled around a connection that works in two directions, the initial connection from the owner to the endpoint and as reversed connection from the endpoint to the owner. Both of these connections have a state and an object type for each endpoint.

This chapter uses initial connection term for the connection from the owner to the endpoint. And reversed connection term for the connection from the endpoint to the connection owner. The initiator of the initial connection is the owner who makes the connection request to either accept or decline the connection. The initiator in the reversed connection is the connection endpoint.

Modeling the relation between connectable and connection

Here's an actual example about the terms and how the database tables will look.

 

 

Image of the connectable relation to the connection as relational UML model.


Image of the initial connection and the reversed connection in PENDING state.


Image of the initial connection and the reversed connection in ACCEPTED state.

When the approve action is made by the user that has an identification name @john (connectable_id = 1) and the connection is made to request Mary for a connection the endpoint identification name is @mary (connectable_id=2).

The Connectable database table rows in the database:

connectable_id name type
1 @john 0
2 @mary 1

The initial connection in pending state in database table Connection:

owner_id endpoint_id state
1 2 0

The reversed connection in discarded state in database table Connection:

owner_id endpoint_id state
2 1 2

The connection in approved state in database table Connection:

owner_id endpoint_id state
1 2 1
2 1 1

How to create connections between identifying names

The Connecting API can be used to create for example a friend's list or a list of devices you are attached to. This can be utilized also as a network of verified connections between participants. 

Connection states can be distincted to four different kind of states. The first one is an unknown state, this is a state where two entities have not seen or heard from each others at all. There is no state for the connection. Let's look at all these different states more carefully.

We use the connectable term for any identifiable participant that can be connected by it's identifiable name. The Connectable is also a class in the Connecting API Java code that is used to store this identification name and it's type that is derived from the name. We'll show this later on in more detail.

Non-existing connection state

In non-existing connection state there is no connection between owner and endpoint. This is the initial state where the connection rows are missing from the database.

Pending connection state

When the connection initiator finds another endpoint to contact to and requests for a connection the connection state is marked first in pending state. Meaning that the connection is not yet verified from the endpoint. The endpoint has the possibility to accept or discard the connection. The state attribute is stored as integer 0 in the database that comes from the index ordinal number from the enumeration class ConnectionState.PENDING, it is merely the first field in the enumeration class ConnectionState. In Java arrays it is common to use the ordinal zero to point to the first index.

The pending state is visible in connection database table as following

owner_id endpoint_id state
1 2 0

Approved connection state

The initial connection will stay in the pending state until the endpoint has chosen to either approve or decline the connection. If the endpoint approves the connection then the initial connection will be updated to an approved state. The state is stored as integer 1 in the database that comes from the index ordinal number from the enumeration class ConnectionState.ACCEPTED.

A new initial connection and reversed connection will be added into the database as following

owner_id endpoint_id state
1 2 1
2 1 1

The first row is the initial connection from owner 1 to endpoint 2 and second row is the reversed connection from owner 2 to endpoint 1. By using two rows we can easily make queries to the database according to who is the owner of the connection. This also helps the indexing of the table.

It would be possible to represent the connection also with only one row. The two-row state has been accepted although because it's clarity for the states.

Discarded connection state

The final state of the connection is to mark it as discarded. Either one the connection owner or endpoint can discard the connection. When doing so both of the initial connection and the reversed connection are marked as discarded in the database. The state is stored as integer 2 in the database that comes from the index ordinal number from the enumeration class ConnectionState.DISCARDED.

The discarded state is visible in connection database table as following

owner_id endpoint_id state
1 2 2
2 1 2

How to program connections

These states of a connection can be used in many contexts and the implementation is developed using the following Java code structure. These examples are in Java and Java Persistent API (Hibernate) where the class represents a database table.

The actual Connecting API Java code uses MySQL database or MariaDB to create the actual running application with Java Persistent API (JPA) auto-create database. The Connecting API project code can be downloaded in the next chapter.

Two connectables creates a connection

Connection class has the data of the connectable's connections. The class represents a many-to-many join table between Connectable classes. The join table is made by creating a new connection class to make it more clarifying and to add new attributes to the Connection class like state and types of the connectables.

Different types of connection owners and endpoints

The Connectable class represents an instance that is either owner or endpoint of a connection. The connectable class has a name attribute that is the identification of the instance. It has also a type attribute that is determined from what type of identifier the name attribute holds.

If the name starts with an @ at sign the ConnectionType is USER.

If the name starts with a # hashtag the ConnectionType is HASHTAG.

Otherwise the ConnectionType is CONNECTABLE. So you have an ability to join users to hashtags, users to other users or an abstract connectable type to any of these. It needs to notice that when connection users to hashtags you can use the PENDING state to let users follow hashtags. This is because a hashtag cannot accept connection unless you specifically program it to.

How to model the connection

The Connection class repsents a directional connection that points from a connectable instance owner to the connectable instance endpoint. A connection instance can have one owner and one endpoint that is represented in the direction of the connection. From owner to the endpoint. Here is a list of the JPA annotations  and data types in the Connection class. 

@OneToOne

private Connectable owner; 

@Column(nullable = false)

private ConnectionType ownerType; 

@OneToOne

private Connectable endpoint; 

@Column(nullable = false)

private ConnectionType endpointType; 

@Column(nullable = false)

private ConnectionState state;

The ConnectionType class tells the different states for the connection. This is a Java enumeration class that is stored as an index number in the database table. The first enumeration is with index 0, the second is index 1 and so on. The JPA automatically maps the Enum.ordinal() to the database table and the database table type in MySQL database will be integer INT(11). This approach is chosen because of the indexability for the fields.

It has to be noted that the Enumeration positions cannot be moved in the code after the initial use of the application.

More about Enums here https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#ordinal--

public enum ConnectionType {

CONNECTABLE, USER, HASHTAG;

}

How to query connections from a database repository

Next let's take a look at how to create simple methods to make queries for the connection. In the ConnectionRepository class we use a way to create database queries presented in Spring Data project's CrudRepository.

Let's create a new interface called ConnectionRepository and add a new interface method under that:

Connection findByOwnerAndEndpointAndOwnerTypeAndEndpointTypeAndApplicationId(

Connectable owner,Connectable endpoint,ConnectionType ownerType,ConnectionType endpointType,Long applicationId);

How to create Spring Data query methods using a CrudRepository

The method name is parsed by the CrudRepository (CRUD means Create Read Update Delete) and the SQL where query is structured using the field names inside the method name. So you basically declare an SQL query as a method name and add all needed fields to the method name.

For Example an SQL Query

Select * from Car where manufacturer = "ZZZ" and transmission = "automatic";

Would be following in Java code.

public interface CarRepository extends CrudRepository<Car, Long> {

public Car findByManufacturerAndTransmission(String manufacturer, String transmission);

}

A more detailed official Spring data documentation about Spring Data Query methods

How to query connectables from a database repository

The ConnectableRepository class is used to access the Connectable database table. In the interface class there is a method that is used to query one Connectable instance by it's name, type and application identifier. The application identifier will be explained lateron.

Connectable findByNameAndTypeAndApplicationId(String Name, ConnectionType type, Long applicationId);

How to create a connectable service layer in front of the connectable repository

The ConnectableServiceImpl class is the implementation class for the service and it has the methods to update connectables to the database with save and delete. Save method does both the initial saving of the object and updating the object.

In the service layer there is a method called findConnectable that renames the longer repository method that does the actual query by the connectable's name, type and applicationId.

public Connectable findConnectable(String name, ConnectionType type, Long applicationId)

How to pass the connection requests between methods

Service method in ConnectableServiceImpl class called createConnectionTransfer creates a ConnectionTransfer object to help passing the connection actions between methods. This method either finds the existing Connectable by the name and type or saves new connectable object to the database and determines the connection type for the Connectable.

public ConnectionTransfer createConnectionTransfer(ConnectionAction action, String ownerName, String endpointName, Long applicationId) 

How to create a connection service in front of the connection repository

The ConnectionServiceImpl class handles the connection database table query transactions with delete and save and there's the following methods to approve and discard connections.

This method is used to find connections by the connection owner and a custom filter. The custom filter class actions are located in the FilterUtil class. The filter actions are to filter the search query by either endpointType or connectionState.

public List<Connection> findConnectionsByOwnerAndFilter(String ownerName, String filter, Long applicationId)

To use the filter you can pass the filter parameter in the API call action for example with a parameter filter=connectionState::pending|endpointType::user

The findConnectionByOwnerAndEndpoint method is used to search for a certain connection between the endpoints.

public Connection findConnectionByOwnerAndEndpoint(String ownerName, String endpointName, Long applicationId)

 The updateConnectionAction is the most important method in this class, it updates the connection state. The input parameter for the method is the ConnectionAction that can be ACCEPT or DISCARD.

public Connection updateConnectionAction(ConnectionAction action, String ownerName, String endpointName, Long applicationId)

The updateConnectionAction uses two Spring service classes AcceptConnectionHandler or DiscardConnectionHandler by the action that the user has chosen.

How to model the algorithm for accepting connections

The AcceptConnectionHandler class has methods to accept the connection between connectables. The main method is acceptConnection.

public Connection acceptConnection(ConnectionTransfer connectionTransfer)

The connection accepting algorithm is as following

  1. Find if there's a reversed connection already existing. If the endpoint has already made an action the reversed connection will exist, check what it is from the following.

    1. If there is a pending connection then accept the connection.

    2. If there is already an approved connection, do nothing.

    3. If the reversed connection has been discarded then update the initial connection state to discarded.

  2. If there's no reversed connection then create a new connection in the pending state and leave it waiting for the reaction from the endpoint connectable.

How to model the algorithm for discarding connections

The DiscardConnectionHandler has methods to discard the connection between connectables. The main method is the discardConnection

public Connection discardConnection(ConnectionTransfer connectionTransfer)

The connection discarding algorithm is following

  1. Find if there's a reversed connection already existing. If there is an existing connection then

    1. Update the reversed connection to discarded state

  2. If there's no reversed connection, update the new or existing connection to the discarded state

How to publish connection actions using a REST API

The ConnectionResource is the main entry point for the application using REST. The class has the following access methods

The getConnection method is used to fetch a list of the connections by the owner's name and filter.

@RequestMapping(method = RequestMethod.GET)

public List<Connection> getConnections(@ConnectableName @RequestParam(required = true) String ownerName, @ConnectableFilter @RequestParam(required = false) String filter, HttpServletRequest request)

The getConnection method is used to fetch the connection state using the connection owner name and connection endpoint name.

@RequestMapping(path = "/{endpointName}", method = RequestMethod.GET)

public Connection getConnection(@ConnectableName @RequestParam(required = true) String ownerName, @ConnectableName @PathVariable(value = "endpointName", required = true) String endpointName, HttpServletRequest request)

The addConnection method is used to add a connection from the connection owner to the connection endpoint.

@RequestMapping(path = "/{endpointName}", method = RequestMethod.POST)

public Connection addConnection(@ConnectableName @RequestParam(required = true) String ownerName@ConnectableName @PathVariable(value = "endpointName", required = true) String endpointName, HttpServletRequest request)

The discardConnection method is used to discard a connection from the connection owner to the connection endpoint.

@RequestMapping(path = "/{endpointName}", method = RequestMethod.DELETE)

public Connection discardConnection(@ConnectableName @RequestParam(required = true) String ownerName@ConnectableName @PathVariable(value = "endpointName", required = true) String endpointName, HttpServletRequest request)

How to validate user input in the REST API using annotations

The validator annotations are used to validate the request parameters. The validator are

ConnectableName

The connectable name must be coherent with this Regular Expression pattern that's located in ConnectableNameValidator.

private static final String VALIDID = "^[a-zA-Z0-9@\\.\\-\\#\\%]+$"; 

ConnectableFilter

The connectable filter must be coherent with this Regular Expression pattern that's located in ConnectableFilterValidator. 

private static final String VALIDFILTER = "^[a-zA-Z0-9\\.\\-\\:\\|]+$";

Connection API published Beta Test version v0.1

About security, the current Connecting API is the v0.1 Beta Test version of the interface. This can be used as a test component by launching the docker application inside a secured server where the Connecting API port is not visible outside. You can then attach secured calls to the interface depending on your architecture.

We will discuss about security later on with Spring Security and OAuth2 to secure the application interfaces. That will be discussed later on in the Using pattern chapter.

That's it. Now you are ready to start building your own connections, next let's see how the Connecting API is used with Eureka registering and Zuul discovering and how to combine and deploy multiple docker microservices with Docker compose.

What new ideas or thoughts this chapter gave you?