AEM CQ5 passing SlingHttpServletRequest Object to a service - osgi

I am trying to pass SlingRequest object from a component jsp to a osgi service as follows. But the service is not getting registered. (not sure why?)
<c:set var="inverterData" value='<%=sling.getService(InverterFactory.class).getOverview(slingRequest, resourceResolver)%>' scope="request" />
Question : Is it allowed to pass a SlingRequest object from a component jsp to a osgi service ? If it is allowed, why my service not getting registered. If I take out SlingRequest object, the service is getting registered and I am able to call the service from jsp.

including your OOTB /libs/foundation/global.jsp makes you to get the default tag libs, sling objects and CQ objects defined.
when you pass the fully qualified name of the service to sling.getService method, SlingRepository gets injected into service by the OSGi bundle managed component.
In your code snippet sling.getService(InverterFactory.class) the service is obtained from the sling SlingScriptHelper object to retrieve OSGi services available in Sling, and this generally will be called on the interface. After your creation of a Service object by using sling.getService, you can invoke any methods exposed by that service.
Have a look at the ScriptHelper api documentation and sling scripting variables
try code snippet below
<% your.qualified.path.InverterFactory Invfac = sling.getService(your.qualified.path.InverterFactory.class); %>
<c:set var="inverterData" value='<%=Invfac.getOverview(slingRequest, resourceResolver)%>' scope="request" />
also i don't think SlingRequest object should cause any problem, i have tried your code snippet syntax and just returned some string from OSGI service, it works fine. Below is my example
HelloService Interface
public interface HelloService {
public String getRepositoryName();
public String getRepositoryName(SlingHttpServletRequest slingRequest, ResourceResolver resourceResolver);
}
HelloServiceImpl
#Service
#Component(metatype = false)
public class HelloServiceImpl implements HelloService {
protected final Logger log = LoggerFactory.getLogger(this.getClass());
#Reference
private SlingRepository repository;
public String getRepositoryName() {
return repository.getDescriptor(Repository.REP_NAME_DESC);
}
public String getRepositoryName(SlingHttpServletRequest slingRequest, ResourceResolver resourceResolver) {
log.info("*** Inside my interface impl OSGI ***");
String returnstr = repository.getDescriptor(Repository.REP_NAME_DESC)+" Data from OSGI";
//return repository.getDescriptor(Repository.REP_NAME_DESC);
return returnstr;
}
}
OSGICalling.jsp
<%# page import="com.mycompany.myrestservice.HelloService" %>
<%
com.mycompany.myrestservice.HelloService hs = sling.getService(com.mycompany.myrestservice.HelloService.class);
String repo = hs.getRepositoryName() ;
out.println("myrepo::" + repo);
%>
<c:set var="inverteraa" value='<%=sling.getService(com.mycompany.myrestservice.HelloService.class).getRepositoryName(slingRequest,resourceResolver)%>' />
<c:out value="${inverteraa}"/>
OutPut

Related

How can I put an instance of an object as session attribute in a Spring MVC project?

I am working on a Spring MVC application and I have the following problem.
I have this RegistrazioneInfo class that contains some information inserted into a form by the user:
public class RegistrazioneInfo {
#NotNull
#Size(min=16, max=16)
private String codiceFiscale;
String gRecaptchaResponse;
public String getCodiceFiscale() {
return codiceFiscale;
}
public void setCodiceFiscale(String codiceFiscale) {
this.codiceFiscale = codiceFiscale;
}
public String getgRecaptchaResponse() {
return gRecaptchaResponse;
}
public void setgRecaptchaResponse(String gRecaptchaResponse) {
this.gRecaptchaResponse = gRecaptchaResponse;
}
}
Then I have this controller class:
#Controller
public class RegistrazioneController extends BaseController {
private RegistrazioneInfo registrazioneInfo;
...............................................
...............................................
...............................................
}
that contains some methods handling request towards some resources.
Ok, my problem is that I want to use an instance of the previous RegistrazioneInfo class as session attribute by the use of the #SessionAttributes Spring annotation as shown here: http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/mvc.html#mvc-ann-sessionattrib
My problem is, in the previous example do something like this:
#SessionAttributes("pet")
public class EditPetForm {
// ...
}
So what exactly is pet? I think that it is something like an id that identify the object that have to be used as a session attribute or something like this. How can I say to put an instance of my RegistrazioneInfo as session attribute?
#SessionAttributes is declared in a Controller Class (#Controller), so on the class level.
Pet is an Bean Object that persist in HttpSession
From the documentation:
This will typically list the names of model attributes which should be transparently stored in the session or some conversational storage, serving as form-backing beans. Declared at the type level, applying to the model attributes that the annotated handler class operates on.
(emphasis is mine)
Also note that, as indicated in the documentation, you should not use that for "non temporary" elements.

AEM:OSGI sling service activate method not being executed

I am trying to create a very basic sling service in AEM:
package com.mypackage;
/**
* A simple service interface
*/
public interface TestService {
/**
* #return the name of the underlying JCR repository implementation
*/
public String getPropertyName();
}
The implementation class:
package com.mymypackage.impl;
import javax.jcr.Repository;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.jcr.api.SlingRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.mypackage.TestService;
#Component(label = "Title", description = "Description.", immediate = true, metatype = true, policy = ConfigurationPolicy.REQUIRE)
#Service(value = {TestService.class})
#Properties({
#Property(name = "propertyPath", label = "Property Label", description = "Property Desc.")
})
public class TestServiceImpl implements TestService {
private static final Logger log = LoggerFactory.getLogger(TestServiceImpl.class);
String propertyPath = null;
#Activate
public void activate(ComponentContext ctx) {
Dictionary properties = ctx.getProperties();
String propertyPath =(String)properties.get("propertyPath");
log.info("====================getPropertyName activate========================"+propertyPath);
this.propertyPath = propertyPath;
}
#Override
public String getPropertyName() {
// TODO Auto-generated method stub
log.info("====================getPropertyName========================"+propertyPath);
return propertyPath;
}
}
and I have created a node of type sling:OsgiConfig inside the config folder. The name of this node is com.mypackage.impl.TestServiceImpl.xml and are the content of it:
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="sling:OsgiConfig"
propertyPath="http://www.myuhc.com"/>
and this is how I am trying to use it inside a Java class:
public static String getTestService() {
TestService testService = new TestServiceImpl();
String prop = testService.getPropertyName();
return prop;
}
This method is being called from a JSP using customtaglib (method being mapped through a .tld file)
When I use this approach the activate method inside the HelloServiceImpl class is not called and hence the property is not set. But when I use the service inside a component JSP like this:
<%#page import="org.osgi.service.cm.ConfigurationAdmin"%>
<%#page import="org.osgi.service.cm.Configuration"%>
<%
Configuration conf = sling.getService(org.osgi.service.cm.ConfigurationAdmin.class).getConfiguration("Name of the config");
String myProp = (String) conf.getProperties().get("property key");
%>
everything works fine. There is something really wrong I must be doing while trying to call the service from a Java class. How can I use that approach. I don't want to use scriptlet inside JSP. Also, any best practices would be highly appreciated.
Thanks in advance
OSGi Services work within a life cycle which manages the creation and deletion of the Service instances.
As part of the container management of these instances, when the container creates the instance it calls the activation method with the appropriate values. So that the property can be assigned.
What you are doing in your first code snippet:
TestService testService = new TestServiceImpl();
String prop = testService.getPropertyName();
Is not using the containers version of your component. Your using the direct implementation and bypassing the container management.
To use the instance that is managed by the container. You need to request it from the container.
Which is exactly what your second snippet shows
sling.getService(org.osgi.service.cm.ConfigurationAdmin.class)
Is requesting the best matching service from the container.
To access a service from the container. You either need to be a Service yourself. Which you can do by the #Reference annotation.
You mentioned however being in a taglib which makes things a bit more complicated. You need to obtain a reference to the SlingScriptHelper which can be obtained from the pageContext like this;
ServletRequest request = pageContext.getRequest();
final SlingBindings bindings = (SlingBindings) request
.getAttribute(SlingBindings.class.getName());
final SlingScriptHelper scriptHelper = bindings.getSling();
TestService service= scriptHelper
.getService(com.mymypackage.impl.TestService.class);
The problem is, that sometimes when you try to re-install a bundle, some old compiled classess are not removed and replaced with a new one. Try to remove the /var/classes and/or /var/clientlibs nodes and re-install your projects.
This may also be useful, if you are unable to use #Reference annotation for injecting your service
// get the TestServiceImpl.java service component
TestServiceImpl testService = getSlingScriptHelper().getService(TestServiceImpl.class);
//com.adobe.cq.sightly.WCMUsePojo.getSlingScriptHelper()

jsf converter loses injected property

I had this working before, but then I changed some things, and I can't get it to work again. I am trying to use my service tier to hit the database and get a correct object from my converter class, depending on what the user clicks. I inject the service property into my converter with spring. During debugging, I can see that the property gets sets properly. But then when I go to call getService, it is null.
#FacesConverter("PlaceConverter")
#SessionScoped
public class PlaceConverter implements Converter {
private SearchQueryService searchQueryService;
/**
* #return the searchQueryService
*/
public SearchQueryService getSearchQueryService() {
return searchQueryService;
}
/**
* #param searchQueryService the searchQueryService to set
*/
public void setSearchQueryService(SearchQueryService searchQueryService) {
this.searchQueryService = searchQueryService;
}
#Override
public Object getAsObject(FacesContext arg0, UIComponent arg1, String submittedValue) {
try {
Criteria criteria = new Criteria();
criteria.setId(Integer.parseInt(submittedValue));
return getSearchQueryService().findPlaces(criteria).get(0);
} catch (NumberFormatException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
#Override
public String getAsString(FacesContext arg0, UIComponent arg1, Object value) {
((Place) value).setCategory(" (" + ((Place) value).getCategory() + ")");
return String.valueOf(((Place) value).getPlaceId());
}
}
<bean id="placeConverterBean" class="com.ghghg.converter.PlaceConverter">
<property name="searchQueryService" ref="searchQueryServiceBean" />
</bean>
Dependency injection in a converter works only if the converter is declared as a managed bean by the dependency injection framework in question. E.g. JSF's own #ManagedBean, or CDI's #Named, or Spring's #Component. You should remove the #FacesConverter altogether and reference the converter instance in EL scope instead of referencing it by the converter ID.
Thus, so
<h:inputXxx converter="#{placeConverter}" />
or
<f:converter binding="#{placeConverter}" />
instead of
<h:inputXxx converter="PlaceConverter" />
or
<f:converter converterId="PlaceConverter" />
Your concrete problem suggests that you were referencing it by converter ID (thus, via #FacesConverter). This way you end up getting a converter instance without any injected dependencies.
See also:
How to inject Spring bean into JSF converter
As to the role of the converter itself, this is mandatory because HTML code is represented as one large string and HTTP request parameter values can only be represented as strings. Complex Java objects would otherwise be printed via Object#toString() like so com.example.Place#hashcode, making it unusable in the server side.
I found a better way, and probably more proper way to do get what I wanted. I was not completely sure how the converter works and how the value of the selected item gets passed back to the managed bean. I just declared a new Place object in my method, set the required values. Then I saw that it got passed to my managed bean
I got it to work like this in java EE with jsf 2.0. By making the converter a member of the backing bean. I instantiate this member using CDI but it should work the same with spring.
First the backing bean:
#ViewScoped
#ManagedBean
public class SomeView implements Serializable {
private static final long serialVersionUID = 1L;
#Inject
private SomeConverter converter;
public Converter getConverter() {
return converter;
}
}
And then this is the jsf xhtml:
<p:selectOneMenu id="someId" value="#{someView.value}" converter="#{someView.converter}">
<f:selectItems value="#{someView.values}" var="object" itemLabel="#{object.name}" />
</p:selectOneMenu>
Converter comes to play before updating your model bean. When user fill some input and this value is transferred to server first are updated your server side components and next conversion has happened. Converted values as saved in your bean (with method getAsObject) and before rendering the view values from beans are again converted to String because from user side everything is a string (then method getAsString is invoked).
In summary - Converter methods are the best place to change user input into your application logic, bean fields and in other way to convert your logic, bean fields into user friendly strings.
Due to your question and problem. You mean that SearchQueryService isn't available inside getAsObject method. Try to add an addnotation #Resource with proper name attribute and then it should be injected by your container.

Using session attributes in spring MVC

I am developing a web application using spring MVC. I just want a simple example of how to do session management in this. I have seen lot of forums but I am not able to get a clear picture of this
My requirement is
I have an object, which I would like to be accessible in all controllers and JSP's I
would like to set that in the controller and get that in JSP
I am looking for something like
Session.setAtribute();
Could you please let me know a very simple instance . Thank you
There are different ways of accessing servlet session in Spring MVC. But I think this one is the one that best suits your problem. You can create a session scoped bean, which holds your desired info:
#Component("myObjectHolder")
#Scope(WebApplicationContext.SCOPE_SESSION)
public class MyObjectHolderImpl implements MyObjectHolder {
private long userId;
private String username;
private Theme theme;
// Getters & Setter
}
Then, you can access to it from other beans:
#Controller
public class MyController {
#Autowired private MyObjectHolder myObjectHolder;
#RequestMapping
public ModelAndView switchTheme(String themeId) {
...
Theme newTheme = themeService.get(themeId);
myObjectHolder.setTheme(newTheme);
...
}
}
You can access directly from your view too, but you must configure it:
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
...
<property name="exposedContextBeanNames" value="myObjectHolder" />
</bean>
And in your JSP:
Hi ${myObjectHolder.username}, you switched
application theme to ${myObjectHolder.theme.name}
The simplest approach is to access HttpSession directly by injecting it into your handler method:
#RequestMapping("/page")
public ModelAndView page(HttpSession session) {
session.getAttribute("foo");
}

Proper way to pass config properties loaded by Spring to JSF world

I have a duplicated configuration file under WEB-INF directory, called configDEV.properties and configPRO.properties (one for development environment, and the other for production environment).
I load the proper file thanks to these Spring declaration and this Tomcat launch parameter:
<context:property-placeholder
location="WEB-INF/config${project.environment}.properties" />
-Dproject.environment=PRO
(or –Dproject.environment=DEV)
Then, in a servlet listener (called StartListener) I do the following, in order to allow JSF to access these properties, in the managed beans, and in the jsp views. (In concrete, we are going to play with a property called cfg.skin.richSelector).
public class StartListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent sce) {
//Environment properties
Map<String, String> vblesEntorno = System.getenv();
//Project properties
String entorno = vblesEntorno.get("project.environment");
String ficheroPropiedades = "/WEB-INF/config" + entorno + ".properties";
try {
Properties props = new Properties();
props.load(sc.getResourceAsStream(ficheroPropiedades));
setSkinRichSelector(sc, props.getProperty("cfg.skin.richSelector"));
} catch (Exception e) {
//...
}
}
private void setSkinRichSelector(ServletContext sc, String skinRichSelector) {
sc.setInitParameter("cfg.skin.richSelector", skinRichSelector);
}
public void contextDestroyed(ServletContextEvent sce) {}
}
In a JSF managed bean:
public class ThemeSwitcher implements Serializable {
private boolean richSelector;
public ThemeSwitcher() {
richSelector = Boolean.parseBoolean(
FacesContext.getCurrentInstance().getExternalContext().getInitParameter("cfg.skin.richSelector"));
if (richSelector) {
//do A
} else {
//do B
}
}
//getters & setters
}
In a xhtml page:
<c:choose>
<c:when test="#{themeSwitcher.richSelector}">
<ui:include src="/app/comun/includes/themeSwitcherRich.xhtml"/>
</c:when>
<c:otherwise>
<ui:include src="/app/comun/includes/themeSwitcher.xhtml"/>
</c:otherwise>
</c:choose>
All of this WORKS OK, but I want to ask the experts if it is the most suitable way to do that, or if this could be simplified in some way???
Thanks in advance for your hints and advices
It depends on which version of Spring you are using. If it happens to be newest Spring 3.1, you can take advantage of #Profile:
Springsource Blog
Springsource reference
Leave the property-placeholder in your applicationContext.xml if you are using it in your spring beans.
Configure a context init param in your web.xml like this:
<context-param>
<param-name>envProp</param-name>
<param-value>${project.environment}</param-value>
</context-param>
Also move the properties file under some package in your classpath (Note: Due to this change you need to locate the resource in the application context using classpath*: prefix)
and then you can load the bundle in your JSF page like this:
<f:loadBundle basename="com.examples.config#{initParam['envProp']}" var="msgs"/>
and use something like this:
<h:outputText value="#{msgs.cfg.skin.richSelector}" />
But instead of setting the system property like this configure ProjectStage via JNDI as mentioned by Ryan Lubke in his blog so that you can use the same property even for javax.faces.PROJECT_STAGE context parameter.

Resources