Skip to content

Commit

Permalink
Merge branch 'release/5.0.0-RELEASE'
Browse files Browse the repository at this point in the history
  • Loading branch information
dgradecak committed Nov 24, 2017
2 parents 1bfd0df + 5e0b63b commit 4991494
Show file tree
Hide file tree
Showing 116 changed files with 2,774 additions and 1,543 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ deployment
local
.idea
*iml
*.log
*.log
*.log.*
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ recommend that a file or class name and description of purpose be included on
the same "printed page" as the copyright notice for easier identification within
third-party archives.

Copyright [yyyy] [name of copyright owner]
Copyright [2010] [Pleo Soft d.o.o of copyright owner]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
273 changes: 138 additions & 135 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,147 +1,140 @@
alfresco @mvc
====
Personally I do not like webscripts because of the boilerplate code that comes with them (XML, FTL, Java/Javascript). Also I am not a big fan of javascript on the server side
as in a medium sized application that becomes unmaintainable. That is why I wrote Alfresco @MVC.

This small library enables the usage of Spring @MVC within Alfresco. Instead of writing webscripts and all the glue configuration that goes with that, you can simply write Springframework
Controllers, Services/Components, ... with Spring annotations.
since Alfresco MVC 5.0.0
---
- a new project structure is created
- no alfresco modules are registered when the jar/amp files are deployed
- include samples
- include a deployable alfresco project (alfresco-mvc-samples-bom/alfresco-5.2.e). You need to configure the database and alf_data
- an AMP artifact can be build from the source code (mvn clean package). You will find it under alfresco-mvc-dist/target. However, it is better to include the dependencies in your build

This library is deployed as an alfresco module (jar packaged) and offers some out of the box configurations for webscript bindings. The entry endpoint is bydefault /mvc only if the DispatcherWebscript
is configured as follows.
Personally I do not like webscripts because of the boilerplate code that comes with them (XML, FTL, Java/Javascript). Also I am not a big fan of javascript on the server side as in a medium sized application that becomes unmaintainable. That is why I wrote Alfresco @MVC.

Alfresco @MVC consist of several libraries, REST, AOP, QueryTemplate. REST and AOP have no third party dependencies, where QueryTemplate do have.

@EnableAlfrescoMvcProxy (latest on dev)
---
might be used in the DispatcherWebscript child context, or in the alfresco module context Java configurations in order to benefit of the same services in different behaviors or so.
This annotation takes care to register a single AutowiredAnnotationBeanPostProcessor and a PackageAutoProxyCreator for each configured package
Alfresco-MVC REST
===
This small library enables the usage of Spring @MVC within Alfresco. Instead of writing webscripts and all the glue configuration that goes with that, you can simply write Springframework Controllers, Services/Components, ... with Spring annotations.

in the module-context.xml add these two lines
```
<bean class="org.springframework.context.annotation.ConfigurationClassPostProcessor" />
<bean class="your.module.ModuleConfig" />
```
@Controller
@RequestMapping("/document")
public class DocumentController {
in the ModuleConfig class
@Autowired
private SomeService service;
@RequestMapping(value = "{id}", method = { RequestMethod.GET })
@ResponseBody
public ResponseEntity<?> index(@@PathVariable Long id) {
// yes this works in Alfresco
return new ResponseEntity<?>(service.get(id), HttpStatus.OK);
}
}
```
@Configuration
@ComponentScan(basePackageClasses = YourServiceClass.class )
@EnableAlfrescoMvcProxy(basePackageClasses = YourServiceClass.class )
public class ModuleConfig {

@Autowired
ListableBeanFactory beanFactory; // just as example
This library offers some out of the box configurations for webscript descriptor bindings. The entry endpoint is by default /alfresco/service/mvc only if the DispatcherWebscript is configured with bean names as follows: "webscript.alfresco-mvc.mvc.post", "webscript.alfresco-mvc.mvc.get", "webscript.alfresco-mvc.mvc.delete", "webscript.alfresco-mvc.mvc.put"

otherwise you are free to create your own webscript descriptors and configure the beans correctly.


A DispatcherWebscript can be connfigured :

with a servlet-conext.xml file
---
```
<bean id="webscript.alfresco-mvc.mvc.post" class="com.gradecak.alfresco.mvc.webscript.DispatcherWebscript" parent="webscript">
<property name="contextConfigLocation" value="classpath:alfresco/module/YOUR_MODULE/context/servlet-context.xml" />
</bean>
<alias name="webscript.alfresco-mvc.mvc.post" alias="webscript.alfresco-mvc.mvc.get" />
```

with Java config
---
```
@Bean(name = { "webscript.alfresco-mvc.mvc.post", "webscript.alfresco-mvc.mvc.get", "webscript.alfresco-mvc.mvc.delete", "webscript.alfresco-mvc.mvc.put" })
public DispatcherWebscript dispatcherWebscript() {
DispatcherWebscript dispatcherWebscript = new DispatcherWebscript();
dispatcherWebscript.setContextClass(org.springframework.web.context.support.AnnotationConfigWebApplicationContext.class);
dispatcherWebscript.setContextConfigLocation(AlfrescoMvcHateoasConfig.class.getName());
return dispatcherWebscript;
}
}
```
note that the DispatcherWebscript also takes its own Java config context


Old XML fashion
---

AlfrescoMvcHateoasConfig has to be a spring' @Configuration class and please note the contextClass property should be AnnotationConfigWebApplicationContext
```
<bean id="webscript.alfresco-mvc.mvc.post" class="com.gradecak.alfresco.mvc.webscript.DispatcherWebscript" parent="webscript">
<property name="contextConfigLocation" value="classpath:alfresco/module/YOUR-MODULE/context/servlet-context.xml" />
</bean>
@Configuration
@ComponentScan(basePackageClasses = { "...controller" })
@EnableWebMvc
public class AlfrescoMvcHateoasConfig {
...
}
```

Surely, you can configure any other webscript descriptor.
=> The library is mainly used on the alfresco repository side, but is also suitable for alfresco share.

in the servlet-context you can simply use
```
<mvc:annotation-driven />
<bean id="my.autowiredProcessor" class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor" />
```

another utility in order to auto proxy all your services and add the 3 spring AOP interceptors would be (check the type="annotation" in component scanning)
Alfresco-MVC AOP
===
Enables a couple of useful annotations on the alfresco repository side.

```
<context:component-scan base-package="com.gradecak.alfresco.sample.service" annotation-config="false">
<context:include-filter expression="org.springframework.stereotype.Service" type="annotation" />
</context:component-scan>
@AlfrescoAuthentication
---
used on a service method to indicate what type of authentication is allowed, same usage as in the webscript decriptor <authentication>user</authentication>.
Four possibilities are NONE, GUEST, USER, ADMIN as defined in the AuthenticationType enum. Defaults to USER

<bean id="my.services" class="com.gradecak.alfresco.mvc.aop.PackageAutoProxyCreator">
<property name="basePackage" value="com.gradecak.alfresco.sample.service" />
</bean>
```

Spring MVC Controllers
@AlfrescoRunAs
---
allows with a simple annotation to use the runas mechanism of alfresco. The value has to be a static string with the username.

those are enabled through the DispatcherWebscript and have to be configured with @ComponentScan or <context:component-scan base-package="..." annotation-config="false">
@AlfrescoTransaction
---
this one uses the RetryingTansaction in order to avoid to write all lines for a RetryingTransactionCallback, Params: readOnly defaults to true and
propagation defaults to org.springframework.transaction.annotation.Propagation.REQUIRED

Configuration:

XML
---
```
@Controller
@RequestMapping("/document/**")
public class DocumentController {
@Autowired
private CoreDocumentService coreDocumentService;
<context:component-scan base-package="com.gradecak.alfresco.mvc.sample.service">
<context:include-filter expression="org.springframework.stereotype.Service" type="annotation" />
</context:component-scan>
@RequestMapping(value = "sample", method = { RequestMethod.POST, RequestMethod.GET })
@ResponseBody
public Map<String, Object> index(@RequestBody final Document content) {
// yes this works in Alfresco
coreDocumentService.get(...)
}
}
<bean class="com.gradecak.alfresco.mvc.aop.PackageAutoProxyCreator">
<property name="basePackage" value="com.gradecak.alfresco.mvc.sample.service" />
</bean>
```

Java Config
---
```
@ComponentScan(basePackageClasses = { "com.gradecak.alfresco.mvc.sample.service" })
@EnableAlfrescoMvcProxy(basePackageClasses = { "com.gradecak.alfresco.mvc.sample.service" })
```
@Service
public class CoreDocumentService {
@Autowired
private ServiceRegistry serviceRegistry;
@Autowired
private QueryTemplate queryTemplate;
@AlfrescoTransaction(readOnly = true)
public <T> T get(NodePropertiesMapper<T> nodeMapper, final NodeRef nodeRef) {
return queryTemplate.queryForObject(nodeRef, nodeMapper);
}
}
```

The invoke URL for the above sample would be:
- http://localhost:8080/share/proxy/alfresco/mvc/document/sample
- http://localhost:8080/localhost/alfresco/service/mvc/document/sample

for more information please check: com.gradecak.alfresco.mvc.sample.controller.DocumentController

Autowiring of Alfresco and custom dependencies is enabled and thus you may finally have a rapid development with Alfresco.
EnableAlfrescoMvcProxy or PackageAutoProxyCreator will auto create spring's proxies for all the classes in the specified package in order to apply the advices

Json is my preferable way to use for Alfresco integrations and some helpers are also provided (can be seen in the sample application). On the other hand Springframework content negotiation resolver could be use in order to allow different kind of responses.
Notice
-
Some issues while using CMIS were spotted if the services are registered via @ComponentScan and used in alfresco behaviors, therefore for now it is recommended to use the xml or java (@Bean) config for service scanning only. This is due to the lifecycle of spring's loading of beans.

A very useful class in this library is com.gradecak.alfresco.mvc.Query. It allows to write alfresco lucene/solr queries in a much simpler way.

New things in 4
---
- deprecated JsonUtils in the Alfresco @MVC package
- NodePropertiesMapper introduced another parameter, which is the NodeRef of the node and therefore any kind of manipulation in the mapper is possible
- EnableAlfrescoMvcProxy annotation
- old Jackson classes removed
There is a spring proxy limitation (spring 3.2.x) in order to use @Autowired on constructors, therefore @Autowired for now should be used on fields. This is due to how CGLIB creates the proxies (a default constructor is needed)

Alfresco-MVC QUERY TEMPLATE
===
Inspired by spring's jdbc/rest templates this is a very useful way of writing alfresco lucene/solr queries (not canned queries). Has a dependencies on Spring Data Commons.
The QueryTemplate class is thread safe and it is advised to use it as singleton.

```
Query query = new Query().path("some path").and().type(Qname).or()...
String q = query.toString();
new Query().type(Qname).or().property(Qname).and(...)...
```

Mapping to POJO
There is also a mapper mechanism that allows mapping to POJO classes
```
public class DocumentNodeMapper implements NodePropertiesMapper<Document> {
private final ServiceRegistry serviceRegistry;
public DocumentPropertiesMapper(final ServiceRegistry serviceRegistry) {
public DocumentNodeMapper(final ServiceRegistry serviceRegistry) {
this.serviceRegistry = serviceRegistry;
}
Expand All @@ -158,60 +151,70 @@ public class DocumentNodeMapper implements NodePropertiesMapper<Document> {
return doc;
}
}
```
The mapper is used in querying with com.gradecak.alfresco.mvc.mapper.QueryTemplate
```
Document document = new QueryTemplate(serviceRegistry).queryForObject(ref, new DocumentNodeMapper(serviceRegistry));
```
```
Document document = new QueryTemplate(serviceRegistry).queryForObject(NodeRef, new DocumentNodeMapper(serviceRegistry));
List<Document> documentList = new QueryTemplate(serviceRegistry).queryForList(new Query().type(ContentModel.TYPE_CONTENT), new DocumentNodeMapper(serviceRegistry));
```

Annotations (AOP Advices/Spring interceptors)
----
there are 3 annotations that come with this library.

- @AlfrescoAuthentication
used on a service method to indicate what type of authentication is allowed, same usage as in the webscript decriptor <authentication>user</authentication>.
Four possibilities are NONE, GUEST, USER, ADMIN as defined in the AuthenticationType enum. Defaults to USER
- @AlfrescoRunAs
allows with a simple annotation to use the runas mechanism of alfresco. The value has to be a static string with the username.
- @AlfrescoTransaction
this one uses the RetryingTansaction in order to avoid to write all lines for a RetryingTransactionCallback, Params: readOnly defaults to true and
propagation defaults to org.springframework.transaction.annotation.Propagation.REQUIRED


There is more things to add, so TBC ...

Alfresco versions
Supported Alfresco versions
----
- Works on Enterprise as well as on community.
- Tested with Alfresco Community 3.4.d, 4.0.x, 4.2.x, 5.0.a, 5.0.d, 5.1.e, 5.2.f
- Tested with Alfresco Enterprise 3.4.5, 4.1.5, 4.2.1, 5.1.x, 5.2.x
- Tested with Alfresco Community 3.4.d, 4.0.x, 4.2.x, 5.0.a, 5.0.d, 5.1.e, 5.2.f, 5.2.g (might work with older version, if not please check previous releases/snapshots)
- Tested with Alfresco Enterprise 3.4.5, 4.1.5, 4.2.1, 5.1.x, 5.2.x (might work with older version, if not please check previous releases/snapshots)

Distribution (TODO as it is not yet inline with the latests @MVC library)
Sample Applications
----
Alfresco @MVC comes with a sample application: https://github.com/dgradecak/alfresco-mvc-sample
and is distributed as an AMP packed in a JAR file.
Alfresco @MVC comes with a couple of sample applications that are located in /alfresco-mvc-samples-bom

- alfresco-mvc-rest-sample => http://localhost:8080/alfresco/service/mvc/rest/sample
- alfresco-mvc-aop-sample => http://localhost:8080/alfresco/service/mvc/aop/sample
- alfresco-mvc-querytemplate-sample => http://localhost:8080/alfresco/service/mvc/querytemplate/sample
http://localhost:8080/alfresco/service/mvc/querytemplate/search (search engine has to be enabled)

alfresco-mvc-querytemplate-sample is the most complete sample that reassemble all the features of Alfresco @MVC

Maven dependency:
----
Latest snapshot version:
```
<dependency>
<groupId>com.gradecak.alfresco</groupId>
<artifactId>alfresco-mvc</artifactId>
<version>5.0.0-SNAPSHOT</version>
</dependency>
Latest snapshot version comes with a BOM:
```
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.gradecak.alfresco-mvc</groupId>
<artifactId>alfresco-mvc-bom</artifactId>
<version>5.0.1-SNAPSHOT</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependency>
<groupId>com.gradecak.alfresco-mvc</groupId>
<artifactId>alfresco-mvc-rest</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.gradecak.alfresco-mvc</groupId>
<artifactId>alfresco-mvc-aop</artifactId>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.gradecak.alfresco-mvc</groupId>
<artifactId>alfresco-mvc-querytemplate</artifactId>
<scope>compile</scope>
</dependency>
```

Latest release version:
```
<dependency>
<groupId>com.gradecak.alfresco</groupId>
<artifactId>alfresco-mvc</artifactId>
<version>4.5.0-RELEASE</version>
<version>5.0.0-RELEASE</version>
</dependency>
```

Expand Down
Loading

0 comments on commit 4991494

Please sign in to comment.