I am trying to use HTTP/2 to send an apple notification to my device on production.
I am passing this -Xbootclasspath/p:/home/mohamed/Desktop/alpn-boot-8.1.9.v20160720.jar as a Default VM arguments in eclipse.
Here are the code which i am using now:
public static void pushoNotification() {
try {
// create a low-level Jetty HTTP/2 client
HTTP2Client lowLevelClient = new HTTP2Client();
lowLevelClient.start();
// APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeated header keys and values.
KeyStore ks = KeyStore.getInstance("PKCS12");
// Ensure that the password is the same as the one used later in setKeyStorePassword()
ks.load(PushNotifications.class.getClassLoader().getResourceAsStream("Prod2.p12"), "a12B34".toCharArray());
SslContextFactory ssl = new SslContextFactory(true);
ssl.setKeyStore(ks);
ssl.setKeyStorePassword("a12B34");
// create a high-level Jetty client
HttpClient client = new HttpClient(new HttpClientTransportOverHTTP2(lowLevelClient), ssl);
client.start();
// request-response exchange
ContentResponse response = client.POST("https://api.push.apple.com").path("/3/device/19297dba97212ac6fd16b9cd50f2d86629aed0e49576b2b52ed05086087da802")
.content(new StringContentProvider("{ \"aps\" : { \"alert\" : \"Hello\" } }")).send();
response.toString();
client.stop();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
My dependencies
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.21</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-http-client-transport</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.http2</groupId>
<artifactId>http2-client</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-client</artifactId>
<version>9.4.0.M1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-alpn-client</artifactId>
<version>9.4.0.M1</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.mortbay.jetty.alpn</groupId>
<artifactId>alpn-boot</artifactId>
<version>8.1.9.v20160720</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.2</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.4.1</version>
</dependency>
but when i run this method from main method, it throws java.nio.channels.ClosedChannelException
Also i got this in eclipse console
INFO org.eclipse.jetty.http2.HTTP2Session - Failure while notifying listener org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2$SessionListenerPromise#87eaf9c
Any idea?
Thanks
I am pasting my answer now after about 3 years and 6 month just to help any one get same error, actually i can't recall how i fixed this issue but here are a working code which i am using now...
import java.io.IOException;
import java.io.InputStream;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.inject.Singleton;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.CacheControl;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import org.eclipse.jetty.client.HttpClient;
import org.eclipse.jetty.client.api.ContentResponse;
import org.eclipse.jetty.client.api.Request;
import org.eclipse.jetty.client.util.StringContentProvider;
import org.eclipse.jetty.http2.api.Session;
import org.eclipse.jetty.http2.api.server.ServerSessionListener;
import org.eclipse.jetty.http2.client.HTTP2Client;
import org.eclipse.jetty.http2.client.http.HttpClientTransportOverHTTP2;
import org.eclipse.jetty.util.FuturePromise;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myproject.path.model.APNSObject;
public void sendIOSNotification(APNSObject apnsObject, List<String> deviceIds, String notificationType) {
HTTP2Client lowLevelClient = null;
HttpClient client = null;
String hostname = null;
InputStream inputStream = null;
try {
lowLevelClient = new HTTP2Client(); // create a low-level Jetty HTTP/2 client
lowLevelClient.start();
// APNs requires the use of HPACK (header compression for HTTP/2), which prevents repeated header keys and values.
KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
inputStream = getClass().getClassLoader().getResourceAsStream(APPLE_CERTIFICATE_PATH);
// Ensure that the password is the same as the one used later in setKeyStorePassword()
ks.load(inputStream, APPLE_CERTIFICATE_PASSWORD.toCharArray());
inputStream.close();
SslContextFactory ssl = new SslContextFactory(true);
ssl.setKeyStore(ks);
ssl.setKeyStorePassword(APPLE_CERTIFICATE_PASSWORD);
FuturePromise<Session> sessionPromise = new FuturePromise<>();
if (notificationType != null && notificationType.trim().equalsIgnoreCase("Development"))
hostname = APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME;
else
hostname = APPLE_NOTIFICATION_PRODUCTION_HOSTNAME;
lowLevelClient.connect(ssl, new InetSocketAddress(hostname, Integer.parseInt(APPLE_NOTIFICATION_PORT)), new ServerSessionListener.Adapter(), sessionPromise);
// create a high-level Jetty client
client = new HttpClient(new HttpClientTransportOverHTTP2(lowLevelClient), ssl);
client.start();
// logger.info("Start Sending Notification.");
for (String token : deviceIds) {
ObjectMapper mapper = new ObjectMapper();
String fcmJsonObject = mapper.setSerializationInclusion(Include.NON_NULL).setSerializationInclusion(Include.NON_EMPTY).writeValueAsString(apnsObject);
Request request = client.POST("https://" + hostname).timeout(20, TimeUnit.SECONDS).path("/3/device/" + token)
.content(new StringContentProvider(fcmJsonObject, Charset.forName("UTF-8")));
request = request.header("apns-topic", APPLE_APNS_TOPIC);
ContentResponse response = request.send();
// For development mode if it's not passed in parameters
if (response.getStatus() == 400 && !hostname.equals(APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME)) {
request = client.POST("https://" + APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME).timeout(20, TimeUnit.SECONDS).path("/3/device/" + token)
.content(new StringContentProvider(fcmJsonObject, Charset.forName("UTF-8")));
request = request.header("apns-topic", APPLE_APNS_TOPIC);
response = request.send();
logger.info("Sending notification to '" + token + "' in debugging mode...");
}
if (response.getStatus() == 200)
logger.info("Date: " + new Date() + " Notification sent successfully to '" + token + "' With Response Status: " + response.getStatus());
else
logger.warning("Sending Notification to token '" + token + "' Failed :( >> Response Status: " + response.getStatus() + "\nReason: " + response.getReason());
}
logger.info("End Sending Notification.");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (lowLevelClient != null && !lowLevelClient.isStopped())
lowLevelClient.stop();
if (client != null && !client.isStopped())
client.stop();
} catch (Exception e) {
e.printStackTrace();
}
try {
if (inputStream != null)
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
APNSObject.java class
import java.io.Serializable;
public class APNSObject implements Serializable {
// {\"aps\":{\"alert\":{" + messageTitle + "\"body\":\"" + alert + "\"}, \"sound\":\"default\"}" + payload + "}
private static final long serialVersionUID = 1L;
private Aps aps;
private TripBruEntity payload;// Our custom JSON Object
public APNSObject() {
}
public APNSObject(String title, String body, TripBruEntity payload) {
this(title, body, null, payload);
}
public APNSObject(String title, String body, String sound, TripBruEntity payload) {
aps = new Aps(title, body, sound);
this.payload = payload;
}
public Aps getAps() {
return aps;
}
public void setAps(Aps aps) {
this.aps = aps;
}
public TripBruEntity getPayload() {
return payload;
}
public void setPayload(TripBruEntity payload) {
this.payload = payload;
}
static class Aps {
private Alert alert;
private String sound;
public Aps() {
}
public Aps(String title, String body, String sound) {
this.alert = new Alert(title, body);
this.sound = sound == null || sound.isEmpty() ? "default" : sound;
}
public Alert getAlert() {
return alert;
}
public void setAlert(Alert alert) {
this.alert = alert;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
static class Alert {
private String title;
private String body;
public Alert() {
}
public Alert(String title, String body) {
this.title = title;
this.body = body;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
}
}
}
and here are my configuration file:
APPLE_CERTIFICATE_PATH=/my/apply/certificate/path/so/plz/change/it/Certificates.p12
APPLE_CERTIFICATE_PASSWORD=myPassword(plz change it)
KEYSTORE_TYPE=PKCS12
APPLE_NOTIFICATION_DEVELOPMENT_HOSTNAME=api.development.push.apple.com
APPLE_NOTIFICATION_PRODUCTION_HOSTNAME=api.push.apple.com
APPLE_NOTIFICATION_PORT=2197
APPLE_APNS_TOPIC=MyAPNS_Topic(plz change it)
Last thing, here are jars i used in my project:
Related
I am trying to use aws Transcribe to convert a wav file to text. I have uploaded a wav file to S3, which is located here and it has public read/write permissions: https://s3.us-east-1.amazonaws.com/csld8xmsdksdf8s9sk3mmdjsdifkjksdijsldk/Transcribe2.wav. The wav file is valid. I can download it in my browser and replay it (and it sounds like the origin recording), so I think we can rule out an invalid input file, file permissions, etc.
I am using java version: 1.8.0_275 for mac.
I expect my program to give me back the transcribed text: "Hello amazon Subscribe, what is this?"
Here is the actual program output, including exception:
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java "-javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=60898:/Applications/IntelliJ IDEA CE.app/Contents/bin" -Dfile.encoding=UTF-8 -classpath /Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/charsets.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/cldrdata.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/dnsns.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/jaccess.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/localedata.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/nashorn.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/sunec.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/ext/zipfs.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/jce.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/jfr.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/jsse.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/management-agent.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/resources.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/jre/lib/rt.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/lib/dt.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/lib/jconsole.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/lib/sa-jdi.jar:/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/lib/tools.jar:/Users/cdornin/work/transcribe/target/classes:/Users/cdornin/.m2/repository/org/apiguardian/apiguardian-api/1.0.0/apiguardian-api-1.0.0.jar:/Users/cdornin/.m2/repository/org/junit/platform/junit-platform-commons/1.4.0/junit-platform-commons-1.4.0.jar:/Users/cdornin/.m2/repository/org/slf4j/slf4j-log4j12/1.7.25/slf4j-log4j12-1.7.25.jar:/Users/cdornin/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/cdornin/.m2/repository/log4j/log4j/1.2.17/log4j-1.2.17.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/transcribe/2.15.65/transcribe-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/protocol-core/2.15.65/protocol-core-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/aws-json-protocol/2.15.65/aws-json-protocol-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/sdk-core/2.15.65/sdk-core-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/profiles/2.15.65/profiles-2.15.65.jar:/Users/cdornin/.m2/repository/org/reactivestreams/reactive-streams/1.0.2/reactive-streams-1.0.2.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/auth/2.15.65/auth-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/eventstream/eventstream/1.0.1/eventstream-1.0.1.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/http-client-spi/2.15.65/http-client-spi-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/regions/2.15.65/regions-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/annotations/2.15.65/annotations-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/utils/2.15.65/utils-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/aws-core/2.15.65/aws-core-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/metrics-spi/2.15.65/metrics-spi-2.15.65.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/apache-client/2.15.65/apache-client-2.15.65.jar:/Users/cdornin/.m2/repository/org/apache/httpcomponents/httpclient/4.5.13/httpclient-4.5.13.jar:/Users/cdornin/.m2/repository/commons-codec/commons-codec/1.11/commons-codec-1.11.jar:/Users/cdornin/.m2/repository/org/apache/httpcomponents/httpcore/4.4.11/httpcore-4.4.11.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/netty-nio-client/2.15.65/netty-nio-client-2.15.65.jar:/Users/cdornin/.m2/repository/io/netty/netty-codec-http/4.1.53.Final/netty-codec-http-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-codec-http2/4.1.53.Final/netty-codec-http2-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-codec/4.1.53.Final/netty-codec-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-transport/4.1.53.Final/netty-transport-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-resolver/4.1.53.Final/netty-resolver-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-common/4.1.53.Final/netty-common-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-buffer/4.1.53.Final/netty-buffer-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-handler/4.1.53.Final/netty-handler-4.1.53.Final.jar:/Users/cdornin/.m2/repository/io/netty/netty-transport-native-epoll/4.1.53.Final/netty-transport-native-epoll-4.1.53.Final-linux-x86_64.jar:/Users/cdornin/.m2/repository/io/netty/netty-transport-native-unix-common/4.1.53.Final/netty-transport-native-unix-common-4.1.53.Final.jar:/Users/cdornin/.m2/repository/com/typesafe/netty/netty-reactive-streams-http/2.0.4/netty-reactive-streams-http-2.0.4.jar:/Users/cdornin/.m2/repository/com/typesafe/netty/netty-reactive-streams/2.0.4/netty-reactive-streams-2.0.4.jar:/Users/cdornin/.m2/repository/software/amazon/awssdk/transcribestreaming/2.15.65/transcribestreaming-2.15.65.jar:/Users/cdornin/.m2/repository/com/amazonaws/aws-java-sdk-s3/1.11.939/aws-java-sdk-s3-1.11.939.jar:/Users/cdornin/.m2/repository/com/amazonaws/aws-java-sdk-kms/1.11.939/aws-java-sdk-kms-1.11.939.jar:/Users/cdornin/.m2/repository/com/amazonaws/aws-java-sdk-core/1.11.939/aws-java-sdk-core-1.11.939.jar:/Users/cdornin/.m2/repository/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar:/Users/cdornin/.m2/repository/software/amazon/ion/ion-java/1.0.2/ion-java-1.0.2.jar:/Users/cdornin/.m2/repository/com/fasterxml/jackson/dataformat/jackson-dataformat-cbor/2.6.7/jackson-dataformat-cbor-2.6.7.jar:/Users/cdornin/.m2/repository/joda-time/joda-time/2.8.1/joda-time-2.8.1.jar:/Users/cdornin/.m2/repository/com/amazonaws/jmespath-java/1.11.939/jmespath-java-1.11.939.jar:/Users/cdornin/.m2/repository/com/amazonaws/aws-java-sdk-transcribe/1.11.939/aws-java-sdk-transcribe-1.11.939.jar:/Users/cdornin/.m2/repository/io/minio/minio/8.0.3/minio-8.0.3.jar:/Users/cdornin/.m2/repository/com/carrotsearch/thirdparty/simple-xml-safe/2.7.1/simple-xml-safe-2.7.1.jar:/Users/cdornin/.m2/repository/com/google/guava/guava/29.0-jre/guava-29.0-jre.jar:/Users/cdornin/.m2/repository/com/google/guava/failureaccess/1.0.1/failureaccess-1.0.1.jar:/Users/cdornin/.m2/repository/com/google/guava/listenablefuture/9999.0-empty-to-avoid-conflict-with-guava/listenablefuture-9999.0-empty-to-avoid-conflict-with-guava.jar:/Users/cdornin/.m2/repository/com/google/code/findbugs/jsr305/3.0.2/jsr305-3.0.2.jar:/Users/cdornin/.m2/repository/org/checkerframework/checker-qual/2.11.1/checker-qual-2.11.1.jar:/Users/cdornin/.m2/repository/com/google/errorprone/error_prone_annotations/2.3.4/error_prone_annotations-2.3.4.jar:/Users/cdornin/.m2/repository/com/google/j2objc/j2objc-annotations/1.3/j2objc-annotations-1.3.jar:/Users/cdornin/.m2/repository/com/squareup/okhttp3/okhttp/4.8.1/okhttp-4.8.1.jar:/Users/cdornin/.m2/repository/com/squareup/okio/okio/2.7.0/okio-2.7.0.jar:/Users/cdornin/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib-common/1.3.70/kotlin-stdlib-common-1.3.70.jar:/Users/cdornin/.m2/repository/org/jetbrains/kotlin/kotlin-stdlib/1.3.72/kotlin-stdlib-1.3.72.jar:/Users/cdornin/.m2/repository/org/jetbrains/annotations/13.0/annotations-13.0.jar:/Users/cdornin/.m2/repository/com/fasterxml/jackson/core/jackson-annotations/2.11.2/jackson-annotations-2.11.2.jar:/Users/cdornin/.m2/repository/com/fasterxml/jackson/core/jackson-core/2.11.2/jackson-core-2.11.2.jar:/Users/cdornin/.m2/repository/com/fasterxml/jackson/core/jackson-databind/2.11.2/jackson-databind-2.11.2.jar com.amazonaws.transcribe.AmazonTranscribeServiceImpl
log4j:WARN Continuable parsing error 2 and column 30
log4j:WARN Document root element "Configuration", must match DOCTYPE root "null".
log4j:WARN Continuable parsing error 2 and column 30
log4j:WARN Document is invalid: no grammar found.
log4j:ERROR DOM element is - not a <log4j:configuration> element.
log4j:WARN No appenders could be found for logger (com.amazonaws.AmazonWebServiceClient).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Exception in thread "main" com.amazonaws.services.transcribe.model.AmazonTranscribeException: null (Service: AmazonTranscribe; Status Code: 400; Error Code: null; Request ID: 6BBE51FDC2CA981B; Proxy: null)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1819)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleServiceErrorResponse(AmazonHttpClient.java:1403)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1372)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1145)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:802)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeWithTimer(AmazonHttpClient.java:770)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.execute(AmazonHttpClient.java:744)
at com.amazonaws.http.AmazonHttpClient$RequestExecutor.access$500(AmazonHttpClient.java:704)
at com.amazonaws.http.AmazonHttpClient$RequestExecutionBuilderImpl.execute(AmazonHttpClient.java:686)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:550)
at com.amazonaws.http.AmazonHttpClient.execute(AmazonHttpClient.java:530)
at com.amazonaws.services.transcribe.AmazonTranscribeClient.doInvoke(AmazonTranscribeClient.java:1995)
at com.amazonaws.services.transcribe.AmazonTranscribeClient.invoke(AmazonTranscribeClient.java:1962)
at com.amazonaws.services.transcribe.AmazonTranscribeClient.invoke(AmazonTranscribeClient.java:1951)
at com.amazonaws.services.transcribe.AmazonTranscribeClient.executeStartTranscriptionJob(AmazonTranscribeClient.java:1712)
at com.amazonaws.services.transcribe.AmazonTranscribeClient.startTranscriptionJob(AmazonTranscribeClient.java:1681)
at com.amazonaws.transcribe.AmazonTranscribeServiceImpl.callTranscribeService(AmazonTranscribeServiceImpl.java:34)
at com.amazonaws.transcribe.AmazonTranscribeServiceImpl.main(AmazonTranscribeServiceImpl.java:20)
Here is my java code (add your aws key and secret)
package com.amazonaws.transcribe;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.DefaultAWSCredentialsProviderChain;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.transcribe.AmazonTranscribe;
import com.amazonaws.services.transcribe.AmazonTranscribeClientBuilder;
import com.amazonaws.services.transcribe.model.Media;
import com.amazonaws.services.transcribe.model.StartTranscriptionJobRequest;
import com.amazonaws.services.transcribe.model.StartTranscriptionJobResult;
/**
* #author ravindu.s
*/
public class AmazonTranscribeServiceImpl {
public static void main(String[] args) throws Exception {
System.setProperty("aws.accessKeyId", "myKey");
System.setProperty("aws.secretAccessKey", "mySecret");
callTranscribeService("https://s3.us-east-1.amazonaws.com/csld8xmsdksdf8s9sk3mmdjsdifkjksdijsldk/Transcribe2.wav");
}
public static void callTranscribeService(String mediaFile) {
ClientConfiguration clientConfig = new ClientConfiguration();
clientConfig.setConnectionTimeout(60000);
clientConfig.setMaxConnections(100);
clientConfig.setSocketTimeout(60000);
AmazonTranscribe transcribeClient = AmazonTranscribeClientBuilder.standard().withCredentials(
DefaultAWSCredentialsProviderChain.getInstance()).withEndpointConfiguration(
new AwsClientBuilder.EndpointConfiguration(mediaFile, "us-east-1")).withClientConfiguration(clientConfig).build();
StartTranscriptionJobRequest request = buildRequest(mediaFile);
StartTranscriptionJobResult response = transcribeClient.startTranscriptionJob(request);
System.out.println(response.getTranscriptionJob().getTranscriptionJobStatus());
}
private static StartTranscriptionJobRequest buildRequest(String mediaFile) {
StartTranscriptionJobRequest request = new StartTranscriptionJobRequest();
request.setMediaSampleRateHertz(16000);
request.setMediaFormat("wav");
request.setLanguageCode("en-US");
request.setTranscriptionJobName("JOB-001");
Media media = new Media();
media.setMediaFileUri(mediaFile);
request.setMedia(media);
return request;
}
}
Here is my pom.xml file
<?xml version="1.0" encoding="UTF-8"?>
<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>play</groupId>
<artifactId>transcribeTest</artifactId>
<version>1.0-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<!--<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>-->
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-commons</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.25</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>transcribe</artifactId>
<version>2.15.65</version>
</dependency>
<!-- https://mvnrepository.com/artifact/software.amazon.awssdk/transcribestreaming -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>transcribestreaming</artifactId>
<version>2.15.65</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-s3 -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.939</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazonaws/aws-java-sdk-transcribe -->
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-transcribe</artifactId>
<version>1.11.939</version>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>
</dependencies>
</project>
Here is a Java Code Example that transcribes an audio file located in C:. This is V2.
import org.reactivestreams.Publisher;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import software.amazon.awssdk.core.SdkBytes;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.transcribestreaming.TranscribeStreamingAsyncClient;
import software.amazon.awssdk.services.transcribestreaming.model.*;
import javax.sound.sampled.*;
import java.io.*;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicLong;
public class TranscribeStreamingDemoFile {
private static final Region REGION = Region.US_EAST_1;
private static TranscribeStreamingAsyncClient client;
public static void main(String args[]) throws URISyntaxException, ExecutionException, InterruptedException, LineUnavailableException {
client = TranscribeStreamingAsyncClient.builder()
.region(REGION)
.build();
CompletableFuture<Void> result = client.startStreamTranscription(getRequest(16000),
new AudioStreamPublisher(getStreamFromFile()),
getResponseHandler());
result.get();
client.close();
}
private static InputStream getStreamFromFile() {
try {
File inputFile = new File("C:\\test.wav");
InputStream audioStream = new FileInputStream(inputFile);
return audioStream;
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
private static StartStreamTranscriptionRequest getRequest(Integer mediaSampleRateHertz) {
return StartStreamTranscriptionRequest.builder()
.languageCode(LanguageCode.EN_US)
.mediaEncoding(MediaEncoding.PCM)
.mediaSampleRateHertz(mediaSampleRateHertz)
.build();
}
private static StartStreamTranscriptionResponseHandler getResponseHandler() {
return StartStreamTranscriptionResponseHandler.builder()
.onResponse(r -> {
System.out.println("Received Initial response");
})
.onError(e -> {
System.out.println(e.getMessage());
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
System.out.println("Error Occurred: " + sw.toString());
})
.onComplete(() -> {
System.out.println("=== All records stream successfully ===");
})
.subscriber(event -> {
List<Result> results = ((TranscriptEvent) event).transcript().results();
if (results.size() > 0) {
if (!results.get(0).alternatives().get(0).transcript().isEmpty()) {
System.out.println(results.get(0).alternatives().get(0).transcript());
}
}
})
.build();
}
private static class AudioStreamPublisher implements Publisher<AudioStream> {
private final InputStream inputStream;
private static Subscription currentSubscription;
private AudioStreamPublisher(InputStream inputStream) {
this.inputStream = inputStream;
}
#Override
public void subscribe(Subscriber<? super AudioStream> s) {
if (this.currentSubscription == null) {
this.currentSubscription = new SubscriptionImpl(s, inputStream);
} else {
this.currentSubscription.cancel();
this.currentSubscription = new SubscriptionImpl(s, inputStream);
}
s.onSubscribe(currentSubscription);
}
}
public static class SubscriptionImpl implements Subscription {
private static final int CHUNK_SIZE_IN_BYTES = 1024 * 1;
private final Subscriber<? super AudioStream> subscriber;
private final InputStream inputStream;
private ExecutorService executor = Executors.newFixedThreadPool(1);
private AtomicLong demand = new AtomicLong(0);
SubscriptionImpl(Subscriber<? super AudioStream> s, InputStream inputStream) {
this.subscriber = s;
this.inputStream = inputStream;
}
#Override
public void request(long n) {
if (n <= 0) {
subscriber.onError(new IllegalArgumentException("Demand must be positive"));
}
demand.getAndAdd(n);
executor.submit(() -> {
try {
do {
ByteBuffer audioBuffer = getNextEvent();
if (audioBuffer.remaining() > 0) {
AudioEvent audioEvent = audioEventFromBuffer(audioBuffer);
subscriber.onNext(audioEvent);
} else {
subscriber.onComplete();
break;
}
} while (demand.decrementAndGet() > 0);
} catch (Exception e) {
subscriber.onError(e);
}
});
}
#Override
public void cancel() {
executor.shutdown();
}
private ByteBuffer getNextEvent() {
ByteBuffer audioBuffer = null;
byte[] audioBytes = new byte[CHUNK_SIZE_IN_BYTES];
int len = 0;
try {
len = inputStream.read(audioBytes);
if (len <= 0) {
audioBuffer = ByteBuffer.allocate(0);
} else {
audioBuffer = ByteBuffer.wrap(audioBytes, 0, len);
}
} catch (IOException e) {
throw new UncheckedIOException(e);
}
return audioBuffer;
}
private AudioEvent audioEventFromBuffer(ByteBuffer bb) {
return AudioEvent.builder()
.audioChunk(SdkBytes.fromByteBuffer(bb))
.build();
}
}
}
I had a small mistake in my code. This line wasn't necessary and when I removed, it worked:
withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(mediaFile, "us-east-1"))
I'm trying to write an Http Server using Apache Mina.
According to Mina's architecture, there should be 2 filters for this task, one for Http Request Passing and another for processing the request and generating the response. So using the Mina example codes, I came up with the following code, that has an acceptor, logging filter, Http filter, and a filter for processing request.
Initiation of the server runs correctly, but the request does not come to DummyHttpSever filter. I tried to debug, but could not find the issue. What is going wrong here?
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.mina.filter.logging.LoggingFilter;
import org.apache.mina.api.AbstractIoFilter;
import org.apache.mina.api.IoSession;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.mina.filterchain.ReadFilterChainController;
import org.apache.mina.http.DateUtil;
import org.apache.mina.http.HttpDecoderState;
import org.apache.mina.http.HttpServerDecoder;
import org.apache.mina.http.HttpServerEncoder;
import org.apache.mina.http.api.DefaultHttpResponse;
import org.apache.mina.http.api.HttpContentChunk;
import org.apache.mina.http.api.HttpEndOfContent;
import org.apache.mina.http.api.HttpMethod;
import org.apache.mina.http.api.HttpPdu;
import org.apache.mina.http.api.HttpRequest;
import org.apache.mina.http.api.HttpStatus;
import org.apache.mina.http.api.HttpVersion;
import org.apache.mina.transport.nio.NioTcpServer;
public class HttpTest {
public static void main(String[] args) throws Exception {
NioTcpServer httpServer = new NioTcpServer();
httpServer.setReuseAddress(true);
httpServer.setFilters(new ProtocolCodecFilter<HttpPdu, ByteBuffer, Void, HttpDecoderState>(new HttpServerEncoder(),
new HttpServerDecoder()), new LoggingFilter("DECODED"), new DummyHttpSever());
httpServer.getSessionConfig().setTcpNoDelay(true);
httpServer.bind(new InetSocketAddress(8080));
// run for 20 seconds
Thread.sleep(2000000000);
httpServer.unbind();
}
private static class DummyHttpSever extends AbstractIoFilter {
private HttpRequest incomingRequest;
private List<ByteBuffer> body;
#Override
public void messageReceived(IoSession session, Object message, ReadFilterChainController controller) {
if (message instanceof HttpRequest) {
System.out.println("This shit is working");
incomingRequest = (HttpRequest) message;
body = new ArrayList<ByteBuffer>();
// check if this request is going to be followed by and HTTP body or not
if (incomingRequest.getMethod() != HttpMethod.POST && incomingRequest.getMethod() != HttpMethod.PUT) {
sendResponse(session, incomingRequest);
} else {
}
} else if (message instanceof ByteBuffer) {
body.add((ByteBuffer) message);
} else if (message instanceof HttpEndOfContent) {
// we received all the post content, send the crap back
sendResponse(session, incomingRequest);
}
}
public void sendResponse(IoSession session, HttpRequest request) {
Map<String, String> headers = new HashMap<String, String>();
headers.put("Server", "Apache MINA Dummy test server/0.0.");
headers.put("Date", DateUtil.getCurrentAsString());
headers.put("Connection", "Close");
String strContent = "Hello ! we reply to request !";
ByteBuffer content = ByteBuffer.wrap(strContent.getBytes());
// compute content len
headers.put("Content-Length", String.valueOf(content.remaining()));
session.write(new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SUCCESS_OK, headers));
session.write(new HttpContentChunk(content));
session.write(new HttpEndOfContent());
session.close(false);
}
}
}
Also, following are dependencies I am using.
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-http</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-coap</artifactId>
<version>2.0.7</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<version>LATEST</version>
</dependency>
This is a simple Http web server, which you can modify according to your need. This example is a modification to the example lightweight component of Apache Mina examples.
Main.java
import java.net.InetSocketAddress;
import org.apache.mina.filter.codec.ProtocolCodecFilter;
import org.apache.asyncweb.common.codec.HttpCodecFactory;
import org.apache.asyncweb.examples.lightweight.HttpProtocolHandler;
import org.apache.mina.transport.socket.SocketAcceptor;
import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
public class Main {
public static void main(String[] args) throws Exception {
SocketAcceptor acceptor = new NioSocketAcceptor();
acceptor.getFilterChain().addLast("codec",
new ProtocolCodecFilter(new HttpCodecFactory()));
acceptor.setReuseAddress(true);
acceptor.getSessionConfig().setReuseAddress(true);
acceptor.getSessionConfig().setReceiveBufferSize(1024);
acceptor.getSessionConfig().setSendBufferSize(1024);
acceptor.getSessionConfig().setTcpNoDelay(true);
acceptor.getSessionConfig().setSoLinger(-1);
acceptor.setBacklog(10240);
acceptor.setHandler(new HttpProtocolHandler());
acceptor.bind(new InetSocketAddress(9012));
}
}
HttpProtocalHandler.java
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.future.IoFutureListener;
import org.apache.mina.core.service.IoHandler;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.future.WriteFuture;
import org.apache.asyncweb.common.HttpRequest;
import org.apache.asyncweb.common.HttpResponseStatus;
import org.apache.asyncweb.common.MutableHttpResponse;
import org.apache.asyncweb.common.DefaultHttpResponse;
import org.apache.asyncweb.common.HttpHeaderConstants;
public class HttpProtocolHandler implements IoHandler {
private static final int CONTENT_PADDING = 0; // 101
private final Map<Integer, IoBuffer> buffers = new ConcurrentHashMap<Integer, IoBuffer>();
private final Timer timer;
public HttpProtocolHandler() {
timer = new Timer(true);
}
public void exceptionCaught(IoSession session, Throwable cause)
throws Exception {
if (!(cause instanceof IOException)) {
cause.printStackTrace();
}
session.close();
}
public Dictionary extractParameters(Map hashParameters){
Dictionary parameters = new Hashtable();
Iterator it = hashParameters.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
parameters.put(pair.getKey(), ((ArrayList) pair.getValue()).get(0) );
// it.remove(); // avoids a ConcurrentModificationException
}
return parameters;
}
public void messageReceived(IoSession session, Object message)
throws Exception {
HttpRequest req = (HttpRequest) message;
String path = req.getRequestUri().getPath(); //path: /echo
String end_point = path;
Dictionary parameters = this.extractParameters(req.getParameters());
String response = "";
/* switch (end_point) {
case "/io":
response= new IOHandler().handleRequest(parameters);
break;
case "/cpu":
response= new CPUHandler().handleRequest(parameters);
break;
case "/db":
response= new DBHandler().handleRequest(parameters);
break;
case "/memory":
response= new MemoryHandler().handleRequest(parameters);
break;
default:
response = "No end point found";
} */
response = "No end point found";
MutableHttpResponse res;
// if (path.startsWith("/size/")) {
// doDataResponse(session, req);
// } else if (path.startsWith("/delay/")) {
// doAsynchronousDelayedResponse(session, req);
// } else if (path.startsWith("/adelay/")) {
// doAsynchronousDelayedResponse(session, req);
// } else {
res = new DefaultHttpResponse();
IoBuffer bb = IoBuffer.allocate(1024);
bb.setAutoExpand(true);
bb.putString(response.toString(), Charset.forName("UTF-8").newEncoder());
bb.flip();
res.setContent(bb);
// res.setHeader("Pragma", "no-cache");
// res.setHeader("Cache-Control", "no-cache");
res.setStatus(HttpResponseStatus.OK);
WriteFuture future = session.write(res);
if (!HttpHeaderConstants.VALUE_KEEP_ALIVE.equalsIgnoreCase(
res.getHeader( HttpHeaderConstants.KEY_CONNECTION))) {
future.addListener(IoFutureListener.CLOSE);
}
}
private void writeResponse(IoSession session, HttpRequest req,
MutableHttpResponse res) {
res.normalize(req);
WriteFuture future = session.write(res);
if (!HttpHeaderConstants.VALUE_KEEP_ALIVE.equalsIgnoreCase(
res.getHeader( HttpHeaderConstants.KEY_CONNECTION))) {
future.addListener(IoFutureListener.CLOSE);
}
}
private void doDataResponse(IoSession session, HttpRequest req) {
String path = req.getRequestUri().getPath();
int size = Integer.parseInt(path.substring(path.lastIndexOf('/') + 1))
+ CONTENT_PADDING;
MutableHttpResponse res = new DefaultHttpResponse();
res.setStatus(HttpResponseStatus.OK);
res.setHeader("ETag", "W/\"" + size + "-1164091960000\"");
res.setHeader("Last-Modified", "Tue, 31 Nov 2006 06:52:40 GMT");
IoBuffer buf = buffers.get(size);
if (buf == null) {
buf = IoBuffer.allocate(size);
buffers.put(size, buf);
}
res.setContent(buf.duplicate());
writeResponse(session, req, res);
}
private void doAsynchronousDelayedResponse(final IoSession session,
final HttpRequest req) {
String path = req.getRequestUri().getPath();
int delay = Integer.parseInt(path.substring(path.lastIndexOf('/') + 1));
final MutableHttpResponse res = new DefaultHttpResponse();
res.setStatus(HttpResponseStatus.OK);
res.setHeader("ETag", "W/\"0-1164091960000\"");
res.setHeader("Last-Modified", "Tue, 31 Nov 2006 06:52:40 GMT");
timer.schedule(new TimerTask() {
#Override
public void run() {
writeResponse(session, req, res);
}
}, delay);
}
public void messageSent(IoSession session, Object message) throws Exception {
}
public void sessionClosed(IoSession session) throws Exception {
}
public void sessionCreated(IoSession session) throws Exception {
}
public void sessionIdle(IoSession session, IdleStatus status)
throws Exception {
session.close();
}
public void sessionOpened(IoSession session) throws Exception {
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 30);
}
}
I am totally new in XMPP and Spring Integration, and want to send message to FCM user. I created an XML configuration for Outbound Message as follows:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-xmpp="http://www.springframework.org/schema/integration/xmpp"
...>
<context:component-scan base-package="com.avantovr.esysync_backend.webservices.restful.fcm.xmppserver" />
<int-xmpp:outbound-channel-adapter id="xmppOutboundAdapter" channel="xmppOutboundChannel" xmpp-connection="xmppConnection"/>
<int:service-activator ref="fcmSender" input-channel="xmppOutbound" />
<int:logging-channel-adapter id="xmppOutboundChannel" log-full-message="true" />
</beans>
Now I want to create a Java Class in which there is method for sending Downstrwam messagr via XMPP to FCM. Pls is there any beginner example for sending and receiving xmpp messages to FCM via Spring integration?
This may not be the best solution but its good enough for me. First time dealing with XMPP.
I dont have any XML configurations other than pom.xml dependencies.
There is a 5 seconds sleep and reconnect after a disconnect. FCM disconnects XMPP connection from time to time to load balance.
Sending ACKs back is working, receiveing ACKs and NACKs are not tested.
To send a message from java -> fcm -> phone;
#Autowired
private XmppConfig xmppConfig;
xmppConfig.getXmppConnection().sendStanza(generateStanza(messageId,json));
json above shoulde be like this, from https://firebase.google.com/docs/cloud-messaging/server
{
"to":"REGISTRATION_ID", // "to" replaces "registration_ids"
"message_id":"m-1366082849205" // new required field
"data":
{
"hello":"world",
}
"time_to_live":"600",
"delivery_receipt_requested": true/false
}
smack dependencies
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-tcp</artifactId>
<version>4.3.4</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-java7</artifactId>
<version>4.3.4</version>
</dependency>
<dependency>
<groupId>org.igniterealtime.smack</groupId>
<artifactId>smack-extensions</artifactId>
<version>4.3.4</version>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20190722</version>
</dependency>
application.properties
fcm.sender_id=YOUR_SENDER_ID#fcm.googleapis.com
fcm.server_key=YOUR_SERVER_KEY
fcm.host=fcm-xmpp.googleapis.com
fcm.port=5235
XmppConfig.java
import com.alessoft.utils.Utils;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.roster.Roster;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jxmpp.stringprep.XmppStringprepException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import javax.annotation.PostConstruct;
import javax.net.ssl.SSLSocketFactory;
#Configuration
class XmppConfig implements ConnectionListener {
#Value("${fcm.sender_id}")
private String senderId;
#Value("${fcm.server_key}")
private String server_key;
#Value("${fcm.host}")
private String host;
#Value("${fcm.port}")
private int port;
#Autowired
private XmppService xmppService;
private Logger logger = LoggerFactory.getLogger(XmppConfig.class);
private volatile boolean xmppConnected;
private XMPPTCPConnection xmppConnection;
public XMPPTCPConnection getXmppConnection() {
return xmppConnection;
}
#PostConstruct
public void postConstruct() throws Exception {
new Thread(() -> prepareXmppConnection()).start();
}
public XMPPConnection prepareXmppConnection() {
XMPPTCPConnectionConfiguration conf = null;
try {
conf = XMPPTCPConnectionConfiguration.builder()
.setHost(host)
.setPort(port)
.setSendPresence(false)
.setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)
.setSocketFactory(SSLSocketFactory.getDefault())
.setUsernameAndPassword(senderId, server_key)
.setXmppDomain("somedomain.com")
.build();
} catch (XmppStringprepException e) {
logger.info("prepareXmppConnection error", e);
}
xmppConnection = new XMPPTCPConnection(conf);
xmppConnection.addAsyncStanzaListener(xmppService, xmppService);
xmppConnection.addConnectionListener(this);
Roster.getInstanceFor(xmppConnection).setRosterLoadedAtLogin(false);
establishXmppConnection();
return xmppConnection;
}
private void establishXmppConnection() {
try {
xmppConnection.connect();
xmppConnection.login();
} catch (Exception e) {
logger.info("XMPP establishXmppConnection error", e);
}
}
#Override
public void connectionClosedOnError(Exception e) {
logger.info("LOST CONNECTION TO FCM XMPP ON ERROR", e);
Utils.sleep(5000);
establishXmppConnection();
}
#Override
public void connectionClosed() {
logger.info("LOST CONNECTION TO FCM XMPP");
Utils.sleep(5000);
establishXmppConnection();
}
#Override
public void connected(XMPPConnection connection) {
logger.info("CONNECTED TO FCM XMPP");
}
#Override
public void authenticated(XMPPConnection connection, boolean resumed) {
logger.info("AUTHENTICATED TO FCM XMPP");
}
}
XmppService.java
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.json.JSONObject;
import org.json.XML;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class XmppService implements StanzaListener, StanzaFilter {
private Logger logger = LoggerFactory.getLogger(XmppService.class);
#Autowired
private XmppConfig xmppConfig;
#Override
public void processStanza(Stanza stanzaXml) throws SmackException.NotConnectedException, InterruptedException, SmackException.NotLoggedInException {
JSONObject stanza = XML.toJSONObject(stanzaXml.toXML(null).toString());
if (!stanza.has("message")) return;
JSONObject message = stanza.getJSONObject("message");
if (message.has("type")) {
normalMessage(message);
} else {
otherMessage(message);
}
}
private void otherMessage(JSONObject message) {
JSONObject gcm = message.getJSONObject("gcm");
String contentString = gcm.getString("content");
JSONObject content = new JSONObject(contentString);
if (content.getString("message_type").equals("ack")) {
logger.info("RECEIVED ACK");
} else if (content.getString("message_type").equals("nack")) {
logger.info("RECEIVED NACK: \n" + content.toString(2));
} else {
logger.info("RECEIVED UNKNOWN: \n" + content.toString());
}
}
private void normalMessage(JSONObject message) {
JSONObject gcm = message.getJSONObject("gcm");
String contentString = gcm.getString("content");
JSONObject content = new JSONObject(contentString);
String message_id = content.getString("message_id");
String from = content.getString("from");
if (content.has("message_type")) {
logger.info("NOT FROM DEVICE:\n" + message.toString());
} else {
processMessage(content);
sendAck(message_id, from);
}
}
private void processMessage(JSONObject content) {
// your own processing
}
private void sendAck(String message_id, String regId) {
try {
JSONObject json = new JSONObject();
json.put("to", regId);
json.put("message_id", message_id);
json.put("message_type", "ack");
String messageString = String.format("<message><gcm xmlns=\"google:mobile:data\">%s</gcm></message>", json.toString());
Stanza stanza = PacketParserUtils.parseStanza(messageString);
xmppConfig.getXmppConnection().sendStanza(stanza);
} catch (Exception e) {
logger.info("fcm sending ack error", e);
}
}
private Stanza generateStanza(String messageId, JSONObject json) {
String messageString = String.format("<message id=\"%s\"><gcm xmlns=\"google:mobile:data\">%s</gcm></message>", messageId, json.toString());
try {
return PacketParserUtils.parseStanza(messageString);
} catch (Exception e) {
logger.info("generateStanza error", e);
return null;
}
}
#Override
public boolean accept(Stanza stanza) {
return true;
}
}
We have JAX RS implementation which needs to send back JSON output. But the response size is huge. And the client expects the same synchronously.
Hence I tried to use StreamingOutput... but the client is not really getting the data in chunks.
Below is sample snippet:
Server Side
streamingOutput = new StreamingOutput() {
#Override
public void write(OutputStream out) throws IOException, WebApplicationException {
JsonGenerator jsonGenerator = mapper.getFactory().createGenerator(out);
jsonGenerator.writeStartArray();
for(int i=0; i < 10; i++) {
jsonGenerator.writeStartObject();
jsonGenerator.writeStringField("Response_State", "Response State - " + i);
jsonGenerator.writeStringField("Response_Report", "Response Report - " + i);
jsonGenerator.writeStringField("Error_details", "Error Details - " + i);
jsonGenerator.writeEndObject();;
jsonGenerator.flush();
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jsonGenerator.writeEndArray();
jsonGenerator.close();
}
};
return Response.status(200).entity(streamingOutput).build();
Client
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost("http://localhost:8080/AccessData/FetchReport");
post.setHeader("Content-type", "application/json");
ResponseHandler<HttpResponse> responseHandler = new BasicResponseHandler();
StringEntity entity = new StringEntity(jsonRequest); //jsonRequest is request string
post.setEntity(entity);
HttpResponse response = client.execute(post);
BufferedReader buffReader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
JsonParser jsonParser = new JsonFactory().createParser(buffReader);
while(jsonParser.nextToken() != JsonToken.END_OBJECT) {
System.out.println(jsonParser.getCurrentName() + ":" + jsonParser.getCurrentValue());
}
String output;
while((output = buffReader.readLine()) != null) {
System.out.println(output);
}
In the server side code, I am putting sleep call just to simulate a gap between chunks of data. What I need is that the client should receive chunks of data as and when it is thrown back by the server.
But here the client gets the response in entirety always.
Any possible solution?
Thanks in advance.
It looks like the client side is not implemented correctly: reading the array of the objects using the parser.
Also, I would like to recommend reading and writing a data transfer object instead of low level field-by-field reading and writing.
For the sake of completeness, here is a complete draft example that uses: Jersey 2.25.1, Jetty 9.2.14.v20151106.
Common
ResponseData class
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;
public class ResponseData {
private final String responseState;
private final String responseReport;
private final String errorDetails;
#JsonCreator
public ResponseData(
#JsonProperty("Response_State") final String responseState,
#JsonProperty("Response_Report") final String responseReport,
#JsonProperty("Error_details") final String errorDetails) {
this.responseState = responseState;
this.responseReport = responseReport;
this.errorDetails = errorDetails;
}
public String getResponseState() {
return this.responseState;
}
public String getResponseReport() {
return this.responseReport;
}
public String getErrorDetails() {
return this.errorDetails;
}
#Override
public String toString() {
return String.format(
"ResponseData: responseState: %s; responseReport: %s; errorDetails: %s",
this.responseState,
this.responseReport,
this.errorDetails
);
}
}
Service
ServerProgram class
import java.net.URI;
import org.glassfish.jersey.jackson.JacksonFeature;
import org.glassfish.jersey.jetty.JettyHttpContainerFactory;
import org.glassfish.jersey.server.ResourceConfig;
public class ServerProgram {
public static void main(final String[] args) {
final URI uri = URI.create("http://localhost:8080/");
final ResourceConfig resourceConfig = new ResourceConfig(TestResource.class);
resourceConfig.register(JacksonFeature.class);
JettyHttpContainerFactory.createServer(uri, resourceConfig);
}
}
TestResource class
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.IOException;
import java.io.OutputStream;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.StreamingOutput;
#Path("/")
public class TestResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response getData() {
final StreamingOutput streamingOutput = new JsonStreamingOutput();
return Response.status(200).entity(streamingOutput).build();
}
private static class JsonStreamingOutput implements StreamingOutput {
#Override
public void write(final OutputStream outputStream) throws IOException, WebApplicationException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonFactory jsonFactory = objectMapper.getFactory();
try (final JsonGenerator jsonGenerator = jsonFactory.createGenerator(outputStream)) {
jsonGenerator.writeStartArray();
for (int i = 0; i < 10; i++) {
final ResponseData responseData = new ResponseData(
"Response State - " + i,
"Response Report - " + i,
"Error Details - " + i
);
jsonGenerator.writeObject(responseData);
jsonGenerator.flush();
try {
Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
jsonGenerator.writeEndArray();
}
}
}
}
Client
ClientProgram class
import com.fasterxml.jackson.core.JsonFactory;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import org.glassfish.jersey.client.ClientProperties;
public class ClientProgram {
public static void main(final String[] args) throws IOException {
Client client = null;
try {
client = ClientBuilder.newClient();
client.property(ClientProperties.READ_TIMEOUT, 10000);
try (final InputStream inputStream = client
.target("http://localhost:8080/")
.request(MediaType.APPLICATION_JSON)
.get(InputStream.class);
final BufferedInputStream bufferedInputStream = new BufferedInputStream(inputStream)) {
processStream(bufferedInputStream);
}
} finally {
if (client != null) {
client.close();
}
}
}
private static void processStream(final InputStream inputStream) throws IOException {
final ObjectMapper objectMapper = new ObjectMapper();
final JsonFactory jsonFactory = objectMapper.getFactory();
try (final JsonParser jsonParser = jsonFactory.createParser(inputStream)) {
final JsonToken arrayToken = jsonParser.nextToken();
if (arrayToken == null) {
// TODO: Return or throw exception.
return;
}
if (!JsonToken.START_ARRAY.equals(arrayToken)) {
// TODO: Return or throw exception.
return;
}
// Iterate through the objects of the array.
while (JsonToken.START_OBJECT.equals(jsonParser.nextToken())) {
final ResponseData responseData = jsonParser.readValueAs(ResponseData.class);
System.out.println(responseData);
}
}
}
}
Hope this helps.
I am learning Protocol Buffer in Java. After basic serialization/deserialization, I am attempting to put compression.
In the provided code, I tried to use GZIP but while deserializing, it reads one extra record. It can be seen in System.out printing an extra "," at end.
This problem does not happen when using same code, but with Snappy (Commented in code below). Any suggestions if I am doing something wrong? Or if I can bypass the problem.
Output with GZIP:
id0,NAME0
,
Output with Snappy:
id0,NAME0
Code:
package testPkg;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import org.xerial.snappy.SnappyInputStream;
import org.xerial.snappy.SnappyOutputStream;
public class TestProtoBuf {
public static String fileNm = "C:/testFile";
public static void main(String[] args) throws IOException {
// creating data
List<DataClass> list = new ArrayList<>();
for (int i = 0; i < 1; i++) {
list.add(new DataClass("id" + i, "NAME" + i));
}
// writing data
try (OutputStream os = new GZIPOutputStream(new BufferedOutputStream(new FileOutputStream(fileNm)))
/*OutputStream os = new SnappyOutputStream(new BufferedOutputStream(new FileOutputStream(fileNm)))*/) {
for (DataClass dc : list) {
DataClassProtoBufProxy.DataClass.Builder bld = DataClassProtoBufProxy.DataClass.newBuilder();
bld.setId(dc.id);
bld.setName(dc.name);
bld.build().writeDelimitedTo(os);
}
os.flush();
}
// reading data
try (InputStream is = new GZIPInputStream(new BufferedInputStream(new FileInputStream(fileNm)))
/*InputStream is = new SnappyInputStream(new BufferedInputStream(new FileInputStream(fileNm)))*/) {
while (is.available() > 0) {
DataClassProtoBufProxy.DataClass.Builder bld = DataClassProtoBufProxy.DataClass.newBuilder();
bld.mergeDelimitedFrom(is);
DataClassProtoBufProxy.DataClass dc = bld.build();
System.out.println(dc.getId() + "," + dc.getName());
}
}
}
static class DataClass {
private String id;
private String name;
DataClass() {
id = null;
name = null;
}
DataClass(String id, String name) {
this.id = id;
this.name = name;
}
}
}
The proto file:
// [START declaration]
syntax = "proto3";
package testPkg;
// [END declaration]
// [START java_declaration]
option java_package = "testPkg";
option java_outer_classname = "DataClassProtoBufProxy";
// [END java_declaration]
// [START messages]
message DataClass {
string id = 1;
string name = 20;
}
// [END messages]
Maven dependencies:
<!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java -->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>3.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.xerial.snappy/snappy-java -->
<dependency>
<groupId>org.xerial.snappy</groupId>
<artifactId>snappy-java</artifactId>
<version>1.1.2.6</version>
</dependency>