Developing the identity service

As we mentioned earlier, we will implement CRUD operations for the organization and person entities, and we will explain one flow of these operations here.

We will add the following mentioned dependencies to the identity service:

        <dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
</dependency>

<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey-server}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
<version>${jersey-json}</version>
</dependency>
<dependency>
<groupId>com.sun.jersey</groupId>
<artifactId>jersey-client</artifactId>
<version>${jersey-client}</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${javax.servlet-api}</version>
</dependency>
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>${cdi-api}</version>
</dependency>

<dependency>
<groupId>org.hibernate.javax.persistence</groupId>
<artifactId>hibernate-jpa-2.1-api</artifactId>
<version>${hibernate-jpa}</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate-core}</version>
</dependency>
<dependency>
<groupId>javax.persistence</groupId>
<artifactId>javax.persistence-api</artifactId>
<version>${javax.persistence-api}</version>
</dependency>

<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>${hibernate-entitymanager}</version>
</dependency>
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>${postgresql}</version>
</dependency>

<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt}</version>
</dependency>
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>${java-jwt}</version>
</dependency>

We will add the following packages to the identity service:

The exception package will have the classes for handling the exceptions in the module, while the response package will have general response classes, util for some constants and utility functions, and the organization and person packages will hold all the classes related to the operations of these entities.

These organization and person packages include other sub-packages, shown as follows:

The controller package is for the classes that expose APIs over the REST. The service package holds service classes that connect the controller and dao classes and executes mapping of types that the controller and dao implementations can understand. The model package holds the request and response classes that are used at the API boundary, while the entity package includes the classes for mapping the entities to the table in the database. These are used by the dao layer. The dao package will have the classes that interact with the database and we use JPA entity manager for this. Note that this layered structure is mvc-based and repeated for the organization and person entities for the separation of concerns.

The filter package is common to these entities and will have logic to intercept the request to validate the JWT that is passed in the request header. It performs the validation by invoking the /authorize/jwt/validate-token API of the authentication service as a REST call.

Let's look at the create organization flow. This will give an understanding of the flow of control around these classes in different packages.

The controller code appears as follows:

@Path("/identity/organization")
class OrganizationController {
@Inject
private lateinit var serviceImpl: OrganizationServiceImpl

@POST
@Produces(MediaType.APPLICATION_JSON)
fun createOrganization(organization: Organization): Response {
try {
var orgId: String = serviceImpl.createOrganization(organization)
var response: GenericResponse = GenericResponse()
response.responseMessage = Constants.IDENTITY_CREATED
return Response.status(Response.Status.CREATED)
.header("location", orgId)
.entity(response).build()
} catch (e: IdentityAlreadyExistsException) {
return sendErrorResponse(e.message!!, Response.Status.CONFLICT.statusCode)
} catch (e: IdentityException) {
return sendErrorResponse(Constants.INTERNAL_SERVER_ERROR_MSG, Response.Status
.INTERNAL_SERVER_ERROR.statusCode)
}
}

We inject the service class instance, serviceImpl, via the @Inject annotation, and we have the @Path annotation for mapping the request to this function and the class. Creating an organization is a post call, and the createOrganization() function takes the organization request that needs to be created. The jersey maps the request body to the organization parameter declared in the function. With this request, we pass the control to the service layer. The service layer returns orgId if it is created successfully, and this orgId will be included in the location header of the response object. A status code of 201 is then returned from the controller, indicating that the requested entity was created successfully in the system.

If the requested organization is already present, we will get IdentityAlreadyExistsException from the dao layer, this exception will be caught in our controller and sends a 409 conflict status code as response. In case of any other exception, we will send the error response. The OrganizationServiceImpl class implements the contract defined by the OrganizationService interface. The interface has declared the createOrganization() function and the implementing class provides the function definition. This is demonstrated by means of the following code:

class OrganizationServiceImpl : OrganizationService {
@Inject
private lateinit var organizationDao: OrganizationDaoImpl

override fun createOrganization(organizationRequest: Organization): String {
var organizationEntity: OrganizationEntity = OrganizationEntity(UUID.randomUUID().toString())
mapOrganizationToOrganizationEntity(organizationRequest,organizationEntity)

var entity: OrganizationEntity = organizationDao.createOrganization(organizationEntity)
return entity.orgId
}
}

The service class maps the request to the entity object and passes the control to the dao layer that is requesting to create the entity. From the service layer, an orgId is returned as a response if the organization is created.

The dao layer code looks as follows:

class OrganizationDaoImpl : OrganizationDao {

private var entityManagerFactory = Persistence.createEntityManagerFactory("local")
private var entityManager = entityManagerFactory.createEntityManager()

override fun createOrganization(organizationEntity: OrganizationEntity): OrganizationEntity {
try {
entityManager.transaction.begin()

entityManager.persist(organizationEntity)
entityManager.transaction.commit()
return organizationEntity
} catch (exception: Exception) {
if (exception is PersistenceException) {
throw IdentityAlreadyExistsException(Constants.IDENTITY_ALREADY_EXIST)
} else {
throw IdentityException(exception.message!!)
}
}
}

We will load EntityManagerFactory from the persistence unit defined in persistence.xml. We have defined the postgresql configuration in the XML file, which we explained in Chapter 5, Kotlin with JPA and EJB.

Then we will create entityManager out of the EntityManagerFactory instance. We use entityManager to interact with the database tables. The createOrganization() function takes the organization entity. Using entityManager, a transaction will be started and the entity will be persisted. When the transaction is committed, an entry will be made in the organization table.

If the entity is already present, we will get PersistenceException, which we wrap into IdentityAlreadyExistsException. In case of any other exceptions, that will be wrapped inside IdentityException, which is handled by the controller layer.

The other CRUD operations follow the same MVC model and the complete implementation is available in the code repository.
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset