!1
Blossom in the Real World
Sr. Software Engineer, Magnolia
Lead developer of Blossom Module
Spring Framework user since 2005
Tobias Mattsson
2@sigget
3
Jan Haderka
Head of Support, Magnolia
@rah003
4
Casey Dement
VP of Architecture, Sharecare
@casey_dement
#Mplify
5
Magnolia + Spring = Blossom 6
@Template
7
TEMPLATEREQUEST CONTENT
CMS
8
TEMPLATEREQUEST CONTENT
CMS + Blossom
9
CONTROLLER
MODEL
VIEW
Page Template
@Controller
@Template(id="myModule:pages/main", title="Main")
public class MainTemplate {
!
   @RequestMappi...
11
PAGE
PAGES CONTAIN 0:n AREAS
12
PAGE
AREA
A
R
E
A
AREA
PAGES CONTAIN 0:n AREAS
13
PAGE
AREA
A
R
E
A
AREA
AREAS HAVE 0:n COMPONENTS
COMPONENT
COMPONENT
Etiam porta sem malesuada ...
Area Template
@Controller
@Template(id="myModule:pages/main",title="Main Template")
public class MainTemplate {
   @Contro...
Component Template
@Controller
@Template(id="myModule:components/shoppingCart",
         title="Shopping Cart")
@TemplateD...
SERVLET
CONTAINER
RENDERING
FILTER
RENDERING
ENGINE
BLOSSOM
DISPATCHER
SERVLET
CONTROLLER
16
How Blossom Works
Blossom 3.0
17
What’s new?
Blossom 3.0
18
Update for Magnolia 5 series
Requires Magnolia 5.1
new ways of building dialogs
availability annotation
19
Dialogs
Fluent Builder-style API
!
@TabFactory("Content")
public void contentTab(UiConfig cfg, TabBuilder tab) {
tab.fields(
cfg.fiel...
Dialogs and the Class Hierarchy
public abstract class BasePageTemplate {

@TabFactory("Meta")

public void metaTab(UiConfig...
Input Validation
...
public void contentTab(UiConfig cfg, TabBuilder tab) {
tab.fields(
cfg.fields.text("name").label("Name")...
Dynamic Dialog
!
!
@Template(id="myModule:components/bookCategory", title="Book category")
@TemplateDescription("A list of...
Dynamic Dialog
!
@Template(id="myModule:components/bookCategory", title="Book category")
@TemplateDescription("A list of b...
@AvailableComponentClasses
25
Components Availability
!
   @ComponentCategory

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.TYPE)
public @in...
@More
27
Content, content, more content
!
@Template(id="myModule:components/bookCategory", title="Book category")
@TemplateDescript...
Now The Real World 29
Thank You!
30
31
magnolia-cms.com/spring
32
How do I get started on my project?
33
mvn archetype:generate -DarchetypeCatalog=http://nexus.magnolia-cms.com/
content/groups/public/
!
choose magnolia-blossom-...
How would I build a REST interface to my CMS
content using Blossom?
35
REST servlet in module descriptor
<servlets>
  <servlet>
    <name>rest</name>
    <class>org.springframework.web.servlet....
REST Controller
@Controller
public class ProductsRestController {
!
@RequestMapping("/products/{productId}")
public Produc...
Can I leverage Magnolia's caching functionality
to improve the performance of my Spring app?
38
Influencing caching 39
@Controller
@Template(title="Text", id="myModule:components/text")
public class TextComponent {
!
@...
How can I present dialogs in different languages
using Blossom?
40
!
@Controller
@Template(title = "Text", id = "blossomSampleModule:components/text")
@I18nBasename("info.magnolia.blossom.s...
!
!
/info/magnolia/blossom/sample/messages_en.properties
textComponent.contentTab.label = Content
textComponent.contentTab...
How do I migrate my existing site to Magnolia/
Blossom?
43
How can I integrate Spring Security?
44
45
How can I dependency inject spring beans into
RenderingModels?
46
Autowired RenderingModel
public class MyRenderingModel extends RenderingModelImpl<TemplateDefinition> {
!
@Autowired
privat...
Autowired RenderingModel
!
public class MyRenderingModel extends AbstractAutowiredRenderingModel<TemplateDefinition> {
!
@A...
Views 49
Rendering an Area
FreeMarker
[@cms.area name="main" /]
!
JSP
<cms:area name="main" />
50
Rendering Components in an Area
FreeMarker
[#list components as component]
   [@cms.component content=component /]
[/#list...
Page Template Availability
@Controller

@Template(title="Article", id="myModule:/pages/article")

public class ArticleTemp...
Available Components
@Controller
@Area("promos")
@AvailableComponentClasses({TextComponent.class,
                        ...
Area Inheritance
@Controller
@Area("promos")
@Inherits
@AvailableComponentClasses({TextComponent.class,
                  ...
Form Submission
/* Standard annotations omitted */
public class ContactFormComponent {

@RequestMapping(value="/contact", ...
But wait a minute …
56
Caused by: org.springframework.web.util.NestedServletException: Reques

 at org.springframework.web...
Controller Pre-execution
57
C M V
PAGE
C M V
Area
C M V
Component
C M V
Component
C M V
Component
C
CPE Implementation 58
Code in View
<form>
<blossom:pecid-input />
<input type=”text” name=”email” />
...
!
HTML Output
<fo...
Spring Web MVC
+
Content
59
Spring Web Flow
60
REQUEST LANDING
PAGE
SPRING
WEB FLOW
Spring Web Flow
61
REQUEST LANDING
PAGE
FORM
SUBMIT?
SPRING
WEB FLOW
62
Trademarks
Other trademarks are the property of their respective owners.
Magnolia
The Pulse are trademarks of
Magnolia ...
Upcoming SlideShare
Loading in …5
×

Getting Healthy with Magnolia, Blossom and Spring

1,870 views

Published on

This presentation was given at Amplify Miami 2014 by Jan Haderka, Senior Developer at Magnolia International, and Casey Dement, VP of Architecture at Sharecare, Inc.

Casey showed how Sharecare integrated Magnolia and Blossom with Spring MVC and Akamai to build a highly flexible and scalable website. Jan gives an introduction and an update on the new features in Blossom 3.

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,870
On SlideShare
0
From Embeds
0
Number of Embeds
34
Actions
Shares
0
Downloads
15
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Getting Healthy with Magnolia, Blossom and Spring

  1. 1. !1 Blossom in the Real World
  2. 2. Sr. Software Engineer, Magnolia Lead developer of Blossom Module Spring Framework user since 2005 Tobias Mattsson 2@sigget
  3. 3. 3 Jan Haderka Head of Support, Magnolia @rah003
  4. 4. 4 Casey Dement VP of Architecture, Sharecare @casey_dement
  5. 5. #Mplify 5
  6. 6. Magnolia + Spring = Blossom 6
  7. 7. @Template 7
  8. 8. TEMPLATEREQUEST CONTENT CMS 8
  9. 9. TEMPLATEREQUEST CONTENT CMS + Blossom 9 CONTROLLER MODEL VIEW
  10. 10. Page Template @Controller @Template(id="myModule:pages/main", title="Main") public class MainTemplate { !    @RequestMapping("/main")    public String render(ModelMap model) {        return "pages/main";    } } 10
  11. 11. 11 PAGE
  12. 12. PAGES CONTAIN 0:n AREAS 12 PAGE AREA A R E A AREA
  13. 13. PAGES CONTAIN 0:n AREAS 13 PAGE AREA A R E A AREA AREAS HAVE 0:n COMPONENTS COMPONENT COMPONENT Etiam porta sem malesuada magna mollis euismod. Duis mollis, est non commodo luctus, nisi erat porttitor ligula, eget lacinia odio sem nec elit. COMPONENT Etiam porta sem malesuada magna mollis euismod. Morbi leo risus, porta ac consectetur ac, vestibulum at eros. Aenean lacinia bibendum nulla sed consectetur. Aenean eu leo quam. Pellentesque ornare sem lacinia quam venenatis vestibulum. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed posuere consectetur est at lobortis. C O M P O N E N T
  14. 14. Area Template @Controller @Template(id="myModule:pages/main",title="Main Template") public class MainTemplate {    @Controller   @Area("main")    public static class MainArea {        @RequestMapping("/main/mainArea")        public String render() {            return "areas/main";        }    ... 14
  15. 15. Component Template @Controller @Template(id="myModule:components/shoppingCart",          title="Shopping Cart") @TemplateDescription("Shopping cart") public class ShoppingCartComponent {    @RequestMapping("/shoppingCart")    public String handleRequest() {        ...        return "components/shoppingCart";    } ... 15
  16. 16. SERVLET CONTAINER RENDERING FILTER RENDERING ENGINE BLOSSOM DISPATCHER SERVLET CONTROLLER 16 How Blossom Works
  17. 17. Blossom 3.0 17 What’s new?
  18. 18. Blossom 3.0 18 Update for Magnolia 5 series Requires Magnolia 5.1 new ways of building dialogs availability annotation
  19. 19. 19 Dialogs
  20. 20. Fluent Builder-style API ! @TabFactory("Content") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("Heading"),
 cfg.fields.richText("body").label("Text body"),
 cfg.fields.websiteLink("categoryLink").label("Link"),
 cfg.fields.basicUpload("image").label("Image"),
 cfg.fields.checkbox("inlineImage").label("Inline Image")  );
 } 20
  21. 21. Dialogs and the Class Hierarchy public abstract class BasePageTemplate {
 @TabFactory("Meta")
 public void metaTab(UiConfig cfg, TabBuilder tab) {
 tab.fields( cfg.fields.text("metaAuthor").label("Author"),
     cfg.fields.text("metaKeywords").label("Keywords"),
     cfg.fields.text("metaDescription").label("Description")    );
  }
 } 21
  22. 22. Input Validation ... public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("name").label("Name").required(), cfg.fields.text("email").label("Email") .validator(cfg.validators.email()) ); } ... 22
  23. 23. Dynamic Dialog ! ! @Template(id="myModule:components/bookCategory", title="Book category") @TemplateDescription("A list of books in a given category.") @Controller public class BookCategoryComponent {
    @Autowired
    private SalesApplicationWebService service;
 
    @RequestMapping("/bookcategory")
    public String render(Node content, ModelMap model) throws RepositoryException {
        String category = content.getProperty("category").getString();
        model.put("books", service.getBooksInCategory(category));
        return "components/bookCategory";
    } @TabFactory("Content")
    public void contentTab(UiConfig cfg, TabBuilder tab) {
        Collection<String> categories = service.getBookCategories();
        tab.fields(
 cfg.fields.select("category").label("Category").options(categories)
        );
    } } 23
  24. 24. Dynamic Dialog ! @Template(id="myModule:components/bookCategory", title="Book category") @TemplateDescription("A list of books in a given category.") @Controller public class BookCategoryComponent {
    @Autowired
    private SalesApplicationWebService service;
 
    @RequestMapping("/bookcategory")
    public String render(Node content, ModelMap model) throws RepositoryException {
        String category = content.getProperty("category").getString();
        model.put("books", service.getBooksInCategory(category));
        return "components/bookCategory";
    } @TabFactory("Content")
    public void contentTab(UiConfig cfg, TabBuilder tab) {
        Collection<String> categories = service.getBookCategories();
        tab.fields(
 cfg.fields.select("category").label("Category").options(categories)
        );
    } } 24
  25. 25. @AvailableComponentClasses 25
  26. 26. Components Availability !    @ComponentCategory
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.TYPE) public @interface Banner { } ! @Area("banners") @AvailableComponentClasses({Banner.class}) @Controller    public class BannersArea { … } ! @Banner @Template(id="myModule:components/largePromoBanner"), title="Large banner”) @Controller("banner")    public class LargePromoBannerComponent { …
     } 26
  27. 27. @More 27
  28. 28. Content, content, more content ! @Template(id="myModule:components/bookCategory", title="Book category") @TemplateDescription("A list of books in a given category.") @Controller public class BookCategoryComponent {
    @Autowired
    private SalesApplicationWebService service;
 
    @RequestMapping("/bookcategory")    public String render(Node content, ModelMap model) throws RepositoryException {
        String category = content.getProperty("category").getString();        model.put("books", service.getBooksInCategory(category));
        return "components/bookCategory";
    } @TabFactory("Content")
    public void contentTab(UiConfig cfg, TabBuilder tab) {
        Collection<String> categories = service.getBookCategories();
        tab.fields(
 cfg.fields.select("category").label("Category").options(categories)
        );
    } } 28
  29. 29. Now The Real World 29
  30. 30. Thank You! 30
  31. 31. 31 magnolia-cms.com/spring
  32. 32. 32
  33. 33. How do I get started on my project? 33
  34. 34. mvn archetype:generate -DarchetypeCatalog=http://nexus.magnolia-cms.com/ content/groups/public/ ! choose magnolia-blossom-module-archetype ! Define value for property 'groupId': : com.acme Define value for property 'artifactId': : acme-module Define value for property 'version': 1.0-SNAPSHOT: Define value for property 'package': com.acme: Define value for property 'magnolia-version': : 4.5.11 Define value for property 'module-class-name': : AcmeModule Define value for property 'module-name': acme-module: acmeModule ! ! ! ! http://wiki.magnolia-cms.com/display/WIKI/ Creating+a+new+Blossom+project+using+maven+archetypes
  35. 35. How would I build a REST interface to my CMS content using Blossom? 35
  36. 36. REST servlet in module descriptor <servlets>   <servlet>     <name>rest</name>     <class>org.springframework.web.servlet.DispatcherServlet</class>     <mappings>       <mapping>/rest/*</mapping>     </mappings>     <params>       <param>         <name>contextConfigLocation</name>         <value>classpath:/rest-servlet.xml</value>       </param>     </params>   </servlet> </servlets> 36
  37. 37. REST Controller @Controller public class ProductsRestController { ! @RequestMapping("/products/{productId}") public Product findProduct(@PathVariable String productId) { // implementation omitted } } 37
  38. 38. Can I leverage Magnolia's caching functionality to improve the performance of my Spring app? 38
  39. 39. Influencing caching 39 @Controller @Template(title="Text", id="myModule:components/text") public class TextComponent { ! @RequestMapping("/text") public String render(HttpResponse response) { response.setHeader("Cache-Control", "no-cache"); return "components/text.jsp"; } }
  40. 40. How can I present dialogs in different languages using Blossom? 40
  41. 41. ! @Controller @Template(title = "Text", id = "blossomSampleModule:components/text") @I18nBasename("info.magnolia.blossom.sample.messages") public class TextComponent { ! @TabFactory("textComponent.contentTab.label") public void contentTab(UiConfig cfg, TabBuilder tab) { tab.fields( cfg.fields.text("heading").label("textComponent.contentTab.heading") ); } } 41I18n Blossom Dialog
  42. 42. ! ! /info/magnolia/blossom/sample/messages_en.properties textComponent.contentTab.label = Content textComponent.contentTab.heading = Heading ! ! ! /info/magnolia/blossom/sample/messages_sv.properties textComponent.contentTab.label = Innehåll textComponent.contentTab.heading = Rubrik ! 42I18n Blossom Dialog
  43. 43. How do I migrate my existing site to Magnolia/ Blossom? 43
  44. 44. How can I integrate Spring Security? 44
  45. 45. 45
  46. 46. How can I dependency inject spring beans into RenderingModels? 46
  47. 47. Autowired RenderingModel public class MyRenderingModel extends RenderingModelImpl<TemplateDefinition> { ! @Autowired private MyService service; ! public MyRenderingModel(ServletContext servletContext, Node content, TemplateDefinition definition, RenderingModel<?> p super(content, definition, parent); WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(servletContext); AutowireCapableBeanFactory beanFactory = wac.getAutowireCapableBeanFactory(); beanFactory.autowireBean(this); } 47
  48. 48. Autowired RenderingModel ! public class MyRenderingModel extends AbstractAutowiredRenderingModel<TemplateDefinition> { ! @Autowired private MyService service; ! public MyRenderingModel(ServletContext servletContext, Node content, TemplateDefinition definition, RenderingModel<?> super(content, definition, parent, servletContext); } ! ! ! ! 48
  49. 49. Views 49
  50. 50. Rendering an Area FreeMarker [@cms.area name="main" /] ! JSP <cms:area name="main" /> 50
  51. 51. Rendering Components in an Area FreeMarker [#list components as component]    [@cms.component content=component /] [/#list] ! JSP <c:forEach items="${components}" var="component">
    <cms:component content="${component}" />
 </c:forEach> 51
  52. 52. Page Template Availability @Controller
 @Template(title="Article", id="myModule:/pages/article")
 public class ArticleTemplate {    ...    @Available
    public boolean isAvailable(Node node) {
        return node.getPath().startsWith("/articles/");
    } } 52
  53. 53. Available Components @Controller @Area("promos") @AvailableComponentClasses({TextComponent.class,                            ShoppingCartComponent.class}) public static class PromosArea {    @RequestMapping("/main/promos")    public String render() {        return "areas/promos";    } } 53
  54. 54. Area Inheritance @Controller @Area("promos") @Inherits @AvailableComponentClasses({TextComponent.class,                            ShoppingCartComponent.class}) public static class PromosArea {    @RequestMapping("/main/promos")    public String render() {        return "areas/promos";    } } 54
  55. 55. Form Submission /* Standard annotations omitted */ public class ContactFormComponent {
 @RequestMapping(value="/contact", method=RequestMethod.GET)
  public String viewForm(@ModelAttribute ContactForm contactForm) {
 return "components/contactForm"; } @RequestMapping(value="/contact", method=RequestMethod.POST)
 public String handleSubmit(@ModelAttribute ContactForm contactForm, BindingResult result) { new ContactFormValidator().validate(contactForm, result); if (result.hasErrors()) { return "components/contactForm";
 } return "redirect:/home/contact/thankyou.html"; }
 55
  56. 56. But wait a minute … 56 Caused by: org.springframework.web.util.NestedServletException: Reques at org.springframework.web.servlet.FrameworkServlet.processRequest( at org.springframework.web.servlet.FrameworkServlet.doGet(Framewor at javax.servlet.http.HttpServlet.service(HttpServlet.java:617) at info.magnolia.module.blossom.render.BlossomDispatcherServlet.forw at info.magnolia.module.blossom.render.BlossomTemplateRenderer.ren ... 92 more Caused by: java.lang.IllegalStateException at org.apache.catalina.connector.ResponseFacade.sendRedirect(Respons … the response has been sent.
  57. 57. Controller Pre-execution 57 C M V PAGE C M V Area C M V Component C M V Component C M V Component C
  58. 58. CPE Implementation 58 Code in View <form> <blossom:pecid-input /> <input type=”text” name=”email” /> ... ! HTML Output <form> <input type=”hidden” name=”_pecid” value=”ff6cefa6-d958-47b1-af70-c82a414f17e1” /> <input type=”text” name=”email” /> ...
  59. 59. Spring Web MVC + Content 59
  60. 60. Spring Web Flow 60 REQUEST LANDING PAGE SPRING WEB FLOW
  61. 61. Spring Web Flow 61 REQUEST LANDING PAGE FORM SUBMIT? SPRING WEB FLOW
  62. 62. 62 Trademarks Other trademarks are the property of their respective owners. Magnolia The Pulse are trademarks of Magnolia International Limited.}

×