What‘snewinApacheLenya1.4?
AndreasHartmannBeCompanyGmbH
1
Agenda
Modularization
UUIDsforinternallinks
RepositoryAPIchanges
ConfigurableMetaData
PublicationTemplating
UsecaseFramework
NotificationandInboxes
2
Modularization
3
GoalsofModularization
• ImproveSeparationofConcerns
• Reusefunctionality
• Loosecouplingoffunctionalareas
• Bettermaintainability
• Reducelearningcurve
• Easierextensibility
4
ModularizationModule
Core
API
Impl
Foo!Service!API
Default!Foo!Impl Module
AlternativeFoo!Impl
Module
Resource!Type!A
Module
Editor!XIntegration!Code
...
...
5
ModuleDeployment
cocoon.xconf
modules.root.dirs=src/modules: \ src/webapp/lenya/pubs/default/modules: \ /home/john/lenya/modules
modules.copy=false
6
DirectoryStructuremymodule/ config/ configuration files module.xml module descriptor cocoon-xconf/ patches for cocoon.xconf services.xconf sitemap/ patches for main Lenya sitemap transformers.xconf usecases/ myusecase.jx usecase view resources/ images/ image files css/ CSS files schemas/ XML schemas (RNG, XSD, ...) samples/ Samples (in case of resource type modules) java/ src/ Java source files test/ Java test classes lib/ Java libraries xslt/ XSLT stylesheets sitemap.xmap main module sitemap
7
Modularization
Descriptoroftheaccesscontrolmodule<module xmlns="http://apache.org/lenya/module/1.0"> <id>org.apache.lenya.modules.ac</id> <export package="org.apache.lenya.ac.file"/> <depends module="org.apache.lenya.modules.cache"/> <package>org.apache.lenya.modules</package> <version>0.1-dev</version> <name>Access control</name> <lenya-version>@lenya.version@</lenya-version> <description>Access control</description></module>
8
ModuleAPIModule Foo!Service!API
Default!Foo!Impl
org.project.foo.*
org.project.foo.impl.*org.project.foo.util.*org.otherproject.*
<module> ... <export package="org.project.foo"/> ...</module>
Stable
SubjecttoChange
9
ModuleDependencies
<module> <id>org.project.modules.foo</id> <export package="org.project.foo"/></module>
<module> <id>com.company.modules.bar</id> <depends module="org.project.modules.foo"/></module>
Foo
Bar
package com.company.bar;
import org.project.foo.*;import org.project.foo.impl.*;
class SomeService { ...
10
RequeststoModuleSitemaps
• cocoon://modules/foo/...
• http://.../index.html?lenya.module=foo
• http://.../modules/foo/...
• http://.../mypub/modules/foo/...
11
NextSteps
• Requirements• Easyinstallation• Hot-deployingmodules• Versioningofmodules
• Approaches• Maven• OSGi
12
UUIDsforinternallinks
13
WhatisaUUID?
• UniversallyUniqueIdentifier
• StandardizedbytheOpenSoftwareFoundation
• Canonicalform:32hexadecimaldigits550e8400-e29b-41d4-a716-446655440000
• Neglectableriskofduplicates:UUID-basedcollectionscanbecombinedwithoutproblems
14
AdvantagesofUUIDs
• SeparationofConcerns:NoduplicationofURLinformation(sitetreeanddocumentpath)
• Noneedtocopy/movefileswhenURLschange
• NoneedforlinkrewritingwhenURLschange
• Multipleviews(URLspaces)fordocumentspace
• Documentcollectionscanbecombined(import)
15
getUri()!:!StringgetPubId()!:!StringgetArea()!:!StringgetUuid()!:!StringgetLanguage()!:!String
Link
resolve(sourceDocument,!uri)!:!LinkTargetgetFallbackMode()!:!intsetFallbackMode(int)
MODE_DEFAULT_LANGUAGEMODE_FAIL
<<interface>>!LinkResolver
exists()!:!booleangetDocument()!:!documentisRevisionSpecified()!:!booleangetRevisionNumber()!:!int
LinkTarget
getLinksFrom(sourceDocument)!:!Link[]getReferencingDocuments(targetDoc)!:!Document[]
<<interface>>!LinkManager
ContentLinkManager
matches(url)!:!booleanrewrite(url)!:!String
<<interface>>!LinkRewriter
IncomingLinkRewriter
OutgoingLinkRewriter
UuidToUrlRewriter
UrlToUuidRewriter
16
LinkTransformers
• UuidToUrlTransformer• urls=absolute|relative
• ProxyTransformer
• IncomingProxyTransformer
• UrlToUuidTransformer
17
NextSteps
• MoreefficientLinkManagerimplementations• Basedonmetadata?
18
RepositoryAPIChanges
19
ContentHandlingLayers
RepositorySession
Lenya!Core
Modules
Node
MetaData
History
Publication
Area
Document
SiteStructure
SiteNodeLink
CollectionWrapper AddNewsMessage
20
<<interface>>RepositoryItem
exists()!:!booleangetContentLength()!:!longgetInputStream()!:!InputStreamgetlastModified()!:!longgetMimeType()!:!StringgetSourceURI()!:!String
<<interface>>!ContentHolder
<<interface>>!MetaDataOwner
checkin(),!checkout()lock(),!unlock()exists()!:!booleandelete()getChildren()!:!CollectiongetHistory()!:!History
<<interface>>!Node
SourceNode
JCRSourceNode
*
commit()rollback()
<<interface>>Session
21
getDocuments()!:!Document[]getDocument(uuid,!language)!:!Documentcontains(uuid,!language)!:!booleangetSite()!:!SiteStructure
<<interface>>!Area
getAreaNames()!:!String[]getArea(String)!:!Area
<<interface>>Publication
*
getUUID()!:!StringgetLanguages()!:!String[]getTranslation(String)!:!DocumentgetRepositoryNode()!:!NodegetInputStream()!:!InputStreamgetOutputStream()!:!OutputStream
<<interface>>Document
*
getNodes()!:!SiteNode[]getNode(path)!:!SiteNodegetByUuid(uuid,!language)!:!Linkcontains(path)!:!booleancontains(path,!language)!:!booleancontainsByUuid(uuid,!language)!:!booelanadd(path)!:!SiteNodeadd(path,!Document)!:!Link
<<interface>>!SiteStructure
getUuid()!:!StringgetChildren()!:!SiteNode[]hasLink(language)!:!booleangetLink(language)!:!LinkisVisible()!:!booleansetVisible(boolean)
<<interface>>!SiteNode*
getLanguage()!:!StringgetLabel()!:!StringsetLabel(String)getDocument()!:!Document
<<interface>>!Link*
0..1
22
getDocuments()!:!Document[]add(Document)remove(Document)clear()contains(Document)!:!boolean
<<interface>>!Collection
checkin(),!checkout()lock(),!unlock()exists()!:!booleandelete()getChildren()!:!CollectiongetHistory()!:!History
CollectionWrapper
getInputStream()getOutputStream()
<<interface>>Document
addNewsMessage(NewsMessage)
NewsWrapper
execute()
<<interface>>!Usecase
execute()
AddNewsMessage
23
NextSteps
• QueryablemetadataString xPath = “*[@media:width > 100]“;Query query = new XPathQuery(xPath);Document[] docs = area.getDocuments(query);
24
CodeExamplepublic void addNewsDocument(String newsPath, String uuid, String language) {
Session session = RepositoryUtil.getSession(this.manager, this.request); DocumentFactory factory = DocumentUtil.getDocumentFactory(this.manager, this.request);
String webappUrl = ServletHelper.getWebappUrl(this.request); URLInformation info = new URLInformation(webappUrl); Publication pub = factory.getPublication(info.getPublicationId());
Area authoring = pub.getArea(„authoring“); Document[] docs = authoring.getDocuments(); Document messageDoc = authoring.getDocument(uuid, language);
SiteStructure site = authoring.getSite(); SiteNode node = site.getNode(newsPath); String[] languages = node.getLanguages(); Link link = node.getLink(language); Document newsDoc = link.getDocument();
NewsWrapper newsWrapper = new NewsWrapper(newsDoc, getLogger()); wrapper.add(0, messageDoc);}
25
ConfigurableMetaData
26
getAvailableKeys()addValue(key,!value)setValue(key,!value)getValues(key)
<<interface>>MetaData
getMetaData(namespaceUri)!:!MetaDatagetMetaDataNamespaceUris()!:!String[]
<<interface>>MetaDataOwner
getNamespaceUri()!:!StringgetElements()!:!Element[]getElement(name)!:!elementcontainsElement(name)!:!boolean
<<interface>>!ElementSet
getName()!:!StringisEditable()!:!StringisMultiple()!:!StringgetActionOnCopy()!:!int
ONCOPY_COPYONCOPY_DELETEONCOPY_IGNORE
<<interface>>!Element*
*
getElementSet(namespaceUri)!:!ElementSetgetNamespaceUris()!:!String[]register(namespaceUri,!elementSet)isRegistered(namespaceUri)!:!boolean
<<interface>>!MetaDataRegistry
*
27
Meta-DataCodeExample
<meta-data> ... <component-instance name="http://apache.org/lenya/metadata/media/1.0" class="org.apache.lenya.cms.metadata.ConfigurableElementSet"> <element name="filename" multiple="false"/> <element name="width" multiple="false"/> <element name="height" multiple="false"/> </component-instance> ...</meta-data>
String mediaNamespace = "http://apache.org/lenya/metadata/media/1.0";MetaData metaData = document.getMetaData(mediaNamespace);String width = metaData.getFirstValue("width");
28
PublicationTemplating
29
University
Mat
h
LanguagesSciencePh
ysic
s
Chem
istr
y
Biol
ogy
Engl
ish
Fren
ch
Italia
n
Span
ish
30
OverridingResources
University
Physics
Science
XSLT!A XSLT!B
XSLT!B'
XSLT!B''
XSLT!A
XSLT!A
main.css head.css
main.css
main.css
head.css
head.css
@import!...
<xsl:import>
31
TemplatingAPI
visit(resolver,!sourceUri)
<<interface>>SourceVisitor
visit(publication,!publicationVisitor)visit(publication,!path,!sourceVisitor)
<<interface>>PublicationTemplateManager
visit(publication)
<<interface>>PublicationVisitor
getSource()!:!Source
<<interface>>VisitingSourceResolver
ExistingSourceResolver
instantiate(templatePub,!id,!name)
<<interface>>Instantiator
ExistingAncestorSourceResolvergetUris()!:!String[]
AllExistingSourceResolver
32
PublicationandSourceVisitors• Bottom-uptraversalofpublicationtree
• PublicationVisitorGeneralpurpose
• ExistingSourceResolver-fallback://Findfirstexistingsource
• ExistingAncestorSourceResolver-template-fallback://Findsecondexistingsource(worksonlyforleafsource!)
• AllExistingSourceResolver-aggregate-fallback://Findallexistingsources
33
UsecaseFramework
34
Usecases
• Userinteraction• Typicallyform-based• Editandmanagecontent• Interactwithotherapplications(newsletter)• Functionalityforwebsitevisitors(contactform)• ...
• Triggeredusingarequestparameter(lenya.usecase)
• Fullscreenordocument-based
35
Usecase!Handler
Sitemap!+!Flowscript
TemplateView
Controller
Model Documents,!...
Form
Documents,!...
Template
Form
continuation
vali-dation
! !
!
36
DeclaringaUsecase
<component-instance name="site.create" class="o.a.lenya.cms.site.usecases.CreateDocument">
<view template="modules/.../usecases/site/create.jx"> <parameter name=“...“ value=“...“/> </view>
<parameter name=“...“ value=“...“/> <parameter name=“...“ value=“...“/>
<transaction policy=“pessimistic“/> <exit usecase=“...“> <parameter name=“...“ value=“...“/> </exit>
</component-instance>
37
ExampleUsecase:ContactForm
AbstractUsecase
notify(recipients,!sender,!message)
<<interface>>Notifier
initParameters()checkPreconditions()advance()checkExecutionConditions()execute()checkPostconditions()
<<interface>>Usecase
ContactForm
MailNotifier SmsNotifier InboxNotifier
getUser(userId)!:!User
<<interface>>UserManager
38
NotificationandInboxes
39
notify(message)
<<interface>>Notifier
EmailNotifier
InboxNotifier
notify(message)notify(user,!translatedMessage)translateMessage(locale,!message)
AbstractNotifier
getSender()!:!IdentifiablegetSubject()!:!StringgetSubjectParameters()!:!String[]getBody()!:!StringgetBodyParameters()!:!String[]getTime()!:!Date
Message
eventFired(RepositoryEvent)
<<interface>>RepositoryListener
NotificationListener
getDescriptor()!:!Object
RepositoryEvent
Object
getMessage()!:!Message
NotificationEventDescriptor
40
CreatingaMessageUser recipient = userManager.getUser(userId);Identifiable[] recipients = { recipient }; String subject = "publish-notification";String[] subjectParams = {}; String body = "document-was-published"String[] bodyParams = { DublinCoreHelper.getTitle(document) };
Message message = new Message(subject, subjectParams, body, bodyParams, sender, recipients);
41
SendingNotificationMessages
a)Directly• Immediatenotification
b)Viarepositoryobservation• Notificationwhen(if)sessioniscommitted
NotificationUtil.notify(this.manager, message);
NotificationEventDescriptor descriptor = new NotificationEventDescriptor(message);RepositoryEvent event = RepositoryEventFactory .createEvent(this.manager, authoringDocument, getLogger(), descriptor);getSession().enqueueEvent(event);
42
InboxAPIgetInbox(User)!:!Inbox
<<interface>>InboxManager
getMessages()!:!InboxMessage[]getMessage(id)!:!InboxMessageadd(message)remove(message)
<<interface>>Inbox
getId()!:!StringgetMessage()!:!MessageisMarkedAsRead()!:!booleanmarkAsRead(boolean)
<<interface>>InboxMessage getSender()!:!Identifiable
getSubject()!:!StringgetSubjectParameters()!:!String[]getBody()!:!StringgetBodyParameters()!:!String[]getTime()!:!Date
Message*
43
ConfiguringNotification
cocoon.xconf
LenyaInbox:<component logger="lenya.notification" role="org.apache.lenya.notification.Notifier" class="org.apache.lenya.inbox.InboxNotifier"/>
E-Mail:<component logger="lenya.notification" role="org.apache.lenya.notification.Notifier" class="org.apache.lenya.notification.EmailNotifier"> <smtp host="localhost" username="john" password="..."/></component>
44
QuestionsandDiscussion
45
Recommended