Skip to content

Spring stereotype annotations for simplifying Alfresco development

License

Notifications You must be signed in to change notification settings

andreacomo/alfresco-annotations

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

42 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Alfresco Annotations

Spring stereotype annotations for simplifying development with Alfresco

Released Version

CI Health

  • master

    Build Status

  • develop

    Build Status

Why

Tired of compiling boring Spring xml for defining Alfresco beans? Always forget what's the Java-based WebScripts' naming convention or the Action Executer parent bean name? Then this project is for you!

Supported Platforms

Tested on:

  • Alfresco Community 4.2.c
  • Alfresco Community 4.2.d
  • Alfresco Community 4.2.e
  • Alfresco Community 4.2.f
  • Alfresco Community 5.0.c
  • Alfresco Community 5.0.d
  • Alfresco Community 5.1.x
  • Alfresco Community 5.2.x
  • Alfresco Enterprise 5.2.x (ACS)
  • Alfresco ACS 6.2 (Enterprise)

May works on other versions. Please edit this file and pull-request if works on other versions.

Where is the magic?

There is no magic! This project is simply a collection of Spring stereotypes annotations, some Spring lifecycle processors to do boilerplate code for you and an annotation processor to stop writing webscript xml descriptor! Just add it to your REPO project dependencies:

<dependency>
  <groupId>it.cosenonjaviste</groupId>
  <artifactId>alfresco-annotations</artifactId>
  <version>1.0.0</version>
</dependency>

enable annotation discovery by package in your module-context.xml (or any other config file you prefer):

<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="my.module.base.package" />
</beans>

and there you go! If you want annotation processor to write webscript descriptors for you, just set where to write them on Maven Compiler Plugin, for example in target folder where they are expected:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <generatedSourcesDirectory>${project.build.directory}/${project.build.finalName}/config/alfresco/extension/templates/webscripts</generatedSourcesDirectory>
    </configuration>
</plugin>

If you are using Alfresco SDK 3, destination folder (generatedSourcesDirectory) will be different and likely will be like this:

...
<generatedSourcesDirectory>${project.build.directory}/classes/alfresco/extension/templates/webscripts</generatedSourcesDirectory>
...

Annotations

Each annotation's javadoc helps you to remember which class you should or must extend, what annotation attributes you must provide and what are default values

@ActionExecuter

From

Creating a Java Action it was a matter of writing a class which extends ActionExecuterAbstractBase

public class MyAction extends ActionExecuterAbstractBase {

  @Override
  protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
    // my action code
  }

  @Override
  protected void addParameterDefinitions(List<ParameterDefinition> paramList) {

  }
}

and an xml bean declaration with parent action-executer:

<bean id="myAction"
      class="it.cosenonjaviste.annotations.MyAction"
      parent="action-executer">
    
</bean>
To

Now, just annotate your class and that's all! Forget about bean parent name, @ActionExecuter will take care of it!

@ActionExecuter("myAction")
public class MyAction extends ActionExecuterAbstractBase {

  @Override
  protected void executeImpl(Action action, NodeRef actionedUponNodeRef) {
    // my action code
  }

  @Override
  protected void addParameterDefinitions(List<ParameterDefinition> paramList) {

  }
}

And if you don't remember parent class you must extends, annotation's javadoc will remind you.

@Behaviour

From

Remembering how to register a behavior is always annoying. You have to write a class implementing one or more ClassPolicy children and register for which content type trigger it, for example:

public class MyBehavior implements NodeServicePolicies.OnUpdatePropertiesPolicy {

  private PolicyComponent policyComponent;

  public void init() {
    Behaviour onUpdateProperties = new JavaBehaviour(this, "onUpdateProperties",
            Behaviour.NotificationFrequency.TRANSACTION_COMMIT);

    this.policyComponent.bindClassBehaviour(QName.createQName(
                    NamespaceService.ALFRESCO_URI, "onUpdateProperties"), ContentModel.TYPE_CONTENT,
            this.onUpdateProperties);
  }

  @Override
  public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after) {
    // do stuff on properties update for cm:content
  }
}

Then write xml bean definition:

<bean id="myBehaviour" class="it.cosenonjaviste.annotations.MyBehavior" init-method="init">

</bean>
To

Stop remembering messy Behaviour policy registration: just annotate your bean like that:

@Behaviour(value = "myBehaviour", type = "cm:content")
public class MyBehavior implements NodeServicePolicies.OnUpdatePropertiesPolicy {

  @Override
  public void onUpdateProperties(NodeRef nodeRef, Map<QName, Serializable> before, Map<QName, Serializable> after) {
    // do stuff on properties update for cm:content
  }
}

and thre you go, ready to behave! BehaviourConfigurer will take care of registering behaviour methods to PolicyComponent.

Since Alfresco 5, you can choose to use standard annotations org.alfresco.repo.policy.annotation.Behaviour and org.alfresco.repo.policy.annotation.BehaviourBean.

@JsExtension

JavaScript API is easy and succinct in Alfresco, always powerful but sometimes not enought!

From

To plug a new feature in from Java you have to extends BaseScopableProcessorExtension or BaseProcessorExtension:

public class HelloExtension extends BaseScopableProcessorExtension {

  public String sayIt() {
    return "Hello";
  }
}

and register it in context xml file along with bean parent name baseJavaScriptExtension and providing an extensionName:

<bean id="helloExtension"
      class="it.cosenonjaviste.annotations.HelloExtension"
      parent="baseJavaScriptExtension">
    <property name="extensionName">
        <value>hello</value>
    </property>
</bean>
To

Now it's easier: annotate your bean

@JsExtension("hello")
public class HelloExtension extends BaseScopableProcessorExtension {

  public String sayIt() {
    return "Hello";
  }
}

then access your new service in JavaScript like this:

logger.log(hello.sayIt());

JsExtensionConfigurer will register bean name as Extension name.

@ModuleComponent

Module Components are special beans to be aimed at single execution for a specific AMP version, useful for initialization/update purpose.

Module Components require a bean extending AbstractModuleComponent

public class HelloComponent extends AbstractModuleComponent {

  @Override
  protected void executeInternal() throws Throwable {
    // execute on startup
  }
}

a bunch of xml configuration attributes and a bean parent module.baseComponent a such as:

<bean id="myComponent" class="it.cosenonjaviste.annotations.HelloComponent" parent="module.baseComponent">
    <property name="moduleId" value="my-module-id" />
    <property name="name" value="myComponent" />
    <property name="description" value="A description" />
    <property name="sinceVersion" value="1.0.0" />
</bean>
To

Now you can achieve all of this through annotation parameters:

@ModuleComponent(moduleId = "my-module-id", name = "myComponent", sinceVersion = "1.0.0")
public class HelloComponent extends AbstractModuleComponent {

  @Override
  protected void executeInternal() throws Throwable {
    // execute on startup
  }
}

and ModuleComponentConfigurer will set these values to bean instance.

Take care of moduleId: it must correspond to your module ID, defined by module.id property in module.properties file of your AMP. Usually corresponds to Maven artifactId.

@WebScript

WebScript are the most used feature in Alfresco, allowing access to repository feature in a RESTful way.

From

For creating a new Java-backed WebScript you can extends DeclarativeWebScript (or one of its parent)

public class MyWebScript extends DeclarativeWebScript {

  @Override
  protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
    Map<String, Object> model = new HashMap<>();
    // do stuff
    return model;
  }
}

and follow a specific naming convention along with parent bean webscript while registering on xml context file:

<bean id="webscript.it.cnj.myWebscript.post"
      class="it.cosenonjaviste.annotations.MyWebscript"
      parent="webscript">
</bean>
To

Remembering Java-backed WebScript controller naming convention is pretty boring. I'd like to set a bean name and an HTTP method to define a new WebScript such as:

@WebScript(value = "it.cnj.myWebscript", method = HttpMethod.POST)
public class MyWebScript extends DeclarativeWebScript {

  @Override
  protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
    Map<String, Object> model = new HashMap<>();
    // do stuff
    return model;
  }
}

If method is not specified, HttpMethod.GET is assumed as default.

@WebScriptDescriptor

The most annoying thing to deal with WebScripts is to write xml descriptor. If you registered <generatedSourcesDirectory> in maven-compiler-plugin, a class annotated like this:

@WebScript("myWebScript")
@WebScriptDescriptor(shortName = "my-webscript", urls = "/v1/my-webscript", format = FormatType.JSON, authentication = AuthenticationType.USER)
public class MyWebScript extends DeclarativeWebScript {

  @Override
  protected Map<String, Object> executeImpl(WebScriptRequest req, Status status, Cache cache) {
    Map<String, Object> model = new HashMap<>();
    // do stuff
    return model;
  }
}

will generate myWebScript.get.desc.xml for you at compile time through WebScriptDescriptorGenerator:

<webscript>
  <shortname>hello-again</shortname>
  <description></description>
  <url>/v1/my-webscript</url>
  <authentication>user</authentication>
  <format default="json">any</format>
</webscript>

It's up to you now to complete MVC with myWebScript.get.json.ftl file.

Right now this annotation does not support some advanced descriptor features such as family, cache, negotiate, kind and lifecycle.

About

Spring stereotype annotations for simplifying Alfresco development

Resources

License

Stars

Watchers

Forks

Packages

No packages published