Stripes ActionBean event always resolve to default event - java

I am using cleanurls formatted like /View/{arg1}/{arg2}/{$event}.
ActionBeanView has multiple events. However irrespective of which event I invoke from browser, this always gets resolved to the default event.
Any ideas what am I doing wrong (fairly new to Stripes).
Here is the error log:
11:24:18,497 DEBUG UrlBindingFactory:145 - Matched /View/myarg1/myarg2/ADD.action to [/View/{id}/{asof}/{$event}]
11:24:18,497 DEBUG ExecutionContext:150 - Transitioning to lifecycle stage Reque
stInit
11:24:18,497 DEBUG ExecutionContext:150 - Transitioning to lifecycle stage Actio
nBeanResolution
11:24:18,497 DEBUG UrlBindingFactory:145 - Matched /View/myarg1/myarg2/ADD.action to [/View/{id}/{asof}/{$event}]
11:24:18,497 DEBUG UrlBindingFactory:145 - Matched /View/myarg1/myarg2/ADD.action to [/View/{id}/{asof}/{$event}]
11:24:18,497 DEBUG ExecutionContext:150 - Transitioning to lifecycle stage Handl
erResolution
11:24:18,497 DEBUG UrlBindingFactory:145 - Matched /View/myarg1/myarg2/ADD.action to [/View/{id}/{asof}/{$event}]
11:24:18,497 DEBUG DispatcherHelper:184 - Resolved event: myDefaultEvent; will invoke:
ViewActionBean.myDefaultEvent()
11:24:18,497 DEBUG ExecutionContext:150 - Transitioning to lifecycle stage Bindi
ngAndValidation
11:24:18,497 DEBUG DefaultActionBeanPropertyBinder:453 - Running required field
validation on bean class www.ViewActionBean
11:24:18,497 DEBUG DefaultActionBeanPropertyBinder:779 - Converting 1 value(s) u
sing converter net.sourceforge.stripes.validation.StringTypeConverter
11:24:18,513 DEBUG DefaultActionBeanPropertyBinder:779 - Converting 1 value(s) u
sing converter net.sourceforge.stripes.validation.StringTypeConverter
11:24:18,513 DEBUG DefaultActionBeanPropertyBinder:282 - Could not bind property
with name [ADD.action] to bean of type: ViewActionBean : Bean class www.View
ActionBean does not contain a property called 'ADD'. As a result the followin
g expression could not be evaluated: ADD.action
----

When you are trying to match an URL like: /View/myarg1/myarg2/ADD.action with an UrlBinding /View/{arg1}/{arg2}/{$event} then I would expect Stripes to resolve this to the event named: "ADD.action".
As you did not provide any source code of the Action Bean, I suspect that you didn't annotated the event handler with an HandlesEvent like this:
#HandlesEvent("ADD.action")
public Resolution add() {
... do handle add ...
}

Related

Delay in "Transport is org.apache.axis.transport.http.HTTPTransport"

In the Web Service (SOAP) Client call, i can see org.apache.axis.transport.http.HTTPTransport is taking almost 500 ms for each call. This is leading to the latency in all the transactions. Anyone has experienced the same issue and how was it resolved?
I'm using Axis 1.4 and Java8
2022-11-13 07:42:51,930 DEBUG ProjectResourceBundle:72 - org.apache.axis.i18n.resource::handleGetObject(transport00)
2022-11-13 07:42:51,930 DEBUG Call:2119 - Transport is org.apache.axis.transport.http.HTTPTransport#1d20e46
2022-11-13 07:42:52,429 DEBUG Call:2351 - Enter: Call::invoke(ns, meth, args)
2022-11-13 07:42:52,436 DEBUG Call:2043 - operation=name: addRequest
I tried using CommonsHTTPSender, but till facing this latency.

Java Spring Security Authentication Server does not display error description

My Java Spring Authentication and Authorization Server is working.
I want to solve the errors in the requests I send from a client according to the OAuth2 flow. But none of the errors I get are detailed. For example, this request sent to /oauth2/authorize:
https://MY_DOMAIN/authorize?
response_type=code&
client_id=MY_CLIENT_ID&
redirect_uri=MY_CALLBACK_URL&
scope=SCOPE&
state=STATE
Gives the following error after I enter credentials:
My goal is not to resolve the error here, but there are different errors I get like this and I need to see a more informative error message so I can debug them all.
The console also has a non-informative output that goes like this:
...
2022-08-15 15:52:33.739 DEBUG 50827 --- [nio-9000-exec-4] s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
2022-08-15 15:52:33.739 DEBUG 50827 --- [nio-9000-exec-4] o.a.c.c.C.[Tomcat].[localhost] : Processing ErrorPage[errorCode=0, location=/error]
2022-08-15 15:52:33.739 DEBUG 50827 --- [nio-9000-exec-4] o.s.security.web.FilterChainProxy : Securing GET /error?protocol=oauth2&response_type=code&access_type&client_id=articles-client&redirect_uri=http%3A%2F%2F127.0.0.1%3A3000%2Flms%2Flogin&scope=openid%20articles.read&state=XqqDv6wx6O&code_challenge_method=plain&code_challenge=e964fe0c4b609ef3cf29658efc6077e7feb591f78c458c2092aa56c9
...

CSP Error in Eclipse Scout (One Day Tutorial)?

I'm currently on the one day tutorial of the Eclipse Scout Framework, and I'm stuck at exactly this part. I don't think that my question is Tutorial-specific, which is why I'm asking my question here: Suddenly, when I try to open a menu in my scout localhost environment; I get an "access denied" message in my browser, and the java console gives back the following log:
2022-04-06 22:27:06,597 WARN [qtp1600667055-41] org.eclipse.scout.rt.server.commons.authentication.DevelopmentAccessController.handle(DevelopmentAccessController.java:66) -
+++ Development access control with user xxx.yyy - MDC[]
2022-04-06 22:27:06,875 INFO [qtp1600667055-33] org.eclipse.scout.rt.ui.html.csp.ContentSecurityPolicyReportHandler.log(ContentSecurityPolicyReportHandler.java:80) - CSP-REPORT: {
"csp-report": {
"blocked-uri": "inline",
"column-number": 797897,
"document-uri": "http:\/\/localhost:8082\/",
"line-number": 71,
"original-policy": "img-src 'self'; style-src 'self' 'unsafe-inline'; child-src *; default-src 'self'; report-uri http:\/\/localhost:8082\/csp-report; script-src 'self'",
"referrer": "",
"source-file": "moz-extension",
"violated-directive": "script-src"
}
} - MDC[principal=xxx.yyy,
httpUri=/csp-report,
cid=d3e5c2b5-19b8-4f62-b512-56bbd82eb685]
2022-04-06 22:27:07,
575 INFO [scout-model-thread-4 Starting ClientSession [sessionId=v6r80rs8kch0k2pohlnc4u4n2917m8ohb0smftl2jbf4a62i7ah]] org.eclipse.scout.rt.client.AbstractClientSession.start(AbstractClientSession.java:294) - Client session started [session=org.eclipse.scout.contacts.client.ClientSession#49956588[id = v6r80rs8kch0k2pohlnc4u4n2917m8ohb0smftl2jbf4a62i7ah], user=xxx.yyy] - MDC[principal=xxx.yyy, httpUri=/json, jobName=Starting ClientSession [sessionId=v6r80rs8kch0k2pohlnc4u4n2917m8ohb0smftl2jbf4a62i7ah], cid=Sq8Jw6Nn9Gq/1]
2022-04-06 22:27:07,575 INFO [qtp1600667055-45] org.eclipse.scout.rt.ui.html.UiSession.getOrCreateClientSession(UiSession.java:303) - Created new client session [clientSessionId=v6r80rs8kch0k2pohlnc4u4n2917m8ohb0smftl2jbf4a62i7ah, userAgent=HTML|DESKTOP|FIREFOX|WINDOWS|Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:99.0) Gecko/20100101 Firefox/99.0] - MDC[principal=xxx.yyy, httpUri=/json, cid=Sq8Jw6Nn9Gq/1]
2022-04-06 22:27:07,575 INFO [qtp1600667055-45] org.eclipse.scout.rt.ui.html.UiThemeHelper.getConfiguredTheme(UiThemeHelper.java:59) - UI theme configured in config.properties: default - MDC[principal=xxx.yyy, httpUri=/json, cid=Sq8Jw6Nn9Gq/1]
2022-04-06 22:27:07,591 INFO [scout-model-thread-10 Starting JsonClientSession] org.eclipse.scout.rt.ui.html.json.MainJsonObjectFactory.getFactories(MainJsonObjectFactory.java:36) - Using following object factories: [org.eclipse.scout.rt.ui.html.JsonObjectFactory#7646906d] - MDC[principal=xxx.yyy, httpUri=/json, scoutSession=v6r80rs8kch0k2pohlnc4u4n2917m8ohb0smftl2jbf4a62i7ah, jobName=Starting JsonClientSession, cid=Sq8Jw6Nn9Gq/1]
2022-04-06 22:27:07,701 INFO [qtp1600667055-45] org.eclipse.scout.rt.ui.html.UiSession.init(UiSession.java:264) - UiSession with ID 1:gsk4adjmlv49n219mb0v7ono8bfv2g3bo4kdiimvse5duppfdl4 initialized - MDC[principal=xxx.yyy, httpUri=/json, cid=Sq8Jw6Nn9Gq/1]
2022-04-06 22:27:07,717 INFO [qtp1600667055-45] org.eclipse.scout.rt.ui.html.json.JsonMessageRequestHandler.createUiSession(JsonMessageRequestHandler.java:362) - Created new UI session with ID 1:gsk4adjmlv49n219mb0v7ono8bfv2g3bo4kdiimvse5duppfdl4 in 558.412900 ms [maxIdleTime=14400s, httpSession.maxInactiveInterval=3600s] - MDC[principal=xxx.yyy, httpUri=/json, cid=Sq8Jw6Nn9Gq/1]
2022-04-06 22:27:11,793 INFO [scout-model-thread-18 Processing JSON request] org.eclipse.scout.rt.platform.exception.ExceptionHandler.handlePlatformException(ExceptionHandler.java:125) - VetoException: Zugriff verweigert [severity=ERROR, user=xxx.yyy, remote-service.name=org.eclipse.scout.contacts.shared.person.IPersonService, remote-service.operation=prepareCreate, form=org.eclipse.scout.contacts.client.person.PersonForm, ui.event=action, ui.adapter=Menu[id=5, modelClass=org.eclipse.scout.contacts.client.Desktop$QuickAccessMenu$NewPersonMenu, parentId=4]] - MDC[principal=xxx.yyy, httpUri=/json, uiSession=1:gsk4adjmlv49n219mb0v7ono8bfv2g3bo4kdiimvse5duppfdl4, scoutSession=v6r80rs8kch0k2pohlnc4u4n2917m8ohb0smftl2jbf4a62i7ah, jobName=Processing JSON request, cid=Bp3cD7ar8Gp/4]
To me it seems that there's a Content Security Policy issue somewhere, but no clue if that's the case, and if so how to fix that, even after researching the issue for quite some time now.
Help?
Are you running some kind of ad-blocker or privacy plugin in your browser? This would explain the reported CSP error. By default, the CSP rules block inline JavaScript code (e.g. <script>...</script>). Scout itself does not use inline code. It is therefore likely that a browser plugin has injected code into the page. The reported "source-file" ("moz-extension") also hints to that.
The access denied error is probably not caused by the CSP rules. According to the log file, the click was successfully dispatched to the corresponding Menu instance on the UI server. That code calls a backend service (IPersonService) over the service tunnel, which fails with an exception. There are a lot of things that could have gone wrong here:
Backend not running.
Backend running, but not in a valid state.
Auth keys of UI server and backend server don't match, so the service tunnel cannot be established securely. Check the values of the config properties scout.auth.privateKey and scout.auth.publicKey. If necessary, use the SecurityUtility to create a new pair.
User does not have the necessary permissions. For every call to the backend over the service tunnel, RemoteServiceAccessPermission is required. And for most services, a specific permission is required, e.g. ReadPersonPermission.
User doesn't exist.
To analyze these kinds of errors, first check the logs of both the UI server and the backend server. If this does not help, set some breakpoints and step through the code. Here are some classes that make a good starting point: ServerServletFilter, ServiceTunnelServlet, AccessControlService.
If your are running Java 17 version, then you need to update the private & public keys which can be found on config.properties file.

Spring 5 webclient with jetty connector continues to run after main completes execution

I am trying to test rest api by Spring 5 webclient with jetty connector. I am getting data from api call but main program continues to run even after main completes execution. How to resolve the issue.? What configuration needed so that Jetty connector stops after main completes its execution?
My connector initialization code:
SslContextFactory.Client sslContextFactory = new SslContextFactory.Client();
HttpClient httpClient = new HttpClient();
httpClient.setIdleTimeout(DefaultIdleTimeout);
ClientHttpConnector clientConnector = new JettyClientHttpConnector(httpClient, jettyResourceFactory);
webClient = WebClient.builder().baseUrl(getBaseUrl()).clientConnector(clientConnector).build();
Using webclient in main class :
webClient.get().uri("/getUri").exchange().flatMap(response.bodyToMono(String.class)).subscribe(di -> {
System.out.println(di);
}, error -> {
System.out.println(error.getStackTrace());
}, () -> {
System.out.println("Execution complete");
});
getting below in log:
13:39:11.225 [HttpClient#1165b38-scheduler-1] DEBUG org.eclipse.jetty.io.AbstractConnection - HttpConnectionOverHTTP#4eb423a5::DecryptedEndPoint#4345fb54{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=15016/15000} onFillInterestedFailed {}
13:39:11.225 [HttpClient#1165b38-scheduler-1] DEBUG org.eclipse.jetty.io.ManagedSelector - Wakeup ManagedSelector#75ed9710{STARTED} id=1 keys=0 selected=0 updates=0
13:39:11.226 [HttpClient#1165b38-24] DEBUG org.eclipse.jetty.io.ManagedSelector - Selector sun.nio.ch.WindowsSelectorImpl#3d003adb woken with none selected
13:39:11.226 [HttpClient#1165b38-scheduler-1] DEBUG org.eclipse.jetty.util.thread.QueuedThreadPool - queue org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint#74c9b13c startThread=0
13:39:11.226 [HttpClient#1165b38-24] DEBUG org.eclipse.jetty.io.ManagedSelector - Selector sun.nio.ch.WindowsSelectorImpl#3d003adb woken up from select, 0/0/0 selected
13:39:11.226 [HttpClient#1165b38-scheduler-1] DEBUG org.eclipse.jetty.io.FillInterest - onClose FillInterest#52ac96eb{null}
13:39:11.226 [HttpClient#1165b38-21] DEBUG org.eclipse.jetty.util.thread.QueuedThreadPool - run org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint#74c9b13c in QueuedThreadPool[HttpClient#1165b38]#45efc20d{STARTED,8<=8<=200,i=1,r=8,q=0}[ReservedThreadExecutor#4bef0fe3{s=2/8,p=0}]
13:39:11.226 [HttpClient#1165b38-scheduler-1] DEBUG org.eclipse.jetty.client.http.HttpConnectionOverHTTP - Closed HttpConnectionOverHTTP#4eb423a5::DecryptedEndPoint#4345fb54{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=15017/15000}
13:39:11.226 [HttpClient#1165b38-24] DEBUG org.eclipse.jetty.io.ManagedSelector - Selector sun.nio.ch.WindowsSelectorImpl#3d003adb processing 0 keys, 0 updates
13:39:11.226 [HttpClient#1165b38-24] DEBUG org.eclipse.jetty.io.ManagedSelector - updateable 0
13:39:11.226 [HttpClient#1165b38-24] DEBUG org.eclipse.jetty.io.ManagedSelector - updates 0
13:39:11.226 [HttpClient#1165b38-24] DEBUG org.eclipse.jetty.io.ManagedSelector - Selector sun.nio.ch.WindowsSelectorImpl#3d003adb waiting with 0 keys
13:39:11.226 [HttpClient#1165b38-21] DEBUG org.eclipse.jetty.io.ManagedSelector - Destroyed SocketChannelEndPoint#7a9db40c{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=0/15000}{io=0/0,kio=-1,kro=-1}->SslConnection#53046985{NEED_UNWRAP,eio=-1/-1,di=-1,fill=IDLE,flush=IDLE}~>DecryptedEndPoint#4345fb54{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=15017/15000}=>HttpConnectionOverHTTP#4eb423a5(l:/<sourceIp>:65106 <-> r:<hostname>/<targetIp>:443,closed=true)=>HttpChannelOverHTTP#7dafb76e(exchange=null)[send=HttpSenderOverHTTP#4491419(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator#22805291{s=START}],recv=HttpReceiverOverHTTP#52385f05(rsp=IDLE,failure=null)[HttpParser{s=START,0 of -1}]]
13:39:11.227 [HttpClient#1165b38-21] DEBUG org.eclipse.jetty.io.AbstractConnection - onClose HttpConnectionOverHTTP#4eb423a5::DecryptedEndPoint#4345fb54{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=15018/15000}
13:39:11.227 [HttpClient#1165b38-21] DEBUG org.eclipse.jetty.io.AbstractConnection - onClose SslConnection#53046985::SocketChannelEndPoint#7a9db40c{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=0/15000}{io=0/0,kio=-1,kro=-1}->SslConnection#53046985{NEED_UNWRAP,eio=-1/-1,di=-1,fill=IDLE,flush=IDLE}~>DecryptedEndPoint#4345fb54{<hostname>/<targetIp>:443<->/<sourceIp>:65106,CLOSED,fill=-,flush=-,to=15018/15000}=>HttpConnectionOverHTTP#4eb423a5(l:/<sourceIp>:65106 <-> r:<hostname>/<targetIp>:443,closed=true)=>HttpChannelOverHTTP#7dafb76e(exchange=null)[send=HttpSenderOverHTTP#4491419(req=QUEUED,snd=COMPLETED,failure=null)[HttpGenerator#22805291{s=START}],recv=HttpReceiverOverHTTP#52385f05(rsp=IDLE,failure=null)[HttpParser{s=START,0 of -1}]]
13:39:11.227 [HttpClient#1165b38-21] DEBUG org.eclipse.jetty.util.thread.QueuedThreadPool - ran org.eclipse.jetty.io.ManagedSelector$DestroyEndPoint#74c9b13c in QueuedThreadPool[HttpClient#1165b38]#45efc20d{STARTED,8<=8<=200,i=1,r=8,q=0}[ReservedThreadExecutor#4bef0fe3{s=2/8,p=0}]
and continue to get log in console & program continues to run..................................
Taken from the official docs
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web-reactive.html#webflux-client-builder-jetty
You can share resources between multiple instances of the Jetty client (and server) and ensure that the resources are shut down when the Spring ApplicationContext is closed by declaring a Spring-managed bean of type JettyResourceFactory
Your JettyHttpClientConnector should be instantiated with a jettyResourceFactory bean whose lifecycle should end as the test ends.

Grails, Jobs, Static Helper Methods and Hibernate Session

I have a Grails job-class (grails-app/jobs) who needs to call a static (helper) method (defined in src/groovy). This method calls get- and find-methods respectively on 2 different domain-objects. The result of the method call is returning a simple String (could return anything for that sake - doesn't matter).
My question is, how do I use .withTransaction or .withSession in the job-class when I'm calling a static method containing fetch of 2 (could be more) different domain-classes?
Or, how do I declare/use a Hibernate session in a job-class so that I don't have to use .withBlaBla?
EDIT (another EDIT at the bottom - sorry):
The lines where EZTable and EZRow is fetched is working. EmailReminder I had to wrap with EmailReminder.with... Now the lines with call to ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.subject) are causing an exception (this is added "now" - the entire job-class was working earlier with simple String-values).
class EmailReminderJob implements Job {
EmailReminder emailReminder
EZTable ezTable
EZRow ezRow
static triggers = {}
def void execute(JobExecutionContext context) {
List<String> emails = new ArrayList<String>(0)
ezTable = EZTable.get(new Long(context.mergedJobDataMap.get('ezTableId')))
ezRow = EZRow.get(new Long(context.mergedJobDataMap.get('ezRowId')))
EmailReminder.withTransaction { status ->
emailReminder = EmailReminder.get(new Long(context.mergedJobDataMap.get('emailReminderId')))
if(emailReminder.sendMessageToOwnerUser && emailReminder.ownerUser.email!=null)
emails.add(emailReminder.ownerUser.email)
if(emailReminder.sendMessageToOwnerCompany && emailReminder.ownerCompany.email!=null)
emails.add(emailReminder.ownerCompany.email)
if(emailReminder.emails!=null && emails.size()>0)
emails.addAll(new ArrayList<String>(emailReminder.emails))
if(emailReminder.messageReceiverUsers!=null && emailReminder.messageReceiverUsers.size()>0) {
for(user in emailReminder.messageReceiverUsers) {
if(user.email!=null)
emails.add(user.email)
}
}
}
if(emails.size()>0) {
String host = "localhost";
Properties properties = System.getProperties();
properties.setProperty("mail.smtp.host", host);
Session session = Session.getDefaultInstance(properties);
try{
// Create a default MimeMessage object.
MimeMessage message = new MimeMessage(session);
message.setFrom(new InternetAddress(emailReminder.emailFrom));
for(email in emails) {
message.addRecipient(
Message.RecipientType.TO,
new InternetAddress(email)
);
}
message.setSubject(ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.subject));
message.setText(ServiceUtils.handleSubjectOrMessageString(ezTable, ezRow, emailReminder.definedMessage));
Transport.send(message);
}catch (MessagingException mex) {
mex.printStackTrace();
}
}
}
}
The static-method in my util-class under src/groove (the line EZColumn ezcolumn = EZColumn.get(id) and the next are causing the exception):
def static String handleSubjectOrMessageString(EZTable eztable, EZRow ezrow, String subjectOrMessage) {
String regex = '(?<=\\$\\$)(.*?)(?=\\$\\$)'
Pattern pattern = Pattern.compile(regex)
Matcher matcher = pattern.matcher(subjectOrMessage)
StringBuffer stringBuffer = new StringBuffer();
while(matcher.find()) {
if(subjectOrMessage.substring(matcher.start(), matcher.end()).contains('#')) {
String stringId = subjectOrMessage.substring(matcher.start(), matcher.end()).split('#')[0]
String name = subjectOrMessage.substring(matcher.start(), matcher.end()).split('#')[1]
try {
Long id = new Long(stringId)
EZColumn ezcolumn = EZColumn.get(id)
EZCell ezcell = EZCell.findByEzTableAndEzRowAndEzColumn(eztable, ezrow, ezcolumn)
matcher.appendReplacement(stringBuffer, fetchCellValues(ezcell, ezcolumn))
} catch(NumberFormatException nfe) {
if(stringId.equals("id")) {
if(name.equals("row"))
matcher.appendReplacement(stringBuffer, ezrow.id.toString())
else if(name.equals("table"))
matcher.appendReplacement(stringBuffer, eztable.id.toString())
else
matcher.appendReplacement(stringBuffer, "???")
}
}
}
}
matcher.appendTail(stringBuffer);
println stringBuffer.toString().replaceAll('\\$', "")
return stringBuffer.toString().replaceAll('\\$', "")
}
The exception:
| Error 2015-02-11 10:33:33,954 [quartzScheduler_Worker-1] ERROR core.JobRunShell - Job EmailReminderGroup.ER_3_EZTable_3 threw an unhandled Exception:
Message: null
Line | Method
->> 202 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
| Error 2015-02-11 10:33:33,996 [quartzScheduler_Worker-1] ERROR core.ErrorLogger - Job (EmailReminderGroup.ER_3_EZTable_3 threw an exception.
Message: Job threw an unhandled exception.
Line | Method
->> 213 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by NullPointerException: null
->> 202 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
| Error 2015-02-11 10:33:34,005 [quartzScheduler_Worker-1] ERROR listeners.ExceptionPrinterJobListener - Exception occurred in job: null
Message: org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NullPointerException]
Line | Method
->> 218 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by SchedulerException: Job threw an unhandled exception.
->> 213 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
Caused by NullPointerException: null
->> 202 | run in org.quartz.core.JobRunShell
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
^ 573 | run in org.quartz.simpl.SimpleThreadPool$WorkerThread
EDIT AGAIN :( :
I have many nested calls in my static method (fetchCellValues(ezcell, ezcolumn) in the matcher.appendReplacement(stringBuffer, fetchCellValues(ezcell, ezcolumn))-method is calling deeper to fetch values and I actually get a "no Session"-exception at one call (call regular as all the other calls trying to fetch another domain-object):
Message: org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: org.hibernate.LazyInitializationException: could not initialize proxy - no Session]
You use them like you would anywhere. Both are independent of the class they're called on; withTransaction just runs the wrapped code in a transaction, joining a current active transaction if there is one, and withSession makes the current Hibernate Session available to the wrapped code but otherwise doesn't do anything.
You don't indicate any reason for needing either, so it's not obvious what to advise specifically. You don't need a transaction if you're only reading data, and if you're calling domain class methods you shouldn't need access to the session.
One use for withTransaction that I've advocated in the past (pretty much the only use for it since it's typically misused) is to avoid lazy loading exceptions when there isn't an active session already. Wrapping code in a withTransaction block has the side effect of creating a session and keeping it open for the duration of the block and that lets you work with lazy-loaded instances and collections. Controllers have an active session because there's an open-session-in-view interceptor that starts a session at the beginning of the request, stores it in a ThreadLocal, and flushes and closes it at the end of the request. Jobs are similar because the plugin uses Quartz job start/end events to do the same thing.
But whether you are making your code transactional because of lazy loading or because you're updating, you should usually be doing the work in a transactional service.
Services are great for transactional work because they're transactional by default (only services that have no #Transactional annotations and include static transactional = false are non-transactional), and it's easy to configure transaction demarcation per-class and per-method with the #Transactional annotation. They are also great for encapsulating business logic, independent of how they're called; there's usually no need for a service method to have any HTTP/Job/etc. awareness, just pass it the data needed in String/number/boolean/object arguments and let it do its work.
I like to keep controllers simple, doing data binding from the request params and calling services to do the real work, then rendering a response or routing to the next page, and I do the same thing in Quartz jobs. Use Quartz for its scheduling functionality, but do the real work in a service. Dependency-inject the service like any bean (def fooService) and put all of the business logic and database work there. It keeps things cleanly delineated in the code, and makes testing easier since you can test the service methods without having to mock HTTP calls or Quartz.

Categories