SlideShare a Scribd company logo
Grails	
  Code	
  from	
  the	
  Trenches	
  
Collec3ons.shuffle(dayToDayWork)	
  
Edwin	
  van	
  Nes	
  
	
  
1989 	
  dBase	
  /	
  Clipper	
  /	
  FoxPro	
  
1995	
   	
  Borland	
  Delphi	
  
2000 	
  Java	
  2,	
  Enterprise	
  Edi3on	
  
2005 	
  PHP,	
  Typo3,	
  Joomla!,	
  …	
  
2011 	
  Groovy	
  &	
  Grails	
  
Direc3ons	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
	
  
Weapons	
  of	
  Choice	
  
Specifica3on	
   Google	
  Docs,	
  FogBugz,	
  Balsamiq	
  Mockups,	
  PlantUML,	
  yEd,	
  …	
  
Design	
   similar	
  stuff	
  
Construc3on	
   Grails	
  (dûh!),	
  IntelliJ	
  IDEA,	
  mySQL,	
  SVN	
  -­‐>	
  GIT,	
  …	
  
Tes3ng	
   JUnit,	
  Spock,	
  Kiln,	
  …	
  
Deployment	
   Jenkins,	
  Gradle,	
  OSX,	
  Ubuntu,	
  MS	
  Windows,	
  …	
  
Project	
   Skype,	
  Google	
  Hangout,	
  IRIS,	
  …	
  
Weapons	
  of	
  Choice	
  
Specifica3on	
   Google	
  Docs,	
  FogBugz,	
  Balsamiq	
  Mockups,	
  yEd,	
  …	
  
Design	
   similar	
  stuff	
  
Construc3on	
   Grails	
  (dûh!),	
  IntelliJ	
  IDEA,	
  mySQL,	
  SVN	
  -­‐>	
  GIT,	
  …	
  
Tes3ng	
   JUnit,	
  Spock,	
  Kiln,	
  …	
  
Deployment	
   Jenkins,	
  OSX,	
  Ubuntu,	
  MS	
  Windows,	
  …	
  
Project	
   Skype,	
  Google	
  Hangout,	
  IRIS,	
  …	
  
Weapons	
  of	
  Choice	
  
Specifica3on	
   Google	
  Docs,	
  FogBugz,	
  Balsamiq	
  Mockups,	
  yEd,	
  …	
  
Design	
   similar	
  stuff	
  
Construc3on	
   Grails	
  (dûh!),	
  IntelliJ	
  IDEA,	
  mySQL,	
  SVN	
  -­‐>	
  GIT,	
  …	
  
Tes3ng	
   JUnit,	
  Spock,	
  …	
  
Deployment	
   Jenkins,	
  Gradle,	
  OSX,	
  Ubuntu,	
  MS	
  Windows,	
  …	
  
Project	
   Skype,	
  Google	
  Hangout,	
  IRIS,	
  …	
  
Weapons	
  of	
  Choice	
  
Specifica3on	
   Google	
  Docs,	
  FogBugz,	
  Balsamiq	
  Mockups,	
  yEd,	
  …	
  
Design	
   similar	
  stuff	
  
Construc3on	
   Grails	
  (dûh!),	
  IntelliJ	
  IDEA,	
  mySQL,	
  SVN	
  -­‐>	
  GIT,	
  …	
  
Tes3ng	
   JUnit,	
  Spock,	
  Kiln,	
  …	
  
Deployment	
   Jenkins,	
  OSX,	
  Ubuntu,	
  MS	
  Windows,	
  …	
  
Project	
   Skype,	
  Google	
  Hangout,	
  IRIS,	
  …	
  
Weapons	
  of	
  Choice	
  
Specifica3on	
   Google	
  Docs,	
  FogBugz,	
  Balsamiq	
  Mockups,	
  yEd,	
  …	
  
Design	
   similar	
  stuff	
  
Construc3on	
   Grails	
  (dûh!),	
  IntelliJ	
  IDEA,	
  mySQL,	
  SVN	
  -­‐>	
  GIT,	
  …	
  
Tes3ng	
   JUnit,	
  Spock,	
  …	
  
Deployment	
   Jenkins,	
  Gradle,	
  OSX,	
  Ubuntu,	
  MS	
  Windows,	
  …	
  
Project	
   Skype,	
  Google	
  Hangout,	
  IRIS,	
  …	
  
Weapons	
  of	
  Choice	
  
Specifica3on	
   Google	
  Docs,	
  FogBugz,	
  Balsamiq	
  Mockups,	
  yEd,	
  …	
  
Design	
   similar	
  stuff	
  
Construc3on	
   Grails	
  (dûh!),	
  IntelliJ	
  IDEA,	
  mySQL,	
  SVN	
  -­‐>	
  GIT,	
  …	
  
Tes3ng	
   JUnit,	
  Spock,	
  …	
  
Deployment	
   Jenkins,	
  OSX,	
  Ubuntu,	
  MS	
  Windows,	
  …	
  
Project	
   Skype,	
  Google	
  Hangout,	
  IRIS,	
  …	
  
Direc3ons	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
•  Error	
  Abstrac3on	
  in	
  a	
  Plugin	
  
WhatWeDoMost*	
  
Services	
  
Frontend	
  
Portal	
  
Backend	
  
Portal	
  
Database	
   Our	
  Clients	
  
Consumers	
  
(their	
  clients)	
  
*	
  overly	
  simplified	
  for	
  educa3onal	
  purposes	
  
GR8Tunes	
  
Used	
  here	
  as	
  an	
  example	
  for	
  a	
  
typical	
  Backend	
  portal	
  
GR8Tunes	
  
Used	
  here	
  as	
  an	
  example	
  for	
  a	
  
typical	
  Backend	
  portal	
  
AbstractDomain	
  
•  Not	
  too	
  Groovy	
  probably	
  
•  Add	
  some	
  standard	
  akributes	
  
– Some	
  useful	
  3mestamps	
  
– ‘recentlyUpdated’	
  boolean	
  for	
  
easy	
  highligh3ng	
  
– Each	
  record	
  gets	
  a	
  
‘remarks’	
  akribute	
  
AbstractDomain.Status	
  
AbstractDomain.Status	
  
Hibernate	
  filters	
  Plugin	
  
•  defaultFilter	
  in	
  Backend	
  
–  Status	
  in	
  [Status.ACTIVE,	
  Status.INACTIVE]	
  
•  defaultFilter	
  in	
  Frontend	
  
–  Status	
  ==	
  Status.ACTIVE	
  
AbstractDomain.Status	
  
Hibernate	
  filters	
  
•  defaultFilter	
  in	
  Backend	
  
–  Status	
  in	
  [Status.ACTIVE,	
  Status.INACTIVE]	
  
•  defaultFilter	
  in	
  Frontend	
  
–  Status	
  ==	
  Status.ACTIVE	
  
AbstractDomain.Status	
  
	
  
class	
  DefaultFilters	
  {	
  
	
  
	
  	
  	
  	
  def	
  sessionFactory	
  
	
  
	
  	
  	
  	
  def	
  filters	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  all(controller:'*',	
  action:'*')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  before	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  def	
  session	
  =	
  sessionFactory.currentSession	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (params.filter_status)	
  {	
  
	
  
session.enableFilter('statusFilter').setParameter('status',params.filter_status)	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  
session.enableFilter('defaultFilter')	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
AbstractDomain.Status	
  
	
  
class	
  DefaultFilters	
  {	
  
	
  
	
  	
  	
  	
  def	
  sessionFactory	
  
	
  
	
  	
  	
  	
  def	
  filters	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  all(controller:'*',	
  action:'*')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  before	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  def	
  session	
  =	
  sessionFactory.currentSession	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (params.filter_status)	
  {	
  
	
  
session.enableFilter('statusFilter').setParameter('status',params.filter_status)	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  
session.enableFilter('defaultFilter')	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
AbstractDomain.Status	
  
	
  
class	
  DefaultFilters	
  {	
  
	
  
	
  	
  	
  	
  def	
  sessionFactory	
  
	
  
	
  	
  	
  	
  def	
  filters	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  all(controller:'*',	
  action:'*')	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  before	
  =	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  def	
  session	
  =	
  sessionFactory.currentSession	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  if	
  (params.filter_status)	
  {	
  
	
  
session.enableFilter('statusFilter').setParameter('status',params.filter_status)	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  else	
  {	
  
	
  
session.enableFilter('defaultFilter')	
  
	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
}	
  
	
  
AbstractDomain.change	
  
•  Holds	
  a	
  record	
  of	
  type	
  
AbstractDomain	
  
•  Like	
  a	
  “muta3on-­‐record”	
  
•  i.e.	
  future	
  change	
  to	
  the	
  object	
  
•  example:	
  division	
  of	
  
responsibility	
  (amongst	
  users)	
  	
  
AbstractDomain.change	
  
id	
   version	
   change	
   .tle	
   year	
  
1	
   5	
   7	
   The	
  Bright	
  Side	
  of	
  the	
  Moon	
   1973	
  
id	
   version	
   change	
   .tle	
   year	
  
7	
   5	
   null	
   The	
  Dark	
  Side	
  of	
  the	
  Moon	
   1973	
  
Should	
  verify	
  (op3mis3c)	
  
Hibernate	
  filter:	
  exclude	
  records	
  that	
  are	
  “change	
  records”	
  
Direc3ons	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
•  Error	
  Abstrac3on	
  in	
  a	
  Plugin	
  
Heavy-­‐Duty	
  Scaffolding	
  
•  Substan3al	
  3me	
  spent	
  on	
  tailor-­‐made	
  scaffolding	
  	
  
•  Controllers	
  are	
  always	
  scaffolded	
  
–  Only	
  specific	
  code	
  for	
  a	
  specific	
  domain	
  is	
  coded	
  
•  Views	
  are	
  scaffolded	
  as	
  a	
  start	
  
–  Much	
  more	
  likely	
  to	
  manually	
  adjust	
  
–  But	
  certainly	
  not	
  for	
  each	
  and	
  every	
  Domain	
  Class	
  
•  Domain	
  Classes	
  can	
  contain	
  seungs	
  to	
  influence	
  
rendering	
  during	
  scaffolding	
  
Scaffolded	
  Controllers	
  
•  All	
  Controllers	
  exists	
  as	
  files	
  but	
  are	
  100%	
  scaffolded	
  unless	
  …	
  
	
  
class	
  AlbumController	
  {	
  
	
  static	
  scaffold	
  =	
  true	
  
}	
  
Scaffolded	
  Controllers	
  
•  All	
  Controllers	
  exists	
  as	
  files	
  but	
  are	
  100%	
  scaffolded	
  unless	
  …	
  
	
  
class	
  AlbumController	
  {	
  
	
  static	
  scaffold	
  =	
  true	
  
	
  	
  
	
  def	
  list	
  (Integer	
  max)	
  {	
  
	
   	
  //	
  different	
  implementation	
  of	
  Album.list	
  
	
  }	
  
}	
  
SimpleFlow	
  =	
  true	
  
•  Simple	
  states	
  
–  List	
  
–  Edit	
  
•  Mul3ple	
  ac3ons	
  
–  Create	
  
–  Cancel	
  
–  Save	
  
–  SaveAndClose	
  
–  SaveAndCreate	
  
SimpleFlow	
  =	
  false	
  
•  More	
  states	
  
–  List	
  
–  Create	
  
–  Edit	
  
–  Show	
  
•  Same	
  set	
  of	
  ac3ons	
  
–  Create	
  
–  Cancel	
  
–  Save	
  
–  SaveAndClose	
  
–  SaveAndCreate	
  
Scaffolded	
  Views	
  
•  Views	
  are	
  most	
  likely	
  to	
  be	
  changed	
  
–  Order	
  of	
  fields	
  from	
  Domain	
  Class	
  constraints	
  
static	
  constraints	
  =	
  {	
  
	
  title 	
  (blank:false)	
  
	
  artist	
  (blank:false)	
  
	
  year	
  (display:true)	
  
	
  	
  	
  change	
  (display:false)	
  
}	
  
Scaffolded	
  Views	
  
•  Views	
  are	
  most	
  likely	
  to	
  be	
  changed	
  
–  Order	
  of	
  fields	
  from	
  Domain	
  Class	
  constraints	
  
static	
  constraints	
  =	
  {	
  
	
  title 	
  (blank:false)	
  
	
  artist	
  (blank:false)	
  
	
  year	
  (display:true)	
  
	
  	
  	
  change	
  (display:false)	
  
}	
  
Scaffolded	
  Views	
  
•  Render	
  more	
  artefacts	
  
_form.gsp 	
   	
  =	
  fields	
  used	
  in	
  create	
  /	
  edit	
  
_table.gsp	
   	
  =	
  <table>	
  used	
  in	
  list	
  for	
  reuse	
  
_panel.gsp	
   	
  =	
  simple	
  <div>	
  for	
  reuse	
  
list.csv.gsp 	
  =	
  used	
  for	
  formatting	
  exports	
  
Scaffolded	
  Views	
  
•  Render	
  more	
  artefacts	
  
_form.gsp 	
   	
  =	
  fields	
  used	
  in	
  create	
  /	
  edit	
  
_table.gsp	
   	
  =	
  <table>	
  used	
  in	
  list	
  for	
  reuse	
  
_panel.gsp	
   	
  =	
  simple	
  <div>	
  for	
  reuse	
  
list.csv.gsp 	
  =	
  used	
  for	
  formatting	
  exports	
  
<%@	
  page	
  import="gr8tunes.Album"	
  %>	
  
<g:if	
  test="${albumInstance	
  instanceof	
  Album}">	
  
	
  <div	
  class="domain-­‐panel	
  domain-­‐album">	
  
	
  <h4><small><g:message	
  code="album.title.label"	
  />:</small></h4>	
  
	
  	
  	
  	
  	
   	
  <p>	
  
	
   	
  <g:if	
  test="${!controllerName.equals('album')}">	
  
	
  	
  	
  	
  	
  	
  	
   	
  <g:link	
  controller=”album"	
  action="show"	
  id="${albumInstance.id}">	
  
	
   	
   	
  <g:fieldValue	
  bean="${albumInstance}"	
  field="year"/>	
  
	
   	
   	
  <g:fieldValue	
  bean="${albumInstance}"	
  field="title"/>	
  
	
   	
   	
  </g:link>	
  
	
   	
  </g:if>	
  
	
   	
  <g:else>	
  
	
   	
   	
  <g:fieldValue	
  bean="${albumInstance}"	
  field="year"/>	
  
	
   	
   	
  <g:fieldValue	
  bean="${albumInstance}"	
  field="title"/>	
  
	
  	
  	
  	
  	
  	
  </g:else>	
  
	
  	
  	
  	
  	
  	
  </p>	
  
	
  </div>	
  
</g:if>	
  
_panel.gsp	
  
Scaffolded	
  Views	
  
•  Render	
  more	
  artefacts	
  
_form.gsp 	
   	
  =	
  fields	
  used	
  in	
  create	
  /	
  edit	
  
_table.gsp	
   	
  =	
  <table>	
  used	
  in	
  list	
  for	
  reuse	
  
_panel.gsp	
   	
  =	
  simple	
  <div>	
  for	
  reuse	
  
list.csv.gsp 	
  =	
  used	
  for	
  formatting	
  exports	
  
Scaffolded	
  Views	
  
•  Render	
  more	
  artefacts	
  
_form.gsp 	
   	
  =	
  fields	
  used	
  in	
  create	
  /	
  edit	
  
_table.gsp	
   	
  =	
  <table>	
  used	
  in	
  list	
  for	
  reuse	
  
_panel.gsp	
   	
  =	
  simple	
  <div>	
  for	
  reuse	
  
list.csv.gsp 	
  =	
  used	
  for	
  formatting	
  exports	
  
Scaffolded	
  Views	
  
•  Render	
  more	
  artefacts	
  
_form.gsp 	
   	
  =	
  fields	
  used	
  in	
  create	
  /	
  edit	
  
_table.gsp	
   	
  =	
  <table>	
  used	
  in	
  list	
  for	
  reuse	
  
_panel.gsp	
   	
  =	
  simple	
  <div>	
  for	
  reuse	
  
list.csv.gsp 	
  =	
  used	
  for	
  formatting	
  exports	
  
Scaffolding	
  seungs	
  in	
  Domain	
  Classes	
  
class	
  Item	
  extends	
  AbstractDomain	
  {	
  
	
  ...	
  
	
  static	
  scaffolding	
  =	
  [	
  
	
   	
  simpleFlow:	
  true,	
  
	
   	
  inFilter:	
  	
  	
  ['status',	
  'itemType',	
  'itemCategory'],	
  
	
   	
  inSearch:	
  	
  	
  ['title',	
  'description'],	
  
	
   	
  inSort:	
  	
  	
  	
  	
  ['title',	
  'itemType',	
  'artist']	
  
	
  ]	
  
	
  ...	
  
}	
  
Scaffolding	
  seungs	
  in	
  Domain	
  Classes	
  
class	
  Item	
  extends	
  AbstractDomain	
  {	
  
	
  ...	
  
	
  static	
  scaffolding	
  =	
  [	
  
	
   	
  simpleFlow:	
  true,	
  
	
   	
  inFilter:	
  	
  	
  ['status',	
  'itemType',	
  'itemCategory'],	
  
	
   	
  inSearch:	
  	
  	
  ['title',	
  'description'],	
  
	
   	
  inSort:	
  	
  	
  	
  	
  ['title',	
  'itemType',	
  'artist']	
  
	
  ]	
  
	
  ...	
  
}	
  
Scaffolding	
  seungs	
  in	
  Domain	
  Classes	
  
class	
  Item	
  extends	
  AbstractDomain	
  {	
  
	
  ...	
  
	
  static	
  scaffolding	
  =	
  [	
  
	
   	
  simpleFlow:	
  true,	
  
	
   	
  inFilter:	
  	
  	
  ['status',	
  'itemType',	
  'itemCategory'],	
  
	
   	
  inSearch:	
  	
  	
  ['title',	
  'description'],	
  
	
   	
  inSort:	
  	
  	
  	
  	
  ['title',	
  'itemType',	
  'artist']	
  
	
  ]	
  
	
  ...	
  
}	
  
Direc3ons	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
•  Error	
  Abstrac3on	
  in	
  a	
  Plugin	
  
	
  
Mul3-­‐lingualiza3on	
  
•  Transla3on	
  of	
  program	
  code	
  
–  aka	
  i18n;	
  that’s	
  in	
  Grails	
  right?	
  
–  .proper3es	
  file	
  per	
  ‘group	
  of	
  (Domain)	
  classes’	
  
•  album.proper3es	
  
•  messages.proper3es	
  
•  abstractDomain.proper3es	
  
•  enums.proper3es	
  
•  Transla3on	
  of	
  data	
  (records)	
  
–  That’s	
  what	
  we	
  refer	
  to	
  as	
  “m17n”	
  
Mul3-­‐lingualiza3on	
  
•  Transla3on	
  of	
  program	
  code	
  
–  aka	
  i18n;	
  that’s	
  in	
  Grails	
  
–  .proper3es	
  file	
  per	
  “group	
  of	
  Domain	
  classes”	
  
•  album.proper3es	
  
•  messages.proper3es	
  
•  abstractDomain.proper3es	
  
•  enums.proper3es	
  
•  Transla3on	
  of	
  objects	
  (records)	
  
–  That’s	
  what	
  we	
  refer	
  to	
  as	
  “m17n”	
  
Mul3-­‐lingualiza3on	
  
•  System	
  default	
  Language	
  reflects	
  the	
  language	
  of	
  
all	
  record	
  in	
  the	
  database	
  
•  Data	
  is	
  op3onally	
  “overlayed”	
  with	
  an	
  M17n	
  
record	
  
•  By	
  conven3on	
  
–  i.e.	
  if	
  the	
  domain-­‐name	
  ends	
  in	
  “M17n”	
  
–  Scaffolding	
  renders	
  a	
  different	
  controller	
  
–  Scaffolding	
  renders	
  a	
  different	
  view	
  
AbstractDomain.change	
  
id	
   .tle	
   year	
   image	
   ar.st_id	
   descrip.on	
  
3	
   Licensed	
  to	
  Ill	
   1986	
   /img/4529ad62}.png	
   5	
   The	
  first	
  rap	
  rock	
  LP	
  to	
  top	
  the	
  Billboard	
  
album	
  chart	
  
id	
   album_id	
   language_id	
   .tle	
   descrip.on	
  
1	
   3	
   7	
   Licensed	
  to	
  Ill	
   Es	
  ist	
  das	
  erste	
  reine	
  Hip-­‐Hop-­‐Album,	
  das	
  Platz	
  1	
  
in	
  den	
  US-­‐amerikanischen	
  Billboard-­‐Charts	
  
erreichte.	
  
2	
   3	
   4	
   Licensed	
  to	
  Ill	
   La	
  canzone	
  raggiunse	
  la	
  seuma	
  posizione	
  nella	
  
speciale	
  classifica	
  del	
  ”Billboard	
  Hot	
  100"	
  
Album	
  
AlbumM17n	
  
Language.isSystem	
  ==	
  false	
  
Rela3ons	
  are	
  not	
  overlay	
  /	
  translated	
  
(could	
  be	
  a	
  limita3on)	
  
Not	
  
overlayed	
  
Not	
  
overlayed	
  
m17n	
  service	
  
Class	
  Album	
  extends	
  AbstractDomain	
  {	
  
	
  def	
  m17nService	
  
	
  
	
  private	
  String	
  title	
  
	
  ...	
  
	
  
	
  public	
  String	
  getTitle()	
  {	
  
	
   	
  m17nService.getProperty(this,	
  ‘title’)	
  
	
  }	
  
}	
  
	
  
m17n	
  service	
  
Class	
  Album	
  extends	
  AbstractDomain	
  {	
  
	
  def	
  m17nService	
  
	
  
	
  private	
  String	
  title	
  
	
  ...	
  
	
  
	
  public	
  String	
  getTitle()	
  {	
  
	
   	
  m17nService.getProperty(this,	
  ‘title’)	
  
	
  }	
  
}	
  
	
  
	
  
The	
  m17nService	
  can	
  figure	
  out:	
  
•  If	
  an	
  overlay	
  Class	
  exists	
  (by	
  conven3on)	
  
•  What	
  the	
  system	
  language	
  is	
  …	
  Language.findByIsSystem(true)	
  
•  What	
  the	
  requested	
  Language	
  is	
  (from	
  Session)	
  
•  …	
  or	
  return	
  the	
  un-­‐translated	
  …	
  this[title]	
  
NB.	
  
Session	
  does	
  not	
  necessarily	
  contain	
  browser	
  locale,	
  users	
  can	
  override	
  this	
  
	
  
Direc3ons	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
Types	
  &	
  Categories	
  
•  Types	
  
–  Hardcoded	
  
–  Used	
  by	
  program-­‐code(business-­‐logic,	
  rendering	
  
etc.)	
  
•  Categories	
  
–  Added	
  wherever	
  they	
  could	
  be	
  somewhat	
  useful	
  
to	
  a	
  par3cular	
  user	
  
–  Used	
  in	
  the	
  UI	
  for	
  quick	
  filters	
  
–  Used	
  in	
  the	
  UI	
  for	
  color-­‐coding	
  
Types	
  &	
  Categories	
  
•  Types	
  
–  Hardcoded	
  
–  Use	
  by	
  program-­‐code	
  (business-­‐logic,	
  rendering	
  etc.)	
  
•  Categories	
  
–  Added	
  wherever	
  they	
  could	
  be	
  somewhat	
  useful	
  to	
  a	
  
par3cular	
  user	
  
–  Used	
  in	
  the	
  UI	
  for	
  quick	
  filters	
  
–  Used	
  in	
  the	
  UI	
  for	
  color-­‐coding	
  
Types	
  &	
  Categories	
  
•  Types	
  
–  Hardcoded	
  
–  Use	
  by	
  program-­‐code	
  (business-­‐logic,	
  rendering	
  etc.)	
  
•  Categories	
  
–  Added	
  wherever	
  they	
  could	
  be	
  somewhat	
  useful	
  to	
  a	
  
par3cular	
  user	
  
–  Used	
  in	
  the	
  UI	
  for	
  quick	
  filters	
  
–  Used	
  in	
  the	
  UI	
  for	
  color-­‐coding	
  
An	
  overview	
  …	
  just	
  for	
  the	
  fun	
  of	
  it	
  
Direc3ons	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
Now	
  something	
  completely	
  different	
  
Connector	
  for	
  API	
  -­‐>	
  Grails	
  
•  Example	
  of	
  calling	
  the	
  Flickr	
  REST	
  API	
  
•  Explain	
  my	
  approach	
  to	
  API	
  wrapping	
  
Abstrac3on	
  of	
  an	
  API	
  call	
  
1.  Validate	
  the	
  parameters	
  needed	
  for	
  the	
  
par3cular	
  call	
  
2.  Well	
  eh,	
  do	
  the	
  actual	
  API	
  call	
  
3.  Process	
  the	
  response	
  or	
  handle	
  any	
  errors	
  
Abstrac3on	
  of	
  an	
  API	
  call	
  
1.  Validate	
  the	
  parameters	
  needed	
  for	
  the	
  
par3cular	
  call	
  
2.  Well	
  eh,	
  do	
  the	
  actual	
  API	
  call	
  
3.  Process	
  the	
  response	
  or	
  handle	
  any	
  errors	
  
void	
  apiCall(method,	
  params)	
  {	
  
	
  	
  	
  if	
  (validator(params))	
  {	
  
	
  	
  	
  	
  	
  	
  try	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  def	
  rsp	
  =	
  doApiCall(method,params)	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  process(rsp)	
  
	
  	
  	
  	
  	
  	
  }	
  catch	
  (Exception	
  ex)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  ...	
  
	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  }	
  else	
  {	
  
	
  	
  	
  	
  	
  	
  //	
  todo:	
  raise	
  validation	
  exception	
  
	
  	
  	
  }	
  
}	
  
Params	
  
Validator	
  
Processor	
  
API	
  
Abstrac3on	
  of	
  an	
  API	
  call	
  
//	
  	
  abstracting	
  the	
  whole	
  call	
  handling	
  with	
  closures	
  implemented	
  in	
  individual	
  classes	
  
private	
  def	
  apiCall(FlickrApiMethod	
  apiImplementation,	
  def	
  apiModel	
  =	
  {}	
  )	
  {	
  
	
  	
  	
  	
  def	
  params	
  	
  	
  	
  =	
  apiImplementation.paramsClosure	
  
	
  	
  	
  	
  def	
  validator	
  =	
  apiImplementation.validatorClosure	
  
	
  	
  	
  	
  def	
  processor	
  =	
  apiImplementation.processorClosure	
  
	
  	
  
	
  	
  	
  	
  if	
  (validator(apiModel()))	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  try	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  def	
  rsp	
  =	
  doApiCall(apiImplementation.apiMethod,	
  params(apiModel()))	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  return	
  processor(rsp,apiModel())	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  catch	
  (FlickrException	
  ex)	
  {	
  
	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  	
  FlickrExceptionHandler.handleApiCallException(ex)	
  
	
  	
  	
  	
  	
  	
  	
  	
  }	
  
	
  	
  	
  	
  }	
  
	
  	
  	
  	
  //	
  TODO:	
  raise	
  validation	
  exception	
  
	
  	
  	
  	
  return	
  apiModel()	
  
} 	
  	
  
	
  
Implementa3on	
  
class	
  photosGetInfo	
  implements	
  FlickrApiMethod{ 	
  	
  
	
  //	
  	
  API	
  METHOD 	
  	
  
	
  static	
  final	
  String	
  apiMethod	
  =	
  'flickr.photos.getInfo' 	
  	
  
	
  	
  
	
  //	
  	
  VALIDATOR	
  	
  
	
  Closure	
  validatorClosure	
  =	
  {	
  FlickrPhoto	
  photo	
  -­‐> 	
  	
  
	
   	
  if	
  (!photo	
  ||	
  !photo?.id)	
  {	
  	
  
	
   	
   	
  return	
  [validated:false,	
  message:"Required	
  value	
  FlickrPhoto.id	
  missing”]	
  
	
   	
  } 	
  	
  
	
   	
  return	
  [validated:true] 	
  	
  
	
  } 	
  	
  
	
  	
  
	
  //	
  	
  PARAMS 	
  	
  
	
  Closure	
  paramsClosure	
  =	
  {	
  FlickrPhoto	
  photo	
  -­‐> 	
  	
  
	
   	
  [photo_id:photo?.id,	
  secret:(photo?.secret	
  ?:'')] 	
  	
  
	
  } 	
  	
  
	
  	
  
	
  ...	
  
Implementa3on	
  
class	
  photosGetInfo	
  implements	
  FlickrApiMethod{ 	
  	
  
	
  ...	
  
	
  
	
  //	
  	
  PROCESSOR 	
  	
  
	
  Closure	
  processorClosure	
  =	
  {	
  GPathResult	
  response,	
  FlickrPhoto	
  photo	
  -­‐> 	
  	
  
	
   	
  photo.isPublic	
  =	
  (response.photo.visibility.@ispublic?.toString()	
  ==	
  '1') 	
  	
  
	
   	
  photo.secret 	
  =	
  response.photo.@secret.toString()	
  	
  
	
   	
  photo.serverId	
  =	
  response.photo.@server.toInteger() 	
  	
  
	
   	
  photo.title 	
  =	
  response.photo.title.toString() 	
  	
  
	
   	
  ...	
  
	
  	
  
	
  	
  	
  	
  	
  	
  	
  	
  return	
  photo	
  	
  
	
  	
  	
  	
  }	
  	
  
	
  
... 	
  	
  
Implementa3on	
  
class	
  photosGetInfo	
  implements	
  FlickrApiMethod{ 	
  	
  
	
  ...	
  
	
  //	
  	
  ERROR	
  CODES 	
  	
  
	
  Closure	
  errorsClosure	
  =	
  {	
  GPathResult	
  response	
  -­‐>	
  	
  
	
   	
  if	
  (response.err.@code.toInteger()	
  ==	
  1)	
  {	
  return	
  null	
  } 	
  //	
  photo	
  not	
  found 	
  	
  
	
   	
  //	
  recoverable	
  errors	
  	
  
	
   	
  if	
  ([100,105,116].contains(response.err.@code.toInteger()))	
  { 	
  	
  
	
   	
   	
  return	
  new	
  FlickrServiceApiException(response) 	
  	
  
	
   	
  }	
  else	
  { 	
  	
  
	
   	
   	
  return	
  new	
  FlickrServiceSyntaxException(response)	
  	
  
	
   	
  } 	
  	
  
	
  } 	
  	
  
} 	
  	
  
	
  
We	
  we’re	
  at	
  
•  We’ve	
  got	
  a	
  generic	
  implementa3on	
  of	
  calls	
  
•  A	
  Class	
  that	
  implements	
  a	
  par3cular	
  call	
  
•  The	
  params	
  back-­‐and-­‐forth	
  are	
  Groovy	
  
•  Now	
  3e	
  it	
  all	
  together	
  in	
  a	
  Grails-­‐like	
  way	
  
Service.getPhotoById(..)	
  
class	
  flickrService	
  {	
  
	
  …	
  
	
  //	
  	
  abstracting	
  call	
  handling	
  implemented	
  in	
  individual	
  classes	
  
	
  private	
  def	
  apiCall(def	
  apiImplementation,	
  def	
  apiModel	
  =	
  {})	
  {	
  
	
  …	
  
	
  }	
  
	
  //	
  public	
  service	
  methods	
  
	
  public	
  FlickrPhoto	
  getPhotoById(Long	
  id)	
  { 	
  	
  
	
   	
  return	
  apiCall(	
  
	
   	
   	
  new	
  photosGetInfo(),	
  
	
   	
   	
  {new	
  FlickrPhoto(id:id)}	
  
	
   	
  )	
  as	
  FlickrPhoto 	
  	
  
	
  }	
  
Well,	
  that’s	
  a	
  Wrap	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
Well,	
  that’s	
  a	
  Wrap	
  
•  Weapons	
  of	
  Choice	
  
•  AbstractDomain	
  
•  Heavy-­‐Duty	
  Scaffolding	
  
•  Mul3-­‐lingualiza3on	
  
•  Types	
  &	
  Categories	
  
•  Connec3ng	
  an	
  API	
  
 
edwin@ihomer.nl	
  
	
  
linkedin.com/in/edwinvannes	
  
	
  
twiker.com/edwinvannes	
  

More Related Content

What's hot

Chapter06 designing class-zuul bad
Chapter06 designing class-zuul badChapter06 designing class-zuul bad
Chapter06 designing class-zuul bad
Fajar Baskoro
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - StockholmJan Kronquist
 
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
e-Legion
 
Chapter ii(oop)
Chapter ii(oop)Chapter ii(oop)
Chapter ii(oop)
Chhom Karath
 
Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2
Ralph Schindler
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
Pavlo Baron
 
iPhone Memory Management
iPhone Memory ManagementiPhone Memory Management
iPhone Memory Management
Vadim Zimin
 
Java synchronizers
Java synchronizersJava synchronizers
Java synchronizers
ts_v_murthy
 
Automatic Reference Counting @ Pragma Night
Automatic Reference Counting @ Pragma NightAutomatic Reference Counting @ Pragma Night
Automatic Reference Counting @ Pragma Night
Giuseppe Arici
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
Mohammed El Rafie Tarabay
 
Dart London hackathon
Dart  London hackathonDart  London hackathon
Dart London hackathon
chrisbuckett
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyJaime Buelta
 
Arc of developer part1
Arc of developer part1Arc of developer part1
Arc of developer part1Junpei Wada
 
iPhone Seminar Part 2
iPhone Seminar Part 2iPhone Seminar Part 2
iPhone Seminar Part 2
NAILBITER
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
Arawn Park
 
GateIn Frameworks
GateIn FrameworksGateIn Frameworks
GateIn Frameworksjviet
 
Xtext Eclipse Con
Xtext Eclipse ConXtext Eclipse Con
Xtext Eclipse Con
Sven Efftinge
 
Chapter iii(oop)
Chapter iii(oop)Chapter iii(oop)
Chapter iii(oop)
Chhom Karath
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lispelliando dias
 
Best Guide for Javascript Objects
Best Guide for Javascript ObjectsBest Guide for Javascript Objects
Best Guide for Javascript Objects
Muhammad khurram khan
 

What's hot (20)

Chapter06 designing class-zuul bad
Chapter06 designing class-zuul badChapter06 designing class-zuul bad
Chapter06 designing class-zuul bad
 
Clojure for Java developers - Stockholm
Clojure for Java developers - StockholmClojure for Java developers - Stockholm
Clojure for Java developers - Stockholm
 
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
«Objective-C Runtime в примерах» — Алексей Сторожев, e-Legion
 
Chapter ii(oop)
Chapter ii(oop)Chapter ii(oop)
Chapter ii(oop)
 
Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2Zend Framework 1 + Doctrine 2
Zend Framework 1 + Doctrine 2
 
What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)What can be done with Java, but should better be done with Erlang (@pavlobaron)
What can be done with Java, but should better be done with Erlang (@pavlobaron)
 
iPhone Memory Management
iPhone Memory ManagementiPhone Memory Management
iPhone Memory Management
 
Java synchronizers
Java synchronizersJava synchronizers
Java synchronizers
 
Automatic Reference Counting @ Pragma Night
Automatic Reference Counting @ Pragma NightAutomatic Reference Counting @ Pragma Night
Automatic Reference Counting @ Pragma Night
 
Django - sql alchemy - jquery
Django - sql alchemy - jqueryDjango - sql alchemy - jquery
Django - sql alchemy - jquery
 
Dart London hackathon
Dart  London hackathonDart  London hackathon
Dart London hackathon
 
Database madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemyDatabase madness with_mongoengine_and_sql_alchemy
Database madness with_mongoengine_and_sql_alchemy
 
Arc of developer part1
Arc of developer part1Arc of developer part1
Arc of developer part1
 
iPhone Seminar Part 2
iPhone Seminar Part 2iPhone Seminar Part 2
iPhone Seminar Part 2
 
#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기#살아있다 #자프링외길12년차 #코프링2개월생존기
#살아있다 #자프링외길12년차 #코프링2개월생존기
 
GateIn Frameworks
GateIn FrameworksGateIn Frameworks
GateIn Frameworks
 
Xtext Eclipse Con
Xtext Eclipse ConXtext Eclipse Con
Xtext Eclipse Con
 
Chapter iii(oop)
Chapter iii(oop)Chapter iii(oop)
Chapter iii(oop)
 
Clojure - A new Lisp
Clojure - A new LispClojure - A new Lisp
Clojure - A new Lisp
 
Best Guide for Javascript Objects
Best Guide for Javascript ObjectsBest Guide for Javascript Objects
Best Guide for Javascript Objects
 

Viewers also liked

GGG for Nursing_Certificate of Completion
GGG for Nursing_Certificate of CompletionGGG for Nursing_Certificate of Completion
GGG for Nursing_Certificate of CompletionJimmy Durham, RN
 
Samenwerking coöperaties en energieleveranciers levert veel op
Samenwerking coöperaties en energieleveranciers levert veel opSamenwerking coöperaties en energieleveranciers levert veel op
Samenwerking coöperaties en energieleveranciers levert veel op
Merlijn de Bakker
 
CLP Presentation - Experiential Learning in Practice - 2-17-15
CLP Presentation - Experiential Learning in Practice - 2-17-15CLP Presentation - Experiential Learning in Practice - 2-17-15
CLP Presentation - Experiential Learning in Practice - 2-17-15Sean Gallagan, Ph.D.
 
Apresentação da nova plataforma Dotstore
Apresentação da nova plataforma DotstoreApresentação da nova plataforma Dotstore
Apresentação da nova plataforma Dotstore
Felipe Martins
 
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Alvaro Sanchez-Mariscal
 
гп экономическое развитие
гп экономическое развитиегп экономическое развитие
гп экономическое развитие
Anastasia Vinogradova
 
Spotify architecture - Pressing play
Spotify architecture - Pressing playSpotify architecture - Pressing play
Spotify architecture - Pressing play
Niklas Gustavsson
 
Dorking & Pentesting with Tacyt
Dorking & Pentesting with TacytDorking & Pentesting with Tacyt
Dorking & Pentesting with Tacyt
Chema Alonso
 
Hacking iOS: iPhone & iPad (2º Edición) [Índice]
Hacking iOS: iPhone & iPad (2º Edición) [Índice]Hacking iOS: iPhone & iPad (2º Edición) [Índice]
Hacking iOS: iPhone & iPad (2º Edición) [Índice]
Telefónica
 
Computação na nuvem
Computação na nuvemComputação na nuvem
Computação na nuvem
Lucas Sabadini
 
новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016
новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016
новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016
Anastasia Vinogradova
 

Viewers also liked (13)

Educao infantil
Educao infantilEducao infantil
Educao infantil
 
GGG for Nursing_Certificate of Completion
GGG for Nursing_Certificate of CompletionGGG for Nursing_Certificate of Completion
GGG for Nursing_Certificate of Completion
 
Samenwerking coöperaties en energieleveranciers levert veel op
Samenwerking coöperaties en energieleveranciers levert veel opSamenwerking coöperaties en energieleveranciers levert veel op
Samenwerking coöperaties en energieleveranciers levert veel op
 
Asa branca
Asa brancaAsa branca
Asa branca
 
CLP Presentation - Experiential Learning in Practice - 2-17-15
CLP Presentation - Experiential Learning in Practice - 2-17-15CLP Presentation - Experiential Learning in Practice - 2-17-15
CLP Presentation - Experiential Learning in Practice - 2-17-15
 
Apresentação da nova plataforma Dotstore
Apresentação da nova plataforma DotstoreApresentação da nova plataforma Dotstore
Apresentação da nova plataforma Dotstore
 
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
Creating applications with Grails, Angular JS and Spring Security - G3 Summit...
 
гп экономическое развитие
гп экономическое развитиегп экономическое развитие
гп экономическое развитие
 
Spotify architecture - Pressing play
Spotify architecture - Pressing playSpotify architecture - Pressing play
Spotify architecture - Pressing play
 
Dorking & Pentesting with Tacyt
Dorking & Pentesting with TacytDorking & Pentesting with Tacyt
Dorking & Pentesting with Tacyt
 
Hacking iOS: iPhone & iPad (2º Edición) [Índice]
Hacking iOS: iPhone & iPad (2º Edición) [Índice]Hacking iOS: iPhone & iPad (2º Edición) [Índice]
Hacking iOS: iPhone & iPad (2º Edición) [Índice]
 
Computação na nuvem
Computação na nuvemComputação na nuvem
Computação na nuvem
 
новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016
новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016
новый порядок расчета_налога_от _кадастровой_стоимости_28_10_2016
 

Similar to 2013 gr8 conf_grails_code_from_the_trenches

Clojure and Modularity
Clojure and ModularityClojure and Modularity
Clojure and Modularityelliando dias
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
Yakov Fain
 
Kerberizing spark. Spark Summit east
Kerberizing spark. Spark Summit eastKerberizing spark. Spark Summit east
Kerberizing spark. Spark Summit east
Jorge Lopez-Malla
 
The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014
Matthias Noback
 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training
Yevgeniy Brikman
 
Django Good Practices
Django Good PracticesDjango Good Practices
Django Good Practices
Solution4Future
 
PuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into OperationsPuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into Operationsgrim_radical
 
Scaling Flink in Cloud
Scaling Flink in CloudScaling Flink in Cloud
Scaling Flink in Cloud
Steven Wu
 
Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverageTesting NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoveragemlilley
 
Virtual Bash! A Lunchtime Introduction to Kafka
Virtual Bash! A Lunchtime Introduction to KafkaVirtual Bash! A Lunchtime Introduction to Kafka
Virtual Bash! A Lunchtime Introduction to Kafka
Jason Bell
 
NET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxNET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptx
petabridge
 
The Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup BelgiumThe Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup Belgium
Matthias Noback
 
Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016
Alvaro Sanchez-Mariscal
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
Matthias Noback
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rick Copeland
 
The Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony Barcelona
Matthias Noback
 
Privilege Escalation with Metasploit
Privilege Escalation with MetasploitPrivilege Escalation with Metasploit
Privilege Escalation with Metasploit
egypt
 
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Codemotion
 
Building Content Types with Dexterity
Building Content Types with DexterityBuilding Content Types with Dexterity
Building Content Types with Dexterity
David Glick
 
Terraform modules restructured
Terraform modules restructuredTerraform modules restructured
Terraform modules restructured
Ami Mahloof
 

Similar to 2013 gr8 conf_grails_code_from_the_trenches (20)

Clojure and Modularity
Clojure and ModularityClojure and Modularity
Clojure and Modularity
 
TypeScript for Java Developers
TypeScript for Java DevelopersTypeScript for Java Developers
TypeScript for Java Developers
 
Kerberizing spark. Spark Summit east
Kerberizing spark. Spark Summit eastKerberizing spark. Spark Summit east
Kerberizing spark. Spark Summit east
 
The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014The Naked Bundle - Symfony Live London 2014
The Naked Bundle - Symfony Live London 2014
 
Comprehensive Terraform Training
Comprehensive Terraform TrainingComprehensive Terraform Training
Comprehensive Terraform Training
 
Django Good Practices
Django Good PracticesDjango Good Practices
Django Good Practices
 
PuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into OperationsPuppetDB: Sneaking Clojure into Operations
PuppetDB: Sneaking Clojure into Operations
 
Scaling Flink in Cloud
Scaling Flink in CloudScaling Flink in Cloud
Scaling Flink in Cloud
 
Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverageTesting NodeJS with Mocha, Should, Sinon, and JSCoverage
Testing NodeJS with Mocha, Should, Sinon, and JSCoverage
 
Virtual Bash! A Lunchtime Introduction to Kafka
Virtual Bash! A Lunchtime Introduction to KafkaVirtual Bash! A Lunchtime Introduction to Kafka
Virtual Bash! A Lunchtime Introduction to Kafka
 
NET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptxNET Systems Programming Learned the Hard Way.pptx
NET Systems Programming Learned the Hard Way.pptx
 
The Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup BelgiumThe Naked Bundle - Symfony Usergroup Belgium
The Naked Bundle - Symfony Usergroup Belgium
 
Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016Mastering Grails 3 Plugins - G3 Summit 2016
Mastering Grails 3 Plugins - G3 Summit 2016
 
The Naked Bundle - Tryout
The Naked Bundle - TryoutThe Naked Bundle - Tryout
The Naked Bundle - Tryout
 
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and MingRapid and Scalable Development with MongoDB, PyMongo, and Ming
Rapid and Scalable Development with MongoDB, PyMongo, and Ming
 
The Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony BarcelonaThe Naked Bundle - Symfony Barcelona
The Naked Bundle - Symfony Barcelona
 
Privilege Escalation with Metasploit
Privilege Escalation with MetasploitPrivilege Escalation with Metasploit
Privilege Escalation with Metasploit
 
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
Jan Stępień - GraalVM: Fast, Polyglot, Native - Codemotion Berlin 2018
 
Building Content Types with Dexterity
Building Content Types with DexterityBuilding Content Types with Dexterity
Building Content Types with Dexterity
 
Terraform modules restructured
Terraform modules restructuredTerraform modules restructured
Terraform modules restructured
 

2013 gr8 conf_grails_code_from_the_trenches

  • 1. Grails  Code  from  the  Trenches   Collec3ons.shuffle(dayToDayWork)  
  • 2. Edwin  van  Nes     1989  dBase  /  Clipper  /  FoxPro   1995    Borland  Delphi   2000  Java  2,  Enterprise  Edi3on   2005  PHP,  Typo3,  Joomla!,  …   2011  Groovy  &  Grails  
  • 3. Direc3ons   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API    
  • 4. Weapons  of  Choice   Specifica3on   Google  Docs,  FogBugz,  Balsamiq  Mockups,  PlantUML,  yEd,  …   Design   similar  stuff   Construc3on   Grails  (dûh!),  IntelliJ  IDEA,  mySQL,  SVN  -­‐>  GIT,  …   Tes3ng   JUnit,  Spock,  Kiln,  …   Deployment   Jenkins,  Gradle,  OSX,  Ubuntu,  MS  Windows,  …   Project   Skype,  Google  Hangout,  IRIS,  …  
  • 5. Weapons  of  Choice   Specifica3on   Google  Docs,  FogBugz,  Balsamiq  Mockups,  yEd,  …   Design   similar  stuff   Construc3on   Grails  (dûh!),  IntelliJ  IDEA,  mySQL,  SVN  -­‐>  GIT,  …   Tes3ng   JUnit,  Spock,  Kiln,  …   Deployment   Jenkins,  OSX,  Ubuntu,  MS  Windows,  …   Project   Skype,  Google  Hangout,  IRIS,  …  
  • 6. Weapons  of  Choice   Specifica3on   Google  Docs,  FogBugz,  Balsamiq  Mockups,  yEd,  …   Design   similar  stuff   Construc3on   Grails  (dûh!),  IntelliJ  IDEA,  mySQL,  SVN  -­‐>  GIT,  …   Tes3ng   JUnit,  Spock,  …   Deployment   Jenkins,  Gradle,  OSX,  Ubuntu,  MS  Windows,  …   Project   Skype,  Google  Hangout,  IRIS,  …  
  • 7. Weapons  of  Choice   Specifica3on   Google  Docs,  FogBugz,  Balsamiq  Mockups,  yEd,  …   Design   similar  stuff   Construc3on   Grails  (dûh!),  IntelliJ  IDEA,  mySQL,  SVN  -­‐>  GIT,  …   Tes3ng   JUnit,  Spock,  Kiln,  …   Deployment   Jenkins,  OSX,  Ubuntu,  MS  Windows,  …   Project   Skype,  Google  Hangout,  IRIS,  …  
  • 8. Weapons  of  Choice   Specifica3on   Google  Docs,  FogBugz,  Balsamiq  Mockups,  yEd,  …   Design   similar  stuff   Construc3on   Grails  (dûh!),  IntelliJ  IDEA,  mySQL,  SVN  -­‐>  GIT,  …   Tes3ng   JUnit,  Spock,  …   Deployment   Jenkins,  Gradle,  OSX,  Ubuntu,  MS  Windows,  …   Project   Skype,  Google  Hangout,  IRIS,  …  
  • 9. Weapons  of  Choice   Specifica3on   Google  Docs,  FogBugz,  Balsamiq  Mockups,  yEd,  …   Design   similar  stuff   Construc3on   Grails  (dûh!),  IntelliJ  IDEA,  mySQL,  SVN  -­‐>  GIT,  …   Tes3ng   JUnit,  Spock,  …   Deployment   Jenkins,  OSX,  Ubuntu,  MS  Windows,  …   Project   Skype,  Google  Hangout,  IRIS,  …  
  • 10. Direc3ons   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API   •  Error  Abstrac3on  in  a  Plugin  
  • 11. WhatWeDoMost*   Services   Frontend   Portal   Backend   Portal   Database   Our  Clients   Consumers   (their  clients)   *  overly  simplified  for  educa3onal  purposes  
  • 12. GR8Tunes   Used  here  as  an  example  for  a   typical  Backend  portal  
  • 13. GR8Tunes   Used  here  as  an  example  for  a   typical  Backend  portal  
  • 14. AbstractDomain   •  Not  too  Groovy  probably   •  Add  some  standard  akributes   – Some  useful  3mestamps   – ‘recentlyUpdated’  boolean  for   easy  highligh3ng   – Each  record  gets  a   ‘remarks’  akribute  
  • 16. AbstractDomain.Status   Hibernate  filters  Plugin   •  defaultFilter  in  Backend   –  Status  in  [Status.ACTIVE,  Status.INACTIVE]   •  defaultFilter  in  Frontend   –  Status  ==  Status.ACTIVE  
  • 17. AbstractDomain.Status   Hibernate  filters   •  defaultFilter  in  Backend   –  Status  in  [Status.ACTIVE,  Status.INACTIVE]   •  defaultFilter  in  Frontend   –  Status  ==  Status.ACTIVE  
  • 18. AbstractDomain.Status     class  DefaultFilters  {            def  sessionFactory            def  filters  =  {                  all(controller:'*',  action:'*')  {                          before  =  {                                  def  session  =  sessionFactory.currentSession                                  if  (params.filter_status)  {     session.enableFilter('statusFilter').setParameter('status',params.filter_status)                                    }  else  {     session.enableFilter('defaultFilter')                                    }                          }                  }          }   }    
  • 19. AbstractDomain.Status     class  DefaultFilters  {            def  sessionFactory            def  filters  =  {                  all(controller:'*',  action:'*')  {                          before  =  {                                  def  session  =  sessionFactory.currentSession                                  if  (params.filter_status)  {     session.enableFilter('statusFilter').setParameter('status',params.filter_status)                                    }  else  {     session.enableFilter('defaultFilter')                                    }                          }                  }          }   }    
  • 20. AbstractDomain.Status     class  DefaultFilters  {            def  sessionFactory            def  filters  =  {                  all(controller:'*',  action:'*')  {                          before  =  {                                  def  session  =  sessionFactory.currentSession                                  if  (params.filter_status)  {     session.enableFilter('statusFilter').setParameter('status',params.filter_status)                                    }  else  {     session.enableFilter('defaultFilter')                                    }                          }                  }          }   }    
  • 21. AbstractDomain.change   •  Holds  a  record  of  type   AbstractDomain   •  Like  a  “muta3on-­‐record”   •  i.e.  future  change  to  the  object   •  example:  division  of   responsibility  (amongst  users)    
  • 22. AbstractDomain.change   id   version   change   .tle   year   1   5   7   The  Bright  Side  of  the  Moon   1973   id   version   change   .tle   year   7   5   null   The  Dark  Side  of  the  Moon   1973   Should  verify  (op3mis3c)   Hibernate  filter:  exclude  records  that  are  “change  records”  
  • 23. Direc3ons   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API   •  Error  Abstrac3on  in  a  Plugin  
  • 24. Heavy-­‐Duty  Scaffolding   •  Substan3al  3me  spent  on  tailor-­‐made  scaffolding     •  Controllers  are  always  scaffolded   –  Only  specific  code  for  a  specific  domain  is  coded   •  Views  are  scaffolded  as  a  start   –  Much  more  likely  to  manually  adjust   –  But  certainly  not  for  each  and  every  Domain  Class   •  Domain  Classes  can  contain  seungs  to  influence   rendering  during  scaffolding  
  • 25. Scaffolded  Controllers   •  All  Controllers  exists  as  files  but  are  100%  scaffolded  unless  …     class  AlbumController  {    static  scaffold  =  true   }  
  • 26. Scaffolded  Controllers   •  All  Controllers  exists  as  files  but  are  100%  scaffolded  unless  …     class  AlbumController  {    static  scaffold  =  true        def  list  (Integer  max)  {      //  different  implementation  of  Album.list    }   }  
  • 27. SimpleFlow  =  true   •  Simple  states   –  List   –  Edit   •  Mul3ple  ac3ons   –  Create   –  Cancel   –  Save   –  SaveAndClose   –  SaveAndCreate  
  • 28. SimpleFlow  =  false   •  More  states   –  List   –  Create   –  Edit   –  Show   •  Same  set  of  ac3ons   –  Create   –  Cancel   –  Save   –  SaveAndClose   –  SaveAndCreate  
  • 29. Scaffolded  Views   •  Views  are  most  likely  to  be  changed   –  Order  of  fields  from  Domain  Class  constraints   static  constraints  =  {    title  (blank:false)    artist  (blank:false)    year  (display:true)        change  (display:false)   }  
  • 30. Scaffolded  Views   •  Views  are  most  likely  to  be  changed   –  Order  of  fields  from  Domain  Class  constraints   static  constraints  =  {    title  (blank:false)    artist  (blank:false)    year  (display:true)        change  (display:false)   }  
  • 31. Scaffolded  Views   •  Render  more  artefacts   _form.gsp    =  fields  used  in  create  /  edit   _table.gsp    =  <table>  used  in  list  for  reuse   _panel.gsp    =  simple  <div>  for  reuse   list.csv.gsp  =  used  for  formatting  exports  
  • 32. Scaffolded  Views   •  Render  more  artefacts   _form.gsp    =  fields  used  in  create  /  edit   _table.gsp    =  <table>  used  in  list  for  reuse   _panel.gsp    =  simple  <div>  for  reuse   list.csv.gsp  =  used  for  formatting  exports   <%@  page  import="gr8tunes.Album"  %>   <g:if  test="${albumInstance  instanceof  Album}">    <div  class="domain-­‐panel  domain-­‐album">    <h4><small><g:message  code="album.title.label"  />:</small></h4>              <p>      <g:if  test="${!controllerName.equals('album')}">                  <g:link  controller=”album"  action="show"  id="${albumInstance.id}">        <g:fieldValue  bean="${albumInstance}"  field="year"/>        <g:fieldValue  bean="${albumInstance}"  field="title"/>        </g:link>      </g:if>      <g:else>        <g:fieldValue  bean="${albumInstance}"  field="year"/>        <g:fieldValue  bean="${albumInstance}"  field="title"/>              </g:else>              </p>    </div>   </g:if>   _panel.gsp  
  • 33. Scaffolded  Views   •  Render  more  artefacts   _form.gsp    =  fields  used  in  create  /  edit   _table.gsp    =  <table>  used  in  list  for  reuse   _panel.gsp    =  simple  <div>  for  reuse   list.csv.gsp  =  used  for  formatting  exports  
  • 34. Scaffolded  Views   •  Render  more  artefacts   _form.gsp    =  fields  used  in  create  /  edit   _table.gsp    =  <table>  used  in  list  for  reuse   _panel.gsp    =  simple  <div>  for  reuse   list.csv.gsp  =  used  for  formatting  exports  
  • 35. Scaffolded  Views   •  Render  more  artefacts   _form.gsp    =  fields  used  in  create  /  edit   _table.gsp    =  <table>  used  in  list  for  reuse   _panel.gsp    =  simple  <div>  for  reuse   list.csv.gsp  =  used  for  formatting  exports  
  • 36. Scaffolding  seungs  in  Domain  Classes   class  Item  extends  AbstractDomain  {    ...    static  scaffolding  =  [      simpleFlow:  true,      inFilter:      ['status',  'itemType',  'itemCategory'],      inSearch:      ['title',  'description'],      inSort:          ['title',  'itemType',  'artist']    ]    ...   }  
  • 37. Scaffolding  seungs  in  Domain  Classes   class  Item  extends  AbstractDomain  {    ...    static  scaffolding  =  [      simpleFlow:  true,      inFilter:      ['status',  'itemType',  'itemCategory'],      inSearch:      ['title',  'description'],      inSort:          ['title',  'itemType',  'artist']    ]    ...   }  
  • 38. Scaffolding  seungs  in  Domain  Classes   class  Item  extends  AbstractDomain  {    ...    static  scaffolding  =  [      simpleFlow:  true,      inFilter:      ['status',  'itemType',  'itemCategory'],      inSearch:      ['title',  'description'],      inSort:          ['title',  'itemType',  'artist']    ]    ...   }  
  • 39. Direc3ons   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API   •  Error  Abstrac3on  in  a  Plugin    
  • 40. Mul3-­‐lingualiza3on   •  Transla3on  of  program  code   –  aka  i18n;  that’s  in  Grails  right?   –  .proper3es  file  per  ‘group  of  (Domain)  classes’   •  album.proper3es   •  messages.proper3es   •  abstractDomain.proper3es   •  enums.proper3es   •  Transla3on  of  data  (records)   –  That’s  what  we  refer  to  as  “m17n”  
  • 41. Mul3-­‐lingualiza3on   •  Transla3on  of  program  code   –  aka  i18n;  that’s  in  Grails   –  .proper3es  file  per  “group  of  Domain  classes”   •  album.proper3es   •  messages.proper3es   •  abstractDomain.proper3es   •  enums.proper3es   •  Transla3on  of  objects  (records)   –  That’s  what  we  refer  to  as  “m17n”  
  • 42. Mul3-­‐lingualiza3on   •  System  default  Language  reflects  the  language  of   all  record  in  the  database   •  Data  is  op3onally  “overlayed”  with  an  M17n   record   •  By  conven3on   –  i.e.  if  the  domain-­‐name  ends  in  “M17n”   –  Scaffolding  renders  a  different  controller   –  Scaffolding  renders  a  different  view  
  • 43. AbstractDomain.change   id   .tle   year   image   ar.st_id   descrip.on   3   Licensed  to  Ill   1986   /img/4529ad62}.png   5   The  first  rap  rock  LP  to  top  the  Billboard   album  chart   id   album_id   language_id   .tle   descrip.on   1   3   7   Licensed  to  Ill   Es  ist  das  erste  reine  Hip-­‐Hop-­‐Album,  das  Platz  1   in  den  US-­‐amerikanischen  Billboard-­‐Charts   erreichte.   2   3   4   Licensed  to  Ill   La  canzone  raggiunse  la  seuma  posizione  nella   speciale  classifica  del  ”Billboard  Hot  100"   Album   AlbumM17n   Language.isSystem  ==  false   Rela3ons  are  not  overlay  /  translated   (could  be  a  limita3on)   Not   overlayed   Not   overlayed  
  • 44. m17n  service   Class  Album  extends  AbstractDomain  {    def  m17nService      private  String  title    ...      public  String  getTitle()  {      m17nService.getProperty(this,  ‘title’)    }   }    
  • 45. m17n  service   Class  Album  extends  AbstractDomain  {    def  m17nService      private  String  title    ...      public  String  getTitle()  {      m17nService.getProperty(this,  ‘title’)    }   }       The  m17nService  can  figure  out:   •  If  an  overlay  Class  exists  (by  conven3on)   •  What  the  system  language  is  …  Language.findByIsSystem(true)   •  What  the  requested  Language  is  (from  Session)   •  …  or  return  the  un-­‐translated  …  this[title]   NB.   Session  does  not  necessarily  contain  browser  locale,  users  can  override  this    
  • 46. Direc3ons   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API  
  • 47. Types  &  Categories   •  Types   –  Hardcoded   –  Used  by  program-­‐code(business-­‐logic,  rendering   etc.)   •  Categories   –  Added  wherever  they  could  be  somewhat  useful   to  a  par3cular  user   –  Used  in  the  UI  for  quick  filters   –  Used  in  the  UI  for  color-­‐coding  
  • 48. Types  &  Categories   •  Types   –  Hardcoded   –  Use  by  program-­‐code  (business-­‐logic,  rendering  etc.)   •  Categories   –  Added  wherever  they  could  be  somewhat  useful  to  a   par3cular  user   –  Used  in  the  UI  for  quick  filters   –  Used  in  the  UI  for  color-­‐coding  
  • 49. Types  &  Categories   •  Types   –  Hardcoded   –  Use  by  program-­‐code  (business-­‐logic,  rendering  etc.)   •  Categories   –  Added  wherever  they  could  be  somewhat  useful  to  a   par3cular  user   –  Used  in  the  UI  for  quick  filters   –  Used  in  the  UI  for  color-­‐coding  
  • 50. An  overview  …  just  for  the  fun  of  it  
  • 51. Direc3ons   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API  
  • 52. Now  something  completely  different  
  • 53. Connector  for  API  -­‐>  Grails   •  Example  of  calling  the  Flickr  REST  API   •  Explain  my  approach  to  API  wrapping  
  • 54. Abstrac3on  of  an  API  call   1.  Validate  the  parameters  needed  for  the   par3cular  call   2.  Well  eh,  do  the  actual  API  call   3.  Process  the  response  or  handle  any  errors  
  • 55. Abstrac3on  of  an  API  call   1.  Validate  the  parameters  needed  for  the   par3cular  call   2.  Well  eh,  do  the  actual  API  call   3.  Process  the  response  or  handle  any  errors   void  apiCall(method,  params)  {        if  (validator(params))  {              try  {                    def  rsp  =  doApiCall(method,params)                    return  process(rsp)              }  catch  (Exception  ex)  {                    ...              }        }  else  {              //  todo:  raise  validation  exception        }   }   Params   Validator   Processor   API  
  • 56. Abstrac3on  of  an  API  call   //    abstracting  the  whole  call  handling  with  closures  implemented  in  individual  classes   private  def  apiCall(FlickrApiMethod  apiImplementation,  def  apiModel  =  {}  )  {          def  params        =  apiImplementation.paramsClosure          def  validator  =  apiImplementation.validatorClosure          def  processor  =  apiImplementation.processorClosure              if  (validator(apiModel()))  {                  try  {                          def  rsp  =  doApiCall(apiImplementation.apiMethod,  params(apiModel()))                          return  processor(rsp,apiModel())                  }  catch  (FlickrException  ex)  {                          FlickrExceptionHandler.handleApiCallException(ex)                  }          }          //  TODO:  raise  validation  exception          return  apiModel()   }      
  • 57. Implementa3on   class  photosGetInfo  implements  FlickrApiMethod{      //    API  METHOD      static  final  String  apiMethod  =  'flickr.photos.getInfo'          //    VALIDATOR      Closure  validatorClosure  =  {  FlickrPhoto  photo  -­‐>        if  (!photo  ||  !photo?.id)  {          return  [validated:false,  message:"Required  value  FlickrPhoto.id  missing”]      }        return  [validated:true]      }          //    PARAMS      Closure  paramsClosure  =  {  FlickrPhoto  photo  -­‐>        [photo_id:photo?.id,  secret:(photo?.secret  ?:'')]      }          ...  
  • 58. Implementa3on   class  photosGetInfo  implements  FlickrApiMethod{      ...      //    PROCESSOR      Closure  processorClosure  =  {  GPathResult  response,  FlickrPhoto  photo  -­‐>        photo.isPublic  =  (response.photo.visibility.@ispublic?.toString()  ==  '1')        photo.secret  =  response.photo.@secret.toString()        photo.serverId  =  response.photo.@server.toInteger()        photo.title  =  response.photo.title.toString()        ...                      return  photo            }       ...    
  • 59. Implementa3on   class  photosGetInfo  implements  FlickrApiMethod{      ...    //    ERROR  CODES      Closure  errorsClosure  =  {  GPathResult  response  -­‐>        if  (response.err.@code.toInteger()  ==  1)  {  return  null  }  //  photo  not  found        //  recoverable  errors        if  ([100,105,116].contains(response.err.@code.toInteger()))  {          return  new  FlickrServiceApiException(response)        }  else  {          return  new  FlickrServiceSyntaxException(response)        }      }     }      
  • 60. We  we’re  at   •  We’ve  got  a  generic  implementa3on  of  calls   •  A  Class  that  implements  a  par3cular  call   •  The  params  back-­‐and-­‐forth  are  Groovy   •  Now  3e  it  all  together  in  a  Grails-­‐like  way  
  • 61. Service.getPhotoById(..)   class  flickrService  {    …    //    abstracting  call  handling  implemented  in  individual  classes    private  def  apiCall(def  apiImplementation,  def  apiModel  =  {})  {    …    }    //  public  service  methods    public  FlickrPhoto  getPhotoById(Long  id)  {        return  apiCall(        new  photosGetInfo(),        {new  FlickrPhoto(id:id)}      )  as  FlickrPhoto      }  
  • 62. Well,  that’s  a  Wrap   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API  
  • 63. Well,  that’s  a  Wrap   •  Weapons  of  Choice   •  AbstractDomain   •  Heavy-­‐Duty  Scaffolding   •  Mul3-­‐lingualiza3on   •  Types  &  Categories   •  Connec3ng  an  API  
  • 64.   edwin@ihomer.nl     linkedin.com/in/edwinvannes     twiker.com/edwinvannes