{"id":2643,"date":"2012-12-14T15:51:54","date_gmt":"2012-12-14T20:51:54","guid":{"rendered":"http:\/\/appcrawler.com\/wordpress\/?p=2643"},"modified":"2012-12-14T16:17:07","modified_gmt":"2012-12-14T21:17:07","slug":"atg-custom-property-descriptor-to-change-data-upon-retrieving-and-persisting-property","status":"publish","type":"post","link":"http:\/\/appcrawler.com\/wordpress\/2012\/12\/14\/atg-custom-property-descriptor-to-change-data-upon-retrieving-and-persisting-property\/","title":{"rendered":"ATG custom property descriptor to change data upon retrieving and persisting property"},"content":{"rendered":"<p>While coming up with a soon to be posted simple example of using the ATG stack to create an order, I found that using the encrypted credit number stored in the DPS_USER_CREDIT_CARD table was not usable upon checkout, as it did not meet the 16 character requirement and algorithm for a valid credit card number.<\/p>\n<p>This is when I found that a custom property descriptor can be created to change data when fetched from the repository (and ultimately the database, in this case), as well as when it written\/persisted back to the repository\/database.<\/p>\n<p>This post will provide a simple example of doing this.<\/p>\n<p>For a complete example, we first create our table in the database:<\/p>\n<pre lang=\"sql\">\r\ncreate table core.mytab (id varchar2(254),\r\n                                  col1 varchar2(254),\r\n                                  col2 number(0)\r\n                                  primary key (id)\r\n                                 );\r\ninsert into core.mytab values(\u2018foo\u2019,\u2019Steve\u2019,\u20191\u2019);\r\ncommit;\r\n<\/pre>\n<p>We then create our properties file for our repository.<\/p>\n<pre lang=\"text\">\r\n$class=atg.adapter.gsa.GSARepository\r\n$scope=global\r\nrepositoryName=MyRepository\r\ndefinitionFiles=\/repository\/myrepo.xml\r\ndataSource=\/atg\/dynamo\/service\/jdbc\/JTDataSource\r\n\r\nXMLToolsFactory=\/atg\/dynamo\/service\/xml\/XMLToolsFactory\r\ntransactionManager=\/atg\/dynamo\/transaction\/TransactionManager\r\nidGenerator=\/atg\/dynamo\/service\/IdGenerator\r\nlockManager=\/atg\/dynamo\/service\/ClientLockManager\r\n\r\ncacheSwitchHot=false\r\n<\/pre>\n<p>Next, we create our java class to both write as well as read from the repository.<\/p>\n<pre lang=\"java\">\r\nimport java.io.*;\r\nimport javax.servlet.*;\r\nimport javax.servlet.http.*;\r\nimport atg.servlet.*;\r\nimport atg.repository.*;\r\nimport atg.repository.rql.*;\r\nimport atg.adapter.gsa.query.*;\r\nimport atg.nucleus.*;\r\n\r\npublic class getMyTab extends GenericService {\r\n  public getMyTab() {}\r\n  public void updateIt() {\r\n    try {\r\n      vlogInfo(\"started getMyTab()\");\r\n      MutableRepository repo = (MutableRepository)Nucleus.getGlobalNucleus().resolveName(\"\/repository\/MyRepository\");\r\n      RepositoryView view = repo.getView(\"mytab\");\r\n      RqlStatement rql = RqlStatement.parseRqlStatement(\"id = ?0\");\r\n      Object params[] = new Object[1];\r\n      params[0] = new String(\"foo\");\r\n      RepositoryItem[] answer = rql.executeQuery(view,params);\r\n      MutableRepositoryItem obj = repo.getItemForUpdate(answer[0].getRepositoryId(),answer[0].getItemDescriptor().getItemDescriptorName());\r\n      obj.setPropertyValue(\"col1\", \"New value in mixed case\");\r\n      repo.updateItem(obj);\r\n    }\r\n    catch (Exception ce) {\r\n      ce.printStackTrace();\r\n    }\r\n  }\r\n  public void callIt() {\r\n    try {\r\n      vlogInfo(\"started getMyTab()\");\r\n      MutableRepository repo = (MutableRepository)Nucleus.getGlobalNucleus().resolveName(\"\/repository\/MyRepository\");\r\n      RepositoryView view = repo.getView(\"mytab\");\r\n      Object params[] = new Object[0];\r\n      Builder builder = (Builder)view.getQueryBuilder();\r\n      String str = \"select * from mytab\";\r\n      RepositoryItem[] items = view.executeQuery (builder.createSqlPassthroughQuery(str, params));\r\n      view.executeQuery (builder.createSqlPassthroughQuery(str, params));\r\n      if (items == null) {\r\n        vlogInfo(\"id\", \"No items were found\");\r\n      }\r\n      else {\r\n        for (int i = 0; i < items.length; i++){\r\n          System.out.print(items[i].getPropertyValue(\"id\"));\r\n          System.out.print(items[i].getPropertyValue(\"col1\"));\r\n          System.out.println(items[i].getPropertyValue(\"col2\"));\r\n        }\r\n      }\r\n    }\r\n    catch (Exception ce) {\r\n      ce.printStackTrace();\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>Finally, we create our xml mapping file to map our component properties to our database table columns.<\/p>\n<pre lang=\"xml\">\r\n<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n\r\n<!DOCTYPE gsa-template\r\n   PUBLIC \"-\/\/Art Technology Group, Inc.\/\/DTD General SQL Adapter\/\/EN\"\r\n   \"http:\/\/www.atg.com\/dtds\/gsa\/gsa_1.0.dtd\">\r\n\r\n<gsa-template>\r\n  <header>\r\n    <name>Test Repository<\/name>\r\n    <author>Steve Howard<\/author>\r\n    <version>1<\/version>\r\n  <\/header>\r\n\r\n  <item-descriptor name=\"mytab\" item-cache-size=\"20000\" query-cache-size=\"20000\" cache-mode=\"simple\">\r\n    <table name=\"mytab\" type=\"primary\" id-column-name=\"id\">\r\n      <property name=\"id\" column-name=\"id\" data-type=\"string\" \/>\r\n      <property name=\"col1\"\r\n                column-name=\"col1\"\r\n                data-type=\"string\"\r\n                property-type=\"myEncryptDecrypt\">\r\n      <\/property>\r\n      <property name=\"col2\" column-name=\"col2\" data-type=\"int\" \/>\r\n    <\/table>\r\n  <\/item-descriptor>\r\n<\/gsa-template>\r\n<\/pre>\n<p>Before we go any further, note the property type of myEncryptDecrypt.  This is our custom repository item descriptor.  As you may expect, this is a java class which extends the GSAPropertyDescriptor class.<\/p>\n<p>In our simple test case, we encrypt the value by converting it to upper case upon writing (tricky, eh? :)), and convert it to lower case when we fetch it from the repository.  This simulates an encryption\/decryption of a credit card used during purchase.<\/p>\n<pre lang=\"java\">\r\nimport atg.adapter.gsa.*;\r\nimport atg.core.util.*;\r\nimport atg.nucleus.*;\r\nimport atg.repository.*;\r\n\r\npublic class myEncryptDecrypt extends GSAPropertyDescriptor {\r\n  public myEncryptDecrypt() {\r\n    super();\r\n  }\r\n\r\n  public boolean isQueryable() {\r\n    return false;\r\n  }\r\n\r\n  public void setPropertyValue(RepositoryItemImpl pItem, Object pValue) {\r\n    try {\r\n      super.setPropertyValue(pItem, pValue.toString().toUpperCase());\r\n    }\r\n    catch (Exception e) {\r\n      e.printStackTrace();\r\n    }\r\n  }\r\n\r\n  public Object getPropertyValue(RepositoryItemImpl pItem, Object pValue) {\r\n    try {\r\n      return super.getPropertyValue(pItem, pValue.toString().toLowerCase());\r\n    }\r\n    catch (Exception e) {\r\n      e.printStackTrace();\r\n      return null;\r\n    }\r\n  }\r\n}\r\n<\/pre>\n<p>The java class above does not require a properties file, as it is only ever referenced by the repository during its normal course of operation.<\/p>\n<p>Finally, we need to instruct ATG to load this repository upon startup.  Add the following to a file named ContentRepositories.properties, located in localconfig\/atg\/registry under your ATG-Data directory.<\/p>\n<p>Restart your application server.<\/p>\n<pre lang=\"text\">\r\ninitialRepositories+=\/repository\/MyRepository\r\n<\/pre>\n<p>In our test, we first show the value in the database is 'Steve', as we originally inserted it.<\/p>\n<pre lang=\"sql\">\r\nSQL> select * from core.mytab;\r\n\r\nID                   COL1                       COL2\r\n-------------------- -------------------- ----------\r\nfoo                  Steve                         1\r\n\r\nSQL>\r\n<\/pre>\n<p>When we execute the callIt() method in our getMyTab{} class (via an invoke method in dynamo administration on the component), we see it is converted to lower case, as we expected.<\/p>\n<pre lang=\"text\">\r\n15:25:26,102 INFO  [MyRepository] SQL Repository startup complete\r\n15:25:26,131 INFO  [STDOUT] foo\r\n15:25:26,131 INFO  [STDOUT] steve\r\n15:25:26,132 INFO  [STDOUT] 1\r\n<\/pre>\n<p>After we call our updateIt() method in our getMyTab{} class (once again, via an invoke method button call in dynamo admininstration), we see that our new value in the database is in upper case, even though we simply said update it to \"New value in mixed case\".<\/p>\n<pre lang=\"sql\">\r\nSQL> select * from core.mytab;\r\n\r\nID                   COL1                                 COL2\r\n-------------------- ------------------------------ ----------\r\nfoo                  NEW VALUE IN MIXED CASE                 1\r\n\r\nSQL>\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>While coming up with a soon to be posted simple example of using the ATG stack to create an order, I found that using the encrypted credit number stored in the DPS_USER_CREDIT_CARD table was not usable upon checkout, as it&hellip;<\/p>\n<p class=\"more-link-p\"><a class=\"more-link\" href=\"http:\/\/appcrawler.com\/wordpress\/2012\/12\/14\/atg-custom-property-descriptor-to-change-data-upon-retrieving-and-persisting-property\/\">Read more &rarr;<\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"footnotes":""},"categories":[37,38,24,25],"tags":[],"_links":{"self":[{"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/posts\/2643"}],"collection":[{"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/comments?post=2643"}],"version-history":[{"count":23,"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/posts\/2643\/revisions"}],"predecessor-version":[{"id":2673,"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/posts\/2643\/revisions\/2673"}],"wp:attachment":[{"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/media?parent=2643"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/categories?post=2643"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/appcrawler.com\/wordpress\/wp-json\/wp\/v2\/tags?post=2643"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}