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.
The build.sbt is a file which describes project settings.
We are using the slf4j dependency to add a logging framework to our application.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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") |
Client class is the class which will actually call the logging methods.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 ") | |
} |
The LoggerHelper class will scramble the logs.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
} | |
} | |
} |
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
} |
Hope you liked the blog. Thanks for reading!
References:
- https://www.scala-lang.org/old/sites/default/files/FrederikThesis.pdf
- https://sourcemaking.com/design_patterns/proxy