Scala : Proxy Design Pattern

Reading Time: 2 minutes

Hi Everyone!
In our previous blogs, we have discussed Decorator design pattern and Adapter design pattern.
Now, its time to discuss another Structural design pattern i.e. the Proxy design pattern. We will implement the same EUGDPR problem using the Proxy design pattern, which we implemented using the Adapter design pattern in our previous blog.

Problem Statement:
Earlier, in many applications, all the user-specific details like username, IP addresses, phone number, etc were logged directly without scrambling it. But after new data protection law i.e. EUGDPR, it is now mandatory to scramble any user-specific data.

Solution:
We will add a proxy class between our logging framework(slf4j) and our client.

What is Proxy design pattern?

A proxy is a class functioning as an interface to something else.

Proxy design pattern focuses on providing a surrogate or placeholder for another object to control access to it.

We will create a LoggerProxy class which will be called before calling Logging framework and it will scramble the logs and call the logging framework methods.

ProxyDesignPatternUml

The build.sbt is a file which describes project settings.
We are using the slf4j dependency to add a logging framework to our application.

name := "ProxyDesignPattern"
version := "0.1"
scalaVersion := "2.12.6"
// https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12
libraryDependencies ++= Seq("org.slf4j" % "slf4j-api" % "1.7.5",
"org.slf4j" % "slf4j-simple" % "1.7.5")

view raw
build.sbt
hosted with ❤ by GitHub

Client class is the class which will actually call the logging methods.

package com.knoldus
object Client extends App {
val logger = LoggerProxy.getLogger(this.getClass.getName)
logger.info("Log Contains IP address: 127.0.0.1")
logger.debug("UserName: jainnancy trying to sign in")
logger.error("Password: abxyz is wrong ")
}

view raw
Client.scala
hosted with ❤ by GitHub

The LoggerHelper class will scramble the logs.

package com.knoldus
class LoggerHelper {
private val regex = "\\b\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b"
private val password = "Password: "
private val userName = "UserName: "
def scramble(message : String) = scrambleUsername(scrambleIp((scramblePassword(message))))
private def scrambleUsername(message : String) = {
if(message.contains(userName)) {
val index = message.indexOf(userName) + userName.length()
val textStartedPassword = message.substring(index)
message.substring(0, index) + "X" + textStartedPassword.substring(textStartedPassword.indexOf(" "))
}
else {
message
}
}
private def scrambleIp(message : String) = message.replaceAll(regex, "XXX.XXX.XXX.XXX")
private def scramblePassword(message : String) = {
if(message.contains(password)) {
val index = message.indexOf(password) + password.length()
val textStartedPassword = message.substring(index)
message.substring(0, index) + "X" + textStartedPassword.substring(textStartedPassword.indexOf(" "))
}
else {
message
}
}
}

view raw
LoggerHelper.scala
hosted with ❤ by GitHub

The LoggerProxy is the new class which will act as a proxy between client and logging framework and will make sure that logs are scrambled before logging.
LoggerProxy
will implement the Logger interface which is defined in the slf4j framework.

package com.knoldus
import org.slf4j.{Logger, LoggerFactory, Marker}
object LoggerProxy extends Logger {
private var logger : Logger = _
private val loggerHelper = new LoggerHelper
def getLogger(name : String) : Logger = {
logger = LoggerFactory.getLogger(name)
LoggerProxy
}
def getName : String = logger.getName
def debug(msg : String) : Unit = logger.debug(loggerHelper.scramble(msg))
def debug(format : String, arg : scala.Any) : Unit = logger.debug(loggerHelper.scramble(format),arg)
def debug(format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit = logger.debug(loggerHelper.scramble(format), arg1, arg2)
def debug(format : String, arguments : AnyRef*) : Unit = logger.debug(loggerHelper.scramble(format), arguments)
def debug(msg : String, t : Throwable) : Unit = logger.debug(loggerHelper.scramble(msg), t)
def debug(marker : Marker, msg : String) : Unit = logger.debug(marker, loggerHelper.scramble(msg))
def debug(marker : Marker, format : String, arg : scala.Any) : Unit = logger.debug(marker, loggerHelper.scramble(format), arg)
def debug(marker : Marker, format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit =
logger.debug(marker, loggerHelper.scramble(format), arg1, arg2)
def debug(marker : Marker, format : String, arguments : AnyRef*) : Unit = logger.debug(marker, loggerHelper.scramble(format), arguments)
def debug(marker : Marker, msg : String, t : Throwable) : Unit = logger.debug(marker, loggerHelper.scramble(msg), t)
def isWarnEnabled : Boolean = logger.isWarnEnabled
def isWarnEnabled(marker : Marker) : Boolean = logger.isWarnEnabled(marker)
def error(msg : String) : Unit = logger.error(loggerHelper.scramble(msg))
def error(format : String, arg : scala.Any) : Unit = logger.error(loggerHelper.scramble(format), arg)
def error(format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit = logger.error(loggerHelper.scramble(format), arg1, arg2)
def error(format : String, arguments : AnyRef*) : Unit = logger.error(loggerHelper.scramble(format), arguments)
def error(msg : String, t : Throwable) : Unit = logger.error(loggerHelper.scramble(msg), t)
def error(marker : Marker, msg : String) : Unit = logger.error(marker, loggerHelper.scramble(msg))
def error(marker : Marker, format : String, arg : scala.Any) : Unit = logger.error(marker, loggerHelper.scramble(format), arg)
def error(marker : Marker, format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit =
logger.error(marker, loggerHelper.scramble(format), arg1, arg2)
def error(marker : Marker, format : String, arguments : AnyRef*) : Unit = logger.error(marker, loggerHelper.scramble(format), arguments)
def error(marker : Marker, msg : String, t : Throwable) : Unit = logger.error(marker, loggerHelper.scramble(msg), t)
def warn(msg : String) : Unit = logger.warn(loggerHelper.scramble(msg))
def warn(format : String, arg : scala.Any) : Unit = logger.warn(loggerHelper.scramble(format), arg)
def warn(format : String, arguments : AnyRef*) : Unit = logger.warn(loggerHelper.scramble(format), arguments)
def warn(format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit = logger.warn(loggerHelper.scramble(format), arg1, arg2)
def warn(msg : String, t : Throwable) : Unit = logger.warn(loggerHelper.scramble(msg), t)
def warn(marker : Marker, msg : String) : Unit = logger.warn(marker, loggerHelper.scramble(msg))
def warn(marker : Marker, format : String, arg : scala.Any) : Unit = logger.warn(marker, loggerHelper.scramble(format), arg)
def warn(marker : Marker, format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit =
logger.warn(marker, loggerHelper.scramble(format), arg1, arg2)
def warn(marker : Marker, format : String, arguments : AnyRef*) : Unit = logger.warn(marker, loggerHelper.scramble(format), arguments)
def warn(marker : Marker, msg : String, t : Throwable) : Unit = logger.warn(marker, loggerHelper.scramble(msg), t)
def trace(msg : String) : Unit = logger.trace(loggerHelper.scramble(msg))
def trace(format : String, arg : scala.Any) : Unit = logger.trace(loggerHelper.scramble(format), arg)
def trace(format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit = logger.trace(loggerHelper.scramble(format), arg1, arg2)
def trace(format : String, arguments : AnyRef*) : Unit = logger.trace(loggerHelper.scramble(format), arguments)
def trace(msg : String, t : Throwable) : Unit = logger.trace(loggerHelper.scramble(msg), t)
def trace(marker : Marker, msg : String) : Unit = logger.trace(marker, loggerHelper.scramble(msg))
def trace(marker : Marker, format : String, arg : scala.Any) : Unit = logger.trace(marker, loggerHelper.scramble(format), arg)
def trace(marker : Marker, format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit =
logger.trace(marker, loggerHelper.scramble(format), arg1, arg2)
def trace(marker : Marker, format : String, argArray : AnyRef*) : Unit = logger.trace(marker, loggerHelper.scramble(format), argArray)
def trace(marker : Marker, msg : String, t : Throwable) : Unit = logger.trace(marker, loggerHelper.scramble(msg), t)
def isInfoEnabled : Boolean = logger.isInfoEnabled
def isInfoEnabled(marker : Marker) : Boolean = logger.isInfoEnabled(marker)
def isErrorEnabled : Boolean = logger.isErrorEnabled
def isErrorEnabled(marker : Marker) : Boolean = logger.isErrorEnabled(marker)
def isTraceEnabled : Boolean = logger.isTraceEnabled
def isTraceEnabled(marker : Marker) : Boolean = logger.isTraceEnabled(marker)
def isDebugEnabled : Boolean = logger.isDebugEnabled
def isDebugEnabled(marker : Marker) : Boolean = logger.isDebugEnabled(marker)
def info(msg : String) : Unit = logger.info(loggerHelper.scramble(msg))
def info(format : String, arg : scala.Any) : Unit = logger.info(loggerHelper.scramble(format), arg)
def info(format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit = logger.info(loggerHelper.scramble(format), arg1, arg2)
def info(format : String, arguments : AnyRef*) : Unit = logger.info(loggerHelper.scramble(format), arguments)
def info(msg : String, t : Throwable) : Unit = logger.info(loggerHelper.scramble(msg), t)
def info(marker : Marker, msg : String) : Unit = logger.info(marker, loggerHelper.scramble(msg))
def info(marker : Marker, format : String, arg : scala.Any) : Unit = logger.info(marker, loggerHelper.scramble(format), arg)
def info(marker : Marker, format : String, arg1 : scala.Any, arg2 : scala.Any) : Unit =
logger.info(marker, loggerHelper.scramble(format), arg1, arg2)
def info(marker : Marker, format : String, arguments : AnyRef*) : Unit = logger.info(marker, loggerHelper.scramble(format), arguments)
def info(marker : Marker, msg : String, t : Throwable) : Unit = logger.info(marker, loggerHelper.scramble(msg), t)
}

view raw
LoggerProxy.scala
hosted with ❤ by GitHub

 

Hope you liked the blog. Thanks for reading!

References:


knoldus-advt-sticker

Written by 

Nancy jain is a software consultant with experience of more than 6 months. She likes to explore new technologies and trends in the IT world. Her hobbies include watching web series, writing and travelling. Nancy is familiar with programming languages such as Java, Scala, C, C++, HTML, Javascript and she is currently working on reactive technologies like Scala, DynamoDb, AkkaHttp.