An Alfresco Developer’s Challenge and Journey

Alfresco is a very flexible content-platform in general. It provides mechanisms to customize almost every component (Spring-Bean, Webscript, Templates) shipped with the core product.

Still, sometimes the technical solution does not prove to be even close to what the developer had in mind. This post is about a recent personal challenge and the journey to the solution in an Alfresco Share customization project targeting version 3.4.

Business Requirements

The project consisted of various stories. One was about customization of the Share invitation email with the following requirements:

  • As a Site-Manager, we want an optional personal message to be included in the invitation-email.
  • As a Site-Manager, we want to receive invitee read-receipts for invitation-emails
  • As a Site-Manager, we want the company logo to appear in the invitation email.

The customer was fairly pragmatic – requirements implemented quickly and decently priced being far more important than educational value of the code. Hence, it was ok to apply these customizations on a global level – to all share sites with no further scoping. That all sounded reasonably to me and I was confident to get it implemented “properly”.

The project was of type fixed-scope and fixed-price. A No-Go due to Heisenberg’s uncertainty principle – sure, but there was no way around.

Now, if you are an Alfresco developer reading this, please take a minute virtually outlining your solution and make a rough effort estimation before proceeding with solution journey on the next page. But even if you have no clue what Alfresco is, it might be worth reading further.

Seiten: 1 2

Andreas Steffan
Pragmatic ? Scientist and DevOps Mind @ Contentreich. Believes in Open Source, the Open Web and Linux. Freelancing in DevOps-, Cloud-, Kubernetes, JVM- and Contentland and speaks Clojure, Kotlin, Groovy, Go, Python, JavaScript, Java, Alfresco and WordPress. Built infrastructure before it was cool. ❤️ Emacs.

8 thoughts on “An Alfresco Developer’s Challenge and Journey”

  1. Hi Andreas,
    mmmh – really dirty, isn’t it?
    modifying the processsdefinition is OK, but why didn’t you add a tiny Javascript extension to replace org.alfresco.repo.site.script.Site.inviteNominated?

  2. Hi Jan,

    I tried to make clear that the solution introduced may not be the most beautiful one in the world and I’m not proud of it.

    org.alfresco.repo.site.script.Site.inviteNominated calls

    public NominatedInvitation inviteNominated(
    String inviteeUserName,
    Invitation.ResourceType resourceType,
    String resourceName,
    String inviteeRole,
    String serverPath,
    String acceptUrl,
    String rejectUrl) ;

    defined by InvitationService (interface) implemented in InvitationServiceImpl. Parameters semantics look fairly strict to me and I don’t see a clean way to get the additional information through here.

    Or are you suggesting to bypass InvitationService ?

  3. Hi,
    no, not bypassing:
    1.) custom JS extension with a method appropriate to your parameters & calls CustomSiteServiceImpl (= bean siteService)
    2) CustomSiteService extentends SiteServiceImpl & declares custom inviteNom­i­nated method
    3.) CustomSiteServiceImpl extends SiteServiceImpl, implements CustomSiteService with implemented custom invitation logic…

  4. Ok, but providing a custom inviteNom­i­nated method effectively bypasses declarations of the interface, right ?

    That would have been fine with me in this case – Javascript does not care about interfaces anyways. I even considered doing this in the beginning.

    Abondoned the idea because I felt bypassing an interface is ugly and confusing. :) Besides the method doing the heavy-lifting in InvitationServiceImpl (as shipped) is

    private NominatedInvitation startNominatedInvite(…)

    It has almost the same parameters as inviteNominated and rougly 250 LOC, so this class does not really make a good candidate for subclassing.

    That was the time I concluded it would be overall easier and safer to abuse a String parameter. :) I chose acceptUrl because I was fairly sure, its only purpose is to get rendered into the email.

    Either way, at this point you are only half way down the rabbit-hole, you still have to pass the BPM layer, render the mail text, and set headers and content-type.

    Thanks for commenting.

  5. Nice exposé about the drawbacks of a pretty hard-set/-coded interface and workflow. This reminds me of the efforts that we once had to put into adding custom permissions to an Alfresco system, restricting what kind of site roles could invite other users using role-based restricted lists of invitee roles to choose from.

    Considering the project parameters you explained I find it an acceptable solution. In terms of using the acceptUrl as your “transport medium” I would tend towards using the transaction context instead (AlfrescoTransactionSupport instead of the mentioned ThreadLocal).

    I personally do not like custom extensions of Alfresco services as I have seen too many examples that violate internal service contracts. Facading in combination with transaction context data or implementing a contributable patch to the OOTB service are my preferred options. In terms of the InvitationService I could see a simple API extension which would allow passing of a custom data / property map, provide a “map-to-workflow mapper strategy” and a “mail / notification action” extension point (delegating based on site type / state evaluators).

  6. Thanks for your feedback, Axel.

    Funny, it reminds you of security related efforts you had. I am right now facing requirements to extend the Share Site security model. :)

    For the particular case of the InvitationService, it might indeed make sense to widen the tight interface we have today and work out a longer term solution. But an approach like that is of course not feasible in most real world projects.

    Honestly – the more I think about it, the more I realize that “hacks” in general (i.e. not only in Alfresco environments) are actually fairly common. Truth is, that I am now exercising all kinds of nasty Javascript while implementing the new security requirements.

    In the end, I guess a big share of these problems boils down to the nature of the tools we are given – the Java type system, accessibility modifiers (private, package, final) and so on. For me, these tend to get in the way quite often. That is why I like “tools” such as dynamically typed languages in customization projects.

    Maybe I’ll start a “best hacks” or “worst practice” post series. ;)

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert