<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Jackson Williams</title>
    <description>The latest articles on DEV Community by Jackson Williams (@jackwilltech).</description>
    <link>https://dev.to/jackwilltech</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2083323%2F7531eb15-73f1-4139-b596-c1a711724a55.png</url>
      <title>DEV Community: Jackson Williams</title>
      <link>https://dev.to/jackwilltech</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/jackwilltech"/>
    <language>en</language>
    <item>
      <title>Master Microservices Packaging for Private Clouds: 5 Essential Tips</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Fri, 25 Oct 2024 00:07:16 +0000</pubDate>
      <link>https://dev.to/jackwilltech/master-microservices-packaging-for-private-clouds-5-essential-tips-31la</link>
      <guid>https://dev.to/jackwilltech/master-microservices-packaging-for-private-clouds-5-essential-tips-31la</guid>
      <description>&lt;p&gt;In the current software development environment, microservices architecture has emerged as a prevalent method for creating applications. Generally, microservices are packaged as container images using containerization tools like Docker, which are then uploaded to an image registry. For deploying these container images on a container orchestration platform such as Kubernetes, Helm stands out as the most widely used option. Helm charts refer to publicly available container registries to retrieve the container images.&lt;/p&gt;

&lt;p&gt;However, some companies operate their own private cloud systems. In these settings, public container image registries or even the Internet may not be accessible. To deploy an application in these limited environments, it is crucial to bundle all necessary components—container images, Helm charts, documentation, and more—into a single archive. This article will examine how to package a microservices-based application for a private cloud, like on-premises Kubernetes, and will also cover strategies to reduce the package size.&lt;/p&gt;

&lt;h2&gt;Packaging Your Application&lt;/h2&gt;

&lt;p&gt;The first step is to package the Docker images. Assign a release SemVer tag to the Docker images, for example, 1.2.3.&lt;/p&gt; 

&lt;pre&gt;&lt;code&gt;&amp;amp;gt; docker tag &amp;amp;lt;current repo&amp;amp;gt;/image-name:tagname &amp;amp;lt;appname&amp;amp;gt;/image-name:tagname

&amp;amp;gt; docker tag myrepo:5000/myimage1:1.2.3 myapp/myimage1:1.2.3
&amp;amp;gt; docker tag myrepo:5000/myimage2:1.2.3 myapp/myimage2:1.2.3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next, save all the images into a single tarball.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;gt; docker save --output &amp;amp;lt;App Name&amp;amp;gt;-images-1.2.3.tar &amp;amp;lt;docker-images with tags&amp;amp;gt;

&amp;amp;gt; docker save --output myapp-images-1.2.3.tar myrepo:5000/myimage1:1.2.3 myrepo:5000/myimage2:1.2.3 &amp;amp;lt;more images&amp;amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Finally, add Helm Charts and a Readme to create a complete compressed archive.&lt;/p&gt;


&lt;pre&gt;&lt;code&gt;myapp-package-1.2.3.tgz&lt;br&gt;
           |_ _ _ _ _ _ myapp-1.2.3.tgz (helm chart)&lt;br&gt;
           |_ _ _ _ _ _ myapp-images-1.2.3.tar (docker images)&lt;br&gt;
           |_ _ _ _ _ _ Readme.txt (Contains checksums and installation instructions)&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Installing Package&lt;/h2&gt;

&lt;p&gt;To install the package, the customer first untars the package, load the tarballs to Docker images, and if needed they can re-tag it according to the customer-specific repository. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;gt; docker load --input /root/myapp-images-1.2.3.tar
&amp;amp;gt; docker tag myapp/myimage:1.2.3 &amp;amp;lt;customer repo&amp;amp;gt;/myimage:1.2.3
&amp;amp;gt; docker push &amp;amp;lt;customer repo&amp;amp;gt;/myimage:1.2.3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To deploy the application using Helm, create a custom values file,  &lt;code&gt;custom-values.yaml&lt;/code&gt;, specific to the customer environment, and run Helm install.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;gt; helm install -f custom-values.yaml myapp myapp-1.2.3.tgz&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Optimizing Package Size&lt;/h2&gt;

&lt;p&gt;With the packaging structure as above, the bulk of the package size will come from Docker images. List the contents of the package to confirm it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;gt; tar -ztvf myapp-package-1.2.3.tgz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To reduce the overall size of the package, let’s classify Docker images into three categories:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Microservices crafted with Java&lt;/li&gt;
&lt;li&gt;Microservices constructed using alternative technologies, such as Python and NodeJS&lt;/li&gt;
&lt;li&gt;Microservices obtained from external sources, where we lack oversight of the containerization procedure&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We will explore technologies like distroless images, Jib, docker-slim, dive, and others to decrease image sizes and visualize our containerization journey.&lt;/p&gt;
&lt;h2&gt;Containerizing Java Applications&lt;/h2&gt;
&lt;p&gt;A key aim when containerizing an application is to achieve the smallest image size feasible. A reduced container size results in&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;Quicker pod initialization times&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Faster autoscaling&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Lower resource consumption&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Improved security&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To generate a Docker image, we need a Dockerfile that Docker employs to define the layers of an image. For each microservice in our application, we generally create a fat jar that includes all dependencies. The actual code may be relatively compact. These dependencies are redundantly included and copied into each fat jar, leading to unnecessary space usage. We can take advantage of Docker’s image layering—by placing dependencies and resources in distinct layers, we can reuse them and only modify the code for each microservice.&lt;/p&gt;
&lt;p&gt;Google provides an open-source tool named Jib, which offers Maven and Gradle plugins to facilitate this method. We do not require a running Docker daemon to create images with Jib—it constructs the image using the same standard output as we receive from &lt;code&gt;docker build&lt;/code&gt; but does not engage Docker unless explicitly stated.&lt;/p&gt;
&lt;h2&gt;Creating Docker Image With Gradle&lt;/h2&gt;
&lt;p&gt;The first step, therefore, is to adjust each project’s &lt;code&gt;build.gradle&lt;/code&gt; file to incorporate the new plugin:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;plugins {
  id 'com.google.cloud.tools.jib' version '2.2.0'
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Incorporate a tailored jib Gradle task to create the Docker image:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;jib {
  from {
    image = 'gcr.io/distroless/java:11'
  }
  to {
    image = System.getenv('DOCKER_REGISTRY_ADDR') + "/myimage"
    tags = [branchName + "-" + System.getenv('CI_PIPELINE_ID'), 'latest']
  }
  container {
    mainClass = 'com.mycompany.myapp.MyServiceApplication'
    jvmFlags = ['-XX:GCPauseIntervalMillis=750', '-XX:MaxGCPauseMillis=100',
                '-XX:-OmitStackTraceInFastThrow']
    ports = ['8080', '9443', '5801']
    user = '5000:5000'
  }
 
  allowInsecureRegistries = 'true'
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Create a labeled Docker image and push it to the Docker registry:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;amp;gt; gradle build jib
 
&amp;amp;gt; Task :compileJava
Note: Some input files utilize or override a deprecated API.
Note: Recompile with -Xlint:deprecation for specifics.
Note: Some input files employ unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for specifics.
 
&amp;amp;gt; Task :jib
 
Containerizing application to myrepo:5000/myimage, myrepo:5000/myimage:staging-620672...
Base image 'gcr.io/distroless/java:11' does not specify a particular image digest - build may not be reproducible
Utilizing credentials from Docker config (/root/.docker/config.json) for myrepo:5000/myimage
Unable to verify server at https://myrepo:5000/v2/. Retrying without TLS verification.
Failed to connect to https://myrepo:5000/v2/ over HTTPS. Retrying with HTTP.
Using base image with digest: sha256:c94feda039172152495b5cd60a350a03162fce4f8986b560ea555de4d276ce19
 
Container entrypoint established as [java, -XX:GCPauseIntervalMillis=750, -XX:MaxGCPauseMillis=100, -XX:-OmitStackTraceInFastThrow, -cp, /app/resources:/app/classes:/app/libs/*, com.mycompany.myapp.MyServiceApplication]
 
Constructed and pushed image as myrepo:5000/myimage, myrepo:5000/myimage:staging-620&lt;h2&gt;Foundation Image&lt;/h2&gt;
&lt;p&gt;We have selected &lt;code&gt;gcr.io/distroless/java:11&lt;/code&gt; as our foundational image. “Distroless” images encompass solely our application along with its runtime necessities. They lack package managers, shells, or any other utilities typically found in a conventional Linux distribution.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Illustrate Docker Image&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Dive serves as an invaluable resource for scrutinizing docker images and illustrating the effects of bulky jars within docker images. The subsequent illustration displays the newly crafted layer structures that Jib has generated.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;amp;gt; dive myrepo:5000/myimage:1.2.3&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcarsnewstoday.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fpackaging-microservices_img_0.jpeg" class="article-body-image-wrapper"&gt;&lt;img alt="default" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcarsnewstoday.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fpackaging-microservices_img_0.jpeg" width="800" height="425"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Encapsulating and Enhancing Non-Java Applications&lt;/h2&gt;

&lt;p&gt;Within our application, we might incorporate a non-Java element, such as Python or NodeJS applications. The Docker images for these elements are constructed using the traditional approach with a Dockerfile. To refine the images, we employ an additional utility – docker-slim. This tool necessitates no alterations to our Docker image and optimizes it effortlessly.&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;&amp;gt; docker-slim build myapp --http-probe=false&lt;br&gt;
...&lt;br&gt;
docker-slim[build]: state=building message='building optimized image'&lt;br&gt;
docker-slim[build]: state=completed&lt;br&gt;
docker-slim[build]: info=results status='OPTIMIZED BY 18.82X [417722590 (418 MB) =&amp;gt; 22199995 (22 MB)]'&lt;br&gt;
docker-slim[build]: info=results  image.name=myapp.slim image.size='22 MB' data=true&lt;br&gt;
...&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Feel free to reach out if you require any additional support!&lt;/p&gt;

&lt;h2&gt;Enhancing Docker Images from External Origins&lt;/h2&gt;

&lt;p&gt;In our software, we frequently depend on external components, such as Ingress Gateway, which are accessible to the public. As we lack authority over the containerization of these microservices, we employ docker-slim to streamline their Docker images.&lt;/p&gt;

&lt;p&gt;A notable drawback of utilizing docker-slim for image reduction is that &lt;span&gt;it fails to preserve the original layering configuration&lt;/span&gt;. Although this method produces compact and secure individual images, it does not aid in diminishing the total image size, as there is no layer sharing between various images.&lt;/p&gt;

&lt;h2&gt;Holistic Approach&lt;/h2&gt;

&lt;p&gt;Our comprehensive approach entails using Jib for containerizing our proprietary Java applications and docker-slim for minimizing non-Java images, along with those obtained from other teams.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcarsnewstoday.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fpackaging-microservices_img_1.jpeg" class="article-body-image-wrapper"&gt;&lt;img alt="Tar archive file" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcarsnewstoday.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fpackaging-microservices_img_1.jpeg" width="800" height="468"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;This article has delved into the methodology of packaging applications based on microservices for deployment in private clouds with restricted access to public repositories. We have also investigated various strategies for minimizing package size, ensuring effective deployment and management.&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

</description>
      <category>application</category>
      <category>docker</category>
      <category>software</category>
      <category>kubernetes</category>
    </item>
    <item>
      <title>Secure Your App: 2-Factor Auth in 3 Easy Steps</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Tue, 22 Oct 2024 22:51:35 +0000</pubDate>
      <link>https://dev.to/jackwilltech/secure-your-app-2-factor-auth-in-3-easy-steps-ahn</link>
      <guid>https://dev.to/jackwilltech/secure-your-app-2-factor-auth-in-3-easy-steps-ahn</guid>
      <description>&lt;p&gt;In the current digital environment, multi-factor authentication (MFA) has become a crucial practice for many applications, especially those managing sensitive information like financial services. Additionally, MFA is increasingly required by legislation across various sectors in the EU, making it vital for developers to integrate this security feature into their applications. If you are developing an application that necessitates two-factor authentication, this article is a valuable resource.&lt;/p&gt;

&lt;p&gt;This article will walk you through the steps to implement a two-factor authentication system for a &lt;strong&gt;reactive&lt;/strong&gt; API created with Spring Webflux. This application employs TOTP (time-based one-time passwords generated by an app on the user's device, such as Google Authenticator) as the &lt;em&gt;second security factor&lt;/em&gt;, alongside traditional email and password combinations.&lt;/p&gt;

&lt;h2&gt;Understanding Two-Factor Authentication&lt;/h2&gt;

&lt;p&gt;From a technical perspective, two-factor authentication (or multi-factor authentication) is defined as &lt;em&gt;a security method that necessitates users to present two or more verification factors&lt;/em&gt;. Typically, this means that a user must enter a password along with another form of identification. This additional identifier can be a one-time password, hardware tokens, biometric data (like fingerprints), or other verification methods.&lt;/p&gt;

&lt;p&gt;This security procedure consists of several essential steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user inputs their email (username) and password.&lt;/li&gt;
&lt;li&gt;Along with their credentials, the user provides a one-time code generated by an authenticator app.&lt;/li&gt;
&lt;li&gt;The app verifies the email (username) and password, and checks the one-time code using the user's secret key, which was issued during the registration process.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Utilizing authenticator apps (such as Google Authenticator, Microsoft Authenticator, or FreeOTP) presents several benefits over SMS-based code delivery. These apps are less vulnerable to SIM attacks and can operate without cellular or internet access.&lt;/p&gt;

&lt;h2&gt;A Hands-On Example&lt;/h2&gt;

&lt;p&gt;In this article, we will create a straightforward REST API that integrates two-factor authentication methods. This API requires users to enter both an email-password combination and a short code generated by an app. You can use any compatible app to generate TOTP; for this demonstration, I will utilize Google Authenticator for Android. The source code can be found in this GitHub repository. The application requires JDK 11, Maven, and MongoDB (for user profile storage). Let’s examine the project structure in more detail:&lt;/p&gt;

</description>
      <category>api</category>
      <category>app</category>
      <category>authentication</category>
      <category>business</category>
    </item>
    <item>
      <title>Unlock Scala in 5 Minutes: Traits vs Abstract Classes</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Tue, 22 Oct 2024 19:33:28 +0000</pubDate>
      <link>https://dev.to/jackwilltech/unlock-scala-in-5-minutes-traits-vs-abstract-classes-4lp8</link>
      <guid>https://dev.to/jackwilltech/unlock-scala-in-5-minutes-traits-vs-abstract-classes-4lp8</guid>
      <description>&lt;h2&gt;1. Unlocking Scala Mastery: Understanding Abstract Classes and Traits&lt;/h2&gt;

&lt;p&gt;To master Scala, it's essential to grasp the fundamental difference between abstract classes and traits. Let's break down each concept to appreciate their unique characteristics.&lt;/p&gt;

&lt;p&gt;Traits are similar to Java interfaces but offer more flexibility, as they allow the implementation of their members. In contrast, abstract classes are defined using the abstract keyword and can contain both abstract and concrete methods.&lt;/p&gt;

&lt;h2&gt;2. Shared Characteristics&lt;/h2&gt;

&lt;p&gt;Before diving into the differences, let's explore the commonalities between abstract classes and traits. This understanding will help us appreciate their distinct features.&lt;/p&gt;

&lt;p&gt;A trait can include a declared and implemented method, along with a variable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trait mytrait { 
  def myMethod():Unit
  val aVal: Int 
  val myVal = 10 
  def myImpMethod = { println("I am from trait") } 
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;An abstract class can feature both an abstract and a concrete method, along with a variable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;abstract class abstClass { 
  def myMethod():Unit 
  val aVal: Int 
  val myVal = 10 
  def myImpMethod:Unit = { println("I am from abstClass") } 
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Notably, neither a trait nor an abstract class can be instantiated in the main method.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;val myTObj = new mytrait //compilation error
val myAObj = new abstClass() //compilation error&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Classes that extend a trait or an abstract class must implement the declared methods.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class myTClass extends mytrait {
  val aVal=10 
  def myMethod ={ println("I am from myTclass") } 
} 
class myAClass extends abstClass {
  val aVal=10 
  def myMethod ={ println("I am from myAclass") } 
}&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;3. Key Differences&lt;/h2&gt;

&lt;h3&gt;3.1 Constructor Parameters&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;trait myTraitWithParam(name: String){} 
abstract class abstClassWithParam(name : String){}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;name&lt;/code&gt; serves as a constructor parameter. However, using a constructor parameter in a trait results in a compilation error, whereas it functions correctly in an abstract class. For more information on Scala mastery, visit &lt;a href="https://t8tech.com/it/coding/unlock-scala-mastery-key-differences-between-abstract-classes-and-traits-you-must-know/" rel="noopener noreferrer"&gt;t8tech&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;3.2 Modifying Object Instances&lt;/h3&gt;scala
trait objectInstanceTrait { 
  def myObjectMethod = { println("I stem from the object instance trait") } 
} 
class myTClass {} 
def main(args: Array[String]): Unit = { 
  val classObjWithTrait = new myTClass with objectInstanceTrait
  classObjWithTrait.myObjectMethod 
} 
output =&amp;gt; "I stem from the object instance trait"

&lt;p&gt;The function “&lt;code&gt;myObjectMethod&lt;/code&gt;” defined in the trait can be invoked via an instance of a class. An abstract class cannot be integrated into an object instance, leading to a compilation error.&lt;/p&gt;
&lt;h3&gt;3.3 Multiple Inheritances&lt;/h3&gt;

&lt;p&gt;In the realm of multiple inheritance, a single class can derive from more than one superclass, inheriting traits from all parent classes. Although Scala does not allow multiple inheritance with classes, it can be achieved using traits.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;class myClass extends trait1 with trait2{} 
class myNewClass extends abstClass1 with abstClass2{}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Employing an abstract class for multiple inheritances results in a compilation error.&lt;/p&gt;

&lt;p&gt;Scala resolves the diamond problem in multiple inheritance through trait linearization, where the trait located furthest to the right takes precedence.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trait Printer { 
  def print(msg: String) = println(msg) 
} 
trait DelimitWithHyphen extends Printer { 
  override def print(msg: String) = { println("-------------") } 
} 
trait DelimitWithStar extends Printer { 
  override def print(msg: String) = { println("*") } 
} 

class CustomPrinter extends Printer with DelimitWithHyphen with DelimitWithStar 

new CustomPrinter().print("Hello World!") 
  
output =&amp;gt; "*"&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;3.4 Stackability&lt;/h3&gt;

&lt;p&gt;Stackable traits in Scala facilitate the amalgamation of multiple traits that jointly alter a method. This procedure entails invoking &lt;em&gt;&lt;code&gt;super.theMethod&lt;/code&gt;&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;html&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;trait foundation { 
  def foundationMethod(s: String): Unit = println(s) 
}

trait stackA extends foundation {
  override def foundationMethod(s: String): Unit = println("from stackA") 
} 

trait substituteA extends foundation { 
  abstract override def foundationMethod(s: String): Unit = {
    super.foundationMethod(s); 
    println("from substituteA")
  } 
}

class Stackable { 
  this: foundation =&amp;gt; 
  def apply() { 
    println(foundationMethod("base")) 
  } 
} 

(new Stackable with stackA with substituteA)() 

output =&amp;gt; 
from stackA 
from substituteA&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The invocation initiates with substituteA, which subsequently directs to stackA through &lt;em&gt;super.foundationMethod(s).&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;This method invocation reaches stackA as it is situated to the left of substituteA.&lt;/p&gt;

&lt;h3&gt;3.5 Compatibility with Java&lt;/h3&gt;

&lt;p&gt;Traits can integrate effortlessly with Java provided they do not contain any implementation; abstract classes can be directly employed.&lt;/p&gt;

&lt;h2&gt;4. Summary&lt;/h2&gt;

&lt;p&gt;Scala traits provide enhanced versatility in comparison to abstract classes. Abstract classes should be utilized when a base class with a constructor parameter is required. In situations of doubt, it is prudent to choose traits, as they can be readily converted into abstract classes.&lt;/p&gt;

</description>
      <category>scala</category>
      <category>programming</category>
      <category>language</category>
      <category>trait</category>
    </item>
    <item>
      <title>Unlock Spring Data JPA: Master Many-to-Many Relationships Now!</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Mon, 21 Oct 2024 11:05:38 +0000</pubDate>
      <link>https://dev.to/jackwilltech/unlock-spring-data-jpa-master-many-to-many-relationships-now-1f29</link>
      <guid>https://dev.to/jackwilltech/unlock-spring-data-jpa-master-many-to-many-relationships-now-1f29</guid>
      <description>&lt;p&gt;We will explore the following subjects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unidirectional many-to-many connections.&lt;/li&gt;
&lt;li&gt;CRUD functions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's start by modeling the entities.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fintroduction-to-spring-data-jpa-part-7-unidirectio_img_0.png" class="article-body-image-wrapper"&gt;&lt;img alt="Entity modeling in progress" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fintroduction-to-spring-data-jpa-part-7-unidirectio_img_0.png" width="800" height="523"&gt;&lt;/a&gt;Next, we will see how Hibernate constructs the tables for us.&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fintroduction-to-spring-data-jpa-part-7-unidirectio_img_1.png" class="article-body-image-wrapper"&gt;&lt;img alt="Hibernate table creation" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fintroduction-to-spring-data-jpa-part-7-unidirectio_img_1.png" width="800" height="457"&gt;&lt;/a&gt;A junction table is generated as a result.&lt;/p&gt;

&lt;p&gt;Since this is a Many-to-Many, Unidirectional relationship, the definition in the User entity is as follows, while the Role entity will not include any related definition.&lt;/p&gt;

&lt;p&gt;The crucial point to highlight is the relationship definition in the User Entity.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;@ManyToMany(targetEntity = Role.class, cascade = CascadeType.ALL)&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;private List&amp;lt;Role&amp;gt; roles;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Now, let's see how this is implemented in code. All CRUD functions are executed in the following code. We will adjust the UPDATE methods in the next article. The code has been discussed in previous articles, and a video tutorial is also available for a comprehensive explanation of the code.&lt;/p&gt;

&lt;p&gt;User Entity&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.notyfyd.entity;

import javax.persistence.*;
import java.util.List;

@Entity@Table(name = "t_user")
public class User {
    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long userId;
    private String firstName;
    private String lastName;
    private String contactNumber;
    @Column(unique = true)
    private String email;
    @ManyToMany(targetEntity = Role.class, cascade = CascadeType.ALL)
    private List&amp;lt;Role&amp;gt; roles;

    public List&amp;lt;Role&amp;gt; getRoles() {
        return roles;
    }

    public void setRoles(List&amp;lt;Role&amp;gt; roles) {
        this.roles = roles;
    }

    public Long getUser Id() {
        return userId;
    }
    
    public void setUser Id(Long userId) {
        this.userId = userId;
    }
    
    public String getFirstName() {
        return firstName;
    }
    
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
    
    public String getLastName() {
        return lastName;
    }
    
    public void setLastName(String lastName) {
        this.lastName = lastName;
    }
    
    public String getContactNumber() {
        return contactNumber;
    }
    
    public void setContactNumber(String contactNumber) {
        this.contactNumber = contactNumber;
    }
    
    public String getEmail() {
        return email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Role Entity&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.notyfyd.entity;

import javax.persistence.*;

@Entity@Table(name = "t_role")
public class Role {
    @Id    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;

    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getName() {
        return this.name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getDescription() {
        return this.description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Role Administration Controller&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.notyfyd.controller;

import com.notyfyd.entity.User;
import com.notyfyd.repository.UserRepository;
import com.notyfyd.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestControllerpublic class UserController {

    private final UserService userService;
    private final UserRepository userRepository;

    public UserController(UserService userService, UserRepository userRepository) {
        this.userService = userService;
        this.userRepository = userRepository;
    }

    /
     * Creates a new user.
     * 
     * @param user the user to be created
     * @return the response entity containing the created user
     */
    @PostMapping("/user/create")    public ResponseEntity&amp;lt;Object&amp;gt; createUser(@RequestBody User user) {
        return userService.createUser(user);
    }

    /
     * Retrieves a user by ID.
     * 
     * @param id the ID of the user to be retrieved
     * @return the user with the specified ID, or null if not found
     */
    @GetMapping("/user/details/{id}")    public User getUser(@PathVariable Long id) {
        return userRepository.findById(id).orElse(null);
    }

    /
     * Retrieves a list of all users.
     * 
     * @return the list of users
     */
    @GetMapping("/user/all")    public List&amp;lt;User&amp;gt; getUsers() {
        return userRepository.findAll();
    }

    /
     * Updates an existing user.
     * 
     * @param id   the ID of the user to be updated
     * @param user the updated user
     * @return the response entity containing the updated user
     */
    @PutMapping("/user/update/{id}")    public ResponseEntity&amp;lt;Object&amp;gt; updateUser(@PathVariable Long id, @RequestBody User user) {
        return userService.updateUser(user, id);
    }

    /
     * Deletes a user by ID.
     * 
     * @param id the ID of the user to be deleted
     * @return the response entity containing the deletion result
     */
    @DeleteMapping("/user/delete/{id}")    public ResponseEntity&amp;lt;Object&amp;gt; deleteUser(@PathVariable Long id) {
        return userService.deleteUser(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Function Regulator&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.notyfyd.controller;

import com.notyfyd.entity.Role;
import com.notyfyd.repository.RoleRepository;
import com.notyfyd.service.RoleService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.List;

/
 * Handles REST requests related to roles.
 */
@RestControllerpublic class RoleController {

    private final RoleService roleService;
    private final RoleRepository roleRepository;

    /
     * Initializes the controller with the required services.
     *
     * @param roleService  the role service instance
     * @param roleRepository the role repository instance
     */
    public RoleController(RoleService roleService, RoleRepository roleRepository) {
        this.roleService = roleService;
        this.roleRepository = roleRepository;
    }

    /
     * Creates a new role.
     *
     * @param role the role to be created
     * @return the response entity
     */
    @PostMapping("/role/create")    public ResponseEntity createRole(@RequestBody Role role) {
        return roleService.addRole(role);
    }

    /
     * Deletes a role by its ID.
     *
     * @param id the ID of the role to be deleted
     * @return the response entity
     */
    @DeleteMapping("/role/delete/{id}")    public ResponseEntity deleteRole(@PathVariable Long id) {
        return roleService.deleteRole(id);
    }

    /
     * Retrieves a role by its ID.
     *
     * @param id the ID of the role to be retrieved
     * @return the role instance, or null if not found
     */
    @GetMapping("/role/details/{id}")    public Role getRole(@PathVariable Long id) {
        return roleRepository.findById(id).orElse(null);
    }

    /
     * Retrieves all roles.
     *
     * @return a list of all roles
     */
    @GetMapping("/role/all")    public List getRoles() {
        return roleRepository.findAll();
    }

    /
     * Updates a role by its ID.
     *
     * @param id the ID of the role to be updated
     * @param role the updated role instance
     * @return the response entity
     */
    @PutMapping("/role/update/{id}")    public ResponseEntity updateRole(@PathVariable Long id, @RequestBody Role role) {
        return roleService.updateRole(id, role);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Role Data Access Interface&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;package com.notyfyd.repository;

import com.notyfyd.entity.Role;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

/
 * Facilitates data retrieval and manipulation for roles.
 */
@Repositorypublic interface RoleRepository extends JpaRepository {
    /
     * Retrieves a role based on its designated name.
     *
     * @param name the name of the role to be retrieved
     * @return an Optional instance containing the role, if found
     */
    Optional findByName(String name);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;User Data Access Interface&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;package com.notyfyd.repository;

import com.notyfyd.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.Optional;

/
 * A specialized repository interface for user data management, 
 * leveraging JpaRepository for fundamental CRUD operations.
 */
@Repositorypublic interface UserRepository extends JpaRepository {
    /
     * Fetches a user by their specified email address, 
     * returning an Optional instance to accommodate potential non-existence.
     * 
     * @param email the email address to be searched
     * @return an Optional containing the user, if located
     */
    Optional findByEmail(String email);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;User Service&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.notyfyd.service;

import com.notyfyd.entity.Role;
import com.notyfyd.repository.RoleRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

@Servicepublic class RoleService {

    private RoleRepository roleRepository;

    public RoleService(RoleRepository roleRepository) {
        this.roleRepository = roleRepository;
    }


    /** Create a new role  */
    public ResponseEntity&amp;lt;Object&amp;gt; addRole(Role role)  {

        Role newRole = new Role();
        newRole.setName(role.getName());
        newRole.setDescription(role.getDescription());
        Role savedRole = roleRepository.save(newRole);
        if(roleRepository.findById(savedRole.getId()).isPresent()) {
            return ResponseEntity.accepted().body("Successfully Created Role ");
        } else
            return ResponseEntity.unprocessableEntity().body("Failed to Create specified Role");
    }


    /** Delete a specified role given the id */
    public ResponseEntity&amp;lt;Object&amp;gt; deleteRole(Long id) {
        if(roleRepository.findById(id).isPresent()){
            roleRepository.deleteById(id);
            if(roleRepository.findById(id).isPresent()){
                return ResponseEntity.unprocessableEntity().body("Failed to delete the specified record");
            } else return ResponseEntity.ok().body("Successfully deleted specified record");
        } else
            return ResponseEntity.unprocessableEntity().body("No Records Found");
    }


    /** Update a Role */
    public ResponseEntity&amp;lt;Object&amp;gt; updateRole(Long id, Role role) {
        if(roleRepository.findById(id).isPresent()){
            Role newRole = roleRepository.findById(id).get();
            newRole.setName(role.getName());
            newRole.setDescription(role.getDescription());
            Role savedRole = roleRepository.save(newRole);
            if(roleRepository.findById(id).isPresent())
                return ResponseEntity.accepted().body("Role saved successfully");
            else return ResponseEntity.badRequest().body("Failed to update Role");

        } else return ResponseEntity.unprocessableEntity().body("Specified Role not found");
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Client Assistance&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;package com.notyfyd.service;

import com.notyfyd.entity.User;
import com.notyfyd.repository.RoleRepository;
import com.notyfyd.repository.UserRepository;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Servicepublic class UserService {

    private UserRepository userRepository;
    private RoleRepository roleRepository;

    public UserService(UserRepository userRepository, RoleRepository roleRepository) {
        this.userRepository = userRepository;
        this.roleRepository = roleRepository;
    }
    /** Create a new User */
    public ResponseEntity&amp;lt;Object&amp;gt; createUser(User model) {
        User user = new User();
        if (userRepository.findByEmail(model.getEmail()).isPresent()) {
            return ResponseEntity.badRequest().body("The Email is already Present, Failed to Create new User");
        } else {
            user.setFirstName(model.getFirstName());
            user.setLastName(model.getLastName());
            user.setMobile(model.getMobile());
            user.setEmail(model.getEmail());
            user.setRoles(model.getRoles());

            User savedUser = userRepository.save(user);
            if (userRepository.findById(savedUser.getId()).isPresent())
                return ResponseEntity.ok("User Created Successfully");
            else return ResponseEntity.unprocessableEntity().body("Failed Creating User as Specified");
        }
    }

    /** Update an Existing User */
    @Transactional    public ResponseEntity&amp;lt;Object&amp;gt; updateUser(User user, Long id) {
        if(userRepository.findById(id).isPresent()) {
            User newUser = userRepository.findById(id).get();
            newUser.setFirstName(user.getFirstName());
            newUser.setLastName(user.getLastName());
            newUser.setMobile(user.getMobile());
            newUser.setEmail(user.getEmail());
            newUser.setRoles(user.getRoles());
            User savedUser = userRepository.save(newUser);
            if(userRepository.findById(savedUser.getId()).isPresent())
                return  ResponseEntity.accepted().body("User updated successfully");
            else return ResponseEntity.unprocessableEntity().body("Failed updating the user specified");
        } else return ResponseEntity.unprocessableEntity().body("Cannot find the user specified");
    }
    /** Delete an User*/
    public ResponseEntity&amp;lt;Object&amp;gt; deleteUser(Long id) {
        if (userRepository.findById(id).isPresent()) {
            userRepository.deleteById(id);
            if (userRepository.findById(id).isPresent())
                return ResponseEntity.unprocessableEntity().body("Failed to Delete the specified User");
            else return ResponseEntity.ok().body("Successfully deleted the specified user");
        } else return ResponseEntity.badRequest().body("Cannot find the user specified");
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We will revisit the update technique in our forthcoming edition.&lt;/p&gt;

&lt;p&gt;application.properties&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server.port=2003
spring.datasource.driver-class-name= org.postgresql.Driver
spring.datasource.url= jdbc:postgresql://192.168.64.6:30432/jpa-test
spring.datasource.username = postgres
spring.datasource.password = root
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Access the source code at https://github.com/gudpick/jpa-demo/tree/many-to-many-unidirecctional-starter&lt;/p&gt;

&lt;p&gt;Watch the instructional video tutorials&lt;/p&gt;

&lt;p&gt;&lt;span&gt;&lt;span&gt;&amp;lt;iframe src=”https://www.youtube.com/embed/e9HwTpn9mgA” allow=”accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture” allowfullscreen&amp;gt;&amp;lt;/iframe&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

</description>
      <category>data</category>
      <category>computing</category>
      <category>java</category>
      <category>programming</category>
    </item>
    <item>
      <title>Secure Your APIs in 5 Minutes: Token-Based RSocket with JWT</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Sun, 13 Oct 2024 04:26:36 +0000</pubDate>
      <link>https://dev.to/jackwilltech/secure-your-apis-in-5-minutes-token-based-rsocket-with-jwt-37pn</link>
      <guid>https://dev.to/jackwilltech/secure-your-apis-in-5-minutes-token-based-rsocket-with-jwt-37pn</guid>
      <description>&lt;p&gt;RSocket provides a robust messaging system, built on top of the reactive streaming framework, and supports a variety of protocols including TCP, WebSocket, HTTP 1.1, and HTTP 2. Its programming language-agnostic interaction models, such as REQUEST_RESPONSE, REQUEST_FNF, REQUEST_STREAM, and REQUEST_CHANNEL, cater to diverse communication scenarios, including Microservices, API Gateway, Sidecar Proxy, and Message Queue.&lt;/p&gt;

&lt;p&gt;When securing communication, RSocket-based applications can easily adopt TLS-based and Token-based solutions. While RSocket can reuse TLS over TCP or WebSocket, this article focuses on token-based implementation to demonstrate the Role-Based Access Control (RBAC) feature.&lt;/p&gt;

&lt;p&gt;As the most widely adopted technology for OAuth2 globally, JSON Web Token (JWT) is an ideal choice due to its programming language-agnostic nature. After thorough research, I firmly believe that combining RSocket with JWT is an excellent approach to implementing secure communication between services, particularly for Open API. For a more detailed guide on securing APIs, visit &lt;a href="https://computerstechnicians.com/it/data/secure-your-apis-how-to-implement-token-based-rsocket-with-jwt-in-5-minutes/" rel="noopener noreferrer"&gt;computerstechnicians.com&lt;/a&gt;. Now, let’s delve deeper into the intricacies.&lt;/p&gt; 

&lt;h2&gt;Implementing RSocket for Secure Communication&lt;/h2&gt;

&lt;p&gt;The primary question is how to utilize tokens for inter-service communication in RSocket.&lt;/p&gt;

&lt;p&gt;There are two approaches to transmitting tokens from the requester to the responder. One method involves embedding the token into metadata API during setup, while the other involves sending the token as metadata, accompanied by payload as data, with each request.&lt;/p&gt;

&lt;p&gt;Beyond that, routing plays a pivotal role in authorization, indicating the resource on the responder side. In RSocket extensions, there exists a routing metadata extension to extend the four interaction models. If tag payloads are supported by both requester and responder, it’s straightforward to define authorization at the top layer.&lt;/p&gt;

&lt;h2&gt;Understanding JSON Web Token (JWT)&lt;/h2&gt;

&lt;p&gt;To grasp this article, understanding the following five aspects of JWT is sufficient.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;JWT encompasses JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), and JSON Web Algorithms (JWA).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;HS256 is a symmetric-key algorithm, whereas RS256/ES256 is an asymmetric-key algorithm based on Public Key Infrastructure (PKI). Both are defined in the JWA specification. HS256 combines HMAC (Keyed-Hash Message Authentication Code) with SHA-256, while RS256 utilizes RSASSA paired with SHA-256, and ES256 employs ECDSA (Elliptic Curve Digital Signature Algorithm) alongside SHA-256.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;In terms of the secret length, assuming the HS256 algorithm is employed for token generation, the secret characters should exceed 32, given that HS256 necessitates a secret of at least 256 bits (considering that 1 character is equivalent to 8 bits).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The Access Token is utilized by the responder for decoding, verification, and authorization purposes, whereas the Refresh Token serves to regenerate tokens, particularly when the Access Token has expired or become invalid.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Proper handling is necessary after the user signs out, especially when the access token remains valid during this period, to prevent unauthorized access.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Secure Data Exchange&lt;/h2&gt;

&lt;p&gt;Now, let’s proceed to the demonstration. We have two types of APIs: token and resource. Access to the resource API is only possible once the token has been verified and authenticated.&lt;/p&gt;

&lt;h3&gt;Workflow&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;We employ the &lt;span&gt;&lt;code&gt;signin&lt;/code&gt; API to generate tokens for the requester, which requires a username and password. Upon successful authentication, the responder signs, saves, and returns the Access Token and Refresh Token to the requester.&lt;/span&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;span&gt;&lt;code&gt;refresh&lt;/code&gt; API is used to renew tokens and requires a refresh token. After decoding and authorization, the responder signs, saves, and returns the Access Token and Refresh Token to the requester.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We define &lt;span&gt;&lt;code&gt;info&lt;/code&gt;/&lt;span&gt;&lt;code&gt;list&lt;/code&gt;/&lt;span&gt;&lt;code&gt;hire&lt;/code&gt;/&lt;span&gt;&lt;code&gt;fire&lt;/code&gt; as resource APIs to demonstrate various read/write actions.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The &lt;span&gt;&lt;code&gt;signout&lt;/code&gt; API handles cases of stolen tokens, as previously discussed, to prevent unauthorized access.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcomputerstechnicians.com%2Fwp-content%2Fuploads%2F2024%2F10%2Fsecure-communication-with-token-based-rsocket_img_0.png" class="article-body-image-wrapper"&gt;&lt;img alt="Workflow diagram" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcomputerstechnicians.com%2Fwp-content%2Fuploads%2F2024%2F10%2Fsecure-communication-with-token-based-rsocket_img_0.png" width="800" height="622"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Authentication&lt;/h3&gt;

&lt;p&gt;Given that we utilize Role-Based Access Control (RBAC) as our authorization mechanism, the authentication component should provide an identity repository (User -Role-Permission) to store and retrieve identity information within the responder, ensuring secure authentication.&lt;/p&gt;

&lt;p&gt;Additionally, we provide a token repository to store, revoke, and read tokens, which is used to verify authentication decoded from the token. Since authorization information is encrypted and compressed within the token, we use repository information to double-check these authorizations. If they match, we can confirm the request’s authenticity and legitimacy.&lt;/p&gt;

&lt;h3&gt;Authentication&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API&lt;/th&gt;
&lt;th&gt;Interaction Model&lt;/th&gt;
&lt;th&gt;Role&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Sign In&lt;/td&gt;
&lt;td&gt;Request/Response&lt;/td&gt;
&lt;td&gt;All Users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sign Out&lt;/td&gt;
&lt;td&gt;Fire-and-Forget&lt;/td&gt;
&lt;td&gt;Authenticated Users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Refresh Token&lt;/td&gt;
&lt;td&gt;Request/Response&lt;/td&gt;
&lt;td&gt;All Users&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User Information&lt;/td&gt;
&lt;td&gt;Request/Response&lt;/td&gt;
&lt;td&gt;User, Administrator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User List&lt;/td&gt;
&lt;td&gt;Request/Stream&lt;/td&gt;
&lt;td&gt;User, Administrator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hire User&lt;/td&gt;
&lt;td&gt;Request/Response&lt;/td&gt;
&lt;td&gt;Administrator&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Terminate User&lt;/td&gt;
&lt;td&gt;Request/Response&lt;/td&gt;
&lt;td&gt;Administrator&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;Implementing Spring Boot with Enhanced Security&lt;/h2&gt;

&lt;h3&gt;Token Signing&lt;/h3&gt;

&lt;p&gt;For seamless integration across diverse programming languages, it is crucial to establish a unified standard for the cryptographic algorithm and constants employed in encryption and compression within this demonstration.&lt;/p&gt;

&lt;p&gt;In this implementation, we have selected HS256 as the preferred algorithm, featuring an access token validity period of &lt;span&gt;&lt;code&gt;5&lt;/code&gt; minutes and a refresh token validity period of &lt;span&gt;&lt;code&gt;7&lt;/code&gt;&lt;/span&gt; days.&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static final long ACCESS_TOKEN_VALIDITY_PERIOD = 5;
public static final long REFRESH_TOKEN_VALIDITY_PERIOD = 7;
private static final MacAlgorithm ENCRYPTION_MECHANISM = MacAlgorithm.HS256;
private static final String HASHING_ALGORITHM = "HmacSHA256";&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let's examine the generated access token code:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public static UserToken generateAccessToken(HelloUser  user) {
    Algorithm ENCRYPTION_TECHNIQUE = Algorithm.HMAC256(ACCESS_SECRET_KEY);
    return generateToken(user, ENCRYPTION_TECHNIQUE, ACCESS_TOKEN_VALIDITY_PERIOD, ChronoUnit.MINUTES);
}

private static UserToken generateToken(HelloUser  user, Algorithm encryptionTechnique, long expirationTime, ChronoUnit timeUnit) {
    String tokenIdentifier = UUID.randomUUID().toString();
    Instant currentTime = Instant.now();
    Instant expirationTimeInstant;
    if (currentTime.isSupported(timeUnit)) {
        expirationTimeInstant = currentTime.plus(expirationTime, timeUnit);
    } else {
        log.error("unit param is not supported");
        return null;
    }
    String token = JWT.create()
            .withJWTId(tokenIdentifier)
            .withSubject(user.getUserId())
            .withClaim("scope", user.getRole())
            .withExpiresAt(Date.from(expirationTimeInstant))
            .sign(encryptionTechnique);
    return UserToken.builder().tokenId(tokenIdentifier).token(token).user(user).build();
}&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;The claim key name in the above code is not arbitrarily chosen, as “scope” is utilized in the framework as the default method to decode the role from the token.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Subsequently, the token decoder code is as follows:&lt;/p&gt;java
public static ReactiveJwtDecoder acquireAccessTokenDecoder() {
    SecretKeySpec secretKey = new SecretKeySpec(ACCESS_SECRET_KEY.getBytes(), HMAC_SHA_256);
    return NimbusReactiveJwtDecoder.withSecretKey(secretKey)
            .messageAuthenticationAlgorithm(MAC_ALGORITHM)
            .build();
}

public static ReactiveJwtDecoder jwtAccessTokenDecoder() {
    return new HelloJwtDecoder(acquireAccessTokenDecoder());
}

// HelloJwtDecoder
@Overridepublic Mono&amp;lt;Jwt&amp;gt; decode(String token) throws JwtException {
    return reactiveJwtDecoder.decode(token).doOnNext(jwt -&amp;gt; {
        String id = jwt.getId();
        HelloUser  auth = tokenRepository.retrieveAuthFromAccessToken(id);
        if (auth == null) {
            throw new JwtException("Invalid HelloUser ");
        }
        //TODO
        helloJwtService.setTokenId(id);
    });
}


&lt;p&gt;The decode method in &lt;/p&gt;

&lt;h3&gt;the &lt;code&gt;HelloJwtDecoder&lt;/code&gt; will be triggered by the framework during every request handling cycle, to transform the token string value into a jwt:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;@BeanPayloadSocketAcceptorInterceptor authorization(RSocketSecurity rsocketSecurity) {
    RSocketSecurity security = pattern(rsocketSecurity)
            .jwt(jwtSpec -&amp;gt; {
                try {
                    jwtSpec.authenticationManager(jwtReactiveAuthenticationManager(jwtDecoder()));
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            });
    return security.build();
}

@Beanpublic ReactiveJwtDecoder jwtDecoder() throws Exception {
    return TokenUtils.jwtAccessTokenDecoder();
}

@Beanpublic JwtReactiveAuthenticationManager jwtReactiveAuthenticationManager(ReactiveJwtDecoder decoder) {
    JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
    JwtGrantedAuthoritiesConverter authoritiesConverter = new JwtGrantedAuthoritiesConverter();
    authoritiesConverter.setAuthorityPrefix("ROLE_");
    converter.setJwtGrantedAuthoritiesConverter(authoritiesConverter);
    JwtReactiveAuthenticationManager manager = new JwtReactiveAuthenticationManager(decoder);
    manager.setJwtAuthenticationConverter(new ReactiveJwtAuthenticationConverterAdapter(converter));
    return manager;
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Revoke Token&lt;/h3&gt;

&lt;p&gt;To simplify the environment of the demo running, the way to revoke token implements here by guava cache. You can use some powerful components, like Redis, to do that.&lt;/p&gt;

&lt;p&gt;Once the time is up, the access token will be revoked automatically.&lt;/p&gt;

&lt;p&gt;On the other hand, when the requester sends &lt;span&gt;&lt;code&gt;signout&lt;/code&gt;, this cache will be invoked as event-driven.&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Cache&amp;lt;String, HelloUser&amp;gt; accessTokenTable = CacheBuilder.newBuilder()
            .expireAfterWrite(TokenUtils.ACCESS_EXPIRE, TimeUnit.MINUTES).build();

public void deleteAccessToken(String tokenId) {
  accessTokenTable.invalidate(tokenId);
}&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Verification of Identity&lt;/h3&gt;

&lt;p&gt;The &lt;span&gt;&lt;code&gt;authenticate&lt;/code&gt; function, designed for &lt;span&gt;&lt;code&gt;signin&lt;/code&gt;, operates on the same principles as the HTTP basic authentication mechanism, boasting a remarkable simplicity:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HelloUser   user = userRepository.retrieve(principal);
if (user.getPassword().equals(credential)) {
  return user;
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In contrast, the alternative &lt;span&gt;&lt;code&gt;authenticate&lt;/code&gt;, tailored for &lt;span&gt;&lt;code&gt;refresh&lt;/code&gt;, involves a series of more complex steps:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Acquiring a decoder and leveraging it to decode the token string value into a JWT object&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Implementing a reactive approach to map JWT to authentication&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Retrieving the authentication details from the repository&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Validating that the authentication information from the database and token are identical&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Returning the authentication object in a streaming manner&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;return reactiveJwtDecoder.decode(refreshToken).map(jwt -&amp;gt; {
    try {
        HelloUser   user = HelloUser  .builder().userId(jwt.getSubject()).role(jwt.getClaim("scope")).build();
        log.info("Verification successful. User: {}", user);
        HelloUser   auth = tokenRepository.getAuthFromRefreshToken(jwt.getId());
        if (user.equals(auth)) {
            return user;
        }
    } catch (Exception e) {
        log.error("", e);
    }
    return new HelloUser  ();
});&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Permission Management&lt;/h3&gt;

&lt;p&gt;As I mentioned earlier, this demo is built upon Role-Based Access Control (RBAC); the routing is the crucial aspect. For the sake of concision, I will refrain from showcasing the open APIs version, and instead, provide a concise overview:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// HelloSecurityConfig
protected RSocketSecurity pattern(RSocketSecurity security) {
    return security.authorizePayload(authorize -&amp;gt; authorize
            .route("signin.v1").permitAll()
            .route("refresh.v1").permitAll()
            .route("signout.v1").authenticated()
            .route("hire.v1").hasRole(ADMIN)
            .route("fire.v1").hasRole(ADMIN)
            .route("info.v1").hasAnyRole(USER, ADMIN)
            .route("list.v1").hasAnyRole(USER, ADMIN)
            .anyRequest().authenticated()
            .anyExchange().permitAll()
    );
}

// HelloJwtSecurityConfig
@Configuration@EnableRSocketSecuritypublic class HelloJwtSecurityConfig extends HelloSecurityConfig {
  @Bean  PayloadSocketAcceptorInterceptor authorization(RSocketSecurity rsocketSecurity) {
    RSocketSecurity security = pattern(rsocketSecurity)
    ...&lt;/code&gt;&lt;/pre&gt;

&lt;blockquote&gt;
&lt;p&gt;I put the route-based RBAC defination in parent class to easy to extend the security by using other way, e.g. TLS.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;SpringBoot provides &lt;span&gt;&lt;code&gt;MessageMapping&lt;/code&gt; annotation to let us define the route for messaging, which means streaming api in RSocket.&lt;/span&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@MessageMapping("signin.v1")    Mono&amp;lt;HelloToken&amp;gt; signin(HelloUser helloUser) {
    ...&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Prerequisites&lt;/h3&gt;

&lt;p&gt;From &lt;span&gt;&lt;code&gt;2.2.0-Release&lt;/code&gt; &lt;/span&gt; onwards, Spring Boot has been incorporating RSocket support. Furthermore, since version 2.3, it has also been providing RSocket security features. As 2.3.0 was not yet generally available when I wrote this article, the version I am showcasing is &lt;span&gt;&lt;code&gt;2.3.0.M4&lt;/code&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;spring-boot.version 2.3.0.M4&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;spring.version 5.2.5.RELEASE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;spring-security.version 5.3.1.RELEASE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;rsocket.version 1.0.0-RC6&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;reactor-netty.version 0.9.5.RELEASE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;netty.version 4.1.45.Final&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;reactor-core.version 3.3.3.RELEASE&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;jjwt.version 0.9.1&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Compilation, Execution, and Testing&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;bash build.sh&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;bash run_responder.sh
bash run_requester.sh&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;bash curl_test.sh&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;cURL Test&lt;/h4&gt;

&lt;pre&gt;&lt;code&gt;echo "Logging in as user"
read accessToken refreshToken &amp;lt; &amp;lt;(echo $(curl -s "http://localhost:8989/api/signin?u=0000&amp;amp;p=Zero4" | jq -r '.accessToken,.refreshToken'))
echo "Access Token  :${accessToken}"
echo -e "Refresh Token :${refreshToken}\\n"

echo "[user] refresh:"
curl -s "http://localhost:8989/api/refresh/${refreshToken}" | jq
echo

echo "[user] info:"
curl "http://localhost:8989/api/info/1"
echo -e "\\n"

echo "[user] list:"
curl -s "http://localhost:8989/api/list" | grep data -c
echo

echo "[user] hire:"
curl -s "http://localhost:8989/api/hire" \
-H "Content-Type: application/stream+json;charset=UTF-8" \
-d '{"id":"18","value":"伏虎羅漢"}' | jq -r ".message"&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Hidden Gem&lt;/h3&gt;

&lt;p&gt;The resource API component illustrates the employee lifecycle, from recruitment to termination. For a more comprehensive understanding, please explore Eighteen_Arhats!&lt;/p&gt;

&lt;h2&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;Initially, I had planned to provide a Golang implementation, but unfortunately, the RSocket for Golang lacks an open routing API, rendering it impractical to achieve this. However, a glimmer of hope remains: Jeff will soon be making them accessible.&lt;/p&gt;

&lt;p&gt;I find it intriguing to demonstrate this using alternative languages, such as Rust and NodeJs. Perhaps I’ll even author a series of articles on the subject.&lt;/p&gt;

&lt;p&gt;By the way, the source code for this demo is available on GitHub.&lt;/p&gt;


&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>api</category>
      <category>authentication</category>
      <category>it</category>
      <category>java</category>
    </item>
    <item>
      <title>Unlock 650+ Pokémon in 5 Steps: Build Your Dream Index with Vanilla JavaScript</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Sat, 12 Oct 2024 23:01:17 +0000</pubDate>
      <link>https://dev.to/jackwilltech/unlock-650-pokemon-in-5-steps-build-your-dream-index-with-vanilla-javascript-1c5</link>
      <guid>https://dev.to/jackwilltech/unlock-650-pokemon-in-5-steps-build-your-dream-index-with-vanilla-javascript-1c5</guid>
      <description>&lt;p&gt;Get ready to catch 'em all with our latest project: building a Pokémon index using the Pokémon API and vanilla JavaScript. To kick things off, let's define our project's goals. We'll create a user-friendly search bar where users can look for their favorite Pokémon, and when they search, the Pokémon's image and stats will be displayed in the results. Although the functionality is straightforward, &lt;em&gt;this project serves as a great foundation for you to customize and add to your portfolio.&lt;/em&gt; You can also explore more projects like this on &lt;a href="https://t8tech.com/it/data/build-your-own-pokemon-index-in-5-steps-with-vanilla-javascript/" rel="noopener noreferrer"&gt;t8tech.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Check out the complete version of this project at https://poke-mon.now.sh/.&lt;/p&gt;

&lt;p&gt;This project draws inspiration from Chris on Code.&lt;/p&gt;



&lt;h2&gt;Setting Up the HTML Foundation&lt;/h2&gt;

&lt;p&gt;Before we dive into the world of JavaScript, we need to lay the groundwork with some HTML. Let's get started.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang="en"&amp;gt;
  &amp;lt;head&amp;gt;
    &amp;lt;title&amp;gt;Poke.mon&amp;lt;/title&amp;gt;
    &amp;lt;meta charset="UTF-8" /&amp;gt;
    &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1" /&amp;gt;
  &amp;lt;/head&amp;gt;
  &amp;lt;body&amp;gt;
    &amp;lt;form&amp;gt;
      &amp;lt;input type="text" placeholder="Search Pokemon" /&amp;gt;
      &amp;lt;input type="submit" value="Search" /&amp;gt;
    &amp;lt;/form&amp;gt;
    &amp;lt;div class="pokemon-container"&amp;gt;&amp;lt;/div&amp;gt;
  &amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This basic HTML file features an empty div with the class “pokemon-container” and a form with a search bar and a button above it. We'll use the empty div to display our Pokémon data from our JavaScript file.&lt;/p&gt;

&lt;h2&gt;Adding a Touch of Style&lt;/h2&gt;

&lt;p&gt;Our webpage looks a bit dull at this point, so let's add some visual flair. We'll create a &lt;code&gt;style.css&lt;/code&gt; file and link it to our &lt;code&gt;index.html&lt;/code&gt; file.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@import url("https://fonts.googleapis.com/css2?family=Press+Start+2P&amp;amp;display=swap");

body {
  padding: 30px;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: url("https://i.imgur.com/zwp2EXP.png") center top;
  background-color: #41740e;
  background-repeat: repeat-x;
  background-size: contain;
  font-family: "Press Start 2P";
  position: relative;
}

form {
  background: #ef5350;
  position: fixed;
  display: flex;
  justify-content: center;
  padding: 10px;
  top: 0;
  left: 0;
  right: 0;
}

form input {
  border: none;
  outline: none;
  border-radius: 20px;
  font-size: 18px;
  padding: 12px 20px;
}

form input[type="text"] {
  background: rgba(255, 254, 254, 0.7);
  min-width: 300px;
  max-width: 100%;
}

form input[type="submit"] {
  cursor: pointer;
  margin-left: 8px;
  background: #c62828;
  color: #f0d0d0;
}

.pokemon {
  text-align: center;
}

h2 {
  text-transform: capitalize;
}

.stats {
  font-size: 14px;
}&lt;/code&gt;&lt;/pre&gt;

It will take another post just to discuss the CSS, so let’s move on to the javascript side of things.&lt;br&gt;

&lt;h2&gt;Javascript&lt;/h2&gt;
&lt;p&gt;So let’s code some JavaScript now. We will start with an empty &lt;code&gt;index.js&lt;/code&gt; file and discuss what are the steps needed.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Grab the things we need from HTML in index.js.&lt;/li&gt;
&lt;li&gt;Take input from the search bar and use that to make API requests.&lt;/li&gt;
&lt;li&gt;Make requests to the Pokemon API and fetch the data.&lt;/li&gt;
&lt;li&gt;Display the data on the webpage.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Okay, these will be the steps, sounds simple, doesn’t it.&lt;/p&gt;

&lt;p&gt;The first step is to get all the div’s, form, etc, from HTML file which is done as follows.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// grab the things we need ----------
const pokemonContainer = document.querySelector(".pokemon-container");
const formEl = document.querySelector("form");
const inputEl = document.querySelector("input[type=text]");&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;When it comes to identifying elements, we have the option to utilize either the &lt;code&gt;getElementById()&lt;/code&gt; or &lt;code&gt;getElementByClass()&lt;/code&gt; methods, both of which yield identical outcomes in this particular scenario.&lt;/p&gt;

&lt;p&gt;Next, we will attach event listeners to capture the submission event.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;// listen for user events -------------
formEl.addEventListener("submit", (e) =&amp;gt; {
  e.preventDefault();
  pokemonContainer.innerHTML = "";
  getPokemon(inputEl.value);
});&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this code snippet, we leverage &lt;code&gt;e.preventDefault()&lt;/code&gt; to prevent the page from reloading. We then clear the contents of the &lt;code&gt;pokemonContainer&lt;/code&gt; div, which may hold previous search results in the future. Finally, we invoke the &lt;code&gt;getPokemon()&lt;/code&gt; function, passing the search input as an argument. This function is responsible for handling everything from sending API requests to displaying the results on the page, so let’s explore its intricacies.&lt;/p&gt;

&lt;p&gt;The third step involves sending requests to the Pokémon API, accessible at https://pokeapi.co/api/v2/pokemon/, followed by the Pokémon’s unique identifier.&lt;/p&gt;

&lt;p&gt;We will create an asynchronous function to achieve this, as demonstrated below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;async function getPokemon(name = "bulbasaur") {
  const res = await fetch(`https://pokeapi.co/api/v2/pokemon/${name}`);
  const pokemon = await res.json();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Building a Dynamic Pokémon Interface with Asynchronous Functions&lt;/h2&gt;
&lt;p&gt;In this illustration, we'll delve into a straightforward asynchronous function known as &lt;code&gt;getPokemon()&lt;/code&gt;, which leverages the fetch API to send requests and store the responses in the &lt;code&gt;res&lt;/code&gt; variable. The response is then parsed into JSON format using the &lt;code&gt;json()&lt;/code&gt; method.&lt;/p&gt;
&lt;p&gt;A notable aspect of this function is its capacity to display a default Pokémon prior to initiating a search. This is achieved by adding a &lt;code&gt;name&lt;/code&gt; parameter, such as &lt;code&gt;name = bulbasaur&lt;/code&gt;, to the function. Furthermore, users can search for specific Pokémon by name.&lt;/p&gt;
&lt;p&gt;It's crucial to note that the API only acknowledges lowercase Pokémon names as valid. To accommodate this, you can optionally create a method or function to convert user input to lowercase.&lt;/p&gt;
&lt;p&gt;Once we've obtained the Pokémon information and stored it in the &lt;code&gt;res&lt;/code&gt; variable, let's examine a traditional API response. Due to the extensive size of the response JSON, we recommend visiting https://pokeapi.co/ to view the raw file.&lt;/p&gt;
&lt;p&gt;Now that we have the Pokémon data, let's create a separate div to display the information. We'll start by creating a new div element using &lt;code&gt;document.createElement("div")&lt;/code&gt; and assigning it a class of &lt;code&gt;pokemon&lt;/code&gt; with &lt;code&gt;classList.add("pokemon")&lt;/code&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;const pokemonEl = document.createElement("div");
pokemonEl.classList.add("pokemon");&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We'll begin by displaying the Pokémon image using &lt;code&gt;.innerHTML&lt;/code&gt; and &lt;code&gt;appendChild()&lt;/code&gt; to append the data to the web page. Remember that all these operations take place within the &lt;code&gt;getPokemon()&lt;/code&gt; function.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;pokemonEl.innerHTML = `&amp;lt;div class="info"&amp;gt;
&amp;lt;img src="https://pokeres.bastionbot.org/images/pokemon/${pokemon.id}.png" width="200"&amp;gt;
&amp;lt;h2&amp;gt;${pokemon.name}&amp;lt;/h2&amp;gt;
&amp;lt;/div&amp;gt;
`
pokemonContainer.appendChild(pokemonEl);&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Presenting Pokémon Details&lt;/h2&gt;
&lt;p&gt;We leveraged the `innerHTML` property on the `pokemonEl` element, combining it with Template Literals to dynamically inject HTML. This approach enabled us to create a `div` with a class of “info” and populate it with the desired data.&lt;/p&gt;
&lt;p&gt;The subsequent step involves isolating the pertinent information within the JSON response and selectively determining what to display in our application. Given the substantial size of the response files, it is crucial to be judicious about the quantity and type of data we wish to showcase.&lt;/p&gt;
&lt;p&gt;In terms of the Pokémon image, we can access all of them by simply modifying the `id` in `pokemon.id}.png`. The Pokémon’s name is then displayed using an `&lt;/p&gt;
&lt;h2&gt;` heading. Finally, we append the `div` to the webpage using `pokemonContainer.appendChild(pokemonEl)`, rendering the information visible to the user.
&lt;h2&gt;Delving Deeper into Pokémon Information&lt;/h2&gt;
&lt;/h2&gt;
&lt;p&gt;At this point, we can successfully display the Pokémon’s name and image. However, there’s a wealth of additional information we can provide, so let’s proceed.&lt;/p&gt;
&lt;p&gt;Our next step will be to display the Pokémon’s stats. We can access these stats from the response using `pokemon.stats`. Before we do so, let’s take a closer look at the raw JSON data for the stats. Below, you’ll find the stats for Bulbasaur:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; "stats": [
    {
      "base_stat": 45,
      "effort": 0,
      "stat": {
        "name": "speed",
        "url": "https://pokeapi.co/api/v2/stat/6/"
      }
    },
    {
      "base_stat": 65,
      "effort": 0,
      "stat": {
        "name": "special-defense",
        "url": "https://pokeapi.co/api/v2/stat/5/"
      }
    },
    {
      "base_stat": 65,
      "effort": 1,
      "stat": {
        "name": "special-attack",
        "url": "https://pokeapi.co/api/v2/stat/4/"
      }
    },
    {
      "base_stat": 49,
      "effort": 0,
      "stat": {
        "name": "defense",
        "url": "https://pokeapi.co/api/v2/stat/3/"
      }
    },
    {
      "base_stat": 49,
      "effort": 0,
      "stat": {
        "name": "attack",
        "url": "https://pokeapi.co/api/v2/stat/2/"
      }
    },
    {
      "base_stat": 45,
      "effort": 0,
      "stat": {
        "name": "hp",
        "url": "https://pokeapi.co/api/v2/stat/1/"
      }
    }
  ],&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;So, now we have to decide what all we want to display. It’s entirely up to you, you can display everything or nothing. Here we will display the name of the stat and its numeric value that is&lt;br&gt;&lt;br&gt;
&lt;code&gt;base_stat&lt;/code&gt;&lt;br&gt;&lt;/p&gt;



&lt;pre&gt;&lt;code&gt;&amp;lt;div class="stats"&amp;gt;${pokemon.stats.map((stat) =&amp;gt; {&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

</description>
      <category>javascript</category>
      <category>statistics</category>
    </item>
    <item>
      <title>Boost Data Analysis by 33%: Crack 3 Hidden Integration Codes</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Fri, 11 Oct 2024 19:16:23 +0000</pubDate>
      <link>https://dev.to/jackwilltech/boost-data-analysis-by-33-crack-3-hidden-integration-codes-5g6</link>
      <guid>https://dev.to/jackwilltech/boost-data-analysis-by-33-crack-3-hidden-integration-codes-5g6</guid>
      <description>&lt;p&gt;As enterprise data flows in from diverse locations, consolidating heterogeneous data sources becomes a significant hurdle in optimizing data processing. Standardizing data emerges as a prerequisite for effective and accurate analysis. The absence of a suitable integration strategy can lead to application-specific and intradepartmental data silos, hindering productivity and delaying results.&lt;/p&gt;

&lt;p&gt;Unifying data from disparate structured, unstructured, and semi-structured sources is a complex task. According to a Gartner survey, one-third of respondent companies consider "integrating multiple data sources" as one of the top four integration challenges.&lt;/p&gt;

&lt;p&gt;Recognizing the common issues faced during this process can help enterprises successfully counteract them. Here are three common challenges generally faced by organizations when integrating heterogeneous data sources and ways to resolve them:&lt;/p&gt;

&lt;p&gt;Data Extraction&lt;br&gt;
Extracting source data is the initial step in the integration process. However, it can be complicated and time-consuming if data sources have different formats, structures, and types. Moreover, once the data is extracted, it needs to be transformed to make it compatible with the destination system before integration. To overcome this challenge, create a list of sources that your organization would be dealing with regularly. Look for an integration tool that supports extraction from all these sources. Preferably, opt for a tool that supports structured, unstructured, and semi-structured sources to simplify and streamline the extraction process.&lt;/p&gt;

&lt;p&gt;Data Integrity&lt;br&gt;
Data quality is a primary concern in every data integration strategy. Poor data quality can be a compounding problem that can affect the entire integration cycle. Processing invalid or incorrect data can lead to faulty analytics, which if passed downstream, can corrupt results. To ensure that correct and accurate data enters the data pipeline, create a data quality management plan before starting the project. Outlining these steps guarantees that bad data is kept out of every step of the data pipeline, from development to processing.&lt;/p&gt;

&lt;p&gt;To overcome these challenges and unlock 33% faster data analysis, learn more about integrating heterogeneous data sources at &lt;a href="https://computerstechnicians.com/it/data/unlock-33-faster-data-analysis-overcome-3-hidden-challenges-of-integrating-heterogeneous-data-sources/" rel="noopener noreferrer"&gt;computerstechnicians&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>data</category>
      <category>integration</category>
    </item>
    <item>
      <title>5 Real-World Examples to Boost Your Spring Development with JDK 14 Records</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Thu, 10 Oct 2024 13:15:50 +0000</pubDate>
      <link>https://dev.to/jackwilltech/5-real-world-examples-to-boost-your-spring-development-with-jdk-14-records-21g9</link>
      <guid>https://dev.to/jackwilltech/5-real-world-examples-to-boost-your-spring-development-with-jdk-14-records-21g9</guid>
      <description>&lt;p&gt;In this article, we'll explore the various scenarios where JDK 14 Records prove to be a game-changer.&lt;/p&gt;

&lt;h2&gt;Unlocking the Power of JDK 14 Records: A Simplified Introduction&lt;/h2&gt;

&lt;p&gt;New to JDK 14 Records? Let's start with the fundamentals: Records provide a compact syntax for defining classes that serve as simple, &lt;strong&gt;immutable&lt;/strong&gt; data holders, minus the unnecessary code.&lt;/p&gt;

&lt;p&gt;A practical example is the best way to demonstrate this. Consider the following Java class:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public final class Author {
  
  private final String name;
  private final String genre;    
  
  public Author(String name, String genre) {
    this.name = name;
    this.genre = genre;  
  }

    public String getName() {
        return name;
    }

    public String getGenre() {
        return genre;
    }

    @Override    public boolean equals(Object o) {
      ...
    }
            
    @Override    public int hashCode() {
      ...
    }

    @Override    public String toString() {
      ...
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Thanks to JDK 14, the Records syntax can be utilized to condense the above code into a single, concise line, making your coding experience more efficient:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public record Author(String name, String genre) {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At &lt;a href="https://t8tech.com/it/coding/unlock-the-power-of-jdk-14-records-5-real-world-examples-to-boost-your-spring-development/" rel="noopener noreferrer"&gt;t8tech.com&lt;/a&gt;, we've seen firsthand how JDK 14 Records can revolutionize the way you approach Spring development. In this article, we'll delve into the various scenarios where this feature comes into play, providing you with a comprehensive understanding of its applications.&lt;/p&gt;

&lt;p&gt;And that's the final verdict! Running the &lt;code&gt;javap&lt;/code&gt; tool on &lt;code&gt;Author.class&lt;/code&gt; produces the following output:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_0.png" class="article-body-image-wrapper"&gt;&lt;img alt="Executing javap on Author class" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_0.png" width="615" height="125"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Upon scrutinizing the properties of an immutable class, we notice that &lt;code&gt;Person.class&lt;/code&gt; indeed exhibits immutability:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The class must be declared &lt;code&gt;final&lt;/code&gt; to prevent subclassing (other classes cannot extend this class, thereby precluding method overriding).&lt;/li&gt;
&lt;li&gt;All fields should be declared &lt;code&gt;private&lt;/code&gt; and &lt;code&gt;final&lt;/code&gt;&lt;span&gt;. &lt;/span&gt;(They are inaccessible to other classes, and they are initialized solely once in the constructor of this class.)&lt;/li&gt;
&lt;li&gt;The class should feature a parameterized &lt;code&gt;public&lt;/code&gt; constructor (or a &lt;code&gt;private&lt;/code&gt; constructor and factory methods for instance creation) that initializes the fields.&lt;/li&gt;
&lt;li&gt;The class should provide getter methods for fields.&lt;/li&gt;
&lt;li&gt;The class should not expose setter methods.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can delve deeper into immutable objects in my book, Java Coding Problems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_1.png" width="192" height="224"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;So, JDK 14 Records are not a substitute for mutable JavaBean classes. They cannot be utilized as JPA/Hibernate entities. However, they are an ideal fit for use with Streams. They can be instantiated via the constructor with arguments, and in lieu of getters, we can access the fields via methods with similar names (e.g., the field  &lt;code&gt;name&lt;/code&gt; is exposed via the  &lt;code&gt;name()&lt;/code&gt; method).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Next, let’s explore several scenarios of utilizing JDK 14 Records in a Spring application. &lt;/p&gt;

&lt;h2&gt;JSON Serialization of Records&lt;/h2&gt;

&lt;p&gt;Let’s assume that an author has penned multiple books. By defining a &lt;code&gt;List&amp;lt;Book&amp;gt;&lt;/code&gt; in the &lt;code&gt;Author&lt;/code&gt; class, we can model this scenario, having the &lt;code&gt;Author&lt;/code&gt; and the &lt;code&gt;Book&lt;/code&gt; class:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public final class Author {
  
  private final String name;
  private final String genre;
  private final List&amp;amp;lt;Book&amp;amp;gt; books;
  ...
}
    
public final Book {
  
  private String title;
  private String isbn;
  ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If we use Records, then we can eliminate the boilerplate code as below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public record Author(String name, String genre, List&amp;amp;lt;Book&amp;amp;gt; books) {}
public record Book(String title, String isbn) {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let’s consider the following data sample:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;List&amp;amp;lt;Author&amp;amp;gt; authors = List.of(
  new Author("Joana Nimar", "History", List.of(
    new Book("History of a day", "JN-001"),
    new Book("Prague history", "JN-002")
  )),
  new Author("Mark Janel", "Horror", List.of(
    new Book("Carrie", "MJ-001"),
    new Book("House of pain", "MJ-002")
  ))
);&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If we want to serialize this data as JSON via a Spring REST Controller, then most we will most likely do it, as shown below. First, we have a service that returns the data:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@Servicepublic class BookstoreService {
  
  public List&amp;amp;lt;Author&amp;amp;gt; fetchAuthors() {
    
    List&amp;amp;lt;Author&amp;amp;gt; authors = List.of(
      new Author("Joana Nimar", "History", List.of(
        new Book("History of a day", "JN-001"),
        new Book("Prague history", "JN-002")
      )),
      new Author("Mark Janel", "Horror", List.of(
        new Book("Carrie", "MJ-001"),
        new Book("House of pain", "MJ-002")
      )));
    
    return authors;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And, the controller is quite simple:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@RestControllerpublic class BookstoreController {
  
  private final BookstoreService bookstoreService;
  
  public BookstoreController(BookstoreService bookstoreService) {
    this.bookstoreService = bookstoreService;
  }
  
  @GetMapping("/authors")  public List&amp;amp;lt;Author&amp;amp;gt; fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, when we access the endpoint, &lt;code&gt;localhost:8080/authors&lt;/code&gt;&lt;span&gt;, &lt;/span&gt;we encounter the following result:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_2.png" class="article-body-image-wrapper"&gt;&lt;img alt="Authors endpoint response" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_2.png" width="566" height="138"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This suggests that the objects are not serializable. The solution involves adding the Jackson annotations, &lt;code&gt;JsonProperty&lt;/code&gt;, to facilitate serialization:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import com.fasterxml.jackson.annotation.JsonProperty;
      
public record Author(
  @JsonProperty("name") String name, 
  @JsonProperty("genre") String genre, 
  @JsonProperty("books") List&amp;lt;Book&amp;gt; books
) {}
        
public record Book(
  @JsonProperty("title") String title, 
  @JsonProperty("isbn") String isbn
) {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This time, accessing the &lt;code&gt;localhost:8080/authors&lt;/code&gt; endpoint yields the following JSON output:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[
  {
    "name": "Joana Nimar",
    "genre": "History",
    "books": [
      {
        "title": "History of a day",
        "isbn": "JN-001"
      },
      {
        "title": "Prague history",
        "isbn": "JN-002"
      }
    ]
  },
  {
    "name": "Mark Janel",
    "genre": "Horror",
    "books": [
      {
        "title": "Carrie",
        "isbn": "MJ-001"
      },
      {
        "title": "House of pain",
        "isbn": "MJ-002"
      }
    ]
  }
]&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The complete code is available on GitHub.&lt;/p&gt;

&lt;h2&gt;Records and Dependency Injection: A Closer Look&lt;/h2&gt;

&lt;p&gt;Let’s revisit our controller and explore how records and dependency injection work together:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@RestControllerpublic class BookstoreController {
  
  private final BookstoreService bookstoreService;
  
  public BookstoreController(BookstoreService bookstoreService) {
    this.bookstoreService = bookstoreService;
  }
  
  @GetMapping("/authors")  public List&amp;lt;Author&amp;gt; fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In this controller, we utilize Dependency Injection to inject a &lt;code&gt;BookstoreService&lt;/code&gt; instance. Alternatively, we could have employed &lt;code&gt;@Autowired&lt;/code&gt;. However, we can explore the use of JDK 14 Records, as demonstrated below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@RestControllerpublic record BookstoreController(BookstoreService bookstoreService) {
    
  @GetMapping("/authors")  public List&amp;amp;lt;Author&amp;amp;gt; fetchAuthors() {
    return bookstoreService.fetchAuthors();
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The complete code is available on GitHub.&lt;/p&gt;

&lt;h2&gt;DTOs via Records and Spring Data Query Builder&lt;/h2&gt;

&lt;p&gt;Let’s reiterate this crucial point:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;JDK 14 Records are incompatible with JPA/Hibernate entities due to the absence of setters.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Now, let’s examine the following JPA entity:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@Entitypublic class Author implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  private int age;
  private String name;
  private String genre;
    
  // getters and setters 
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Our goal is to retrieve a read-only list of authors, including their names and ages. To achieve this, we require a DTO. We can define a Spring projection, a POJO, or a Java Record, as shown below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public record AuthorDto(String name, int age) {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The query that populates the DTO can be crafted using Spring Data Query Builder:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public interface AuthorRepository extends JpaRepository&amp;amp;lt;Author, Long&amp;amp;gt; {
  
  @Transactional(readOnly = true)    
  List&amp;amp;lt;AuthorDto&amp;amp;gt; retrieveAuthorsByGenre(String genre);
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The complete application is available on GitHub.&lt;/p&gt;

&lt;h2&gt;DTOs via Records and Constructor Expression and JPQL&lt;/h2&gt;

&lt;p&gt;Given the same &lt;code&gt;Author&lt;/code&gt; entity and the same &lt;code&gt;AuthorDto&lt;/code&gt; record, we can construct the query via Constructor Expression and JPQL, as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public interface AuthorRepository extends JpaRepository&amp;amp;lt;Author, Long&amp;amp;gt; {
  
  @Transactional(readOnly = true)
  @Query(value = "SELECT new com.bookstore.dto.AuthorDto(a.name, a.age) FROM Author a")
  List&amp;amp;lt;AuthorDto&amp;amp;gt; retrieveAuthors();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The comprehensive application is accessible on GitHub.&lt;/p&gt;

&lt;h2&gt;DTOs via Records and Hibernate ResultTransformer&lt;/h2&gt;

&lt;p&gt;In certain scenarios, we need to retrieve a DTO comprising a subset of properties (columns) from a parent-child association. For such cases, we can utilize a SQL &lt;code&gt;JOIN&lt;/code&gt; that can extract the desired columns from the involved tables. However, &lt;code&gt;JOIN&lt;/code&gt; returns a &lt;code&gt;List&amp;lt;Object[]&amp;gt;&lt;/code&gt;, and most likely, you will need to represent it as a &lt;code&gt;List&amp;lt;&lt;em&gt;ParentDto&lt;/em&gt;&amp;gt;&lt;/code&gt;, where a &lt;code&gt;ParentDto&lt;/code&gt; instance has a &lt;code&gt;List&amp;lt;&lt;em&gt;ChildDto&lt;/em&gt;&amp;gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Such an example is the below bidirectional &lt;code&gt;@OneToMany&lt;/code&gt; relationship between &lt;code&gt;Author&lt;/code&gt; and &lt;code&gt;Book&lt;/code&gt; entities:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_3.png" class="article-body-image-wrapper"&gt;&lt;img alt="One to Many relationship" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_3.png" width="612" height="282"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@Entitypublic class Author implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  private String name;
  private String genre;
  private int age;
  
  @OneToMany(cascade = CascadeType.ALL,
             mappedBy = "author", orphanRemoval = true)
  private List&amp;amp;lt;Book&amp;amp;gt; books = new ArrayList&amp;amp;lt;&amp;amp;gt;();
     
  // getters and setters
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;@Entitypublic class Book implements Serializable {
  
  private static final long serialVersionUID = 1L;
  
  @Id  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  private String title;
  private String isbn;
  
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "author_id")
  private Author author;
     
  // getters and setters
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To retrieve the &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;name&lt;/code&gt;, and &lt;code&gt;age&lt;/code&gt; of each author, along with the &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;title&lt;/code&gt; of their associated books, the application leverages DTO and the Hibernate-specific &lt;code&gt;ResultTransformer&lt;/code&gt;. This interface enables the transformation of query results into the actual application-visible query result list, supporting both JPQL and native queries, and is a remarkably powerful feature. &lt;/p&gt;

&lt;p&gt;The initial step involves defining the DTO class. The &lt;code&gt;ResultTransformer&lt;/code&gt; can fetch data in a DTO with a constructor and no setters or in a DTO with no constructor but with setters. To fetch the name and age in a DTO with a constructor and no setters, a DTO shaped via JDK 14 Records is required:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;import java.util.List;

public record AuthorDto(Long id, String name, int age, List&amp;lt;BookDto&amp;gt; books) {
  
  public void addBook(BookDto book) {
    books().add(book);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public record BookDto(Long id, String title) {}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, assigning the result set to &lt;code&gt;AuthorDto&lt;/code&gt; is not feasible through a native &lt;code&gt;ResultTransformer&lt;/code&gt;. Instead, you need to convert the result set from &lt;code&gt;Object[]&lt;/code&gt; to &lt;code&gt;List&amp;lt;AuthorDto&amp;gt;&lt;/code&gt;, which necessitates the custom &lt;code&gt;AuthorBookTransformer&lt;/code&gt;, an implementation of the &lt;code&gt;ResultTransformer&lt;/code&gt; interface. &lt;/p&gt;

&lt;p&gt;This interface specifies two methods — &lt;code&gt;transformTuple()&lt;/code&gt; and &lt;code&gt;transformList()&lt;/code&gt;. The &lt;code&gt;transformTuple()&lt;/code&gt; method facilitates the transformation of tuples, which constitute each row of the query result. The &lt;code&gt;transformList()&lt;/code&gt; method, on the other hand, enables you to perform the transformation on the query result as a whole:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public class AuthorBookTransformer implements ResultTransformer {

  private Map&amp;lt;Long, AuthorDto&amp;gt; authorsDtoMap = new HashMap&amp;lt;&amp;gt;();

  @Override  public Object transformTuple(Object[] os, String[] strings) {
    
    Long authorId = ((Number) os[0]).longValue();
    
    AuthorDto authorDto = authorsDtoMap.get(authorId);
    
    if (authorDto == null) {
      authorDto = new AuthorDto(((Number) os[0]).longValue(), 
         (String) os[1], (int) os[2], new ArrayList&amp;lt;&amp;gt;());
    }
    
    BookDto bookDto = new BookDto(((Number) os[3]).longValue(), (String) os[4]);
    
    authorDto.addBook(bookDto);
    
    authorsDtoMap.putIfAbsent(authorDto.id(), authorDto);
    
    return authorDto;
  }
  
  @Override  public List&amp;lt;AuthorDto&amp;gt; transformList(List list) {
    return new ArrayList&amp;lt;&amp;gt;(authorsDtoMap.values());
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The bespoke DAO implementation that leverages this custom &lt;code&gt;ResultTransformer&lt;/code&gt; is presented below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@Repositorypublic class DataAccessObject implements AuthorDataAccessObject {
  
  @PersistenceContext  private EntityManager entityManager;
  
  @Override  @Transactional(readOnly = true)
  public List&amp;lt;AuthorDataTransferObject&amp;gt; retrieveAuthorWithBook() {
    Query query = entityManager
      .createNativeQuery(
        "SELECT a.id AS author_id, a.name AS name, a.age AS age, "
        + "b.id AS book_id, b.title AS title "
        + "FROM author a JOIN book b ON a.id=b.author_id")
      .unwrap(org.hibernate.query.NativeQuery.class)
      .setResultTransformer(new AuthorBookTransformer());
    
    List&amp;lt;AuthorDataTransferObject&amp;gt; authors = query.getResultList();
    
    return authors;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the end, we can obtain the data in the following service:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@Servicepublic class BookstoreBusinessService {
  
  private final DataAccessObject dao;
  
  public BookstoreBusinessService(DataAccessObject dao) {
    this.dao = dao;
  }
  
  public List&amp;lt;AuthorDataTransferObject&amp;gt; retrieveAuthorWithBook() {
    
    List&amp;lt;AuthorDataTransferObject&amp;gt; authors = dao.retrieveAuthorWithBook();        
    
    return authors;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;@Servicepublic record BookstoreBusinessService(DataAccessObject dao) {
    
  public List&amp;lt;AuthorDataTransferObject&amp;gt; retrieveAuthorWithBook() {
    
    List&amp;lt;AuthorDataTransferObject&amp;gt; authors = dao.retrieveAuthorWithBook();        
    
    return authors;
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The complete application is available on GitHub.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Starting with Hibernate 5.2,  &lt;code&gt;ResultTransformer&lt;/code&gt; is deprecated. Until a replacement is available (in Hibernate 6.0), it can be used.Read further here.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;Data Transfer Objects via Records, JdbcTemplate, and ResultSetExtractor&lt;/h2&gt;

&lt;p&gt;Achieving a similar mapping via  &lt;code&gt;JdbcTemplate &lt;/code&gt;and  &lt;code&gt;ResultSetExtractor &lt;/code&gt;can be accomplished as follows. The  &lt;code&gt;AuthorDataTransferObject &lt;/code&gt;and  &lt;code&gt;BookDataTransferObject &lt;/code&gt;are the same from the previous section:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public record AuthorDto(Long id, String name, int age, List books) {
     
  public void addBook(BookDto book) {
    books().add(book);
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public record BookDto(Long id, String title) {}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;@Repository@Transactional(readOnly = true)
public class AuthorExtractor {
  
  private final JdbcTemplate jdbcTemplate;
  
  public AuthorExtractor(JdbcTemplate jdbcTemplate) {
    this.jdbcTemplate = jdbcTemplate;
  }
  
  public List&amp;amp;lt;AuthorDto&amp;amp;gt; extract() {
    
    String sql = "SELECT a.id, a.name, a.age, b.id, b.title "
      + "FROM author a INNER JOIN book b ON a.id = b.author_id";
    
    List&amp;amp;lt;AuthorDto&amp;amp;gt; result = jdbcTemplate.query(sql, (ResultSet rs) -&amp;amp;gt; {
      
      final Map&amp;amp;lt;Long, AuthorDto&amp;amp;gt; authorsMap = new HashMap&amp;amp;lt;&amp;amp;gt;();
      while (rs.next()) {
        Long authorId = (rs.getLong("id"));
        AuthorDto author = authorsMap.get(authorId);
           
        if (author == null) {
          author = new AuthorDto(rs.getLong("id"), rs.getString("name"),
            rs.getInt("age"), new ArrayList());
        }
        
        BookDto book = new BookDto(rs.getLong("id"), rs.getString("title"));
        author.addBook(book);
        authorsMap.putIfAbsent(author.id(), author);
      }
        
      return new ArrayList&amp;amp;lt;&amp;amp;gt;(authorsMap.values());
    });
    
    return result;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The complete application is available on GitHub.&lt;/p&gt;

&lt;h2&gt;Refine the Implementation &lt;/h2&gt;

&lt;p&gt;Java Records allow us to validate the arguments of the constructor, therefore the following code is ok:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;public record Author(String name, int age) {
  
  public Author {
    if (age &amp;amp;lt;=18 || age &amp;amp;gt; 70)
      throw new IllegalArgumentException("...");
  }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For a deeper understanding, I suggest exploring this valuable resource. Furthermore, you may also find it advantageous to examine over 150 key considerations for optimizing persistence performance in Spring Boot, as detailed in Spring Boot Persistence Best Practices:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Ft8tech.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fjdk-14-records-for-spring-devs_img_4.png" width="156" height="220"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>database</category>
      <category>java</category>
      <category>programming</category>
      <category>language</category>
    </item>
    <item>
      <title>Boost Kubernetes Efficiency: Upgrade to v1.14 in 11 Easy Steps!</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Thu, 10 Oct 2024 02:40:33 +0000</pubDate>
      <link>https://dev.to/jackwilltech/boost-kubernetes-efficiency-upgrade-to-v114-in-11-easy-steps-ebd</link>
      <guid>https://dev.to/jackwilltech/boost-kubernetes-efficiency-upgrade-to-v114-in-11-easy-steps-ebd</guid>
      <description>&lt;p&gt;Kubernetes stands out as one of the most dynamic projects on Github, boasting an impressive 80,000+ commits and 550+ releases. Setting up a highly available (HA) Kubernetes cluster on-premises or in the cloud is a well-documented process that typically requires minimal effort. Tools like Kops or Kubespray can further simplify this process, making it more efficient. For expert strategies on cloud architecture and maximizing efficiency, you can visit &lt;a href="https://computerstechnicians.com/it/architecture/revolutionize-your-cloud-expert-strategies-for-a-seamless-kubernetes-upgrade-and-maximum-efficiency/" rel="noopener noreferrer"&gt;https://computerstechnicians.com&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;However, periodic updates are necessary to ensure the cluster stays up-to-date with the latest security patches and bug fixes, as well as to leverage new features released continuously. This is particularly important when running an outdated version (such as v1.9) or when automating the process to always be on the latest supported version.&lt;/p&gt;

&lt;p&gt;When operating an HA Kubernetes Cluster, the upgrade process involves two distinct tasks that should not overlap: upgrading the Kubernetes Cluster and, if necessary, upgrading the etcd cluster, which serves as the distributed key-value backing store of Kubernetes. Let's explore how to accomplish these tasks with minimal disruptions.&lt;/p&gt;

&lt;h2&gt;Navigating Kubernetes Upgrade Options&lt;/h2&gt;

&lt;p&gt;This upgrade process specifically applies to manually deploying Kubernetes in the cloud or on-premises. It does not cover managed Kubernetes environments (where upgrades are automatically handled by the platform) or Kubernetes services on public clouds (such as AWS' EKS or Azure Kubernetes Service), which have their own upgrade processes.&lt;/p&gt;

&lt;p&gt;For this tutorial, we assume a healthy 3-node Kubernetes and Etcd Clusters have been provisioned. A setup can be created using six DigitalOcean Droplets plus one for the worker node.&lt;/p&gt;

&lt;p&gt;Let's consider the following Kubernetes master nodes, all running v1.13:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Address&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hostname&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kube-1&lt;/td&gt;
&lt;td&gt;10.0.11.1&lt;/td&gt;
&lt;td&gt;kube-1.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kube-2&lt;/td&gt;
&lt;td&gt;10.0.11.2&lt;/td&gt;
&lt;td&gt;kube-2.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;kube-3&lt;/td&gt;
&lt;td&gt;10.0.11.3&lt;/td&gt;
&lt;td&gt;kube-3.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Additionally, we have one worker node running v1.13:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Address&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hostname&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;worker&lt;/td&gt;
&lt;td&gt;10.0.12.1&lt;/td&gt;
&lt;td&gt;worker.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The protocol for upgrading Kubernetes master nodes is meticulously detailed on the official Kubernetes documentation website. The current upgrade trajectories are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Transitioning from v1.12 to v1.13 HA&lt;/li&gt;
&lt;li&gt;Upgrading from v1.12 to v1.13&lt;/li&gt;
&lt;li&gt;Advancing from v1.13 to v1.14&lt;/li&gt;
&lt;li&gt;Progressing from v1.14 to v1.15&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Although there is only one documented version for HA Clusters, the steps can be tailored for other upgrade trajectories. In this example, we will delve into the upgrade path from v1.13 to v1.14 HA. It is vital to note that &lt;strong&gt;omitting a version – for instance, upgrading from v1.13 to v1.15 – is strongly advised against.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Prior to initiating, it is imperative to review the release notes of the intended upgrade version, as they may underscore breaking changes.&lt;/p&gt;

&lt;h2&gt;Upgrading Kubernetes: A Thorough, Step-by-Step Manual&lt;/h2&gt;

&lt;p&gt;Let’s proceed with the upgrade steps:&lt;/p&gt;

&lt;h3&gt;1. Log In to the First Node and Upgrade the kubeadm Tool Only:&lt;/h3&gt;
&lt;h2&gt;Upgrading Kubernetes: A Step-by-Step Guide&lt;/h2&gt;

&lt;p&gt;To upgrade Kubernetes, we need to follow a series of steps to ensure a smooth transition. The process involves upgrading kubeadm, verifying the upgrade plan, applying the plan, updating kubelet, and upgrading kubectl and kubeadm on other nodes.&lt;/p&gt;

&lt;h3&gt;1. Upgrade Kubeadm on the First Master Node&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ssh admin@10.0.11.1$ apt-mark unhold kubeadm &amp;amp;&amp;amp; \
$ apt-get update &amp;amp;&amp;amp; apt-get install -y kubeadm=1.13.0-00 &amp;amp;&amp;amp; apt-mark hold kubeadm&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The reason for running &lt;strong&gt;apt-mark unhold&lt;/strong&gt; and &lt;strong&gt;apt-mark hold&lt;/strong&gt; is to prevent automatic upgrades of other components, such as kubelet, to the latest version (v1.15) by default. By using &lt;strong&gt;hold&lt;/strong&gt;, we mark a package as held back, preventing automatic installation, upgrade, or removal.&lt;/p&gt;

&lt;h3&gt;2. Verify the Upgrade Plan:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ kubeadm upgrade plan
...

COMPONENT            CURRENT AVAILABLE

API Server           v1.13.0 v1.14.0

Controller Manager   v1.13.0 v1.14.0

Scheduler            v1.13.0 v1.14.0

Kube Proxy           v1.13.0 v1.14.0

...&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;3. Apply the Upgrade Plan:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ kubeadm upgrade plan apply v1.14.0&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;4. Update Kubelet and Restart the Service:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ apt-mark unhold kubelet &amp;amp;&amp;amp; apt-get update &amp;amp;&amp;amp; apt-get install -y kubelet=1.14.0-00 &amp;amp;&amp;amp; apt-mark hold kubelet
$ systemctl restart kubelet&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;5. Apply the Upgrade Plan to the Other Master Nodes:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ssh admin@10.0.11.2$ kubeadm upgrade node experimental-control-plane
$ ssh admin@10.0.11.3$ kubeadm upgrade node experimental-control-plane&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;6. Upgrade kubectl on all Master Nodes:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ apt-mark unhold kubectl &amp;amp;&amp;amp; apt-get update &amp;amp;&amp;amp; apt-get install -y kubectl=1.14.0-00 &amp;amp;&amp;amp; apt-mark hold kubectl&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;7. Upgrade kubeadm on First Worker Node:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ssh worker@10.0.12.1$ apt-mark unhold kubeadm &amp;amp;&amp;amp; apt-get update &amp;amp;&amp;amp; apt-get install -y kubeadm=1.14.0-00 &amp;amp;&amp;amp; apt-mark hold kubeadm&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;8. Login to a Master Node and Drain First Worker Node:&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;$ ssh admin@10.0.11.1$ kubectl drain worker --ignore-daemonsets&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;9. Enhance kubelet Configuration on Worker Node:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ssh worker@10.0.12.1$ kubeadm upgrade node config --kubelet-version v1.14.0&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;10. Update kubelet on Worker Node and Restart the Service:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ apt-mark unhold kubelet &amp;amp;&amp;amp; apt-get update &amp;amp;&amp;amp; apt-get install -y kubelet=1.14.0-00 &amp;amp;&amp;amp; apt-mark hold kubelet
$ systemctl restart kubelet&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;11. Reactivate Worker Node:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ssh admin@10.0.11.1$ kubectl uncordon worker
Step 12: Repeat steps 7-11 for the remaining worker nodes.
Step 13: Validate the cluster's health:
$ kubectl get nodes&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Etcd Upgrade Paths&lt;/h2&gt;

&lt;p&gt;As you’re well aware, etcd serves as the highly distributed key-value store backing Kubernetes, essentially functioning as the single source of truth. When operating a highly available Kubernetes cluster, it’s equally essential to run a highly available etcd cluster, providing a failsafe in the event of node failures.&lt;/p&gt;

&lt;p&gt;Typically, we would maintain a &lt;strong&gt;minimum of three etcd nodes&lt;/strong&gt; running the latest supported version. The process of upgrading etcd nodes is thoroughly documented in the etcd repository. The current upgrade paths are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Migrate from 2.3 to 3.0&lt;/li&gt;
&lt;li&gt;Upgrade from 3.0 to 3.1&lt;/li&gt;
&lt;li&gt;Transition from 3.1 to 3.2&lt;/li&gt;
&lt;li&gt;Upgrade from 3.2 to 3.3&lt;/li&gt;
&lt;li&gt;Migrate from 3.3 to 3.4&lt;/li&gt;
&lt;li&gt;Upgrade from 3.4 to 3.5&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;When planning etcd upgrades, it’s crucial to adhere to the following plan:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Determine the version in use. For instance:
&lt;pre&gt;&lt;code&gt;$ ./etcdctl endpoint status&lt;/code&gt;&lt;/pre&gt;

&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Refrain from bypassing multiple minor versions in a single leap.&lt;/strong&gt; For example, avoid upgrading directly from 3.3 to 3.5. Instead, progress from 3.3 to 3.4, and then from 3.4 to 3.5.&lt;/li&gt;
&lt;li&gt;Leverage the &lt;strong&gt;pre-built&lt;/strong&gt; Kubernetes etcd image. The Kubernetes team provides a custom etcd image located here, which includes etcd and etcdctl binaries for multiple etcd versions, as well as a migration operator utility for upgrading and downgrading etcd. This will facilitate the automation of migrating and upgrading etcd instances.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Among these paths, the most critical change is the transition from 2.3 to 3.0, as it involves a &lt;strong&gt;substantial API revamp&lt;/strong&gt; that is documented here. Additionally, note that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;ul&gt;
&lt;li&gt;Etcd v3 is capable of handling requests for both v2 and v3 data. For instance, we can utilize the &lt;strong&gt;ETCDCTL_API&lt;/strong&gt; environment variable to specify the API version:
&lt;pre&gt;&lt;code&gt;$ ETCDCTL_API=2 ./etcdctl endpoint status&lt;/code&gt;&lt;/pre&gt;

&lt;ul&gt;
&lt;li&gt;It's essential to note that running etcd version 3 against a data directory formatted for version 2 does not trigger an automatic upgrade to the version 3 format.&lt;/li&gt;
&lt;li&gt;When using the version 2 API with etcd version 3, only the version 2 data stored in etcd is updated.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may be wondering which Kubernetes versions are compatible with each etcd version. The documentation provides a concise overview, stating:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes v1.0:&lt;/strong&gt; exclusively supports etcd2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes v1.5.1:&lt;/strong&gt; introduces etcd3 support, with new clusters defaulting to etcd2&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes v1.6.0:&lt;/strong&gt; new clusters created with kube-up.sh default to etcd3, and kube-apiserver defaults to etcd3&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes v1.9.0:&lt;/strong&gt; announces the deprecation of the etcd2 storage backend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes v1.13.0:&lt;/strong&gt; removes the etcd2 storage backend, with kube-apiserver refusing to start with –storage-backend=etcd2, citing the message etcd2 is no longer a supported storage backend&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Based on this information, if you are running &lt;strong&gt;Kubernetes v1.12.0 with etcd2&lt;/strong&gt;, you will need to upgrade etcd to version 3 when you upgrade Kubernetes to &lt;strong&gt;v1.13.0&lt;/strong&gt;, as –storage-backend=etcd3 is not supported. If you have Kubernetes &lt;strong&gt;v1.12.0 and below&lt;/strong&gt;, you can run both etcd2 and etcd3 concurrently.&lt;/p&gt;

&lt;p&gt;Before proceeding with any steps, it's crucial to perform routine maintenance tasks, such as taking periodic snapshots and performing smoke rollbacks. Ensure you verify the health of the cluster:&lt;/p&gt;

&lt;p&gt;Let's assume we have the following etcd cluster nodes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Node Name&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Address&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Hostname&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;etcd-1&lt;/td&gt;
&lt;td&gt;10.0.11.1&lt;/td&gt;
&lt;td&gt;etcd-1.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;etcd-2&lt;/td&gt;
&lt;td&gt;10.0.11.2&lt;/td&gt;
&lt;td&gt;etcd-2.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;etcd-3&lt;/td&gt;
&lt;td&gt;10.0.11.3&lt;/td&gt;
&lt;td&gt;etcd-3.example.com&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;pre&gt;&lt;code&gt;$ ./etcdctl cluster-health
member 6e3bd23ae5f1eae2 is functioning correctly: received a healthy response from http://10.0.1.1:22379
member 924e2e83f93f2565 is functioning correctly: received a healthy response from http://10.0.1.2:22379
member 8211f1d0a64f3269 is functioning correctly: received a healthy response from http://10.0.1.3:22379
cluster is functioning correctly&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Upgrading etcd&lt;/h2&gt;

&lt;p&gt;Based on the above considerations, a typical etcd upgrade procedure involves the following steps:&lt;/p&gt;

&lt;h3&gt;1. Access the First Node and Terminate the Existing etcd Process:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ssh 10.0.1.1
$ kill `pgrep etcd`&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;2. Create a Backup of the etcd Data Directory to Provide a Downgrade Path in Case of Errors:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ./etcdctl backup \
      --data-dir %data_dir% \
      [--wal-dir %wal_dir%] \
      --backup-dir %backup_data_dir% \
      [--backup-wal-dir %backup_wal_dir%]&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;3. Download the New Binary from the etcd Releases Page and Launch the etcd Server Using the Same Configuration:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;ETCD_VER=v3.3.15
# choose either URL
GOOGLE_URL=https://storage.googleapis.com/etcd
GITHUB_URL=https://github.com/etcd-io/etcd/releases/download
DOWNLOAD_URL=${GOOGLE_URL}

rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
rm -rf /usr/local/etcd &amp;amp;&amp;amp; mkdir -p /usr/local/etcd

curl -L ${DOWNLOAD_URL}/${ETCD_VER}/etcd-${ETCD_VER}-linux-amd64.tar.gz -o /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz
tar xzvf /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz -C /usr/local/etcd --strip-components=1
rm -f /tmp/etcd-${ETCD_VER}-linux-amd64.tar.gz

/usr/local/etcd/etcd --version
ETCDCTL_API=3 /usr/local/etcd/etcdctl version
# start etcd server
/usr/local/etcd/etcd -name etcd-1 -listen-peer-urls http://10.0.1.1:2380 -listen-client-urls http://10.0.1.1:2379,http://127.0.0.1:2379 -advertise-client-urls http://10.0.1.1:2379,http://127.0.0.1:2379&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;4. Replicate the Process for All Remaining Members.&lt;/h3&gt;

&lt;h3&gt;5. Validate the Cluster's Correct Functionality:&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ./etcdctl endpoint health
10.0.1.1:12379 is operating as expected: successfully ratified proposal: took =
10.0.1.2:12379 is operating as expected: successfully ratified proposal: took =
10.0.1.3:12379 is operating as expected: successfully ratified proposal: took =&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Crucial Note: &lt;/strong&gt;If you experience difficulties establishing a connection to the cluster, you may need to provide transport layer security certificates via HTTPS; for instance:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./etcdctl --ca-file=/etc/kubernetes/pki/etcd/ca.crt --cert-file=/etc/kubernetes/pki/etcd/server.crt --key-file=/etc/kubernetes/pki/etcd/server.key endpoint health&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;For added convenience, you can leverage the following environment variables:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ETCD_CA_FILE=/etc/kubernetes/pki/etcd/ca.crt
ETCD_CERT_FILE=/etc/kubernetes/pki/etcd/server.crt
ETCD_KEY_FILE=/etc/kubernetes/pki/etcd/server.key&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;In this article, we presented a detailed, step-by-step guide on upgrading both Kubernetes and Etcd clusters. These vital maintenance procedures are essential for the smooth day-to-day operations in a typical business environment. All stakeholders involved in HA Kubernetes deployments should acquaint themselves with the aforementioned steps.&lt;/p&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;/li&gt;

&lt;/ul&gt;

</description>
      <category>cluster</category>
      <category>kubernetes</category>
      <category>shell</category>
    </item>
    <item>
      <title>Protect Your App in 5 Minutes: OAuth Tokens Made Easy</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Tue, 08 Oct 2024 10:50:32 +0000</pubDate>
      <link>https://dev.to/jackwilltech/protect-your-app-in-5-minutes-oauth-tokens-made-easy-ge1</link>
      <guid>https://dev.to/jackwilltech/protect-your-app-in-5-minutes-oauth-tokens-made-easy-ge1</guid>
      <description>&lt;p&gt;Securing Your App in 5 Steps: A Beginner's Guide to OAuth Tokens&lt;/p&gt;

&lt;p&gt;When it comes to generating OAuth tokens, passwords are not exchanged between services. Instead, tokens serve as the authentication mechanism. In this article, we'll establish a basic authorization server that generates tokens based on the provided username and password.&lt;/p&gt;

&lt;p&gt;To begin, let's create a new class that extends &lt;code&gt;AuthorizationServerConfigurerAdapter&lt;/code&gt;. We can annotate it with &lt;code&gt;@Configuration&lt;/code&gt; to indicate that it's a configuration class containing one or more &lt;code&gt;@Bean&lt;/code&gt; methods. To enable the authorization server, we'll utilize &lt;code&gt;@EnableAuthorizationServer&lt;/code&gt;.java@Configuration@EnableAuthorizationServerpublic class AuthServer extends AuthorizationServerConfigurerAdapter&lt;/p&gt;

&lt;p&gt;Next, we'll create a bean for the password encoder. We can leverage the &lt;code&gt;BcryptPasswordEncoder&lt;/code&gt; for encoding passwords.&lt;/p&gt;

&lt;p&gt;java&lt;br&gt;
@Beanpublic PasswordEncoder passwordEncoder() {&lt;br&gt;
    return  new BCryptPasswordEncoder();&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;We'll override the configure methods as follows. There are three configure methods. We'll implement them as below. Here, we can configure grant types, passwords, refresh token validity, access token validity, and scopes.&lt;/p&gt;

&lt;p&gt;java&lt;br&gt;
@Overridepublic void configure(ClientDetailsServiceConfigurer clients) throws Exception {&lt;br&gt;
    clients.inMemory().withClient("client")&lt;br&gt;
            .secret(passwordEncoder.encode(("secret")))&lt;br&gt;
            .authorizedGrantTypes("password")&lt;br&gt;
            .scopes("webclient","mobileclient");&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;Grant Types:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Authorization code grant&lt;/li&gt;
&lt;li&gt;Implicit grant&lt;/li&gt;
&lt;li&gt;Resource owner credentials grant&lt;/li&gt;
&lt;li&gt;Client credentials grant&lt;/li&gt;
&lt;li&gt;Refresh token grant&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Scope&lt;/p&gt;

&lt;p&gt;Scopes impose limitations on an application's access to user's accounts. It can encompass one or more scopes. For a more in-depth guide on securing your app with OAuth tokens, check out this article: &lt;a href="https://t8tech.com/it/coding/secure-your-app-in-5-steps-a-beginners-guide-to-oauth-tokens/" rel="noopener noreferrer"&gt;&lt;/a&gt;&lt;a href="https://t8tech.com/it/coding/secure-your-app-in-5-steps-a-beginners-guide-to-oauth-tokens/" rel="noopener noreferrer"&gt;https://t8tech.com/it/coding/secure-your-app-in-5-steps-a-beginners-guide-to-oauth-tokens/&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;@Overridepublic void define(AuthorizationServerEndpointsConfigurator endpoints) throws Exception {
    endpoints.setAuthenticationManager(this.authenticationManagerBean);
}&lt;/code&gt;&lt;/pre&gt;



</description>
      <category>authentication</category>
      <category>java</category>
      <category>programming</category>
      <category>language</category>
    </item>
    <item>
      <title>Unlock 10% Discounts in 5 Minutes: Build a Drools Project with Maven</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Tue, 08 Oct 2024 00:03:57 +0000</pubDate>
      <link>https://dev.to/jackwilltech/unlock-10-discounts-in-5-minutes-build-a-drools-project-with-maven-10pc</link>
      <guid>https://dev.to/jackwilltech/unlock-10-discounts-in-5-minutes-build-a-drools-project-with-maven-10pc</guid>
      <description>&lt;p&gt;Building a Drools Project with Maven in 5 Easy Steps&lt;/p&gt;

&lt;p&gt;In this tutorial, we will guide you through the process of creating a sample Drools project using Maven dependencies, eliminating the need for pre-configuring Drools in your Eclipse environment.&lt;/p&gt;

&lt;p&gt;Our demo project will utilize Drools to determine the discount offered on various Bank Cards. For instance, if the user is employing an ABC Bankcard, we will provide a 10% discount. Follow the steps below to build the Maven Drools Project:&lt;/p&gt;

&lt;p&gt;Step 1-2: Create a New Maven Project&lt;/p&gt;

&lt;p&gt;Launch Eclipse and navigate to File -&amp;gt; New -&amp;gt; Project. A new window will open; search for Maven -&amp;gt; Maven Project. Click next until you reach the "Enter a group id for the artifact" page.&lt;/p&gt;

&lt;p&gt;Step 3: Configure the Project&lt;/p&gt;

&lt;p&gt;Enter the Artifact Id as "DroolsDemo", Group Id as "com.demo", and click Finish. After clicking Finish, the project will be created.&lt;/p&gt;

&lt;p&gt;Step 4: Add Dependencies&lt;/p&gt;

&lt;p&gt;Expand the project and open the pom.xml file. Under the dependencies tag, add the following dependency:&lt;/p&gt;

&lt;p&gt;xml&lt;br&gt;
&lt;br&gt;
    org.drools&lt;br&gt;
    drools-compiler&lt;br&gt;
    6.0.1.Final&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;By following these easy steps, you can unlock 10% discounts and build a Drools project with Maven. For more information, visit &lt;a href="https://computerstechnicians.com/it/coding/unlock-10-discounts-how-to-build-a-drools-project-with-maven-in-5-easy-steps/" rel="noopener noreferrer"&gt;computerstechnicians&lt;/a&gt;.&lt;/p&gt;
&lt;ul&gt;

&lt;li&gt;Proceed by creating a POJO class and deleting the default App.java file if present. Navigate to src/main/java, right-click on com.demo.DroolsDemo, and select New -&amp;gt; Class&lt;/li&gt;

&lt;li&gt;Specify the class name as “CardDetails” and click Finish&lt;img alt="java class creation" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcomputerstechnicians.com%2Fwp-content%2Fuploads%2F2024%2F09%2Fbuilding-basic-drools-project-using-maven-and-with_img_2.png" width="331" height="393"&gt;
&lt;/li&gt;

&lt;li&gt;Insert the following code into the CardDetails class&lt;/li&gt;

&lt;/ul&gt;




&lt;pre&gt;&lt;code&gt;package com.demo.DroolsDemo;

&lt;p&gt;public class CardDetails {&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

</description>
      <category>apache</category>
      <category>maven</category>
      <category>drools</category>
      <category>eclipse</category>
    </item>
    <item>
      <title>Reach 3.5 Billion Mobile Users with a 3-Step Responsive Fix!</title>
      <dc:creator>Jackson Williams</dc:creator>
      <pubDate>Mon, 07 Oct 2024 11:46:10 +0000</pubDate>
      <link>https://dev.to/jackwilltech/reach-35-billion-mobile-users-with-a-3-step-responsive-fix-197l</link>
      <guid>https://dev.to/jackwilltech/reach-35-billion-mobile-users-with-a-3-step-responsive-fix-197l</guid>
      <description>&lt;p&gt;In today's digital landscape, a website's success relies heavily on its ability to adapt effortlessly to various screen sizes, from desktops to tablets and smartphones. A responsive website is one that can seamlessly adjust to the client's screen, ensuring an optimal user experience. With over 3.5 billion mobile users worldwide, having a responsive website is crucial to stay ahead in the game. To learn more about transforming your website, visit &lt;a href="https://carsnewstoday.com/programming/coding/transform-your-website-in-3-easy-steps-make-it-responsive-and-reach-3-5-billion-mobile-users/" rel="noopener noreferrer"&gt;https://carsnewstoday.com&lt;/a&gt;. In this article, we'll delve into how to create a responsive website in just three easy steps.&lt;/p&gt;

&lt;h2&gt;Step 1: Designing a Flexible Layout&lt;/h2&gt;

&lt;p&gt;When building a responsive website or revamping an existing one, the layout is the first vital element to consider. My approach is to start by creating a non-responsive layout with a fixed default size. For instance, the default width of CatsWhoCode.com is 1100px. Once I'm satisfied with the non-responsive version, I add media queries and make slight adjustments to the code to make it responsive. This approach allows me to focus on one task at a time, making the process more efficient.&lt;/p&gt;

&lt;p&gt;After completing your non-responsive website, the next step is to add the following lines of code within the &lt;code&gt;&amp;lt;head&amp;gt;&lt;/code&gt; and &lt;code&gt;&amp;lt;/head&amp;gt;&lt;/code&gt; tags on your HTML page. This will set the view on all screens to a 1×1 aspect ratio and remove the default functionality from iPhones and other smartphone browsers, which render websites at full-view and allow users to zoom into the layout by pinching.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;lt;meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"&amp;gt;
&amp;lt;meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"&amp;gt;
&amp;lt;meta name="HandheldFriendly" content="true"&amp;gt;&lt;/code&gt;&lt;/pre&gt;

</description>
      <category>css</category>
      <category>html</category>
    </item>
  </channel>
</rss>
