Date post: | 13-Jul-2015 |
Category: |
Technology |
Upload: | yuval-ararat |
View: | 864 times |
Download: | 3 times |
INTEGRATION
PATTERNS IN AEMYuval Ararat
• Basics
• Sling
• Integration
• Sample
• Other resources
• Sling Models
• What do we integrate with?
– Backend API layer• SAP PI, Oracle Fusion or other middleware layer.
• Bespoke API
– DB
– File System
– Forms Engine
• First questions when arriving to the scene.
– Is it exposed to WWW?
– What authentication does the layer require?
– What can I cache?
– Protocol and output formats.
• Exposed to WWW?
– Client side integration
– Mixed integration
• Not exposed to the WWW
– Server Side
– Tunneled through
• SlingMainServlet
– Outermost Request Handler
– Starts Request Processing
• ResourceResolver
– Resolves the URL to a Resource
• ServletResolver
– Resolve the Resource Type to a Servlet/Script
• Resolve the Resource
– Source: Request URI
• Resolve Servlet or Script
– Source: Resource Type
• sling:resourceType
• sling:resourceSuperType
• Call Servlet Filters
• Call Servlet or Script
protocol host path selector extension
http:// myhost/ .print.a4 .html /tools/spy
suffix
a/b ?
param(s)
x=12
• ResourceProvider
• Sling Filter
• Custom SlingServlet
• OSGi HTTP Service
• Provides access to resources from different locations
through a single ResourceResolver
• Registered to a path in the virtual resource tree
• The last fallback is always the JCR repository
• PlanetResourceProvider Sample
• Respond with a relevant planet resource when calling
“/planets/<planet>”
https://svn.apache.org/repos/asf/sling/trunk/launchpad/test-
services/src/main/java/org/apache/sling/launchpad/testservices/resourceprovider/
@Component
@Service
@Properties({
@Property(name=ResourceProvider.ROOTS, value=PlanetsResourceProvider.ROOT)
})
public class PlanetsResourceProvider implements ResourceProvider {
private static final Map<String, ValueMap> PLANETS = new HashMap<String, ValueMap>();
/** This can be configurable of course */
public static final String ROOT = "planets";
public static final String ABS_ROOT = "/" + ROOT;
static {
definePlanet("Mercury", 57910);
definePlanet("Venus", 108200);
definePlanet("Earth", 149600).put("comment", "Resources can have different sets of properties");
definePlanet("Mars", 227940);
definePlanet("Jupiter", 4332);
definePlanet("Saturn", 10759);
definePlanet("Uranus", 30685);
definePlanet("Neptune", 60190);
// Add the moon to test a two-level hierarchy
final String moonPath = ABS_ROOT + "/earth/moon";
PLANETS.put(moonPath, new PlanetResource.PlanetValueMap("Moon", 384));
}
public Resource getResource(ResourceResolver resolver, HttpServletRequest req, String path) {
// Synthetic resource for our root, so that /planets works
if((ABS_ROOT).equals(path)) {
return new SyntheticResource(resolver, path, PlanetResource.RESOURCE_TYPE);
}
// Not root, return a Planet if we have one
final ValueMap data = PLANETS.get(path);
return data == null ? null : new PlanetResource(resolver, path, data);
}
public Iterator<Resource> listChildren(Resource parent) {
if(parent.getPath().startsWith(ABS_ROOT)) {
// Not the most efficient thing...good enough for this example
final List<Resource> kids = new ArrayList<Resource>();
for(Map.Entry<String, ValueMap> e : PLANETS.entrySet()) {
if(parent.getPath().equals(parentPath(e.getKey()))) {
kids.add(new PlanetResource(parent.getResourceResolver(), e.getKey(), e.getValue()));
}
}
return kids.iterator();
} else {
return null;
}
}
@Adaptable(adaptableClass=Resource.class, adapters={
@Adapter({ValueMap.class})
})
public class PlanetResource extends AbstractResource implements Resource {
private final String path;
private final ResourceMetadata metadata;
private final ValueMap valueMap;
private final ResourceResolver resolver;
public static final String RESOURCE_TYPE = "sling/test-services/planet";
PlanetResource(ResourceResolver resolver, String path, ValueMap valueMap) {
this.path = path;
this.valueMap = valueMap;
this.resolver = resolver;
metadata = new ResourceMetadata();
metadata.setResolutionPath(path);
}
– BundleResourceProvider provides access to files and directories
contained in an OSGi bundle
– The BundleResourceProvider is responsible for mapping the
directory tree into the resource tree
– It‘s most conveniently configured as instruction in the maven-
bundle-plugin:<configuration>
<instructions>
<Sling-Bundle-Resources>/resource/tree;path:=/bundle/tree</Sling-Bundle-Resources>
</instructions>
</configuration>
– FsResourceProvider, which is part of org.apache.sling.fsresource,
maps file system paths as resources.
– Requires installation.
– Configuration through fsresource.xml:
• provider.roots
• Provider.files
– http://sling.apache.org/documentation/bundles/accessing-filesystem-resources-
extensions-fsresource.html
• Sling Models
– Creating an adaptable class from a POJO by annotations
• Blueprints
– Dependency injection framework for OSGi
– Implementations include SpringDM (Historical) and Neba.io
• Cognifide Slice framework
– God’s speed…
• Creating an adaptable class from a POJO by annotations
– Resource resource = getResource();– Return resource.adaptTo(YourCustom.class);
– @Model(adaptables = Resource.class)– public class YourCustom {
– ...– }
• Use Sling Models for Controller or Business Logic that is “context-aware”• Use Value Map to read resource data
• http://sling.apache.org/documentation/bundles/models.html
• Use Sling Models for Dependency
Injection
– Inject Sling Context Objects via @SlingObject
– Inject AEM Context Objects via @AemObject
– Inject Business Classes via @Self
– Inject Resource Data or Parameters
• Dependencies can be mocked with tools like
Mockito@InjectMocks
• Injecting
@Model(adaptables= Resource.class) public class YourCustom{
@Inject // we expected always an email-property
private String email;
@Inject @Optional // first name can be empty
private String firstName;
// read property “surname” if empty use “empty”
@Inject @Named(“surname“) @Default(values=“empty“)
private String lastName;
}
@Model(adaptables= Resource.class)Public class YourCustom{
@Inject// OSGiServiceprivate Externalizer externalizer;
@PostConstructProtected void init() {
// gets executed after the class is created// set to protected, so it can be unit-tested
}}
@Model(adaptables= Resource.class)Public class YourCustom{
//option1@Selfprivate Resource resource;
//option2public YourCustom(Resource resource) {
// to get access to the adaptorthis.resource= resource;
}}
• Available for AEM6
– Can be installed in CQ5.6.1
– Sling Models Content Packages
– https://github.com/Adobe-Consulting-
Services/com.adobe.acs.bundles.sling-
models/releases
• What’s new in Sling Models 1.1
– http://adapt.to/2014/en/schedule/whats-new-in-sling-
models-11.html
• Recommended pattern: Controller per concern,
not per component!
• Controllers are Sling Models
• Component/View can re-use multiple controllers
• Sling Models Documentation
– http://sling.apache.org/documentation/bundles/model
s.html
• Sling Models 1.0.x Introduction by Justin Edelson
– http://slideshare.net/justinedelson/sling-models-
overview
• AEM Object Injector Implementations
– http://wcm.io/sling/models/
– http://adobe-consulting-services.github.io/acs-aem-
commons/features/aem-sling-models-injectors.html