Sms not receiving from java web application - sms

I have written java code which is used to send sms using sms gateway. JAVA OpenSMPP API is used to implement the logic for sending SMPP request. I have needed below information which is used to connect to the sms gateway and which is used to send sms :
SMS_GATEWAY_USERNAME 906o2portt02
SMS_GATEWAY_PORT 9205 S
SMS_GATEWAY_IP_2 34.22.91.166
SMS_GATEWAY_IP_1 80.77.67.145
I am able to send sms but i dont understand for what reason i am not receiving sms. I have also put the debug statement in my code to check for any error. When i checked the log file i am getting below information which says sms has been send. Previously I had different port number,username and password and i was able to send and recieve sms using the same java code. But now i have the requirement to send sms on this gateway and its also sending an sms. but for some reason i am not receiving sms. Is there any way to check what happened to my sms which has been send ?
Below is my code :
public class SMSClient
{
private static final Logger logger = LoggerFactory
.getLogger(SMSClient.class);
#Autowired
private SMSSettings smsSettings;
#Autowired
private OracleSettings oracleSettings;
/**
* If the application is bound to the SMSC.
*/
boolean _bound = false;
public boolean send(String text,
List<AlertCommunicationAddress> toAddressesSMS)
{
List<String> toAddressesSMSString = new ArrayList<String>();
for (AlertCommunicationAddress alertComAddr : toAddressesSMS)
{
List<AlertRecpGrpMember> recpMembers = alertComAddr
.getAlertRecipientsGroup().getAlertRecpGrpMembers();
for (AlertRecpGrpMember recpMem : recpMembers)
{
// check here if the member belongs to the same environment on
// which SMS is being sent.
if ((recpMem.getIsDefault() != null && recpMem.getIsDefault()
.equalsIgnoreCase("Y"))
|| (recpMem.getRunEnvironment() != null && recpMem
.getRunEnvironment().equalsIgnoreCase(
oracleSettings.getRunEnv())))
{
toAddressesSMSString.add(recpMem.getMember());
}
}
}
logger.debug("Original SMS to be sent : " + text);
String smscHost1 = smsSettings.getHost1();
Integer smscPort = smsSettings.getPort();
if (toAddressesSMSString.isEmpty())
{
return false;
}
for (String phoneNumber : toAddressesSMSString)
{
try
{
Session session = getSession(smscHost1, smscPort,
smsSettings.getUsername(), smsSettings.getPassword());
if (session == null)
{
String smscHost2 = smsSettings.getHost2();
logger.error("SMS --- Unable to get the session with Host 1 (" + smscHost1 + ":" + smscPort + ") , will try Host 2 (" + smscHost2 + ") now.");
session = getSession(smscHost2, smscPort,
smsSettings.getUsername(),
smsSettings.getPassword());
if (session == null)
{
logger.error("SMS --- Unable to get the session with Host 1 (" + smscHost1 + ") and Host 2 (" + smscHost2 + "). Please check with the SMS Gateway.");
return false;
}
}
logger.debug("SMS --- Created Session object " + session);
SubmitSM request = new SubmitSM();
request.setSourceAddr(new Address((byte) 5, (byte) 0,
"RM2Support"));
request.setDestAddr(createAddress(phoneNumber));
request.setProtocolId((byte) 0);
request.setPriorityFlag((byte) 0);
request.setRegisteredDelivery((byte) 1); // we want delivery
// reports
request.setDataCoding((byte) 0);
request.setSmDefaultMsgId((byte) 0);
// request.setScheduleDeliveryTime(deliveryTime); // you can
// skip
// this
request.setReplaceIfPresentFlag((byte) 0);
// Send the request
request.assignSequenceNumber(true);
// this is to send long messages
request.setEsmClass((byte) Data.SM_UDH_GSM);
String[] splittedMsg = splitMessage(text, 153);
int totalSegments = splittedMsg.length;
logger.debug("SMS : Number of splitted segments :: "
+ totalSegments);
// iterating on splittedMsg array. Only Sequence Number and
// short
// message text will change each time
Random random = new Random();
int randomInt = random.nextInt();
logger.debug("SMS---- Reference Number : " + randomInt);
for (int i = 0; i < totalSegments; i++)
{
ByteBuffer ed = new ByteBuffer();
ed.appendByte((byte) 5); // UDH Length
ed.appendByte((byte) 0x00); // IE Identifier
ed.appendByte((byte) 3); // IE Data Length
ed.appendByte((byte) randomInt); // Reference Number
ed.appendByte((byte) totalSegments); // Number of pieces
ed.appendByte((byte) (i + 1)); // Sequence number
ed.appendString(splittedMsg[i], Data.ENC_ASCII);
request.setShortMessageData(ed);
logger.debug("Hello...reached here...now about the submit the request::::");
SubmitSMResp response = session.submit(request);
logger.debug("SMS --- Submit response "
+ response.getCommandStatus());
// response = smsSession.submitMulti(request);
logger.debug("SMS --- Submit response "
+ response.getCommandStatus());
String messageId = response.getMessageId();
logger.debug("SMS --- Message ID = " + messageId);
}
enquireLink(session);
unbind(session);
} catch (Exception e)
{
logger.debug("Exception while sending SMS with Phone number :::" + phoneNumber + "::::" + e);
continue;
}
}
return true;
}
private Session getSession(String smscHost, int smscPort,
String smscUsername, String smscPassword) throws Exception
{
try
{
TCPIPConnection connection = new TCPIPConnection(smscHost, smscPort);
connection.setReceiveTimeout(6000);
connection.setIOBufferSize(8188);
connection.setReceiveBufferSize(8188);
Session session = new Session(connection);
// bind now
if (_bound)
{
logger.debug("Already bound, unbind first.");
return session;
}
BindRequest request = new BindTransmitter();
request.setSystemId(smscUsername);
request.setPassword(smscPassword);
// request.setSystemType(systemType);
// request.setAddressRange(addressRange);
request.setInterfaceVersion((byte) 0x34); // SMPP protocol version
logger.debug("SMS --- Bind request :: " + request.debugString());
logger.debug("SMS --- Created Session object :: " + session);
BindResponse response = session.bind(request);
logger.debug("Bind response " + response.debugString());
if (response.getCommandStatus() == Data.ESME_ROK)
{
logger.debug("SMS --- Binded with SMSC Server");
_bound = true;
} else
{
logger.error("SMS --- Unable to bind with SMSC Server :: Code :: "
+ response.getCommandStatus());
}
Integer respCode = new Integer(response.getCommandStatus());
logger.debug("SMS -- Response Code ::" + respCode);
response.setCommandStatus(respCode);
Integer comLength = new Integer(response.getCommandLength());
logger.debug("SMS -- CommandLength ::" + comLength);
response.setCommandLength(comLength);
logger.debug("SMS --- Response from SMSC" + response.toString());
return session;
} catch (WrongLengthOfStringException e)
{
logger.error("SMS -- Wrong length string exception"
+ e.getMessage());
} catch (ValueNotSetException e)
{
logger.error("SMS -- Value not set exception" + e.getMessage());
} catch (TimeoutException e)
{
logger.error("SMS -- Timeout exception " + e.getMessage());
} catch (PDUException e)
{
logger.error("SMS -- PDU exception " + e.getMessage());
} catch (WrongSessionStateException e)
{
logger.error("SMS -- Wrong Session exception " + e.getMessage());
} catch (IOException e)
{
logger.error("SMS --- Could not able to connect the host/port or Check the Username/Password for connection ::"
+ e.getMessage());
} catch (Exception e)
{
logger.error("SMS -- Error while sending SMS :: " + e.getMessage());
}
return null;
}
private Address createAddress(String address)
throws WrongLengthOfStringException
{
Address addressInst = new Address();
addressInst.setTon((byte) 5); // national ton
addressInst.setNpi((byte) 0); // numeric plan indicator
addressInst.setAddress(address, Data.SM_ADDR_LEN);
logger.debug("SMS -------- Address :: " + addressInst);
return addressInst;
}
private Session unbind(Session session)
{
try
{
if (!_bound)
{
System.out.println("Not bound, cannot unbind.");
return session;
}
// send the request
logger.debug("Going to unbind.");
if (session.getReceiver().isReceiver())
{
logger.debug("SMS --- Unbinding --- It can take a while to stop the receiver.");
}
UnbindResp response = session.unbind();
logger.debug("Unbind response " + response.debugString());
_bound = false;
} catch (Exception e)
{
logger.debug("Unbind operation failed. " + e);
}
return session;
}
/**
* Creates a new instance of <code>EnquireSM</code> class. This PDU is used
* to check that application level of the other party is alive. It can be
* sent both by SMSC and ESME.
*
* See "SMPP Protocol Specification 3.4, 4.11 ENQUIRE_LINK Operation."
*
* #see Session#enquireLink(EnquireLink)
* #see EnquireLink
* #see EnquireLinkResp
*/
private void enquireLink(Session session)
{
try
{
EnquireLink request = new EnquireLink();
EnquireLinkResp response;
logger.debug("SMS ---- Enquire Link request "
+ request.debugString());
response = session.enquireLink(request);
logger.debug("SMS --- Enquire Link response "
+ response.debugString());
} catch (Exception e)
{
logger.debug("SMS ---- Enquire Link operation failed :: " + e);
}
}
private String[] splitMessage(String s, int size)
{
if (s == null || size <= 0)
return null;
int chunks = s.length() / size + ((s.length() % size > 0) ? 1 : 0);
String[] arr = new String[chunks];
for (int i = 0, j = 0, l = s.length(); i < l; i += size, j++)
arr[j] = s.substring(i, Math.min(l, i + size));
return arr;
}
}
Below is the parameter i need to consider while send/receive sms. But i really dont know whetherJAVA OpenSMPP APIuses this settings:

You can use the following code to query SMPP server to check what happend to you message (from https://github.com/OpenSmpp/opensmpp/blob/master/client/src/main/java/org/smpp/test/SMPPTest.java):
/**
* Creates a new instance of <code>QuerySM</code> class, lets you set
* subset of fields of it. This PDU is used to fetch information
* about status of already submitted message providing that you 'remember'
* message id of the submitted message. The message id is assigned
* by SMSC and is returned to you with the response to the submision
* PDU (SubmitSM, DataSM etc.).
*
* See "SMPP Protocol Specification 3.4, 4.8 QUERY_SM Operation."
* #see Session#query(QuerySM)
* #see QuerySM
* #see QuerySMResp
*/
private void query() {
debug.enter(this, "SMPPTest.query()");
try {
QuerySM request = new QuerySM();
QuerySMResp response;
// input values
messageId = getParam("Message id", messageId);
sourceAddress = getAddress("Source", sourceAddress);
// set values
request.setMessageId(messageId);
request.setSourceAddr(sourceAddress);
// send the request
System.out.println("Query request " + request.debugString());
if (asynchronous) {
session.query(request);
} else {
response = session.query(request);
System.out.println("Query response " + response.debugString());
messageId = response.getMessageId();
}
} catch (Exception e) {
event.write(e, "");
debug.write("Query operation failed. " + e);
System.out.println("Query operation failed. " + e);
} finally {
debug.exit(this);
}
}

Related

Incorrect file being produced using websockets in helidon

I am trying to upload a file using websockets in Helidon.I think i am doing it write the right way but the code seems to be flaky in terms of the size of the file produced which is different. The size of the file being produced is different for different runs.
How can i make sure that the file size is same on both ends?
I use a simple protocol for handshake[code below]:
Step1 client sends filesize=11000 buffer=5000
Step2 server sends SENDFILE
Step3 client >> buffer 1 server >> write 1 5000
Step4 client >> buffer 2 server >> write 2 5000
Step5 client >> buffer 3 server >> write 3 1000
Step6 client sends ENDOFFILE server >> session.close
//SERVER side OnOpen session below
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
System.out.println("Server >> " + message);
if (message.contains("FILESIZE")) {
session.getBasicRemote().sendText("SENDFILENOW");
}
if(message.contains("ENDOFFILE")) {
System.out.println("Server >> FILE_SIZE=" + FILE_SIZE);
finalFileOutputStream.close();
session.close();
}
}
});
session.addMessageHandler(new MessageHandler.Whole<ByteBuffer>() {
#Override
public void onMessage(ByteBuffer b) {
finalFileOutputStream.write(b.array(), 0, b.array().length);
finalFileOutputStream.flush();
}
});
//CLIENT OnOpen session below
session.getBasicRemote().sendText("FILESIZE=" + FILE_SIZE);
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String message) {
long M = FILE_SIZE / BUFFER_SIZE;
long R = FILE_SIZE % BUFFER_SIZE;
if(!message.equals("SENDFILENOW"))
return;
try {
System.out.println("Starting File read ... " + path + " " + FILE_SIZE + " " + M + " " +message );
byte[] buffer = new byte[(int) BUFFER_SIZE];
while (M > 0) {
fileInputStream.read(buffer);
ByteBuffer bytebuffer = ByteBuffer.wrap(buffer);
session.getBasicRemote().sendBinary(bytebuffer);
M--;
}
buffer = new byte[(int) R];
fileInputStream.read(buffer, 0, (int) R);
fileInputStream.close();
ByteBuffer bytebuffer = ByteBuffer.wrap(buffer);
session.getBasicRemote().sendBinary(bytebuffer);
session.getBasicRemote().sendText("FILEREADDONE");
session.close();
f.complete(true);
} catch (IOException e) {
fail("Unexpected exception " + e);
}
}
});
Your solution is unnecessarily built on top of several levels of abstraction just to use websockets. Do you really need that? Helidon is very well equipped to handle huge file upload directly and much more efficiently.
public class LargeUpload {
public static void main(String[] args) {
ExecutorService executor = ThreadPoolSupplier.create("upload-thread-pool").get();
WebServer server = WebServer.builder(Routing.builder()
.post("/streamUpload", (req, res) -> req.content()
.map(DataChunk::data)
.flatMapIterable(Arrays::asList)
.to(IoMulti.writeToFile(createFile(req.queryParams().first("fileName").orElse("bigFile.mkv")))
.executor(executor)
.build())
.onError(res::send)
.onComplete(() -> {
res.status(Http.Status.ACCEPTED_202);
res.send();
}).ignoreElement())
.build())
.port(8080)
.build()
.start()
.await(Duration.ofSeconds(10));
// Server started - do upload
//several gigs file
Path file = Path.of("/home/kec/helidon-kafka.mkv");
try (FileInputStream fis = new FileInputStream(file.toFile())) {
WebClient.builder()
.baseUri("http://localhost:8080")
.build()
.post()
.path("/streamUpload")
.queryParam("fileName", "bigFile_" + System.currentTimeMillis() + ".mkv")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.submit(IoMulti.multiFromByteChannelBuilder(fis.getChannel())
.bufferCapacity(1024 * 1024 * 4)
.build()
.map(DataChunk::create)
)
.await(Duration.ofMinutes(10));
} catch (IOException e) {
throw new RuntimeException(e);
}
executor.shutdown();
server.shutdown()
.await(Duration.ofSeconds(10));
}
static Path createFile(String path) {
try {
Path filePath = Path.of("/home/kec/tmp/" + path);
System.out.println("Creating " + filePath);
return Files.createFile(filePath);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

How to set MQ headers using JSR223 sampler in Jmeter

I am working on IBM MQ testing. I able to inject my payloads request in MQ destination. I need to put the headers values in MQ to get the correct response. I used various option but still i am unable to put headers values in MQ server. Kindly let me know how can i solve this in JMeter.
Option 1 :
sendmsg = new MQMessage();
sendmsg.setStringProperty("QueryName", "GetPortfolio");
sendmsg.setStringProperty("Country", "LV");
Option 2:
rfh2.setFieldValue('usr', 'QueryName=', 'GetPortfolio')
Option 3:
SampleResult.setRequestHeaders("QueryName=GetPortfolio")
Option # 1 is the correct way of doing it.
Option # 2 could be used but why? And the parameter should not include the equals sign ( i.e. "=").
I have no idea what option # 3 is.
Here is a sample Java/MQ program that puts a message on a queue with named properties .
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import com.ibm.mq.MQException;
import com.ibm.mq.MQMessage;
import com.ibm.mq.MQPutMessageOptions;
import com.ibm.mq.MQQueue;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
/**
* Program Name
* MQTest11P
*
* Description
* This java class will connect to a remote queue manager with the
* MQ setting stored in a HashTable and put a message on a queue.
*
* Sample Command Line Parameters
* -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -q TEST.Q1 -u UserID -x Password
*
* #author Roger Lacroix
*/
public class MQTest11P
{
private static final SimpleDateFormat LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
private Hashtable<String,String> params;
private Hashtable<String,Object> mqht;
private String qMgrName;
private String outputQName;
/**
* The constructor
*/
public MQTest11P()
{
super();
params = new Hashtable<String,String>();
mqht = new Hashtable<String,Object>();
}
/**
* Make sure the required parameters are present.
* #return true/false
*/
private boolean allParamsPresent()
{
boolean b = params.containsKey("-h") && params.containsKey("-p") &&
params.containsKey("-c") && params.containsKey("-m") &&
params.containsKey("-q") &&
params.containsKey("-u") && params.containsKey("-x");
if (b)
{
try
{
Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
b = false;
}
}
return b;
}
/**
* Extract the command-line parameters and initialize the MQ HashTable.
* #param args
* #throws IllegalArgumentException
*/
private void init(String[] args) throws IllegalArgumentException
{
int port = 1414;
if (args.length > 0 && (args.length % 2) == 0)
{
for (int i = 0; i < args.length; i += 2)
{
params.put(args[i], args[i + 1]);
}
}
else
{
throw new IllegalArgumentException();
}
if (allParamsPresent())
{
qMgrName = (String) params.get("-m");
outputQName = (String) params.get("-q");
try
{
port = Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
port = 1414;
}
mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));
mqht.put(CMQC.PORT_PROPERTY, new Integer(port));
mqht.put(CMQC.USER_ID_PROPERTY, params.get("-u"));
mqht.put(CMQC.PASSWORD_PROPERTY, params.get("-x"));
// I don't want to see MQ exceptions at the console.
MQException.log = null;
}
else
{
throw new IllegalArgumentException();
}
}
/**
* Connect, open queue, write a message, close queue and disconnect.
*
*/
private void testSend()
{
MQQueueManager qMgr = null;
MQQueue queue = null;
String msgData = "This is a test message from MQTest11P";
int openOptions = CMQC.MQOO_OUTPUT + CMQC.MQOO_FAIL_IF_QUIESCING;
MQPutMessageOptions pmo = new MQPutMessageOptions();
try
{
qMgr = new MQQueueManager(qMgrName, mqht);
MQTest11P.logger("successfully connected to "+ qMgrName);
queue = qMgr.accessQueue(outputQName, openOptions);
MQTest11P.logger("successfully opened "+ outputQName);
// Define a simple MQ message, and write some text
MQMessage sendmsg = new MQMessage();
sendmsg.format = CMQC.MQFMT_STRING;
sendmsg.feedback = CMQC.MQFB_NONE;
sendmsg.messageType = CMQC.MQMT_DATAGRAM;
sendmsg.messageId = CMQC.MQMI_NONE;
sendmsg.correlationId = CMQC.MQCI_NONE;
// Write message data
sendmsg.writeString(msgData);
/**
* Set named properties aka message properties
* that will create a JMS message.
*/
// sendmsg.setStringProperty("mcd.Msd", "jms_text");
// sendmsg.setStringProperty("jms.Dst", "queue:///"+outputQName);
// sendmsg.setStringProperty("jms.Pri", "0");
sendmsg.setStringProperty("QueryName", "GetPortfolio");
sendmsg.setStringProperty("Country", "LV");
// put the message on the queue
queue.put(sendmsg, pmo);
MQTest11P.logger("Message Data>>>" + msgData);
}
catch (MQException e)
{
MQTest11P.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
}
catch (IOException e)
{
MQTest11P.logger("IOException:" +e.getLocalizedMessage());
}
finally
{
try
{
if (queue != null)
{
queue.close();
MQTest11P.logger("closed: "+ outputQName);
}
}
catch (MQException e)
{
MQTest11P.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
}
try
{
if (qMgr != null)
{
qMgr.disconnect();
MQTest11P.logger("disconnected from "+ qMgrName);
}
}
catch (MQException e)
{
MQTest11P.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
}
}
}
/**
* A simple logger method
* #param data
*/
public static void logger(String data)
{
String className = Thread.currentThread().getStackTrace()[2].getClassName();
// Remove the package info.
if ( (className != null) && (className.lastIndexOf('.') != -1) )
className = className.substring(className.lastIndexOf('.')+1);
System.out.println(LOGGER_TIMESTAMP.format(new Date())+" "+className+": "+Thread.currentThread().getStackTrace()[2].getMethodName()+": "+data);
}
/**
* main line
* #param args
*/
public static void main(String[] args)
{
MQTest11P write = new MQTest11P();
try
{
write.init(args);
write.testSend();
}
catch (IllegalArgumentException e)
{
MQTest11P.logger("Usage: java MQTest11P -m QueueManagerName -h host -p port -c channel -q QueueName -u UserID -x Password");
System.exit(1);
}
System.exit(0);
}
}
When I look at the message in the queue with MQ Visual Edit, I see:
So, your 2 named properties are with the message.
The question becomes do you want JUST named properties attached to the message or are you really looking to create a JMS message with named properties?
Note: A JMS message is internally defined as an MQRFH2 message. i.e. JMS message ==> MQRFH2 message but the opposite may not be true.
Hence, if you want a JMS message with named properties then you need to uncomment those 3 lines in MQTest11P.java above.
i.e.
sendmsg.setStringProperty("mcd.Msd", "jms_text");
sendmsg.setStringProperty("jms.Dst", "queue:///"+outputQName);
sendmsg.setStringProperty("jms.Pri", "0");

How to display local queues where curdepth reached its maxdepth in ibm mq

I want to display all local queues where curdepth reached its maxdepth.
I understand that the below where condition in runmqsc will not work.
DIS QL(*) WHERE(CURDEPTH EQ MAXDEPTH)
I am trying to parse it with sed and awk but not even close as I am no expert in scripting
Please help in getting desired output. Thanks
Isn't this like trying to squeeze a fully blown up balloon into a wine bottle?
It would seem far, far simpler to just run a Java/MQ/PCF application to get both the current and maximum depths and compare the values.
Here is a simple (complete) Java/MQ/PCF application to do that:
Note: It has a filter on the PCF command to only return queues with a current depth greater than zero. Hence, the queue manager's command server will return less data and make over all processing faster.
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import com.ibm.mq.MQException;
import com.ibm.mq.MQQueueManager;
import com.ibm.mq.constants.CMQC;
import com.ibm.mq.constants.CMQCFC;
import com.ibm.mq.headers.MQDataException;
import com.ibm.mq.headers.pcf.PCFMessage;
import com.ibm.mq.headers.pcf.PCFMessageAgent;
/**
* Program Name
* MQCurrentDepthMonitor01
*
* Description
* This java class issues a PCF "inquire queue" request message for all ("*") local queues
* with a queue depth greater than 0 (zero) of a remote queue manager and
* (1) output an error message if current depth is the same as max depth or
* (2) output a warning message if current depth is within 90% of max depth.
*
* Sample Command Line Parameters
* -m MQA1 -h 127.0.0.1 -p 1414 -c TEST.CHL -u UserID -x Password
*
* #author Roger Lacroix
*/
public class MQCurrentDepthMonitor01
{
private static final SimpleDateFormat LOGGER_TIMESTAMP = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
private Hashtable<String,String> params;
private Hashtable<String,Object> mqht;
private String qMgrName;
public MQCurrentDepthMonitor01()
{
super();
params = new Hashtable<String,String>();
mqht = new Hashtable<String,Object>();
}
/**
* Make sure the required parameters are present.
* #return true/false
*/
private boolean allParamsPresent()
{
boolean b = params.containsKey("-h") && params.containsKey("-p") &&
params.containsKey("-c") && params.containsKey("-m") &&
params.containsKey("-u") && params.containsKey("-x");
if (b)
{
try
{
Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
b = false;
}
}
return b;
}
/**
* Extract the command-line parameters and initialize the MQ HashTable.
* #param args
* #throws IllegalArgumentException
*/
private void init(String[] args) throws IllegalArgumentException
{
int port = 1414;
if (args.length > 0 && (args.length % 2) == 0)
{
for (int i = 0; i < args.length; i += 2)
{
params.put(args[i], args[i + 1]);
}
}
else
{
throw new IllegalArgumentException();
}
if (allParamsPresent())
{
qMgrName = (String) params.get("-m");
try
{
port = Integer.parseInt((String) params.get("-p"));
}
catch (NumberFormatException e)
{
port = 1414;
}
mqht.put(CMQC.CHANNEL_PROPERTY, params.get("-c"));
mqht.put(CMQC.HOST_NAME_PROPERTY, params.get("-h"));
mqht.put(CMQC.PORT_PROPERTY, new Integer(port));
mqht.put(CMQC.USER_ID_PROPERTY, params.get("-u"));
mqht.put(CMQC.PASSWORD_PROPERTY, params.get("-x"));
// I don't want to see MQ exceptions at the console.
MQException.log = null;
}
else
{
throw new IllegalArgumentException();
}
}
/**
* Handle connecting to the queue manager, issuing PCF command then
* looping through PCF response messages and disconnecting from
* the queue manager.
*/
private void doPCF()
{
MQQueueManager qMgr = null;
PCFMessageAgent agent = null;
PCFMessage request = null;
PCFMessage[] responses = null;
try
{
qMgr = new MQQueueManager(qMgrName, mqht);
MQCurrentDepthMonitor01.logger("successfully connected to "+ qMgrName);
agent = new PCFMessageAgent(qMgr);
MQCurrentDepthMonitor01.logger("successfully created agent");
// https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.ref.adm.doc/q087800_.htm
request = new PCFMessage(CMQCFC.MQCMD_INQUIRE_Q);
/**
* You can explicitly set a queue name like "TEST.Q1" or
* use a wild card like "TEST.*"
*/
request.addParameter(CMQC.MQCA_Q_NAME, "*");
// Add parameter to request only local queues
request.addParameter(CMQC.MQIA_Q_TYPE, CMQC.MQQT_LOCAL);
// Add parameter to request only queue name, current depth and max depth
request.addParameter(CMQCFC.MQIACF_Q_ATTRS, new int [] {
CMQC.MQCA_Q_NAME,
CMQC.MQIA_CURRENT_Q_DEPTH,
CMQC.MQIA_MAX_Q_DEPTH
});
// Add filter to only return responses with a queue depth greater than 0 (zero)
// i.e. non-zero queue depth
request.addFilterParameter(CMQC.MQIA_CURRENT_Q_DEPTH, CMQCFC.MQCFOP_GREATER, 0);
responses = agent.send(request);
// MQCurrentDepthMonitor01.logger("responses.length="+responses.length);
int curDepth = -1;
int maxDepth = -1;
for (int i = 0; i < responses.length; i++)
{
if ( ((responses[i]).getCompCode() == CMQC.MQCC_OK) &&
((responses[i]).getParameterValue(CMQC.MQCA_Q_NAME) != null) )
{
String name = responses[i].getStringParameterValue(CMQC.MQCA_Q_NAME);
if (name != null)
name = name.trim();
curDepth = responses[i].getIntParameterValue(CMQC.MQIA_CURRENT_Q_DEPTH);
maxDepth = responses[i].getIntParameterValue(CMQC.MQIA_MAX_Q_DEPTH);
// MQCurrentDepthMonitor01.logger("Name="+name + " : curDepth="+curDepth + " : maxDepth="+maxDepth);
if (curDepth == maxDepth)
MQCurrentDepthMonitor01.logger("ERROR: Name="+name + " : current depth equals max depth ["+maxDepth+"]");
else if (curDepth >= (maxDepth * 0.9))
MQCurrentDepthMonitor01.logger("Warning: Name="+name + " : current depth ["+curDepth+"] is within 90% of max depth ["+maxDepth+"]");
}
}
}
catch (MQException e)
{
MQCurrentDepthMonitor01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
}
catch (IOException e)
{
MQCurrentDepthMonitor01.logger("IOException:" +e.getLocalizedMessage());
}
catch (MQDataException e)
{
MQCurrentDepthMonitor01.logger("MQDataException:" +e.getLocalizedMessage());
}
finally
{
try
{
if (agent != null)
{
agent.disconnect();
MQCurrentDepthMonitor01.logger("disconnected from agent");
}
}
catch (MQDataException e)
{
MQCurrentDepthMonitor01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
}
try
{
if (qMgr != null)
{
qMgr.disconnect();
MQCurrentDepthMonitor01.logger("disconnected from "+ qMgrName);
}
}
catch (MQException e)
{
MQCurrentDepthMonitor01.logger("CC=" +e.completionCode + " : RC=" + e.reasonCode);
}
}
}
/**
* A simple logger method
* #param data
*/
public static void logger(String data)
{
String className = Thread.currentThread().getStackTrace()[2].getClassName();
// Remove the package info.
if ( (className != null) && (className.lastIndexOf('.') != -1) )
className = className.substring(className.lastIndexOf('.')+1);
System.out.println(LOGGER_TIMESTAMP.format(new Date())+" "+className+": "+Thread.currentThread().getStackTrace()[2].getMethodName()+": "+data);
}
public static void main(String[] args)
{
MQCurrentDepthMonitor01 mqlqs = new MQCurrentDepthMonitor01();
try
{
mqlqs.init(args);
mqlqs.doPCF();
}
catch (IllegalArgumentException e)
{
MQCurrentDepthMonitor01.logger("Usage: java MQCurrentDepthMonitor01 -m QueueManagerName -h host -p port -c channel -u UserID -x Password");
System.exit(1);
}
System.exit(0);
}
}

SSE server sending events in a batch on final close

I have a Jersey server running locally, it exposes a SSE resource just like the examples here: https://jersey.github.io/documentation/latest/sse.html. I have a local webpack Angular app, that binds to the exposed GET endpoint and listens for data.
On the GET, I start up a thread to send notifications at regular intervals over 6-8 seconds. I don't see anything on the client UNTIL the EventOutput object is closed.
What am I doing wrong, and how can I fix this?
The server code WORKS with just a simple curl, i.e.:
curl http://localhost:8002/api/v1/notify
But on both Chrome and Safari the following code exhibits the behavior
Client (TypeScript):
this.evSource = new EventSource('http://localhost:8002/api/v1/notify');
this.evSource.addEventListener(
'event',
(x => console.log('we have ', x))
);
this.evSource.onmessage = (data => console.log(data));
this.evSource.onopen = (data => console.log(data));
this.evSource.onerror = (data => {
console.log(data);
this.evSource.close();
});
Server (Java):
// cache callback
public void eventCallback(Iterable<CacheEntryEvent<? extends Integer, ? extends Integer>> events) {
for (CacheEntryEvent<? extends Integer, ? extends Integer> x : events) {
LOGGER.info("{} Sending the following value: " + x.getValue(), Thread.currentThread().getId());
final OutboundEvent sseEvent = new OutboundEvent.Builder().name("event")
.data(Integer.class, x.getValue()).build();
this.broadcaster.broadcast(sseEvent);
}
}
#GET
#Produces(SseFeature.SERVER_SENT_EVENTS)
#ApiOperation(value = "Setup SSE pipeline", notes = "Sets up the notification pipeline for clients to access")
#ApiResponses(value = {
#ApiResponse(code = HttpURLConnection.HTTP_UNAUTHORIZED,
message = "Missing, bad or untrusted cookie"),
#ApiResponse(code = HttpURLConnection.HTTP_OK,
message = "Events streamed successfully")
})
#Timed
#ResponseMetered
public EventOutput registerNotificationEvents(
#HeaderParam(SseFeature.LAST_EVENT_ID_HEADER) String lastEventId,
#QueryParam(SseFeature.LAST_EVENT_ID_HEADER) String lastEventIdQuery) {
if (!Strings.isNullOrEmpty(lastEventId) || !Strings.isNullOrEmpty(lastEventIdQuery)) {
LOGGER.info("Found Last-Event-ID header: {}", !Strings.isNullOrEmpty(lastEventId) ? lastEventId : lastEventIdQuery );
}
LOGGER.info("{} Received request", Thread.currentThread().getId());
this.continuation = true;
final EventOutput output = new EventOutput();
broadcaster.add(output);
Random rand = new Random();
IntStream rndStream = IntStream.generate(() -> rand.nextInt(90));
List<Integer> lottery = rndStream.limit(15).boxed().collect(Collectors.toList());
IgniteCache<Integer, Integer> cache = this.ignite.cache(topic_name);
executorService.execute(() -> {
try {
lottery.forEach(value -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
LOGGER.info("{} Sending the following value to Ignite: " + value + " : " + count++, Thread.currentThread().getId());
if (!cache.isClosed()) {
cache.put(1, value);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
});
TimeUnit.MILLISECONDS.sleep(500);
continuation = false;
TimeUnit.MILLISECONDS.sleep(500);
if (!output.isClosed()) {
// THIS is where the client sees ALL the data broadcast
// in one shot
output.close();
}
} catch (InterruptedException ex) {
ex.printStackTrace();
} catch (IOException ex) {
ex.printStackTrace();
}
});
LOGGER.info("{} Completing request", Thread.currentThread().getId());
return output;
}
}
Looks like http://github.com/dropwizard/dropwizard/issues/1673 captures the problem. GZip default won't flush even if upper levels ask for it. Solution is something like
((AbstractServerFactory)configuration.getServerFactory()).getGzipFilterFactory().setSyncFlush(true);
will enable flushing to synchronize with GZip if disabling GZip all up is not an option

Transferring assets : Error code 4005 ASSET_UNAVAILABLE

This is driving me crazy. I wrote a code quite a while ago that was working, and opened it again and it happens that I am not able to transfer my assets from the mobile to the wearable device.
public Bitmap loadBitmapFromAsset(Asset asset) {
if (asset == null) {
throw new IllegalArgumentException("Asset must be non-null");
}
// convert asset into a file descriptor and block until it's ready
Log.d(TAG, "api client" + mApiClient);
DataApi.GetFdForAssetResult result = Wearable.DataApi.getFdForAsset(mApiClient, asset).await();
if (result == null) {
Log.w(TAG, "getFdForAsset returned null");
return null;
}
if (result.getStatus().isSuccess()) {
Log.d(TAG, "success");
} else {
Log.d(TAG, result.getStatus().getStatusCode() + ":" + result.getStatus().getStatusMessage());
}
InputStream assetInputStream = result.getInputStream();
if (assetInputStream == null) {
Log.w(TAG, "Requested an unknown Asset.");
return null;
}
// decode the stream into a bitmap
return BitmapFactory.decodeStream(assetInputStream);
}
And this is the code from which I call the loadBitmapFrom Asset method.
DataMap dataMap = DataMapItem.fromDataItem(event.getDataItem()).getDataMap();
ArrayList<DataMap> dataMaps = dataMap.getDataMapArrayList("dataMaps");
ArrayList<String> names = new ArrayList<>();
ArrayList<String> permalinks = new ArrayList<>();
ArrayList<Asset> images = new ArrayList<>();
for (int i = 0 ; i < dataMaps.size() ; i++) {
Log.d(TAG, dataMaps.get(i).getString("name"));
names.add(dataMaps.get(i).getString("name"));
permalinks.add(dataMaps.get(i).getString("permalink"));
images.add(dataMaps.get(i).getAsset("image"));
}
editor.putInt("my_selection_size", names.size());
for (int i=0; i <names.size() ; i++) {
editor.putString("my_selection_name_" + i, names.get(i));
editor.putString("my_selection_permalink_" + i, permalinks.get(i));
Log.d(TAG, "asset number " + i + " " + images.get(i));
Bitmap bitmap = loadBitmapFromAsset(images.get(i));
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
String encoded = Base64.encodeToString(byteArray, Base64.DEFAULT);
editor.putString("my_selection_image_" + i, encoded);
}
And on the mobile side :
private void sendData(PutDataMapRequest dataMap) {
PutDataRequest request = dataMap.asPutDataRequest();
request.setUrgent();
com.google.android.gms.common.api.PendingResult<DataApi.DataItemResult> pendingResult = Wearable.DataApi.putDataItem(mApiClient, request);
pendingResult.setResultCallback(new ResultCallback<DataApi.DataItemResult>() {
#Override
public void onResult(DataApi.DataItemResult dataItemResult) {
com.orange.radio.horizon.tools.Log.d(TAG, "api client : " + mApiClient);
if (dataItemResult.getStatus().isSuccess()) {
com.orange.radio.horizon.tools.Log.d(TAG, "message successfully sent");
} else if (dataItemResult.getStatus().isInterrupted()) {
com.orange.radio.horizon.tools.Log.e(TAG, "couldn't send data to watch (interrupted)");
} else if (dataItemResult.getStatus().isCanceled()) {
com.orange.radio.horizon.tools.Log.e(TAG, "couldn't send data to watch (canceled)");
}
}
});
Log.d(TAG, "Sending data to android wear");
}
class ConfigTask extends AsyncTask<String, Void, String> {
ArrayList<WatchData> mitems;
int mType;
public ConfigTask(ArrayList<WatchData> items, int type)
{
mitems = items;
mType = type;
}
protected String doInBackground(String... str)
{
DataMap dataMap;
ArrayList<DataMap> dataMaps = new ArrayList<>();
Bitmap bitmap = null;
for (int i = 0 ; i < mitems.size() ; i++) {
dataMap = new DataMap();
URL url = null;
try {
url = new URL(mitems.get(i).mUrlSmallLogo);
Log.d(TAG, "url : " + url);
} catch (MalformedURLException e) {
e.printStackTrace();
}
try {
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
} catch (IOException e) {
e.printStackTrace();
}
Asset asset = createAssetFromBitmap(bitmap);
dataMap.putAsset("image", asset);
dataMap.putString("name", mitems.get(i).mName);
dataMap.putString("permalink", mitems.get(i).mPermalink);
dataMaps.add(dataMap);
}
PutDataMapRequest request = null;
switch (mType) {
case 0 :
request = PutDataMapRequest.create(SELECTION_PATH);
break;
case 1 :
request = PutDataMapRequest.create(RADIOS_PATH);
break;
case 2 :
request = PutDataMapRequest.create(PODCASTS_PATH);
break;
}
request.getDataMap().putDataMapArrayList("dataMaps", dataMaps);
request.getDataMap().putString("", "" + System.currentTimeMillis()); //random data to refresh
Log.d(TAG, "last bitmap : " + bitmap);
Log.d(TAG, "===============================SENDING THE DATAMAP ARRAYLIST==================================");
sendData(request);
return "h";
}
protected void onPostExecute(String name)
{
}
}
When executing that code, I see the following error happening :
02-02 14:47:59.586 7585-7601/? D/WearMessageListenerService﹕ 4005:ASSET_UNAVAILABLE
I saw that related thread Why does Wearable.DataApi.getFdForAsset produce a result with status 4005 (Asset Unavailable)? but it didn't really help me
I recently had the same problem... I solved it by updating the Google play service, and adding the same signing configuration to both the app and the wearable module. If it doesn't work on the first build go to "invalidate caches / restart" in files and it should work.

Resources