alfresco from an agile framework perspective

37
Alfresco from an agile framework perspective Jeff Potts [email protected]

Upload: jeff-potts

Post on 08-May-2015

2.912 views

Category:

Technology


2 download

DESCRIPTION

This is a presentation I gave at Alfresco DevCon 2010 in the Best Practices track. It covers patterns of Alfresco customization, compares Spring Surf to agile application development frameworks like Django, and provides best practices and advice around developing Share customizations.

TRANSCRIPT

Page 1: Alfresco from an agile framework perspective

Alfresco from an agile framework perspectiveJeff Potts

[email protected]

Page 2: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Agenda

• Patterns of Alfresco Customization• A Tale of Two Frameworks: Surf vs. Django• Heavy Share Customization: A real-world example• Conclusions & Advice

Page 3: Alfresco from an agile framework perspective

PATTERNS OF ALFRESCO CUSTOMIZATION

Page 4: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Custom Alfresco Patterns

• Non-Alfresco framework on top of Alfresco

• Surf on top of Alfresco• Light Share Customizations• Heavy Share Customizations

• Patterns we aren’t going to talk about:– Explorer client customizations– Portal integration– Embedded Alfresco

Source: thomas hawk

Page 5: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Non-Alfresco Framework

Source: Optaros

+

Page 6: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Surf on Alfresco

Source: Optaros

Page 7: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Light Share Customizations

Page 8: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Heavy Share Customizations

Page 9: Alfresco from an agile framework perspective

A TALE OF TWO FRAMEWORKS

Page 10: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Surf or Something Else?

• Share is a popular, extensible client with a great UI

• When Share is too much or too far from your business requirements…– Which framework on top of

Alfresco?– An experiment…

Source: irargerich

Page 11: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

A word on agile frameworks

• Agile frameworks and scripting languages are very popular

• Examples: Rails, Grails, Django, Wicket, Symfony, Cake, etc.

• Productive, fast dev cycles• Built-in Bootstrapping, ORM, MVC,

tests/fixtures, administrative UI’s• Hundreds available across every

language imaginable• Can be trendy, like frozen yogurt

Source: mswine

Page 12: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Common requirements

• Let content authors create "chunks" and upload files

• Chunks and files get tagged and categorized• Not all objects have files--the UI can't freak out

when it comes across "content-less" objects• Front-end web site needs to be able to query for

chunks, files, and content-less objects• The front-end web site cannot look like Share

– Our users aren't teams– They don't care about “document libraries”

Page 13: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

A simple example: To Do

• Basic requirements– End users create/manage to do list items– To do list items are tagged– End users can upload documents related to To Do’s

• Extended requirements– Certain categories of To Do Lists have associated

content chunks that need to be displayed.• Example: To do list that is categorized as "Writing"

should display with content chunks that give advice on writing.

– Groupings of To Do lists• Friends/Co-workers• Projects, etc.

– RSS feeds

Page 14: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Approaches

• To Do’s, Users, and Files are objects.• I’ll map URLs to various views on those

objects.• I’ll probably use a relational database to

persist everything except the files, which I’ll let my framework handle.

• Files are documents. That’s easy.• To Do’s are “content-less” objects.• I need to figure out a folder for all of this

stuff to live in and how I want to relate To Do’s to files.

• I’ll map URLs to various views which will request data from the repository via REST.

Page 15: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Five-minute look at Django

• Creating a new Django app• Defining a content model• Creating a template• Model View Controller• Using the admin site to edit

object instances

Source: William Gottlieb

Fun Django Facts:•Started as an internal project in 2003 at the Journal-World newspaper (Lawrence, KS)•Named after jazz guitarist, Django Reinhardt•The Onion recently migrated to Django from Drupal

Fun Django Facts:•Started as an internal project in 2003 at the Journal-World newspaper (Lawrence, KS)•Named after jazz guitarist, Django Reinhardt•The Onion recently migrated to Django from Drupal

Page 16: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Model

from django.db import modelsfrom django.contrib.auth.models import Userfrom datetime import date, datetime

class ToDoItem(models.Model): title = models.CharField(max_length=200) dueDate = models.DateField(default=date.today()) priority = models.IntegerField(default=3) status = models.TextField() notes = models.TextField() createdDate = models.DateTimeField(default=datetime.today()) creator = models.ForeignKey(User, related_name='todo_creator') assignee = models.ForeignKey(User, null=True, blank=True, related_name='todo_assignee') #attachments = Document # Array of CMIS documents def __unicode__(self): return self.title

class Tag(models.Model): name = models.CharField(max_length=64, unique=True) toDoItems = models.ManyToManyField(ToDoItem) def __unicode__(self): return self.name

from django.db import modelsfrom django.contrib.auth.models import Userfrom datetime import date, datetime

class ToDoItem(models.Model): title = models.CharField(max_length=200) dueDate = models.DateField(default=date.today()) priority = models.IntegerField(default=3) status = models.TextField() notes = models.TextField() createdDate = models.DateTimeField(default=datetime.today()) creator = models.ForeignKey(User, related_name='todo_creator') assignee = models.ForeignKey(User, null=True, blank=True, related_name='todo_assignee') #attachments = Document # Array of CMIS documents def __unicode__(self): return self.title

class Tag(models.Model): name = models.CharField(max_length=64, unique=True) toDoItems = models.ManyToManyField(ToDoItem) def __unicode__(self): return self.name

models.py

Page 17: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

URLs map to Viewsurlpatterns = patterns('', (r'^admin/', include(admin.site.urls)), (r'^$', main_page), (r'^user/(\w+)/$', user_page), (r'^login/$', 'django.contrib.auth.views.login'), (r'^logout/$', logout_page), (r'^register/$', register_page), (r'^register/success/$', direct_to_template, {'template': 'registration/register_success.html'}), (r'^create/$', todo_create_page), (r'^save/(\d+)/$', todo_save_page), (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': site_media}), (r'^tag/([^\s]+)/$', tag_page), (r'^tag/$', tag_cloud_page),)

urlpatterns = patterns('', (r'^admin/', include(admin.site.urls)), (r'^$', main_page), (r'^user/(\w+)/$', user_page), (r'^login/$', 'django.contrib.auth.views.login'), (r'^logout/$', logout_page), (r'^register/$', register_page), (r'^register/success/$', direct_to_template, {'template': 'registration/register_success.html'}), (r'^create/$', todo_create_page), (r'^save/(\d+)/$', todo_save_page), (r'^site_media/(?P<path>.*)$', 'django.views.static.serve', {'document_root': site_media}), (r'^tag/([^\s]+)/$', tag_page), (r'^tag/$', tag_cloud_page),)

settings.py

def user_page(request, username): user = get_object_or_404(User, username=username) todos = user.todo_assignee.order_by('-id') variables = RequestContext(request, { 'username': username, 'todos': todos, 'show_tags': True, 'show_assignee': False, 'show_creator': True, 'show_edit': username == request.user.username, }) return render_to_response( 'user_page.html', variables )

def user_page(request, username): user = get_object_or_404(User, username=username) todos = user.todo_assignee.order_by('-id') variables = RequestContext(request, { 'username': username, 'todos': todos, 'show_tags': True, 'show_assignee': False, 'show_creator': True, 'show_edit': username == request.user.username, }) return render_to_response( 'user_page.html', variables )

views.py

Page 18: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

<html> <head> <title>Django To Do's | {% block title %}{% endblock %}</title> <link rel="stylesheet" href="/site_media/style.css" type="text/css" /> </head> <body> <div id="nav"> <a href="/">home</a> {% if user.is_authenticated %} welcome, <a href="/user/{{ user.username }}/">{{ user.username }}</a>! | <a href="/create/">new to do</a> | <a href="/logout">logout</a> {% else %} <a href="/login/">login</a> <a href="/register/">register</a> {% endif %} </div> <h1>{% block head %}{% endblock %}</h1> {% block content %}{% endblock %} </body></html>

<html> <head> <title>Django To Do's | {% block title %}{% endblock %}</title> <link rel="stylesheet" href="/site_media/style.css" type="text/css" /> </head> <body> <div id="nav"> <a href="/">home</a> {% if user.is_authenticated %} welcome, <a href="/user/{{ user.username }}/">{{ user.username }}</a>! | <a href="/create/">new to do</a> | <a href="/logout">logout</a> {% else %} <a href="/login/">login</a> <a href="/register/">register</a> {% endif %} </div> <h1>{% block head %}{% endblock %}</h1> {% block content %}{% endblock %} </body></html>

base.html

{% extends "base.html" %}{% block title %}{{ username }}{% endblock %}{% block head %}To Do's for {{ username }}{% endblock %}{% block content %} {% include "todo_list.html" %}{% endblock %}

{% extends "base.html" %}{% block title %}{{ username }}{% endblock %}{% block head %}To Do's for {{ username }}{% endblock %}{% block content %} {% include "todo_list.html" %}{% endblock %}

user_page.html {% if todos %} <ul class="todos"> {% for todo in todos %} <li> <a href="/todo/{{ todo.id }}" class="title">{{ todo.title }}</a> {% if show_edit %} …

{% if todos %} <ul class="todos"> {% for todo in todos %} <li> <a href="/todo/{{ todo.id }}" class="title">{{ todo.title }}</a> {% if show_edit %} …

todo_list.html

Template Inheritance

Page 19: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Alfresco approach

• Content Consumer UI– Custom Surf pages/templates/components for the "front-end"

user interface• Administrative UI

– Lightly-customized Alfresco Share• Data Persistence

– Custom content model for properties, associations (To Do data list happens to already exist)

– Document library for files and content chunks– Data List objects for To Do items– Rule on a folder to add taggable and classifiable aspects to

new objects

Page 20: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Alfresco approach

• Business Logic– Share web scripts to generate UI and handle form

posts– Repo web scripts to handle JSON POSTs that

create new data (file upload, new to do)– Repo web scripts to handle GETs that retrieve

existing data (chunks for a given category, to do list info)

– JavaScript for all web-tier and repo-tier web script controllers (fast dev, cuts down on restarts)

Page 21: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Demo: A tale of two frameworks

• Share site• Data list content model• Surf pages & web

scripts (XML, FreeMarker, JavaScript)

• Repository web scripts (minimal)

• Surf config– Alfresco user factory

• Share config (minimal)

• RDB back-end– Schema managed by

Django• Python classes

– Model– Controllers (“Views”)– Forms

• URL mapping• Admin UI

Page 22: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Work Remaining

• Add file upload to both Django and Alfresco To Do’s– Django has a File type– Django supports custom File Managers (Hello,

CMIS!)– Refactor django-alfresco to use CMIS; e.g.,

CmisDocument type• Add “categorizable chunk” to both• Search• Friends list

Source: jphilipg

Page 23: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Comparison

• Both have decent tooling– pydev for Django– Eclipse/STS, Roo, Maven, Ant

for Alfresco• Model, forms, query much easier

in Django• “Learning where stuff goes”

– Much faster in Django• Surf documentation is “still

evolving”

Source: TheBusyBrain

To Do Demo App

Alfresco Django

Number of files 75 23Alfresco # of Files by Type

Django # of Files by Type

Page 24: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Comparison (cont’d)

• Gotchas– Lack of query-able associations

in DM repo was painful– Add user to Share site on user

registration post– Create a rule on the data list

folder to set owner– Keep track of assignee

add/remove

• Attempt to simplify actually made Surf site harder– Forms without JavaScript– No pickers– Not fully leveraging Alfresco’s

form service

Source: automania

To Do Demo Alfresco Django

Lines of Code 1,578 674

Alfresco LOC by Type

Django LOC by Type

Page 25: Alfresco from an agile framework perspective

HEAVY SHARE CUSTOMIZATION

Page 26: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

A real-world example

• SaaS platform wants a community site with resources their customers need to leverage the platform better

• Content chunks & files• Discussion threads, blogs• Everything tagged against multiple taxonomies• Consumer UI• Content Management / Admin UI

Page 27: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Architecture

Lightly customized Share

Admin UI Consumer UIHeavily

customized Share

•Content Model•Behaviors•Rules•Web Scripts

•Theme•YUI•Form Service•Web Scripts

Content Managers Community Users

Page 28: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Data Model

Global Share Site

Client Share Sites

Project Share Sites

Users & Groups

Client ID on cm:user

One group per client

Client Data List

Snippets & Resources

Categories

Categories for products, topics, processes

Project Data List

Client Logos

Process State Data List

User-uploaded Content

Share Site HierarchyAdmin Data

Team Data List

Page 29: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Content Consumer UI

Page 30: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Content Chunks

Page 31: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

File Resources

Page 32: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Page 33: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Administrative UI

Page 34: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Customization by the Numbers

t = 17,153 lines t = 6,552 lines

t = 192,925 lines t = 118,586 lines

Share LOC Share JS

CustomizationLOC

CustomizationJS

Page 35: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Conclusions & Advice

• Use JavaScript controllers• Turn on Share client debug• Develop on two Tomcats• Don’t deploy to Share as a JAR• Incorporate minification into your build up-

front• Learn something about YUI, JavaScript

closures• Extend, override, augment. Replace as last

resort• Actions, Behaviors, & Form Filters are your

friends

Source: hiram_college

Helpful tools:•curl•Firebug•Tamper Data•www.jsonlint.com•Rhino command-line

Helpful tools:•curl•Firebug•Tamper Data•www.jsonlint.com•Rhino command-line

Page 36: Alfresco from an agile framework perspective

© Copyright 2010, Metaversant Group, Inc. | http://www.metaversant.com

Get Involved!

• Apache Chemistry - http://incubator.apache.org/chemistry/

– OpenCMIS– cmislib– PHP CMIS Client

• Django Framework– http://www.djangoproject.com/– Django 1.0 Web Site Development (Packt), Ayman Hourieh

• django-alfresco on Google Code (non-CMIS)– http://code.google.com/p/django-alfresco/

• Drupal CMIS Module– http://drupal.org/project/cmis

• Spring Surf– http://www.springsurf.org

Page 37: Alfresco from an agile framework perspective

THANK YOU!Tweet me with questions/feedback @jeffpotts01

Get up to speed and stay informed with Alfresco news, tips, & tutorials!