I would like to instantiate a Sling Model from a JSP using a path to a resource like
<sling:adaptTo adaptable="/path/to/my/resource" adaptTo="org.apache.sling.models.it.models.MyModel" var="model"/>
Within the the Sling Model, I would like to access properties of the specified resource via #ValueMapValue annotations.
My question is, how can I adapt my Sling Model to a resource path String so that I can inject the properties of the specified resource?
The sling:getResource EL Function provided by Sling could be used in conjunction with the sling:adaptTo tag which you are endevoring to use:
<sling:adaptTo adaptable="${sling:getResource(resourceResolver,'/path/to/my/resource')}" adaptTo="org.apache.sling.models.it.models.MyModel" var="model"/>
Full documentation concerning the available tags can be found on the Sling site.
Related
I have configured my EF context configured like so
b.RegisterAssemblyTypes(webAssembly, coreAssembly)
.Where(t => t.IsAssignableTo<DbContext>())
.InstancePerLifetimeScope();
I would like to use it from a custom authorization attribute that hits the database using my EF context. This means no constructor-injection. I achieve this by using CommonSeviceLocator
var csl = new AutofacServiceLocator(container);
ServiceLocator.SetLocatorProvider(() => csl);
...
var user = await ServiceLocator.Current
.GetInstance<SiteContext>().FindAsync(id);
I am finding that this fails with a "multiple connections not supported" error if the browser issues two simultaneous requests to routes using this attribute. It seems like this might be due to what is mentioned in this answer. My guess is that ServiceLocator resolves from the root scope rather than the web request scope and the two request are conflicting (either request in isolation works fine).
This seems confirmed by that when I change to InstancePerRequest() I get this from any invocation of the attribute.
Autofac.Core.DependencyResolutionException No scope with a Tag matching 'AutofacWebRequest' is visible from the scope in which the instance was requested. This generally indicates that a component registered as per-HTTP request is
being requested by a SingleInstance() component (or a similar scenario.) Under the web integration always request dependencies from the DependencyResolver.Current or ILifetimeScopeProvider.RequestLifetime, never from the container itself.
So it seems like maybe ServiceLocator is simply not the way to go.
How do I resolve the request-scoped SiteContext from inside the attribute (using a service-locator pattern)?
Your issue derives from the fact that you are trying to put behavior inside of an Attribute. Attributes are for defining meta-data on code elements and assemblies, not for behavior.
Microsoft's marketing of Action Filter Attributes has led people implementing DI down the wrong path by putting both the Filter and the Attribute into the same class. As described in the post passive attributes, the solution is to break apart filter attributes into 2 classes:
An attribute that contains no behavior to mark code elements with meta-data.
A globally-registered filter that scans for the attribute and executes the desired behavior if present.
See the following for more examples:
Constructor Dependency Injection WebApi Attributes
Unity Inject dependencies into MVC filter class with parameters
Implementing passive attributes with dependencies that should be resolved by a DI container
Dependency Injection in Attributes: don’t do it!
Injecting dependencies into ASP.NET MVC 3 action filters. What's wrong with this approach?
How can I test for the presence of an Action Filter with constructor arguments?
Another option is to use IFilterProvider to resolve the filters as in IFilterProvider and separation of concerns.
Once you get your head around the fact that Attributes should not be doing anything themselves, using them with DI is rather straightforward.
I'm trying to understand how CQ form components works.
I see that they use a variable called 'resource' a lot. For example, in the beginning of every componenet it always goes:
final String name = FormsHelper.getParameterName(resource);
final String id = FormsHelper.getFieldId(slingRequest, resource);
final boolean required = FormsHelper.isRequired(resource);
I know that Sling treats everything as a resource. But what exactly is this specific piece of 'resource'? Where is it defined? Where does it come from? And what does it contain?
The resource variable, which is an implementation of org.apache.sling.api.resource.Resource, is an object that represents a node entity in the jcr repository, but comes with some additional convenience methods compared to e.g. lower level javax.jcr.Node object.
In this case the mentioned resource likely represents the component's resource.
To explain why sling is using the terminology Resource:
A resource is a fundamental concept in restful APIs.
Resources are typed objects with associated data, relationships to other resources and methods that operate on it.
Sling is actually a restful layer on top of a Java Content Repository.
For the sling layer the repository is a virtual tree of resources.
I highly recommend you to read the official documentation for more details on this topic https://sling.apache.org/documentation/the-sling-engine/resources.html
TLDR: How do I identify all the Synthetic resources that are defined in an AEM instance?
Issue:
I have a cq:Page named xyz under /content and a URL mapping defined in Apache Sling JCR Resource Resolver as /content/:/
Accessing the page as http://<server>:<port>/content/xyz.html or http://<server>:<port>/xyz/_jcr_content.html works fine, however accessing the same as http://<server>:<port>/xyz.html gives me 404.
Accessing the same using .json extension gives { } and using .infinity.json gives Resource not adaptable to node: /xyz (500)
Resolving the path through Sling Resource Resolver shows
SyntheticResource, type=sling:syntheticResourceProviderResource, path=/xyz and according to the Sling's Documentation accessing a Synthetic resource would result in a 404.
However the question is,
would a Synthetic resource take precedence before the URL mappings are applied?
If that is the case, then how do i identify where such a resource is defined, and what other such resources are available?
I have already gone through this similar question, however the solution provided isn't complete or rather only discusses the same things as described above.
It possible in Resteasy to extract the URI mapping to an external, dedicated file?
Annotating classes and methods is quick and easy but I would like to have a file that maps the URIs to functions. Something like:
/teams/{team}/player/{player-id} TeamResource.fetchPlayer
As far as I know this is not currently supported as part of the JAX-RS specification, but I could see you being able to do this with byte code insertion at runtime using something like javassist.
Basically you would add the #Path annotations to the your resource classes at runtime with the values loaded from your uri mapping file. Once the annotations were added to the resource you would then inject them into Resteasy.
I'm creating a Web Service with the Struts2 REST Plugin, which works great. I just have a problem with the entity names of the XML output.
I have a model class named "ModelClass" in the package "com.mycompany.implementation" with a few properties and a nested class "NestedModelClass", and the XML output looks like:
<com.mycompany.implementation.ModelClass>
...
<com.mycompany.implementation.ModelClass_-NestedModelClass>
...
</com.mycompany.implementation.ModelClass_-NestedModelClass>
</com.mycompany.implementation.ModelClass>
How can I change the XML Entity name to be displayed without package name - or even a different name?
Thanks!
The struts rest plugin uses XStream to serialize your model class to XML. Current versions of XStream support annotating classes and fields to customize the serialization. Unfortunately, the struts rest plugin uses a rather old version of XStream, ignoring those annotations.
The easiest way to get what you want is to write your own ContentTypeHandler and use that instead of the default one provided by the rest plugin. This blog describes how to do that.