⬆️ ⬇️

AD called JSMPP

Apparently in the life of every programmer there comes a time when he becomes necessary to learn how to send SMS messages. Yesterday this moment came at me. I must say at once that this need is in no way connected with advertising mailings and other spam. It was necessary to send SMS messages for purely peaceful purposes, as part of the reaction to events detected during equipment monitoring.



The importance of having the possibility of such distribution is difficult to overestimate. Indeed, having sent the accident notice to the contact person's EMail, we cannot count on an immediate response. It is not known when the addressee will read his mail. SMS is delivered much faster.



Our company has long been successfully using its own implementation of SMPP service, and the thought of using a ready SMPP client in Java seemed logical to me. Bravely typing the words "java smpp client" into the google search bar, I immediately found the library I needed. About what happened next, tells my today's post.



As for building projects, I use maven , first of all, I downloaded the latest version of the library from the site, loaded it into the local repository with the following command:

')

mvn install:install-file -Dfile=jsmpp-2.1.0.jar -DgroupId=org.jsmpp -DartifactId=smpp -Dversion=2.1.0 -Dpackaging=jar 


after which he created a pom-file:



pom.xml
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.acme.ae.tests.smpp</groupId> <artifactId>SMPPTest</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>smppTest-${project.version}</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <resource_dir>${project.basedir}/src/main/resources</resource_dir> </properties> <build> <finalName>${project.name}-${project.version}</finalName> <resources> <resource> <directory>${resource_dir}</directory> </resource> </resources> </build> <dependencies> <dependency> <groupId>org.jsmpp</groupId> <artifactId>smpp</artifactId> <version>2.1.0</version> </dependency> </dependencies> </project> 




Preparation of the test application looked quite standard:



Test.java
 package com.acme.ae.tests.smpp; public class Test { private void start() throws IOException { } private void stop() throws IOException { } private void test() { } public static void main(String[] args) { Test t = new Test(); try { try { t.start(); t.test(); } finally { t.stop(); } } catch (Exception e) { System.out.println(e.toString()); } } } 




This was followed by a study of an example courtesy of the developers. A translation specification was used as the second source of inspiration.



To connect to the server, in full accordance with the above-mentioned example, the following code was used:



Server connection
  ... private SMPPSession session = null; private void start() throws IOException { session = new SMPPSession(); session.connectAndBind(SMPP_IP, SMPP_PORT, new BindParameter( BindType.BIND_TX, SMPP_LOGIN, SMPP_PASS, "cp", TypeOfNumber.UNKNOWN, NumberingPlanIndicator.UNKNOWN, null)); } private void stop() throws IOException { if (session != null) { session.unbindAndClose(); } } ... 




The purpose of the parameters here is quite clear from the context. The remaining parameters were taken from the sample code without changes. Since we're only going to send messages, we use BindType.BIND_TX.



The message transfer code (or rather the encoding job), taken from the example, refused to compile:



 ... new GeneralDataCoding(Alphabet.ALPHA_DEFAULT, MessageClass.CLASS1, false) ... 


After comparing the source code of the downloaded library (the latest available version 2.1.0) with the source code on GitHub , it turned out that the developers, for some reason I did not understand, changed the designer's signature:



 - public GeneralDataCoding(boolean compressed, boolean containMessageClass, - MessageClass messageClass, Alphabet alphabet) { + public GeneralDataCoding(Alphabet alphabet, MessageClass messageClass, + boolean compressed) throws IllegalArgumentException { ... } 


Since I used the old version, I had to make adjustments to the code (the sender and receiver addresses in the code are changed):



Short Message Transfer
  ... private static TimeFormatter timeFormatter = new AbsoluteTimeFormatter(); private void test() throws PDUException, ResponseTimeoutException, InvalidResponseException, NegativeResponseException, IOException { String messageId = session.submitShortMessage( "CMT", TypeOfNumber.ALPHANUMERIC, NumberingPlanIndicator.UNKNOWN, "ACME", TypeOfNumber.INTERNATIONAL, NumberingPlanIndicator.ISDN, "7XXXXXXXXXX", new ESMClass(), (byte)0, (byte)1, timeFormatter.format(new Date()), null, new RegisteredDelivery(SMSCDeliveryReceipt.DEFAULT), (byte)0, new GeneralDataCoding( false, false, MessageClass.CLASS1, Alphabet.ALPHA_DEFAULT), (byte)0, "jSMPP simplify SMPP on Java platform".getBytes()); System.out.println("Message submitted, message_id is " + messageId); } ... 




Running the code for execution was not successful. When attempting to create SMPPSession, an exception was thrown:



 Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory at org.jsmpp.session.AbstractSession.<clinit>(AbstractSession.java:51) at com.amfitel.m2000.ae.tests.smpp.Test.start(Test.java:56) at com.amfitel.m2000.ae.tests.smpp.Test.main(Test.java:179) Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory at java.net.URLClassLoader$1.run(URLClassLoader.java:202) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:190) at java.lang.ClassLoader.loadClass(ClassLoader.java:307) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301) at java.lang.ClassLoader.loadClass(ClassLoader.java:248) ... 3 more 


Indeed, in GettingStarted there was a scant mention of using SLF4J . I had to add a dependency in pom.xml:



  ... <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>1.6.1</version> </dependency> ... 


The version number (1.6.1, not 1.4.3, as was stated in GettingStarted) was taken from a pom-file on GitHub. Now an unpleasant error began to be written to the log, but at least the connection to the server was established:



 SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. 


Remark
The problem was solved by adding another dependency, also taken from the source code on GitHub :



  ... <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.6.1</version> </dependency> ... 


After its addition, a normal log was formed, in accordance with the settings specified in log4j.properties. Thanks Googolplex for the advice.



Sending a message was also successful, but on the phone, instead of letters, “squares” came. WireShark came to the rescue :



image



Our SMPP server developer, argued that, for normal sending of messages in Latin, 0 should be sent to Data Coding. I must say that the process of generating various numeric codes dictated by the specification is not obvious when using the JSMPP API. After a brief meditation on the source code, the problem was solved:



  ... new GeneralDataCoding( false, false, - MessageClass.CLASS1, + MessageClass.CLASS0, Alphabet.ALPHA_DEFAULT) ... 


Now it was necessary to learn to send long messages and messages using Cyrillic. To send long messages, I didn’t get tricky with MESSAGE_PAYLOAD, using the approach suggested in the example from the developers.



To transfer Cyrillic, it was necessary to change the encoding and translate the message to UCS-2. From a practical point of view, the latter was poured into the presentation of the text as a sequence of bytes in UTF-16 encoding (you can read about the difference between UCS-2 and UTF-16 here ). As a result, the message sending code looked like this:



Transmission of a long Cyrillic message
 GeneralDataCoding coding = new GeneralDataCoding( false, false, MessageClass.CLASS0, Alphabet.ALPHA_UCS2); final int totalSegments = 3; Random random = new Random(); OptionalParameter sarMsgRefNum = OptionalParameters.newSarMsgRefNum((short)random.nextInt()); OptionalParameter sarTotalSegments = OptionalParameters.newSarTotalSegments(totalSegments); for (int i = 0; i < totalSegments; i++) { final int seqNum = i + 1; String message = " " + seqNum + " of " + totalSegments + " "; OptionalParameter sarSegmentSeqnum = OptionalParameters.newSarSegmentSeqnum(seqNum); String messageId = session.submitShortMessage( "CMT", TypeOfNumber.ALPHANUMERIC, NumberingPlanIndicator.UNKNOWN, "ACME", TypeOfNumber.INTERNATIONAL, NumberingPlanIndicator.ISDN, "7XXXXXXXXXX", new ESMClass(), SMPP_PROTOCOL_ID, // (byte)0 SMPP_PRIORITY_FLAG, // (byte)1 null, null, new RegisteredDelivery(SMSCDeliveryReceipt.DEFAULT), SMPP_REP_IF_P_FLAG, // (byte)0 coding, (byte)0, message.getBytes(Charset.forName("UTF-16")), sarMsgRefNum, sarSegmentSeqnum, sarTotalSegments); System.out.println("Message submitted, message_id is " + messageId); } 




Concluding this article, I want to emphasize that it was written not for the purpose of criticizing JSMPP. The SMPP specification is complex in itself, and the library's developers have done everything possible to facilitate its use as much as possible. Small flaws, in such a project, are inevitable.



I did not write this post for the purpose of scolding anyone, but only because I wanted to make it easier for other people to walk around the rake he himself walked. Please do not take my grumbling too seriously.

Source: https://habr.com/ru/post/202142/



All Articles