Change default Service Unavailable message when REST api call fails - java

When user tries to do api call but if our server is down (due to many reasons) then my website UI gives following error:
Service Unavailable
The server is temporarily unable to service your request due to
maintenance downtime or capacity problems. Please try again later.
Additionally, a 406 Not Acceptable error was encountered while trying
to use an ErrorDocument to handle the request.
Apache/2.4.7 (Win32) OpenSSL/1.0.1e PHP/5.5.6 Server at localhost Port 80
I don't want this message to be this much detailed. I want to customize this message. How can I do this? Better if you suggest something change on my ajax request (from where I do api calls)
Here is the javascript from where I do all my api request (if it helps)
function request(url, request_type, datatype, callback, postdata){
if(typeof(postdata) == "object"){
postdata = JSON.stringify(postdata);
} else if(typeof(postdata) == "string") {
SY.setContentType("text/plain");
}
$.ajax({
beforeSend: function(xhr){
for(var key in requestHeaders){
if(key == ANOTHER_CONTENT_TYPE)
continue;
xhr.setRequestHeader(key, requestHeaders[key]);
}
var client_id = readCookie(CLIENT_ID);
var client_token = readCookie(CLIENT_TOKEN);
if(client_id != null && client_token != null){
xhr.setRequestHeader(CLIENT_ID, client_id);
xhr.setRequestHeader(CLIENT_TOKEN, client_token);
}
//if there is another content type defined then modify the xhr content-type header
var newContentType = requestHeaders[ANOTHER_CONTENT_TYPE];
if(newContentType != undefined) {
SyUtils.log("Changing request content type to ="+newContentType);
xhr.setRequestHeader("Content-Type", newContentType);
delete requestHeaders[ANOTHER_CONTENT_TYPE];
}
var loadingDivId = callback.loadingDivId;
if(loadingDivId){
$("#"+loadingDivId).addClass("loader-small");
}else{
$("body").append("<div id=\"loader\"></div>");
}
},
url: url,
data: postdata,
dataType: datatype,
type: request_type,
success: function(data) {
var loadingDivId = callback.loadingDivId;
if(loadingDivId){
$("#"+loadingDivId).removeClass("loader-small");
}else{
$("#loader").remove();
}
// Write back cookie again so that expiry time refreshes
var client_id = readCookie(CLIENT_ID);
var client_token = readCookie(CLIENT_TOKEN);
if(client_id != null && client_token != null){
saveCredentials(client_id, client_token);
}
callback("success", data);
},
error: function(xhr, status, error) {
var loadingDivId = callback.loadingDivId;
if(loadingDivId){
$("#"+loadingDivId).removeClass("loader-small");
}else{
$("#loader").remove();
}
try{
var errorMessageObj = JSON.parse(xhr.responseText);
}catch(err){
errorMessageObj = {type:"ERROR", message:xhr.responseText};
}
var st = xhr.status;
var currentPage = window.location.pathname; // to avoid infinite redirect loop
if (st == 401 && currentPage != "/login"){
SY.removeCurrentUser();
deleteCookie(CLIENT_ID);
deleteCookie(CLIENT_TOKEN);
window.location.replace("/login?toPage="+currentPage);
}else if(st == 403 && currentPage != "/unauthorized"){
window.location.replace("/unauthorized");
}else if(st == 500 && currentPage != "/error"){
window.location.href = "/error";
}else if(st == 404 && currentPage != "/404"){
window.location.href = "/404";
}else{
callback(error, errorMessageObj);
}
}
});
};

Related

How to prevent ajax from confirming on success content already inside a div

How to prevent ajax from confirming on success content already in in this case in $('.Mydiv').Append(data);
$(document).ready(function (ajaxCall) {
var offset = 0;
var limit = offset + 4;
var cats_in_home = '<?php echo $myCat ?>';
var request_in_progress = false;
$.ajax({
type: 'GET',
url: 'getActivity.php',
data: {
'offset': offset,
'limit': limit,
'cats_in_home': cats_in_home
},
success: function (data) {
$('.get_communication_with_div_class').html(data);
}
});
$('.MySeconddiv').onclick(function () {
if (request_in_progress) {
return;
}
request_in_progress = true;
$.ajax({
type: 'GET',
url: 'getActivity.php',
data: {
'offset': offset += 6,
'limit': limit,
'cats_in_home': cats_in_home
},
success: function (data) {
$('.Mydiv').append(data);
request_in_progress = false;
}
});
});
});
the problem is when i click the MySeconddiv tag its accept duplicates,
plese help
i cant find way to find a solution
i cant find way to find a solution

HTTP Node.js Java API

I am creating a Node.js Java backend. The Node.js middleware receives HTTP requests from an Android application and then relays it to the Java code. The reason for choosing this technologies is to create a highly scalable backend from scratch.
I want the Node.js api to receive the HTTP requests, pass it to the Java-side of the backend, the Java code does its calculations, sends back the result to the Node.js API and then finishes the process by sending the result back to the Android application.
I can receive and parse HTTP requests:
var BodyParser = require('body-parser');
var Express = require('express');
var JavaClient = require('./NodeJavaBridge.js');
var JavaClientInstance = new JavaClient();
var app = Express();
///// Receive message logic \\\\\
app.use(BodyParser.json());
app.post('/', function (request, response)
{
var task = request.body;
response.writeHead(200, { 'content-type': 'text/plain' });
var otherObject = { SomeData: 1234 };
var json = JSON.stringify({
data: otherObject
});
response.end(json);
});
console.log("START --> Java Client Instance");
JavaClientInstance.run();
app.listen(8080); //to port on which the express server listen
console.log("Server listening on: " + 8080);
I can also send and receive data between Node.js and Java:
var Util = require('util');
var EventEmitter = require('events').EventEmitter;
var ChildProc = require('child_process');
var JavaClient = function () {
var _self = this;
// The child process object we get when we spawn the java process
var _javaSpawn = null;
// buffer for receiving messages in part and piecing them together later
var _receiveBuffer = null;
// The location of java and the - we're making these public because maybe
// we want to change them in the user of this module.
_self.javaPath = 'java';
_self.jarPath = 'C:/Dev/Backend_Java.jar';
_self.verbose = true;
// list of events emitted - for informational purposes
_self.events = [
'spawn', 'message', 'exception', 'unknown', 'sent', 'java_error',
// Response messages that then become events themselves
'Error', 'Hello', 'Info'
];
/**
* Attach our own event handler to reply to the hello message.
* This is just a convenience part of the protocol so that clients don't have to do it.
* Also connects if connection data was supplied.
*/
_self.on('Hello', function () {
_self.sendHello();
});
/**
* Executes the java process to begin sending and receiving communication
*/
_self.run = function () {
// Invoke the process
_javaSpawn = ChildProc.spawn(_self.javaPath, ['-jar', _self.jarPath]);
// Wire up events
_javaSpawn.stdout.on('data', onData);
_javaSpawn.stderr.on('data', onJavaError);
_javaSpawn.on('exit', function (code) {
console.log("The java program exited with code " + code + ".");
});
// Emit our own event to indicate to others that we have spawned
_self.emit('spawn', _javaSpawn);
}
// sends the hello request message
_self.sendHello = function () {
sendMessage(
{
messageName : 'Hello',
version : '1.1'
});
}
// sends a message that will be echoed back as an Info message
_self.sendEcho = function (message) {
sendMessage(
{
messageName : "Echo",
message : message
});
}
// sends a message telling the java app to exit
_self.sendGoodbye = function () {
sendMessage(
{
"messageName" : "Goodbye"
});
}
/**
* Sends a message object as a JSON encoded string to the java application for processing.
*/
function sendMessage(aMsg)
{
// convert to json and prepare buffer
var aJsonString = JSON.stringify(aMsg);
var lByteLength = Buffer.byteLength(aJsonString);
var lMsgBuffer = new Buffer(4 + lByteLength);
// Write 4-byte length, followed by json, to buffer
lMsgBuffer.writeUInt32BE(lByteLength, 0);
lMsgBuffer.write(aJsonString, 4, aJsonString.length, 'utf8');
// send buffer to standard input on the java application
_javaSpawn.stdin.write(lMsgBuffer);
_self.emit('sent', aMsg);
}
/**
* Receive data over standard input
*/
function onData(data)
{
// Attach or extend receive buffer
_receiveBuffer = (null == _receiveBuffer) ? data : Buffer.concat([_receiveBuffer, data]);
// Pop all messages until the buffer is exhausted
while (null != _receiveBuffer && _receiveBuffer.length > 3)
{
var size = _receiveBuffer.readInt32BE(0);
// Early exit processing if we don't have enough data yet
if ((size + 4) > _receiveBuffer.length)
{
break;
}
// Pull out the message
var json = _receiveBuffer.toString('utf8', 4, (size + 4));
// Resize the receive buffer
_receiveBuffer = ((size + 4) == _receiveBuffer.length) ? null : _receiveBuffer.slice((size + 4));
// Parse the message as a JSON object
try
{
var msgObj = JSON.parse(json);
// emit the generic message received event
_self.emit('message', msgObj);
// emit an object-type specific event
if ((typeof msgObj.messageName) == 'undefined')
{
_self.emit('unknown', msgObj);
}
else
{
_self.emit(msgObj.messageName, msgObj);
}
}
catch (ex)
{
_self.emit('exception', ex);
}
}
}
/**
* Receive error output from the java process
*/
function onJavaError(data)
{
_self.emit('java_error', data.toString());
}
}
// Make our JavaClient class an EventEmitter
Util.inherits(JavaClient, EventEmitter);
// export our class
module.exports = JavaClient;
My problem: How do I let the POST request send a request to my JavaClient instance, wait for a response and then send it back to origin (Android app).
Here is an example of how I am trying to get the logic working:
var client = require('./JavaClient');
var instance = new client();
instance.on('message', function(msg) {
console.log('Received a message...');
console.log(msg);
});
instance.on('sent', function(msg) {
console.log('Sent a message...');
console.log(msg);
});
instance.on('Info', function(msg) {
console.log("Received info");
console.log(msg.message);
});
(function() {
// Start it up (Hello exchanges happen)
instance.run();
// Receive acknowledgement of hello
instance.once('Info', function() {
// Try echoing something
instance.sendEcho("ECHO!");
});
})();
If I should make something more clear please let me know (it's really late and I assume that my writing capabilities is taking a dive). I would appreciate any answer/suggestion/thisisabadidea type of comments.
Thanks!
var Util = require('util');
var EventEmitter = require('events').EventEmitter;
var ChildProc = require('child_process');
var JavaClient = function () {
var _self = this;
// The child process object we get when we spawn the java process
var _javaSpawn = null;
// buffer for receiving messages in part and piecing them together later
var _receiveBuffer = null;
// The location of java and the - we're making these public because maybe
// we want to change them in the user of this module.
_self.javaPath = 'java';
_self.jarPath = 'C:/Dev/Backend_Java.jar';
_self.verbose = true;
// list of events emitted - for informational purposes
_self.events = [
'spawn', 'message', 'exception', 'unknown', 'sent', 'java_error',
// Response messages that then become events themselves
'Error', 'Hello', 'Info'
];
/**
* Attach our own event handler to reply to the hello message.
* This is just a convenience part of the protocol so that clients don't have to do it.
* Also connects if connection data was supplied.
*/
_self.on('Hello', function () {
_self.sendHello();
});
/**
* Executes the java process to begin sending and receiving communication
*/
_self.run = function () {
// Invoke the process
_javaSpawn = ChildProc.spawn(_self.javaPath, ['-jar', _self.jarPath]);
// Wire up events
_javaSpawn.stdout.on('data', onData);
_javaSpawn.stderr.on('data', onJavaError);
_javaSpawn.on('exit', function (code) {
console.log("The java program exited with code " + code + ".");
});
// Emit our own event to indicate to others that we have spawned
_self.emit('spawn', _javaSpawn);
}
// sends the hello request message
_self.sendHello = function () {
sendMessage(
{
messageName : 'Hello',
version : '1.1'
});
}
// sends a message that will be echoed back as an Info message
_self.sendEcho = function (message) {
sendMessage(
{
messageName : "Echo",
message : message
});
}
// sends a message telling the java app to exit
_self.sendGoodbye = function () {
sendMessage(
{
"messageName" : "Goodbye"
});
}
/**
* Sends a message object as a JSON encoded string to the java application for processing.
*/
function sendMessage(aMsg)
{
// convert to json and prepare buffer
var aJsonString = JSON.stringify(aMsg);
var lByteLength = Buffer.byteLength(aJsonString);
var lMsgBuffer = new Buffer(4 + lByteLength);
// Write 4-byte length, followed by json, to buffer
lMsgBuffer.writeUInt32BE(lByteLength, 0);
lMsgBuffer.write(aJsonString, 4, aJsonString.length, 'utf8');
// send buffer to standard input on the java application
_javaSpawn.stdin.write(lMsgBuffer);
_self.emit('sent', aMsg);
}
/**
* Receive data over standard input
*/
function onData(data)
{
// Attach or extend receive buffer
_receiveBuffer = (null == _receiveBuffer) ? data : Buffer.concat([_receiveBuffer, data]);
// Pop all messages until the buffer is exhausted
while (null != _receiveBuffer && _receiveBuffer.length > 3)
{
var size = _receiveBuffer.readInt32BE(0);
// Early exit processing if we don't have enough data yet
if ((size + 4) > _receiveBuffer.length)
{
break;
}
// Pull out the message
var json = _receiveBuffer.toString('utf8', 4, (size + 4));
// Resize the receive buffer
_receiveBuffer = ((size + 4) == _receiveBuffer.length) ? null : _receiveBuffer.slice((size + 4));
// Parse the message as a JSON object
try
{
var msgObj = JSON.parse(json);
// emit the generic message received event
_self.emit('message', msgObj);
// emit an object-type specific event
if ((typeof msgObj.messageName) == 'undefined')
{
_self.emit('unknown', msgObj);
}
else
{
_self.emit(msgObj.messageName, msgObj);
}
}
catch (ex)
{
_self.emit('exception', ex);
}
}
}
/**
* Receive error output from the java process
*/
function onJavaError(data)
{
_self.emit('java_error', data.toString());
}
}
// Make our JavaClient class an EventEmitter
Util.inherits(JavaClient, EventEmitter);
// export our class
module.exports = JavaClient;
var client = require('./JavaClient');
var instance = new client();
instance.on('message', function(msg) {
console.log('Received a message...');
console.log(msg);
});
instance.on('sent', function(msg) {
console.log('Sent a message...');
console.log(msg);
});
instance.on('Info', function(msg) {
console.log("Received info");
console.log(msg.message);
});
(function() {
// Start it up (Hello exchanges happen)
instance.run();
// Receive acknowledgement of hello
instance.once('Info', function() {
// Try echoing something
instance.sendEcho("ECHO!");
});
})();

How do I do a SIP telephone call

I want to constract a telephone-caller inside my java application. For this pupose I used a JAIN-SIP library. After the first INVITE the system needs Proxy-Authentication. The second invite is conscructed with the help of "AuthenticationHelperImpl.class":https://gitorious.org/0xdroid/external_nist-sip/source/1e0f37693341071f316852c8e05a08deef2b7fc4:java/gov/nist/javax/sip/clientauthutils/AuthenticationHelperImpl.java#L311, includes Proxy-Authentication header and lloks like:
INVITE sip:+11111111111#fpbx.de;maddr=fpbx.de SIP/2.0
Call-ID: 1c609509a43b721ab11c396c1e6ea9e7#192.168.17.107
CSeq: 2 INVITE
From: "77735hk6iu" <sip:77735hk6iu#fpbx.de>
To: "+111111111111111" <sip:+11111111111#fpbx.de>
Via: SIP/2.0/UDP 192.168.17.107:34567;rport;branch=z9hG4bK-383337-5bc4fd6b7a616843fce9eaa243bcb10e
Max-Forwards: 70
Contact: <sip:77735hk6iu#192.168.17.107:5060>
Content-Type: application/sdp
Proxy-Authorization: Digest username="77735hk6iu",realm="fpbx.de",nonce="VLaIxVS2h5muPS30F2zLdXHjup6ELyen",uri="sip:+111111111111#fpbx.de:5060;maddr=fpbx.de",response="47ea578c6b01c99fd3ed2b41c60983df"
Content-Length: 61
v=0
o=- 130565705777141827 1 IN IP4 192.168.17.107
s=call
After that I receive at the beginning code 100 message ("your call is very important for us") followed with 408 code message ("Request Timeout").
What I did to imporve the situation:
tried different phone number formats: 004930208488480,
04930208488480, 049, 0049, sdfhajfkhsk. For all these numbers I
become the same combination on messages.
tried to use port in request uri
tried to remove maddr from request uri.
tried to fullfill the message body with codek settings.
to set and remove rport from via header
If you now what I'm doing wrong, please, help me.
Thank you in advance.
I think, Maybe your Proxy-Authorization header is wrong. Maybe you is miscalculated. I wanted to share my resolve.
authUser is your phoneNumber. (for example: 77735hk6iu )
authPass is your user's password.
msg is your invite request.(Headers !)
AccountManagerImpl accountManagerImp = new AccountManagerImpl(authUser, AuthPass);
AuthenticationHelperImpl authenticationHelperImpl = new AuthenticationHelperImpl(accountManagerImp);
try {
this.authentication = authenticationHelperImpl.handleChallenge(msg, (SIPClientTransaction)trans);
AuthenticationHelperImple.java Class :
public AuthorizationHeader handleChallenge(Response challenge, ClientTransaction challengedTransaction) throws SipException {
SIPRequest challengedRequest = ((SIPRequest) challengedTransaction.getRequest());
ListIterator authHeaders = null;
if (challenge.getStatusCode() == Response.UNAUTHORIZED) {
authHeaders = challenge.getHeaders(WWWAuthenticateHeader.NAME);
}
else {
if (challenge.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED) {
authHeaders = challenge.getHeaders(ProxyAuthenticateHeader.NAME);
}
else {
throw new IllegalArgumentException("Unexpected status code ");
}
}
if (authHeaders == null) {
throw new IllegalArgumentException("Could not find WWWAuthenticate or ProxyAuthenticate headers");
}
WWWAuthenticateHeader authHeader = null;
while (authHeaders.hasNext()) {
authHeader = (WWWAuthenticateHeader) authHeaders.next();
String realm = authHeader.getRealm();
this.uri = challengedRequest.getRequestURI();
this.requestMethod = challengedRequest.getMethod();
this.requestBody = (challengedRequest.getContent() == null) ? "" : new String(challengedRequest.getRawContent());
if (this.accountManager instanceof SecureAccountManager) {
UserCredentialHash credHash = ((SecureAccountManager) this.accountManager).getCredentialHash(challengedTransaction,
realm);
if (credHash == null) {
logger.logDebug("Could not find creds");
throw new SipException("Cannot find user creds for the given user name and realm");
}
this.authorizationHeader = this.getAuthorization(requestMethod, uri.toString(), requestBody, authHeader, credHash);
}
else {
UserCredentials userCreds = ((AccountManager) this.accountManager).getCredentials(challengedTransaction, realm);
if (userCreds == null) {
throw new SipException("Cannot find user creds for the given user name and realm");
}
// sipDomain = userCreds.getSipDomain();
// we haven't yet authenticated this realm since we were
// started.
this.authorizationHeader = this.getAuthorization(requestMethod, uri.toString(), requestBody, authHeader, userCreds);
}
}
return this.authorizationHeader;
}
getAuthorization function :
public AuthorizationHeader getAuthorization(String method,
String uri,
String requestBody,
WWWAuthenticateHeader authHeader,
UserCredentials userCredentials) throws SecurityException {
String response = null;
String qopList = authHeader.getQop();
String qop = (qopList != null) ? "auth" : null;
String nc_value = "00000001";
String cnonce = "xyz";
try {
response = MessageDigestAlgorithm.calculateResponse(authHeader.getAlgorithm(),
userCredentials.getUserName(), authHeader.getRealm(),userCredentials.getPassword(), authHeader.getNonce(), nc_value, // JvB added
cnonce, // JvB added
method, uri, requestBody, qop,logger);
}
catch (NullPointerException exc) {
throw new SecurityException("The received authenticate header was malformatted: " + exc.getMessage());
}
AuthorizationHeader authorization = null;
try {
if (authHeader instanceof ProxyAuthenticateHeader) {
if (this.headerFactory != null) {
authorization = headerFactory.createProxyAuthorizationHeader(authHeader.getScheme());
}
else {
authorization = new ProxyAuthorization();
authorization.setScheme(authHeader.getScheme());
}
}
else {
if (this.headerFactory != null) {
authorization = headerFactory.createAuthorizationHeader(authHeader.getScheme());
}
else {
authorization = new Authorization();
authorization.setScheme(authHeader.getScheme());
}
}
authorization.setUsername(userCredentials.getUserName());
authorization.setRealm(authHeader.getRealm());
authorization.setNonce(authHeader.getNonce());
authorization.setParameter("uri", uri);
authorization.setResponse(response);
if (authHeader.getAlgorithm() != null) {
authorization.setAlgorithm(authHeader.getAlgorithm());
}
if (authHeader.getOpaque() != null) {
authorization.setOpaque(authHeader.getOpaque());
}
// jvb added
if (qop != null) {
authorization.setQop(qop);
authorization.setCNonce(cnonce);
authorization.setNonceCount(Integer.parseInt(nc_value));
}
authorization.setResponse(response);
} catch (ParseException ex) {
throw new RuntimeException("Failed to create an authorization header!");
}
return authorization;
}
Finally, your this.authentication variable is ProxyAuthorizationHeader. You must put this.authentication in your INVITE message. And than you will sent SipMessage from transaction or dialog to JAIN-SIP stack.
Good Luck !
The problem was partly solved when a removed "maddr=fpbx.de" from request URI and from proxy-auth. uri
fpr this a used handleCahllenge method with boolean arguments:
inviteTid = authenticationHelper.handleChallenge(response, tid, sipProvider, 15, **true**);
But I still don't know how I can a acchieve sponaneous telephone number.
The 100 message is hop-by-hop, that is to say it just means the next hop got your request. Other messages will typically be end-to-end (so, if you got a 180 Ringing, that typically means the endpoint being called sent the 180). A 408 typically shows up when one of the hops sent the INVITE but never got a response (and your SIP stack might be generating that internally when it doesn't get a provisional response in a reasonable timeframe -- usually about 32 seconds with the default SIP timers).
I don't know your network setup, but there are several private IPs in that message (of the 192.168.x.x variety). If I had to guess, your first hop is sending the 100 back to the IP/port it received it from, but the next response is following the Via headers (as it should), and the hop after you isn't respecting the rport parameter, so the response is getting lost. Alternately, your NAT is poorly configured and is closing the hole it created for the INVITE too quickly.
If you have a proxy on the edge of your network that this message is going out, it is either putting bad Via headers on the message (possibly with the internal IP instead of the external IP) or it is sending the INVITE to the wrong place (causing it to never get a response), and the 408 is coming from it.

JavaEE call page issue on request parameter

I have belowcode in my POSTmethod of a page.
The problem is that I want to go to the url /news-management#tab_default_1 and forward the request too.
So when I use getRequestDispatcher() the request is forwarded but the URLis just /news_management
And when I use sendRedirect() the url is good but the request is not forwarded:
String del = request.getParameter("delete");
Base base = new Base();
if (request.getParameter("object").length() > 200)
request.setAttribute("bad", "Object length is too big");
if (request.getParameter("message").length() > 800)
request.setAttribute("bad", "Content length is too big");
if (del != null)
base.deleteNews(del);
if (request.getParameter("add") != null)
{
Newsletter nl = new Newsletter();
nl.setObject(request.getParameter("object"));
nl.setMessage(request.getParameter("message"));
base.addNews(nl);
}
this.getServletContext().getRequestDispatcher("/WEB-INF/news-management.jsp").forward(request, response);
//response.sendRedirect(request.getContextPath() + "/news-management#tab_default_1");
Any idea on how to get the desired behaviour?

Viewing data on browser

i have a domain with fields like URL, lastModified etc. Now i want to view the information i get from this code into the list page. How can i do tht
def url = new URL("http://www.google.com")
HttpURLConnection connection = (HttpURLConnection)url.openConnection()
// long contentLength = Long.parseLong(connection.getHeaderField("Content-Length"));
connection.setRequestMethod("GET")
connection.connect()
connection.getURL()
println("Date: " + new Date(connection.getDate()))
println("LastModified Date:" + new Date(connection.getLastModified()))
if (connection.responseCode == 200 || connection.responseCode == 201){
def returnMessage = connection.content
//print out the full response
println "${returnMessage}";
System.out.println(connection.getURL());
} else {
println "Error Connecting to " + url
println "Couldn't connect to url"
}
From your controller, you can use the render method,
render returnMessage
(see http://grails.org/doc/2.0.x/ref/Controllers/render.html)
or pass it in a model to a gsp page and then print it from gsp,
return [returnMsg: returnMessage]
....(in .gsp)
${returnMsg}
(see http://grails.org/doc/2.0.x/guide/theWebLayer.html#GSPBasics)

Categories