I have this problem. I have to generate a report using Jasper reports, then I have to update some records according to a some conditions. Here some code:
def crearReporte = {
//FIRST: generate the report
chain(controller:'jasper',action:'index',params:params)
//SECOND: update the reported information
def recepciones = RecepcionDeEstano.findAllByTransportePagadoAndFechaDeRecepcionBetween("NO",fechaInicial1,fechaFinal1)
pagarTransporte recepciones
}
def pagarTransporte = { lista ->
lista.each {
it.transportePagado="SI"
it.save()
}
}
My report needs the transporte_pagado record's field having the value of 'NO', but the updating operation is executed so immediately that the records and the transporte_pagado field involved are updated to 'SI' before the report is generated giving as result and empty report.
How can I delay the updating operation? Or, how can I perform a task strictly after another task is completed?
I solved my problem (Well, Sergio Michels helped me). This is the code I used (I changed some domain class and variables names to offer a general solution):
def createReport = {
Map reportParams = [:]
byte[] bytes
//report parameters
reportParams.put("PARAM_1",params.param1)
reportParams.put("PARAM_2",params.param2)
reportParams.put("PARAM_N",params.paramn)
//here I had to write some IF's to know what report to send
if(aCondition1)
def reportDef = new JasperReportDef(name:'my_report1.jasper',fileFormat:JasperExportFormat.PDF_FORMAT,parameters: reportParams)
bytes = jasperService.generateReport(reportDef).toByteArray()
//update records after they are reported
doSomeUpdate param1
}
if(aCondition2)
def reportDef = new JasperReportDef(name:'my_report2.jasper',fileFormat:JasperExportFormat.PDF_FORMAT,parameters: reportParams)
bytes = jasperService.generateReport(reportDef).toByteArray()
//update records after they are reported
doSomeUpdate param2
}
//send report for download
response.addHeader("Content-Disposition", 'attachment; filename="report.pdf"')
response.contentType = 'application/pdf'
response.outputStream << bytes
response.outputStream.flush()
}
I found that for this case is better to use the server instead of the chain. This works as a charm!
Related
I'm able to copy most test cases with this code (trying to copy shared steps to be part of the test case itself) but this one will not copy but I can not see any error message as to why - could anyone suggest anything else to try. See output from Immediate windows. Thanks John.
?targetTestCase.Error
null
?targetTestCase.InvalidProperties
Count = 0
?targetTestCase.IsDirty
true
?targetTestCase.State
"Ready"
?targetTestCase.Reason
"New"
foreach (ITestAction step in testSteps)
{
if (step is ITestStep)
{
ITestStep sourceStep = (ITestStep)step;
ITestStep targetStep = targetTestCase.CreateTestStep();
targetStep.Title = sourceStep.Title;
targetStep.Description = sourceStep.Description;
targetStep.ExpectedResult = sourceStep.ExpectedResult;
//Copy Attachments
if (sourceStep.Attachments.Count > 0)
{
string attachmentRootFolder = _tfsServiceUtilities.GetAttachmentsFolderPath();
string testCaseFolder = _tfsServiceUtilities.CreateDirectory(attachmentRootFolder, "TestCase_" + targetTestCase.Id);
//Unique folder path for test step
string TestStepAttachementFolder = _tfsServiceUtilities.CreateDirectory(testCaseFolder, "TestStep_" + sourceStep.Id);
using (var client = new WebClient())
{
client.UseDefaultCredentials = true;
foreach (ITestAttachment attachment in sourceStep.Attachments)
{
string attachmentPath = TestStepAttachementFolder + "\\" + attachment.Name;
client.DownloadFile(attachment.Uri, attachmentPath);
ITestAttachment newAttachment = targetTestCase.CreateAttachment(attachmentPath);
newAttachment.Comment = attachment.Comment;
targetStep.Attachments.Add(newAttachment);
}
}
}
targetTestCase.Actions.Add(targetStep);
targetTestCase.Save();
}
Since this code works for most test cases, this issue may come from the particular test case. In order to narrow down the issue, please try the following items:
Run the code on another client machine to see whether it works.
Try to modify this particular test case using the account API uses, to see whether it can be saved successfully.
Try validate the WorkItem prior to save. The validate() method will return an arraylist of invalid fields.
def exportExcel(){
if(!params.max) params.max = 10
if(params?.type && params.type != "html"){
response.contentType = grailsApplication.config.grails.mime.types[params.type]
response.setHeader("Content-disposition", "attachment; filename=agents.${params.extension}")
List fields = ["orgTypeId", "name"]
Map labels = ["orgTypeId":"DP Id", "name":"Name"]
def upperCase = { domain, value ->
return value.toUpperCase()
}
Map parameters = [title: "Agent List", "column.widths":[0.15, 0.4]]
Map formatters = [name: upperCase]
exportService.export(params.type, response.outputStream, Agent.list(params), fields, labels, formatters, parameters)
}
render(view: 'index',model: [organizationTypeCount: Agent.count(), organizationType: Agent.list(params)])
}
This is my code to export excel. When I click on export button. It show Failed-Network error.
If I resume download it will be downloaded.
This is the error : java.lang.IllegalStateException: getOutputStream() has already been called for this response
Please help me resolve this issue.
You cannot write attachment data to the output stream, and then render the index view; that is trying to render your view to the same output stream that you already sent the attachment to. If you remove the line rendering the index view, your code should work as expected.
If you need to generate an attachment/download AND move to another view in your browser, you will need to send two requests to do that.
I use BatchInserters.batchDatabase to create an embedded Neo4j 2.1.5 data base. When I only put a small amount of data in it, everything works fine.
But if I increase the size of data put in, Neo4j fails to persist the latest properties set with setProperty. I can read back those properties with getProperty before I call shutdown. When I load the data base again with new GraphDatabaseFactory().newEmbeddedDatabase those properies are lost.
The strange thing about this is that Neo4j doesn't report any error or throw an exception. So I have no clue what's going wrong or where. Java should have enough memory to handle both the small data base (Database 2.66 MiB, 3,000 nodes, 3,000 relationships) and the big one (Database 26.32 MiB, 197,267 nodes, 390,659 relationships)
It's hard for me to extract a running example to show you the problem, but I can do if this helps. Here the main steps I do though:
def createDataBase(rules: AllRules) {
// empty the data base folder
deleteFileOrDirectory(new File(mainProjectPathNeo4j))
// Create an index on some properties
db = new GraphDatabaseFactory().newEmbeddedDatabase(mainProjectPathNeo4j)
engine = new ExecutionEngine(db)
createIndex()
db.shutdown()
// Fill the data base
db = BatchInserters.batchDatabase(mainProjectPathNeo4j)
//createBatchIndex
try {
// Every function loads some data
loadAllModulesBatch(rules)
loadAllLinkModulesBatch(rules)
loadFormalModulesBatch(rules)
loadInLinksBatch()
loadHILBatch()
createStandardLinkModules(rules)
createStandardLinkSets(rules)
// validateModel shows the problem
validateModel(rules)
} catch {
// I want to see if my environment (BIRT) is catching any exceptions
case _ => val a = 7
} finally {
db.shutdown()
}
}
validateModel is updating some properties of already created nodes
def validateModule(srcM: GenericModule) {
srcM.node.setProperty("isValidated", true)
assert(srcM.node == Neo4jScalaDataSource.testNode)
assert(srcM.node eq Neo4jScalaDataSource.testNode)
assert(srcM.node.getProperty("isValidated").asInstanceOf[Boolean])
When I finally use Cypher to get some data back
the properties set by validateModel are missing
class Neo4jScalaDataSet extends ScriptedDataSetEventAdapter {
override def beforeOpen(...) {
result = Neo4jScalaDataSource.engine.profile(
"""
MATCH (fm:FormalModule {isValidated: true}) RETURN fm.fullName as fullName, fm.uid as uid
""");
iter = result.iterator()
}
override def fetch(...) = {
if (iter.hasNext()) {
for (e <- iter.next().entrySet()) {
row.setColumnValue(e.getKey(), e.getValue())
}
count += 1;
row.setColumnValue("count", count)
return true
} else {
logger.log(Level.INFO, result.executionPlanDescription().toString())
return super.fetch(dataSet, row)
}
}
batchDatabase indeed causes this problem.
I have switched to BatchInserters.inserter and now everything works just fine.
Following is a code fragment obtained from Grails website.
<script>
function messageKeyPress(field,event) {
var theCode = event.keyCode ? event.keyCode : event.which ? event.which : event.charCode;
var message = $('#messageBox').val();
if (theCode == 13){
<g:remoteFunction action="submitMessage" params="\'message=\'+message" update="temp"/>
$('#messageBox').val('');
return false;
} else {
return true;
}
}
function retrieveLatestMessages() {
<g:remoteFunction action="retrieveLatestMessages" update="chatMessages"/>
}
function pollMessages() {
retrieveLatestMessages();
setTimeout('pollMessages()', 5000);
}
pollMessages();
</script>
The above code worked but when i added the Controller it stopped working. I meant that the records gets saved in the DB, but i am not able to retrieve the data and display on screen.
This is what i did
<g:remoteFunction controller="message" action="retrieveLatestMessages" update="chatMessages"/>
The MessageController function is as follows:
#Secured([ 'ROLE_USER'])
def retrieveLatestMessages() {
println "test"
def messages = Message.listOrderByDate(order: 'desc', max:1000)
[messages:messages.reverse()]
println messages
}
The above controller function gets executed (I see the println statements on console), but the data isn't getting populating on the screen.
Can someone help me out here
UPDATE
[{"class":"myPro.Message","id":3,"date":"2014-07-23T17:31:58Z","message":"dfdf","name":"hi"},{"class":"myPro.Message","id":2,"date":"2014-07-23T17:31:56Z","message":"dfdfdf","name":"dd"},{"class":"myPro.Message","id":1,"date":"2014-07-23T17:31:18Z","message":"xxxx","name":"fie"}]
Your method - retrieveLatestMessages() action in your case - must return a model, but it returns the output of println instead.
To make your code work, you must place the model in the last line, or explicitly return it by using return statement:
def retrieveLatestMessages() {
println "test"
def messages = Message.listOrderByDate(order: 'desc', max:1000)
println messages
[messages:messages.reverse()]
}
Try this
import grails.converters.JSON
#Secured([ 'ROLE_USER'])
def retrieveLatestMessages() {
println "test"
def messages = Message.listOrderByDate(order: 'asc', max:1000)
render messages as JSON
}
Enjoy.
I had this sample app working on mine with no issues but here is the thing, this process requires you to poll the page consistently and it is resource intensive:
I ended up writing a domainClass that was bound to a Datasource that was using the HQL db and was outside of my own app, the process requires a DB table to stream chat....
Alternative is to move away from polling and use websockets:
check out this video
https://www.youtube.com/watch?v=8QBdUcFqRkU
Then check out this video
https://www.youtube.com/watch?v=BikL52HYaZg
Finally look at this :
https://github.com/vahidhedayati/grails-websocket-example
This has been updated and includes the 2nd method of using winsocket to make simple chat ....
I'm trying to get a Criteria query to be exported to CSV, Excel, what have you. The issue I'm running into is that the categories code runs cleanly (as in, doesn't throw any errors), but it doesn't generate any data. I know for a fact that data is an ArrayList of List. Anyone have a workaround for this, or tell me if I'm doing something wrong?
Here's my domain object:
class Machine {
String name,
category
// constraints, etc
}
Here's my controller action (taken mostly from the plugin page):
def categories = {
if(params?.format && params.format != "html"){
response.contentType = ConfigurationHolder.config.grails.mime.types[params.format]
response.setHeader("Content-disposition", "attachment; filename=categories.${params.extension}")
def data = Machine.createCriteria().list {
projections {
groupProperty("category")
countDistinct("id")
}
}
exportService.export(params.format, response.outputStream, data, [:], [:])
}
Here's one possible solution that I thought of as soon as I submitted the question: Expando. Here's the changes to the controller method:
// response stuff above
def fields = ["category", "count"]
def labels = ["category": "Category", "count": "# of machines" ]
def data = Machine.createCriteria().list {
projections {
groupProperty("category")
countDistinct("id")
}
}.collect { l -> new Expando("category": l[0], "count": l[1]) }
exportService.export(params.format, response.outputStream, data, fields, labels, [:], [:])
I'm exploiting the fact that the Export plugin tries to get a value from an object. So, I give it an object.
If there's a better solution, I'll be more than happy to see it.