{"id":228,"date":"2018-11-06T10:03:15","date_gmt":"2018-11-06T10:03:15","guid":{"rendered":"https:\/\/www.visionmate.se\/en\/?p=228"},"modified":"2019-04-05T09:42:53","modified_gmt":"2019-04-05T09:42:53","slug":"aspect-oriented-programming","status":"publish","type":"post","link":"https:\/\/www.visionmate.se\/en\/2018\/11\/06\/aspect-oriented-programming\/","title":{"rendered":"Aspect-oriented programming using Spring AOP over Grails framework"},"content":{"rendered":"<p><strong>Preface<\/strong><\/p>\n<p>Aspect-oriented programming (AOP) is a new concept and paradigm. It allows basically to add functionality to modules and classes without modifying the code, it is possible by configuring <em>Pointcut<\/em>, which specifies which pieces of code will be executed after dispatching of a specific event over a method or class.<\/p>\n<p><strong>Goals<\/strong><\/p>\n<p>We aim and assume that after read the article developers will be able to use aspect-oriented programming in their Grails projects.<\/p>\n<p><strong>Requirements<\/strong><\/p>\n<p>Grails 3. *<\/p>\n<p><strong>Dependencies<\/strong>:<\/p>\n<p>Spring Aspects 5. *<\/p>\n<p>AspectJ Weaver 1. *<\/p>\n<p><strong>1- Aspect-oriented programming approach<\/strong><\/p>\n<p>Very often our software solutions involve complex logic and in this case keeping clean and understandable code is quite important. One approach which help in that sense is AOP, which enables an easy way of modularization. AOP allows basically to add functionality to modules and classes without modify the code.<\/p>\n<p><strong>2- Bean setting using Spring<\/strong><\/p>\n<p>The first step is to configure Spring AOP, in the Spring resource file (<strong><em>conf\/spring\/resources.groovy<\/em><\/strong>). We need also specify which bean will work as aspect, in our case will be the Trace bean.<\/p>\n<p>It can be configured in several ways, using for example annotation<em> @Aspect<\/em> in our Bean declaration. In this case we need to inject log dependencies which are provided for Grails, we do not need create any instance for ourselves.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">\/\/ Aspect-Oriented\r\n\r\nxmlns aop:\"http:\/\/www.springframework.org\/schema\/aop\"\r\n\r\ntrace(Trace){\r\n\r\n    log = log\r\n\r\n}\r\n\r\naop{\r\n\r\n    config(\"proxy-target-class\": true) {\r\n\r\n        aspect(id: \"traceService\", ref: \"trace\")\r\n\r\n    }\r\n\r\n}<\/pre>\n<p><strong>3- Implementing logging functionality<\/strong><\/p>\n<p>The main concepts that we need know are: <em>Pointcut, Advices<\/em> and <em>JoinPoint<\/em>. A <em>Pointcut <\/em>is essentially a way to match a method call with a functionality which we add new behavior, it needs to specify the expression and the signature. To execute the new behavior, we need specify some advice and associate it with a <em>Pointcut.<\/em><\/p>\n<p>Advice are declared using annotations like <em>@Before <\/em>and <em>@After <\/em>which specify when the code will be executed. Advice will take as parameter a <em>JoinPoint, <\/em>which contains information about the current call, like values of parameters, called method, etc.<\/p>\n<p>The sample application is related with document management. The main functionalities are upload, convert to HTML and store documents from different formats. The code that we will show pretends to keep track actions over document.<\/p>\n<p>Below you can find the Aspect bean called Trace:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Aspect\r\n\r\nclass Trace {\r\n\r\n    def log\r\n\r\n\r\n    @Pointcut(\"execution(* my.company.myApp.document.DocumentService.add(..))\")\r\n\r\n    void createDocument(){}\r\n\r\n\r\n\r\n    @Pointcut(\"execution(* my.company.myApp.document.DocumentService.update(..)) &amp;&amp; args(document, user,..)\")\r\n\r\n    void updateDocument(Document document, User user){}\r\n\r\n\r\n\r\n    @Pointcut(\"execution(* my.company.myApp.repository.RepositoryService.add*(..))\")\r\n\r\n    void storeDocument(){}\r\n\r\n\r\n\r\n    @Before(\"createDocument()\")\r\n\r\n    void create(JoinPoint jp){\r\n\r\n        Document document = jp.args[0] as Document\r\n\r\n        User user = jp.args[1] as User\r\n\r\n        log.info \"The document: ${document?.name} has been created by user: ${user?.username}\"\r\n\r\n    }\r\n\r\n\r\n\r\n    @Before(\"updateDocument(document, user)\")\r\n\r\n    void update(Document document, User user){\r\n\r\n        log.info \"The document: ${document?.name} has been modified by user: ${user?.username}\"\r\n\r\n    }\r\n\r\n    \r\n\r\n    @Before(\"storeDocument()\")\r\n\r\n    void storeDocument(JoinPoint jp){\r\n\r\n        log.info \"Called ${jp.signature.name} with ${jp.args} on ${jp.target}: Storing a new document\"\r\n\r\n    }\r\n}<\/pre>\n<p>We have declared three <em>Pointcut <\/em>sentences, I will explain below some of them.<\/p>\n<p><strong>Updating documents<\/strong>:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Pointcut(\"execution(* my.company.myApp.document.DocumentService.update(..)) &amp;&amp; args(document, user,..)\")\r\n  \r\n  void updateDocument(Document document, User user){}<\/pre>\n<p>I this case we specify which method we want to track. We can specify arguments in the <em>Pointcut <\/em>declaration, that can be convenient most of time.<\/p>\n<p>Our application contains a method with the next:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">void update(Document document, User user){\r\n\r\n    Version version = new Version(state: State.UPDATED, user: user, date: new Date())\r\n\r\n    document.addToVersions(version)\r\n\r\n    document.save()   \r\n\r\n}<\/pre>\n<p>Then after declaring our <em>Pointcut <\/em>we need to implement the method which will execute the required behavior. We want to add new behavior exactly before the method is executed and then track which user has updated the document.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Before(\"updateDocument(document, user)\")\r\n\r\n    void update(Document document, User user){\r\n      \r\n        log.info \"The document: ${document?.name} has been modified by user: ${user?.username}\"\r\n    \r\n    }<\/pre>\n<p><strong>Storing documents:<\/strong><\/p>\n<p>In this new case we will use the same endpoint to catch a different method call:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Pointcut(\"execution(* my.company.myApp.repository.RepositoryService.add*(..))\")\r\n    \r\n    void storeDocument(){}<\/pre>\n<p>In our system we have a <em>Repository <\/em>class which is responsible for working with our files repository, basically we have two kind of repository, <em>HTML <\/em>and <em>Source<\/em>. We want to track when a document is stored in it.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">def addHtmlDocument(String id, Format format, String fromPath){\r\n\r\n    String repositoryPath = grailsApplication.config.dataStore.repository.html\r\n\r\n    repository = new HtmlRepository(\r\n\r\n            path: repositoryPath,\r\n\r\n            converter: new DocumentFormat(format: Format.HTML),    \r\n\r\n            builder: new AntBuilder())\r\n\r\n    repository.addDocument(id, format, fromPath)\r\n\r\n}\r\n\r\n\r\ndef addSourceDocument(String id, Format format, String fromPath){\r\n\r\n    String repositoryPath = grailsApplication.config.dataStore.repository.source   \r\n\r\n    repository = new SourceRepository(\r\n\r\n            path: repositoryPath,\r\n\r\n            builder: new AntBuilder())\r\n\r\n    repository.addDocument(id, format, fromPath)\r\n\r\n}<\/pre>\n<p>Then our behavior:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"java\">@Before(\"storeDocument()\")\r\n\r\n    void storeDocument(JoinPoint jp){\r\n\r\n        log.info \"Called ${jp.signature.name} with ${jp.args} on ${jp.target}: Storing a new document\"\r\n\r\n    }<\/pre>\n<p>The new behavior will print a log with the name of the called method, arguments and instance description.<\/p>\n<p><strong>4- Conclusion<\/strong><\/p>\n<p>Aspect-Oriented programming is a new concept, by using it correctly we ensure that our code is kept clean and in this sense we can add functionality easier without modify existing classes and methods. Is necessary be careful because code will be related logically and we need to keep updated documentation about that, otherwise we can have unexpected behavior in our application.<\/p>\n<p><strong>5- References<\/strong><\/p>\n<p><a href=\"https:\/\/docs.spring.io\/spring\/docs\/4.0.x\/spring-framework-reference\/html\/aop.html\" target=\"_blank\" rel=\"noopener\">https:\/\/docs.spring.io<\/a><\/p>\n<p>Origin: <a href=\"https:\/\/www.linkedin.com\/pulse\/aspect-oriented-programming-using-spring-aop-over-nu%C3%B1ez-perez\/\" target=\"_blank\" rel=\"noopener\">www.linkedin.com<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Preface Aspect-oriented programming (AOP) is a new concept and paradigm. It allows basically to add&#8230;<\/p>\n","protected":false},"author":1,"featured_media":229,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[16,7],"class_list":["post-228","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized","tag-aop","tag-grails"],"acf":[],"_links":{"self":[{"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/posts\/228","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/comments?post=228"}],"version-history":[{"count":1,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/posts\/228\/revisions"}],"predecessor-version":[{"id":230,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/posts\/228\/revisions\/230"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/media\/229"}],"wp:attachment":[{"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/media?parent=228"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/categories?post=228"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.visionmate.se\/en\/wp-json\/wp\/v2\/tags?post=228"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}