Grails service ->java.lang.NullPointerException: Cannot invoke method serviceMethod() on null object - grails

I have Class in src/groovy . I want to use my service here . but error occurred "No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here ". i try to debug but not able to find . can you please help me that what is my mistake .
class ListenerSession implements HttpSessionListener {
def transactionService = new TransactionService ()
public ListenerSession() {
}
public void sessionCreated(HttpSessionEvent sessionEvent){
}
public void sessionDestroyed(HttpSessionEvent sessionEvent) {
HttpSession session = sessionEvent.getSession();
User user=session["user"]
if(user){
try{
java.util.Date date = session['loginDate']
transactionService.updateUserLastLogin(user,date)
-----}catch (Exception e) {
println e
}
code in service is:
def updateUserLastLogin(User user,Date date){
try{
User.withTransaction{
println "121212"
user.lastLogin=date
user.loginDuration=new Date().time - user?.lastLogin?.time
def x=user.save()
}
}catch (Exception e) {
println e
}
}

Don't instantiate services with new. If they use nearly any piece of Grails framework, that piece won't work - like GORM session in this case.
Here's an exactly your question: http://grails.1312388.n4.nabble.com/Injecting-Grails-service-into-HttpSessionListener-can-it-be-done-td1379074.html
with Burt's answer:
ApplicationContext ctx = (ApplicationContext)ServletContextHolder.
getServletContext().getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
transactionService = (TransactionService) ctx.getBean("transactionService")

Grails won't inject your service for you in the src/groovy level and just declaring a new instance of TransactionService will not give you all the goodies (hence your error). You need to get your instance form the spring context like so...
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class ListenerSession implements HttpSessionListener {
public ListenerSession() {
}
public void sessionCreated(HttpSessionEvent sessionEvent){
}
public void sessionDestroyed(HttpSessionEvent sessionEvent) {
HttpSession session = sessionEvent.getSession();
User user=session["user"]
if(user){
try{
java.util.Date date = session['loginDate']
def ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
def transactionService = ctx.transactionService
transactionService.updateUserLastLogin(user,date)
}catch (Exception e) {
println e
}
}
}
}

Related

Is it possible to log spock feature method names and clause labels?

I'd like to be able to log the spock feature names and clause labels when running some automated tests. This would help with debugging test issues when using a headless browser for automation, specifically phantomjs. Reason being, phantomjs does not always behave the same way as when using the chrome WebDriver. It would also be nice to have if this is even possible.
def "Login logout test"(){
given: "Go to login page"
...
when: "Submit username and password"
...
then: "Dashboard page displayed"
...
when: "logout"
...
then: "Returned to login page"
...
}
For example, It would be cool if I could get the above sample spock feature method to log the labels like this.
Login logout test
Go to login page
Submit username and password
logout
Returned to login page
Step1: Create a Your own spock extension Class
package com.example.spock.exetension;
public class MySpockExtension implements IGlobalExtension {
#Override
public void start() {
}
#Override
public void visitSpec(SpecInfo spec) {
spec.addListener(new MyCustomSpockRunListener());
}
#Override
public void stop() {
}
}
Step2: Create a RunListener that can listen to a spock run
package com.example.spock.exetension;
public class MyCustomSpockRunListener extends AbstractRunListener {
private boolean specFailed;
private boolean featureFailed;
#Override
public void beforeSpec(SpecInfo spec) {
// TODO Auto-generated method stub
specFailed = false;
}
#Override
public void beforeFeature(FeatureInfo feature) {
// TODO Auto-generated method stub
featureFailed = false;
}
#Override
public void beforeIteration(IterationInfo iteration) {
}
#Override
public void afterIteration(IterationInfo iteration) {
}
#Override
public void afterFeature(FeatureInfo feature) {
// TODO Auto-generated method stub
for ( BlockInfo block : feature.getBlocks() ) {
System.out.println(block.getKind().name() + " : " + block.getTexts() );
}
}
#Override
public void afterSpec(SpecInfo spec) {
// TODO Auto-generated method stub
System.out.println(spec.getName() + " : STATUS : " + specFailed != null ? "failure":"success");
}
#Override
public void error(ErrorInfo error) {
specFailed = true;
FeatureInfo feature = error.getMethod().getFeature();
if (feature != null) {
featureFailed = true;
System.out.println(error.getMethod().getName() + " : " + error.getException());
}else {
}
}
#Override
public void specSkipped(SpecInfo spec) {
}
#Override
public void featureSkipped(FeatureInfo feature) {
}
}
Step3: Register your new Spock extension
In your classpath or resource path create a below folder structure META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
Have this as the content of file com.example.spock.exetension.MySpockExtension
Step4: Run your spock test and you should see output something like this.
given: "Go to login page"
when: "Submit username and password"
then: "Dashboard page displayed"
when: "logout"
then: "Returned to login page"
Login logout test : STATUS : success
You can get the name of every feature method by following :
import spock.lang.Specification
import org.junit.Rule
import org.junit.rules.TestName
import org.slf4j.Logger
import org.slf4j.LoggerFactory
class MySpec extends Specification{
private static Logger logger = LoggerFactory.getLogger(ClassName.class)
#Rule TestName testName = new TestName()
void setup(){
def featureMethodName = testName.methodName
logger.info("feature method : " + featureMethodName)
}
}
PiggyBacking on #Raghu Kirans answer, I had to do a little bit more to get this to run the way that I wanted with Data Driven tests. In the BeforeIteration method of your RunListener I did the following:
#Override
public void beforeIteration(IterationInfo iteration) {
Optional.of(iteration)
.map(feature -> iteration.getFeature())
.map(FeatureInfo::getBlocks)
.ifPresent( blocks -> blocks.forEach(
blockInfo -> log.info(blockInfo.getKind().name() + " : " + blockInfo.getTexts())));
}
This simply prints out everything prior to each iteration. Also note that getKind().name() on the BlockInfo object does not print out the given, when, then of the spock block in our test but instead prints out SETUP, WHEN, THEN and WHERE instead. getTexts() will print out the combined texts of the block.
Example:
given: "I wake up"
and: "I drink a cup of coffee"
Will be displayed as
SETUP : ["I wake up", "I drink a cup of coffee"]
After continuously searching I found this solution for getting the test name. But can't seem to find anything on the 'when' and 'then' labels. This is okay for now.
import org.junit.Rule
import org.junit.rules.TestName
class MySpec extends Specification {
#Rule TestName name = new TestName()
def "some test"() {
expect: name.methodName == "some test"
}
}
You might want to have a look at the Spock Reports Extension

Stateless EJB not injected in message driven bean (MDB)

I have a message driven bean (MDB) that implements MessageListener and has several EJB attributes but non of them are injected so I have to inject them manually. The MDB also has a resource and a CDI bean that are injected fine.
Why the EJBs are not injected automatically? I use NotificationService EJB at other parts of the application and they are injected. Any clue about how to figure out the problem?
I don't get any error from Weblogic 12.1.3, so I can't figure out what's happening here. My code is (full of traces for debugging purposes). I've removed javadocs and method implementations that are not relevant to the problem:
#MessageDriven(name = "MailMessageConsumer", description = "JMS consumer", mappedName = MailJndiConfiguration.JNDI_QUEUE,
activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode",
propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType",
propertyValue = "javax.jms.Queue")
})
#TransactionAttribute(TransactionAttributeType.REQUIRED)
#MessageReceiver(responsibility = "Consumes JMS messages of type MailMessage")
public class MailMessageConsumer implements MessageListener {
private static final Logger log = LoggerFactory.getLogger(MailMessageConsumer.class);
#Resource
private MessageDrivenContext messageDrivenContext;
#EJB
private NotificationService notificationService;
#EJB
private MailClient mailClient;
#Inject
private ApplicationInformation applicationInformation;
#Override
public void onMessage(Message message) {
if (mailClient == null) {
log.error("mailClient object is null");
try {
log.info("Instantiating MailClient manually...");
mailClient = BeanManagerHelper.getReference(MailClient.class);
} catch (Exception e) {
log.error("Cannot instantiate MailClient manually", e);
}
}
if (notificationService == null) {
log.error("notificationService object is null");
try {
log.info("Instantiating NotificationService manually...");
notificationService = BeanManagerHelper.getReference(NotificationService.class);
} catch (Exception e) {
log.error("Cannot instantiate NotificationService manually", e);
}
}
// This never happens
if (applicationInformation == null) {
log.error("applicationInformation object is null");
}
// This never happens
if (messageDrivenContext == null) {
log.error("messageDrivenContext object is null");
}
deliverMessage(message);
}
private void deliverMessage(Message message) {
// Not important
}
private MailMessage retrieveMessage(Message message) {
// Not important
}
private void sendEmail(MailMessage mailMessage) {
// Not important
}
}
MailClient EJB:
#Stateless
#LocalBean
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Service
public class MailClient {
private static final Logger logger = LoggerFactory.getLogger(MailClient.class);
#Resource(mappedName = MailJndiConfiguration.JNDI_MAIL_SESSION)
private Session mailSession;
#EJB
private NotificationService notificationService;
#Inject
private ApplicationInformation applicationInformation;
enum ValidationError {
NULL_OBJECT("Mail message is null"),
CONTENT_TYPE_EMPTY("Content type not initialized"),
BODY_EMPTY("Message body content is empty");
private static final String ERROR_MESSAGE_PREFIX = "Invalid mail message: ";
private String message = ERROR_MESSAGE_PREFIX;
ValidationError(String message) {
this.message += message;
}
public String getMessage() {
return message;
}
}
public void sendMail(MailMessage mailMessage) throws MailMessageSendingException {
// Not important
}
}
NotificationService EJB:
#Stateless
#LocalBean
#TransactionAttribute(TransactionAttributeType.MANDATORY)
#Service
public class NotificationService {
private static final Logger logger = LoggerFactory.getLogger(NotificationService.class);
#PersistenceContext(unitName = "myEntityManager")
private EntityManager entityManager;
#EJB
private NotificationPendingMessageValidator notificationPendingMessageValidator;
#EJB
private NotificationFinder notificationFinder;
#Inject
private ApplicationInformation applicationInformation;
public NotificationPendingMessageEntity saveNotificationMessageForDeferredMail(NotificationPendingMessageEntity notificationPendingMessageEntity) throws ValidationException {
// Not important
}
public List<NotificationPendingMessageEntity> findNotificationPendingMessageEntities(TimeSlot timeSlot) {
// Not important
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public NotificationMailEntity createNewMailEntity() {
// Not important
}
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void updateMailEntity(NotificationMailEntity mailEntity) {
// Not important
}
public void createNotificationMessageProcessedEntity(NotificationProcessedMessageEntity notificationProcessedMessageEntity) {
// Not important
}
public void removeNotificationMessagePendingEntity(NotificationPendingMessageEntity notificationPendingMessageEntity) {
// Not important
}
public void reportMailFailure(NotificationMailEntity mailEntity, String failureNotice) {
// Not important
}
}
Using #Inject for injecting the EJBs instead of #EJB annotation works fine. So there should be a problem with some Weblogic's patches, because testing it in another Weblogic (same version, different patches) it worked as well

Inject services to src/groovy in Grails 3.0.9

I am trying to create an EndPoint file. So I created a file with name ServerEndPointDemo.groovy
package com.akiong
import grails.util.Environment
import grails.util.Holders
import javax.servlet.ServletContext
import javax.servlet.ServletContextEvent
import javax.servlet.ServletContextListener
import javax.servlet.annotation.WebListener
import javax.websocket.EndpointConfig
import javax.websocket.OnClose
import javax.websocket.OnError
import javax.websocket.OnMessage
import javax.websocket.OnOpen
import javax.websocket.Session
import javax.websocket.server.PathParam
import javax.websocket.server.ServerContainer
import javax.websocket.server.ServerEndpoint
import javax.websocket.EncodeException
import javax.servlet.annotation.WebListener
import java.util.concurrent.CopyOnWriteArraySet
#WebListener
#ServerEndpoint(value="/chat/test/{username}")
public class ServerEndPointDemo implements ServletContextListener {
private static HashMap<String, String> usersMap = new HashMap<String, String>();
private static final Set<ServerEndPointDemo> connections = new CopyOnWriteArraySet<>();
private String username
private Session session
#OnOpen
public void handleOpen(Session session,#PathParam("username") String user){
System.out.println("-------------------------------------");
System.out.println(session.getId() + " has opened a connection");
println "user = "+user
connections.add(this);
this.username = user
this.session = session
addUserToMap(username,session.getId())
try{
def ctx = Holders.applicationContext
chatService = ctx.chatService
}
catch (Exception e){
println "e = "+e
}
}
#OnClose
public void handleClose(Session session){
System.out.println("Session " +session.getId()+" has ended");
}
#OnMessage
public String handleMessage(String message,Session session){
chatService.saveSessionAdminJava(session.getId())
}
#OnError
public void handleError(Throwable t){
println "error ~"
}
private void sendMessageToAll(String message){
println "session.size() = "+sessions.size()
for(Session s : sessions){
try {
s.getBasicRemote().sendText(message);
println "sent to session = "+s.getId()
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
`
I tried to use this code for calling a method from service:
try {
def ctx = Holders.applicationContext
chatService = ctx.chatService
} catch (Exception e) {
println "e = " + e
}
This is my service:
package com.akiong.services
import com.akiong.maintenance.Chat
class ChatService {
def serviceMethod() {
}
def saveSessionAdminJava(def sessionJava) {
println "jaln!!!"
def chatInstance = Chat.findByIsAdmin("1")
chatInstance.sessionJava = sessionJava
chatInstance.save(failOnError: true)
}
}
But after I tried to run this code, I'm getting this error:
Error : groovy.lang.MissingPropertyException: No such property: chatService for
class: com.akiong.ServerEndPointDemo
Anyone know how to call a method from service to file in src/groovy?
So here is the problem. The code you written is correct for injecting service:
try {
def ctx = Holders.applicationContext
chatService = ctx.chatService
} catch (Exception e) {
println "e = "+e
}
But the chatService is not defined anywhere in your class. So even if your handleOpen method is invoked there must be MissingPropertyException being thrown but since you have handled the top level Exception class (which should never be encouraged) that exception from your handleOpen method got suppressed.
Now, later in your handleMessage method, the same problem is occurring again of chatService being undefined and hence you are getting the exception you posted in your question.
So, you know the answer now :-) Simply define the chatService in your ServerEndPointDemo class.
Update:
public class ServerEndPointDemo implements ServletContextListener {
private static HashMap<String, String> usersMap = new HashMap<String, String>();
private static final Set<ServerEndPointDemo> connections = new CopyOnWriteArraySet<>();
private String username
private Session session
def chartService // Initialize here
// rest of your code
}
import org.apache.commons.logging.LogFactory;
import org.codehaus.groovy.grails.commons.ApplicationHolder as AH
class MyClass{
private static final log = LogFactory.getLog(this)
def ctx = AH.application.mainContext
def authService=ctx.authService
def method(){
log.debug "into MyClass method"
}
}

Accessing resources in Grails Plugin

I have a Grails Plugin called 'foo' that uses another Grails Plugin called 'common'.
grails.plugin.location.'common' = "../common"
The 'common' plugin contains domain classes, as well as resource files (.properties files, xml templates, ...). These files are all located in subfolders in common/grails-app/conf/.
There's one class that implements NamespaceContext in my 'common' plugin that uses these files in order to function properly.
public class MyNamespaceContext implements NamespaceContext {
private Map<String, String> namespaces;
public MyNamespaceContext() {
final String XML_NAMESPACES_FILE = "grails-app/conf/xml/xmlNamespaces.properties";
try {
Properties xmlNamespaces = new Properties();
xmlNamespaces.load(new FileReader(XML_NAMESPACES_FILE));
namespaces = new HashMap<String, String>((Map) xmlNamespaces);
} catch (FileNotFoundException e) {
throw new RuntimeException("XML namespaces file '" + XML_NAMESPACES_FILE + "' cannot be found");
} catch (IOException e) {
throw new RuntimeException("IOException");
}
}
...
}
This class is used in several classes, also located in 'common' that form my domain model, implemented as xml decorators.
public class UserXmlDecorator implements User {
private Document xmlDocument;
private XPath xPath;
private final String rawXml;
public UserXmlDecorator(String rawXml) {
this.rawXml = rawXml;
this.xmlDocument = XmlDocumentFactory.INSTANCE.buildXmlDocumentInUTF8(rawXml);
this.xPath = XPathFactory.newInstance().newXPath();
xPath.setNamespaceContext(new MyNamespaceContext());
}
public String getUserName() {
try {
XPathExpression userNameXPathExpr = xPath.compile("...");
String userName = userNameXPathExpr.evaluate(appendixBXmlDocument);
return userName;
} catch (XPathExpressionException e) {
throw new RuntimeException();
}
}
public String getAge() {
try {
XPathExpression ageXPathExpr = xPath.compile("...");
String age = ageXPathExpr.evaluate(appendixBXmlDocument);
return age;
} catch (XPathExpressionException e) {
throw new RuntimeException();
}
}
When creating these decorators in my Grails Plugin 'foo', I get a FileNotFound exception, because it is looking for the template in foo/grails-app/conf/xml/xmlNamespaces.properties, instead of common/grails-app/conf/xml/xmlNamespaces.properties.
I've read
Grails: How to reference a resource located inside an installed plugin? but this could not help me.
Any idea how I can solve this?
Solved this by putting the .properties file in the classpath instead of the conf/ directory and then using the classloader to lod the resource.
xmlNamespaces.load(this.getClass().getClassLoader().getResourceAsStream(XML_NAMESPACES_FILE));

Guice 3.0 #ScopeSession User object not invalidate on session timeout

I have a class :
#SessionScoped
public class LoggedUser {
private User user;
...
}
that I use to keep track if a user is logged in my application.
In my Struts2 application I have a Interceptor to check if the user is logged, if not he's forwarded to the login page.
public class LoggedUserInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 2822434409188961460L;
#Inject
private LoggedUser loggedUser;
#Override
public String intercept(ActionInvocation invocation) throws Exception {
if(loggedUser==null || !loggedUser.isLogged()){
return "login";
}
return invocation.invoke();
}
}
The problem occur when the session timeout. The object LoggdeUser is never null or deleted. I have always the last instance.
I added A session listener.
public class SessionListener implements HttpSessionListener {
private static Logger logger = Logger.getLogger(SessionListener.class.getName());
#Override
public void sessionCreated(HttpSessionEvent event) {
logger.info("sessionCreated = " + event.getSession().getId());
}
#Override
public void sessionDestroyed(HttpSessionEvent event) {
logger.info("sessionDestroyed = " + event.getSession().getId());
}
}
I see that sessionDestroyed is called, but when I enter again in my Interceptor.. LoggedUser is never recreated for a new session.
why ?
my Struts2 Action for the login is this
public class LoginUserAction extends ActionSupport implements ModelDriven<LoggedUser>, ServletRequestAware {
...
#Inject
private LoggedUser loggedUser;
public String execute() throws Exception {
...
loggerUser.setLoggedTime(now);
...
return SUCCESS;
}
I add that too in web.xml
session-config
session-timeout 2 /session-timeout
/session-config
I don't know anything about Struts2, but my guess is that the interceptor's scope is wider than session scope. In other words, the interceptor instance is kept around longer than the session. Guice can't and won't set an injected field to null when the session ends, nor will it ever re-inject an object automatically.
What you need to do if you use an object with a shorter lifecycle inside an object with a longer lifecycle (such as a RequestScoped object inside a SessionScoped object or a SessionScoped object inside a singleton) is inject a Provider for the shorter lived object.
In your case, I think this is probably what you need:
public class LoggedUserInterceptor extends AbstractInterceptor {
private static final long serialVersionUID = 2822434409188961460L;
#Inject
private Provider<LoggedUser> loggedUserProvider;
#Override
public String intercept(ActionInvocation invocation) throws Exception {
LoggedUser loggedUser = loggedUserProvider.get();
if(loggedUser==null || !loggedUser.isLogged()){
return "login";
}
return invocation.invoke();
}
}
I don't know guice but the session is available to the interceptor and can be made readily available to the action via SessionAware :
ActionInvocation provides access to the session. The following is part of a "Authentication" interceptor. If there is not a "User" object then Action.LOGIN is returned.
public String intercept(ActionInvocation invocation) throws Exception {
Map session = invocation.getInvocationContext().getSession();
appLayer.User user = (appLayer.User) session.get("User");
if (user == null){
return Action.LOGIN;
}
return invocation.invoke();
}
I only place the user object on the session when the user logs in.
In the login action I place the user object on the session:
public class Login extends ActionSupport implements SessionAware {
private Map<String, Object> session;
private String userName;
private String password;
public String execute() {
//use DB authentication once this works
//if ("ken".equalsIgnoreCase(userName) && "ken".equalsIgnoreCase(password)){
try {
User user = new User(userName, password);
session.put("User", user);
return ActionSupport.SUCCESS;
} catch (Exception e) {
System.out.println("There was an exception" + e.getMessage());
return ActionSupport.LOGIN;
}
}
public void validate() {
String user = this.getUserName();
String pass = this.getPassword();
//This block is a bit redundant but I couldn't figure out how
//to get just the hibernate part to report an exception on Username/pass
if (!StringUtils.isBlank(this.getUserName()) && !StringUtils.isBlank(this.getPassword())) {
try {
Class.forName("com.ibm.as400.access.AS400JDBCDriver").newInstance();
String url = "jdbc:as400://192.168.1.14";
DriverManager.getConnection(url, user, pass).close();
} catch (Exception e) {
addFieldError("login.error.authenticate", "Bad Username / Password");
}
}
if (StringUtils.isBlank(getUserName())) {
addFieldError("login.error.name", "Missing User Name");
}
if (StringUtils.isBlank(getPassword())) {
addFieldError("login.error.password", "Missing Password");
}
//else both are blank don't report an error at this time
}
... getters/setters....
}//end class
If I remember correctly this comes from at least in part from "Struts2 in Action". Anyways I'm a big believer in DI but since the Session is pretty accessible from the interceptors and the action I don't bother.
the easiest way to do that is finally to put the token in the session at the login and check it with an Interceptor
#Override
public String intercept(ActionInvocation invocation) throws Exception {
loggedUser = (LoggedUser) invocation.getInvocationContext().getSession().get(LoggedUser.SESSIONTOKEN);
if(loggedUser==null || !loggedUser.isLogged()){
logger.info("loggedUser not present in session");
return "login";
}
return invocation.invoke();
}
in the Action
request.getSession().setAttribute(LoggedUser.SESSIONTOKEN, loggedUser);

Resources