how to send push notification in iphone using java - java

I want to send push notification to iphone using java. For this I cam across this library called relayrides pushy. But I am new to this APNS thing.
What I want to do
I want to send simple message like 'hello world' to iphone as a notification.
What I have
I have one, Certificates.p12 file with password. I also have device token and gcn ID.
can any one show me some sample code of connecting and sending push notification using pushy. Which maven dependency should I include?, because every time I am visiting some site, I am getting errors like SimpleApnsPushNotification class not found in library or PushManager class is not found. And also what has SLF4J has to do with sending notifications, please provide me some relevant code snippets for handling these issues, because I am totally messed up.

Just to try and help you along a little, I'm going to include some code that implements pushy. The send() method takes in a token String (the device appId), a String value of the text you wish to send, and a custom property you may want to send along (only included as an example for you). I really hope this helps you out.
public class PushNotificationManager {
private static final Log log = LogFactory.getLog(PushNotificationManager.class);
private static final Object SINGLETON_LOCK = new Object();
private static final Object PUSH_MANAGER_LOCK = new Object();
private static PushNotificationManager singleton;
private final SSLContext ssl;
private PushManager<SimpleApnsPushNotification> pushManager;
private PushNotificationManager() throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException {
File certificateFile = new File(PropertyUtil.getInstance().get("apns", "file"));
ssl = SSLContextUtil.createDefaultSSLContext(certificateFile.getAbsolutePath(), "yourCertPassword");
}
private PushManager<SimpleApnsPushNotification> getPushManager() {
if (pushManager == null || pushManager.isShutDown()) {
synchronized (PUSH_MANAGER_LOCK) {
if (pushManager == null || pushManager.isShutDown()) {
ApnsEnvironment apnsEnviroment = ApnsEnvironment.getSandboxEnvironment();
PushManagerConfiguration config = new PushManagerConfiguration();
ApnsConnectionConfiguration connectionConfiguration = new ApnsConnectionConfiguration();
config.setConnectionConfiguration(connectionConfiguration);
PushManager<SimpleApnsPushNotification> newPushManager = new PushManager<SimpleApnsPushNotification>(apnsEnviroment, ssl, null, null, null, config, "ExamplePushManager");
newPushManager.start();
pushManager = newPushManager;
}
}
}
return pushManager;
}
public static PushNotificationManager getInstance() {
if (singleton == null) {
synchronized (SINGLETON_LOCK) {
if (singleton == null) {
try {
singleton = new PushNotificationManager();
} catch (UnrecoverableKeyException | KeyManagementException | KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException e) {
log.error("Error loading key.", e);
}
}
}
}
return singleton;
}
public void send(String tokenString, String text, String customProperty) throws MalformedTokenStringException, InterruptedException {
try {
final byte[] token = TokenUtil.tokenStringToByteArray(tokenString);
final ApnsPayloadBuilder payloadBuilder = new ApnsPayloadBuilder();
payloadBuilder.setAlertBody(text);
payloadBuilder.addCustomProperty("customProperty", customProperty);
getPushManager().getQueue().put(new SimpleApnsPushNotification(token, payloadBuilder.buildWithDefaultMaximumLength()));
} catch (Exception e) {
pushManager = null;
throw e;
}
}

Related

Mixed up Test configuration when using #ResourceArg

TL:DR; When running tests with different #ResourceArgs, the configuration of different tests get thrown around and override others, breaking tests meant to run with specific configurations.
So, I have a service that has tests that run in different configuration setups. The main difference at the moment is the service can either manage its own authentication or get it from an external source (Keycloak).
I firstly control this using test profiles, which seem to work fine. Unfortunately, in order to support both cases, the ResourceLifecycleManager I have setup supports setting up a Keycloak instance and returns config values that break the config for self authentication (This is due primarily to the fact that I have not found out how to get the lifecycle manager to determine on its own what profile or config is currently running. If I could do this, I think I would be much better off than using #ResourceArg, so would love to know if I missed something here).
To remedy this shortcoming, I have attempted to use #ResourceArgs to convey to the lifecycle manager when to setup for external auth. However, I have noticed some really odd execution timings and the config that ends up at my test/service isn't what I intend based on the test class's annotations, where it is obvious the lifecycle manager has setup for external auth.
Additionally, it should be noted that I have my tests ordered such that the profiles and configs shouldn't be running out of order; all the tests that don't care are run first, then the 'normal' tests with self auth, then the tests with the external auth profile. I can see this working appropriately when I run in intellij, and the fact I can tell the time is being taken to start up the new service instance between the test profiles.
Looking at the logs when I throw a breakpoint in places, some odd things are obvious:
When breakpoint on an erring test (before the external-configured tests run)
The start() method of my TestResourceLifecycleManager has been called twice
The first run ran with Keycloak starting, would override/break config
though the time I would expect to need to be taken to start up keycloak not happening, a little confused here
The second run is correct, not starting keycloak
The profile config is what is expected, except for what the keycloak setup would override
When breakpoint on an external-configured test (after all self-configured tests run):
The start() method has now been called 4 times; appears that things were started in the same order as before again for the new run of the app
There could be some weirdness in how Intellij/Gradle shows logs, but I am interpreting this as:
Quarkus initting the two instances of LifecycleManager when starting the app for some reason, and one's config overrides the other, causing my woes.
The lifecycle manager is working as expected; it appropriately starts/ doesn't start keycloak when configured either way
At this point I can't tell if I'm doing something wrong, or if there's a bug.
Test class example for self-auth test (same annotations for all tests in this (test) profile):
#Slf4j
#QuarkusTest
#QuarkusTestResource(TestResourceLifecycleManager.class)
#TestHTTPEndpoint(Auth.class)
class AuthTest extends RunningServerTest {
Test class example for external auth test (same annotations for all tests in this (externalAuth) profile):
#Slf4j
#QuarkusTest
#TestProfile(ExternalAuthTestProfile.class)
#QuarkusTestResource(value = TestResourceLifecycleManager.class, initArgs = #ResourceArg(name=TestResourceLifecycleManager.EXTERNAL_AUTH_ARG, value="true"))
#TestHTTPEndpoint(Auth.class)
class AuthExternalTest extends RunningServerTest {
ExternalAuthTestProfile extends this, providing the appropriate profile name:
public class NonDefaultTestProfile implements QuarkusTestProfile {
private final String testProfile;
private final Map<String, String> overrides = new HashMap<>();
protected NonDefaultTestProfile(String testProfile) {
this.testProfile = testProfile;
}
protected NonDefaultTestProfile(String testProfile, Map<String, String> configOverrides) {
this(testProfile);
this.overrides.putAll(configOverrides);
}
#Override
public Map<String, String> getConfigOverrides() {
return new HashMap<>(this.overrides);
}
#Override
public String getConfigProfile() {
return testProfile;
}
#Override
public List<TestResourceEntry> testResources() {
return QuarkusTestProfile.super.testResources();
}
}
Lifecycle manager:
#Slf4j
public class TestResourceLifecycleManager implements QuarkusTestResourceLifecycleManager {
public static final String EXTERNAL_AUTH_ARG = "externalAuth";
private static volatile MongodExecutable MONGO_EXE = null;
private static volatile KeycloakContainer KEYCLOAK_CONTAINER = null;
private boolean externalAuth = false;
public synchronized Map<String, String> startKeycloakTestServer() {
if(!this.externalAuth){
log.info("No need for keycloak.");
return Map.of();
}
if (KEYCLOAK_CONTAINER != null) {
log.info("Keycloak already started.");
} else {
KEYCLOAK_CONTAINER = new KeycloakContainer()
// .withEnv("hello","world")
.withRealmImportFile("keycloak-realm.json");
KEYCLOAK_CONTAINER.start();
log.info(
"Test keycloak started at endpoint: {}\tAdmin creds: {}:{}",
KEYCLOAK_CONTAINER.getAuthServerUrl(),
KEYCLOAK_CONTAINER.getAdminUsername(),
KEYCLOAK_CONTAINER.getAdminPassword()
);
}
String clientId;
String clientSecret;
String publicKey = "";
try (
Keycloak keycloak = KeycloakBuilder.builder()
.serverUrl(KEYCLOAK_CONTAINER.getAuthServerUrl())
.realm("master")
.grantType(OAuth2Constants.PASSWORD)
.clientId("admin-cli")
.username(KEYCLOAK_CONTAINER.getAdminUsername())
.password(KEYCLOAK_CONTAINER.getAdminPassword())
.build();
) {
RealmResource appsRealmResource = keycloak.realms().realm("apps");
ClientRepresentation qmClientResource = appsRealmResource.clients().findByClientId("quartermaster").get(0);
clientSecret = qmClientResource.getSecret();
log.info("Got client id \"{}\" with secret: {}", "quartermaster", clientSecret);
//get private key
for (KeysMetadataRepresentation.KeyMetadataRepresentation curKey : appsRealmResource.keys().getKeyMetadata().getKeys()) {
if (!SIG.equals(curKey.getUse())) {
continue;
}
if (!"RSA".equals(curKey.getType())) {
continue;
}
String publicKeyTemp = curKey.getPublicKey();
if (publicKeyTemp == null || publicKeyTemp.isBlank()) {
continue;
}
publicKey = publicKeyTemp;
log.info("Found a relevant key for public key use: {} / {}", curKey.getKid(), publicKey);
}
}
// write public key
// = new File(TestResourceLifecycleManager.class.getResource("/").toURI().toString() + "/security/testKeycloakPublicKey.pem");
File publicKeyFile;
try {
publicKeyFile = File.createTempFile("oqmTestKeycloakPublicKey",".pem");
// publicKeyFile = new File(TestResourceLifecycleManager.class.getResource("/").toURI().toString().replace("/classes/java/", "/resources/") + "/security/testKeycloakPublicKey.pem");
log.info("path of public key: {}", publicKeyFile);
// if(publicKeyFile.createNewFile()){
// log.info("created new public key file");
//
// } else {
// log.info("Public file already exists");
// }
try (
FileOutputStream os = new FileOutputStream(
publicKeyFile
);
) {
IOUtils.write(publicKey, os, UTF_8);
} catch (IOException e) {
log.error("Failed to write out public key of keycloak: ", e);
throw new IllegalStateException("Failed to write out public key of keycloak.", e);
}
} catch (IOException e) {
log.error("Failed to create public key file: ", e);
throw new IllegalStateException("Failed to create public key file", e);
}
String keycloakUrl = KEYCLOAK_CONTAINER.getAuthServerUrl().replace("/auth", "");
return Map.of(
"test.keycloak.url", keycloakUrl,
"test.keycloak.authUrl", KEYCLOAK_CONTAINER.getAuthServerUrl(),
"test.keycloak.adminName", KEYCLOAK_CONTAINER.getAdminUsername(),
"test.keycloak.adminPass", KEYCLOAK_CONTAINER.getAdminPassword(),
//TODO:: add config for server to talk to
"service.externalAuth.url", keycloakUrl,
"mp.jwt.verify.publickey.location", publicKeyFile.getAbsolutePath()
);
}
public static synchronized void startMongoTestServer() throws IOException {
if (MONGO_EXE != null) {
log.info("Flapdoodle Mongo already started.");
return;
}
Version.Main version = Version.Main.V4_0;
int port = 27018;
log.info("Starting Flapdoodle Test Mongo {} on port {}", version, port);
IMongodConfig config = new MongodConfigBuilder()
.version(version)
.net(new Net(port, Network.localhostIsIPv6()))
.build();
try {
MONGO_EXE = MongodStarter.getDefaultInstance().prepare(config);
MongodProcess process = MONGO_EXE.start();
if (!process.isProcessRunning()) {
throw new IOException();
}
} catch (Throwable e) {
log.error("FAILED to start test mongo server: ", e);
MONGO_EXE = null;
throw e;
}
}
public static synchronized void stopMongoTestServer() {
if (MONGO_EXE == null) {
log.warn("Mongo was not started.");
return;
}
MONGO_EXE.stop();
MONGO_EXE = null;
}
public synchronized static void cleanMongo() throws IOException {
if (MONGO_EXE == null) {
log.warn("Mongo was not started.");
return;
}
log.info("Cleaning Mongo of all entries.");
}
#Override
public void init(Map<String, String> initArgs) {
this.externalAuth = Boolean.parseBoolean(initArgs.getOrDefault(EXTERNAL_AUTH_ARG, Boolean.toString(this.externalAuth)));
}
#Override
public Map<String, String> start() {
log.info("STARTING test lifecycle resources.");
Map<String, String> configOverride = new HashMap<>();
try {
startMongoTestServer();
} catch (IOException e) {
log.error("Unable to start Flapdoodle Mongo server");
}
configOverride.putAll(startKeycloakTestServer());
return configOverride;
}
#Override
public void stop() {
log.info("STOPPING test lifecycle resources.");
stopMongoTestServer();
}
}
The app can be found here: https://github.com/Epic-Breakfast-Productions/OpenQuarterMaster/tree/main/software/open-qm-base-station
The tests are currently failing in the ways I am describing, so feel free to look around.
Note that to run this, you will need to run ./gradlew build publishToMavenLocal in https://github.com/Epic-Breakfast-Productions/OpenQuarterMaster/tree/main/software/libs/open-qm-core to install a dependency locally.
Github issue also tracking this: https://github.com/quarkusio/quarkus/issues/22025
Any use of #QuarkusTestResource() without restrictToAnnotatedClass set to true, means that the QuarkusTestResourceLifecycleManager will be applied to all tests no matter where the annotation is placed.
Hope restrictToAnnotatedClass will solve the problem.

Java - Override a WebRequest on Web Service Call

Quick background, our company connects to an ERP system (Sage) via web services for some functions. We have both c# (.net) and java code that performs calls to the Web Service (WS). Recently Sage introduced Basic Authentication into their WS.
Please note: This is a JAVA question, but I'll show an example in C# first to explain.
In the c# program, I first would create an object that is for accessing the WS:
var sageService = new CAdxWebServiceXmlCCServiceBasicAuth();
I then set up credential information:
var sageServiceCallContext = SageFactory.Instance.GetCallContext();
sageService.Credentials = new NetworkCredential(SageUser, SagePwd);
sageService.PreAuthenticate = true;
then finally the call to the specific web service method:
sageCustomerSvcResponse = sageService.run(sageServiceCallContext, "YTDPROF", sageCustomerRequestInXml);
When I set up the service object I use a custom class that looks like this:
public class CAdxWebServiceXmlCCServiceBasicAuth : CAdxWebServiceXmlCCService
{
protected override WebRequest GetWebRequest(Uri uri)
{
HttpWebRequest webRequest = (HttpWebRequest)base.GetWebRequest(uri);
NetworkCredential credentials = Credentials as NetworkCredential;
if (credentials != null)
{
string authInfo = "";
if (credentials.Domain != null && credentials.Domain.Length > 0)
{
authInfo = string.Format(#"{0}\{1}:{2}", credentials.Domain, credentials.UserName, credentials.Password);
}
else
{
authInfo = string.Format(#"{0}:{1}", credentials.UserName, credentials.Password);
};
authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo));
webRequest.Headers["Authorization"] = "Basic " + authInfo;
}
return webRequest;
}
}
What happens is that now, when I perform any call to the web service methods, the GetWebRequest from the class is invoked every time. This is how we implemented basis authentication in c#.
How do I do this in Java?
In the java code currently, I create the service object (that which accesses the web services) this way:
WebServiceInvoker service = new WebServiceInvoker(SageWSURL,"");
and the WebServiceInvoker looks like this (truncated for brevity):
public WebServiceInvoker(String url, String dummy) throws ServiceException, IOException {
serviceLocator = new CAdxWebServiceXmlCCServiceLocator();
service = serviceLocator.getCAdxWebServiceXmlCC(url);
cc = new CAdxCallContext();
cc.setCodeLang("ENG");
cc.setCodeUser("USER");
cc.setPassword("PAWWORD");
cc.setPoolAlias("POOL");
cc.setRequestConfig("adxwss.trace.on=on&adxwss.trace.size=16384&adonix.trace.on=on&adonix.trace.level=3&adonix.trace.size=8");
log = new PrintWriter(new BufferedWriter(new FileWriter("C:/Kalio/service/orders/log.txt")));
}
the webservice locator looks like this:
public class CAdxWebServiceXmlCCServiceLocator extends org.apache.axis.client.Service implements com.adonix.www.WSS.CAdxWebServiceXmlCCService {
public CAdxWebServiceXmlCCServiceLocator() {
}
public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC() throws javax.xml.rpc.ServiceException {
java.net.URL endpoint;
System.out.println("using local Sage Web Servivce URL:" + CAdxWebServiceXmlCC_address);
try {
endpoint = new java.net.URL(CAdxWebServiceXmlCC_address);
}
catch (java.net.MalformedURLException e) {
throw new javax.xml.rpc.ServiceException(e);
}
return getCAdxWebServiceXmlCC(endpoint);
}
public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(java.net.URL portAddress) throws javax.xml.rpc.ServiceException {
try {
com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub _stub = new com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub(portAddress, this);
_stub.setPortName(getCAdxWebServiceXmlCCWSDDServiceName());
return _stub;
}
catch (org.apache.axis.AxisFault e) {
return null;
}
}
and the specific method within that class is this:
public String getCustomer(String constructedXML) throws RemoteException {
**CAdxResultXml result = service.run(cc, "XTDPROF", constructedXML);**
CAdxMessage[] messages = result.getMessages();
for (int i = 0; i<messages.length; i++) {
CAdxMessage message = messages[i];
log.println("X3 get customer message: " + message.getMessage());
log.println("X3 get customer message type: " + message.getType());
}
return result.getResultXml();
}
So my questions is, how to I emulate that override that I see in the .net program in Java? It seems like it would be somewhere in either the service locator or invoker, but the program does not use standard http classes, but this adxwss stuff. I tried a straight c# to java conversion and that way didn't help. I have seen examples where basicAuth is implemented, but not against web service calls.
The c# is pretty clear cut, because once I create the service object using the basicAuth override, every web service calls goes through the orderride. How does that happen in Java?
I'll be happy to provide more info if needed and I'll continue to look/experiment, but at the moment I'm treading water.
Adding:
In tracing through the java code I found the specific web service call (run) where an apache "call" object is created. Is this where basicauth can be added?
public com.adonix.www.WSS.CAdxResultXml run(com.adonix.www.WSS.CAdxCallContext callContext, java.lang.String publicName, java.lang.String inputXml) throws java.rmi.RemoteException {
if (super.cachedEndpoint == null) {
throw new org.apache.axis.NoEndPointException();
}
org.apache.axis.client.Call _call = createCall();
_call.setOperation(_operations[0]);
_call.setUseSOAPAction(true);
_call.setSOAPActionURI("");
_call.setSOAPVersion(org.apache.axis.soap.SOAPConstants.SOAP11_CONSTANTS);
_call.setOperationName(new javax.xml.namespace.QName("http://www.adonix.com/WSS", "run"));
setRequestHeaders(_call);
setAttachments(_call);
try { java.lang.Object _resp = _call.invoke(new java.lang.Object[] {callContext, publicName, inputXml});
if (_resp instanceof java.rmi.RemoteException) {
throw (java.rmi.RemoteException)_resp;
}
else {
extractAttachments(_call);
try {
return (com.adonix.www.WSS.CAdxResultXml) _resp;
} catch (java.lang.Exception _exception) {
return (com.adonix.www.WSS.CAdxResultXml) org.apache.axis.utils.JavaUtils.convert(_resp, com.adonix.www.WSS.CAdxResultXml.class);
}
}
} catch (org.apache.axis.AxisFault axisFaultException) {
throw axisFaultException;
}
}
The solution I came up with is not elegant, but then I'm not a guru in Java, just know enough to be given these tasks.
Our company uses Sage as our ERP system and Sage has a WSDL to define the basic web services it provides.
Sage Web Servicew WSDL
In their latest version of Sage they went with basic authentication, but did not build it into the new WSDL. Since I could not seem to extend the class (CAdxWebServiceXmlCCService), I just copied/pasted a new class called CAdxWebServiceXmlCCServiceBasicAuth. The full code is shown below if anyone ever has need to deal with something like this in a web service.
The key point where BaiscAuth set set up is in the getCAdxWebServiceXmlCC method. I added setPassword and setUserName to the stub that is returned. What this accomplishes is that every time I perform a webservice method call, that stub is now part of the header.
package com.adonix.www.WSS;
import java.net.URL;
import java.util.Base64;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import javax.xml.rpc.ServiceException;
public class CAdxWebServiceXmlCCServiceBasicAuth extends org.apache.axis.client.Service implements com.adonix.www.WSS.CAdxWebServiceXmlCCService {
public CAdxWebServiceXmlCCServiceBasicAuth() {
}
public CAdxWebServiceXmlCCServiceBasicAuth(org.apache.axis.EngineConfiguration config) {
super(config);
}
public CAdxWebServiceXmlCCServiceBasicAuth(java.lang.String wsdlLoc, javax.xml.namespace.QName sName) throws javax.xml.rpc.ServiceException {
super(wsdlLoc, sName);
}
// Use to get a proxy class for CAdxWebServiceXmlCC
private java.lang.String CAdxWebServiceXmlCC_address = "http://10.28.0.7:8124/soap-generic/syracuse/collaboration/syracuse/CAdxWebServiceXmlCC";
public java.lang.String getCAdxWebServiceXmlCCAddress() {
return CAdxWebServiceXmlCC_address;
}
// The WSDD service name defaults to the port name.
private java.lang.String CAdxWebServiceXmlCCWSDDServiceName = "CAdxWebServiceXmlCC";
public java.lang.String getCAdxWebServiceXmlCCWSDDServiceName() {
return CAdxWebServiceXmlCCWSDDServiceName;
}
public void setCAdxWebServiceXmlCCWSDDServiceName(java.lang.String name) {
CAdxWebServiceXmlCCWSDDServiceName = name;
}
public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(String userName,String password) throws javax.xml.rpc.ServiceException {
java.net.URL endpoint;
try {
endpoint = new java.net.URL(CAdxWebServiceXmlCC_address);
}
catch (java.net.MalformedURLException e) {
throw new javax.xml.rpc.ServiceException(e);
}
return getCAdxWebServiceXmlCC(endpoint,userName,password);
}
public com.adonix.www.WSS.CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(java.net.URL portAddress,String userName,String password) throws javax.xml.rpc.ServiceException {
try {
com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub _stub = new com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub(portAddress, this);
_stub.setPortName(getCAdxWebServiceXmlCCWSDDServiceName());
_stub.setPassword(password);
_stub.setUsername(userName);
return _stub;
}
catch (org.apache.axis.AxisFault e) {
return null;
}
}
public void setCAdxWebServiceXmlCCEndpointAddress(java.lang.String address) {
CAdxWebServiceXmlCC_address = address;
}
/**
* For the given interface, get the stub implementation.
* If this service has no port for the given interface,
* then ServiceException is thrown.
*/
public java.rmi.Remote getPort(Class serviceEndpointInterface) throws javax.xml.rpc.ServiceException {
try {
if (com.adonix.www.WSS.CAdxWebServiceXmlCC.class.isAssignableFrom(serviceEndpointInterface)) {
com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub _stub = new com.adonix.www.WSS.CAdxWebServiceXmlCCSoapBindingStub(new java.net.URL(CAdxWebServiceXmlCC_address), this);
_stub.setPortName(getCAdxWebServiceXmlCCWSDDServiceName());
return _stub;
}
}
catch (java.lang.Throwable t) {
throw new javax.xml.rpc.ServiceException(t);
}
throw new javax.xml.rpc.ServiceException("There is no stub implementation for the interface: " + (serviceEndpointInterface == null ? "null" : serviceEndpointInterface.getName()));
}
/**
* For the given interface, get the stub implementation.
* If this service has no port for the given interface,
* then ServiceException is thrown.
*/
public java.rmi.Remote getPort(javax.xml.namespace.QName portName, Class serviceEndpointInterface) throws javax.xml.rpc.ServiceException {
if (portName == null) {
return getPort(serviceEndpointInterface);
}
java.lang.String inputPortName = portName.getLocalPart();
if ("CAdxWebServiceXmlCC".equals(inputPortName)) {
return getCAdxWebServiceXmlCC();
}
else {
java.rmi.Remote _stub = getPort(serviceEndpointInterface);
((org.apache.axis.client.Stub) _stub).setPortName(portName);
return _stub;
}
}
public javax.xml.namespace.QName getServiceName() {
return new javax.xml.namespace.QName("http://www.adonix.com/WSS", "CAdxWebServiceXmlCCService");
}
private java.util.HashSet ports = null;
public java.util.Iterator getPorts() {
if (ports == null) {
ports = new java.util.HashSet();
ports.add(new javax.xml.namespace.QName("http://www.adonix.com/WSS", "CAdxWebServiceXmlCC"));
}
return ports.iterator();
}
/**
* Set the endpoint address for the specified port name.
*/
public void setEndpointAddress(java.lang.String portName, java.lang.String address) throws javax.xml.rpc.ServiceException {
if ("CAdxWebServiceXmlCC".equals(portName)) {
setCAdxWebServiceXmlCCEndpointAddress(address);
}
else
{ // Unknown Port Name
throw new javax.xml.rpc.ServiceException(" Cannot set Endpoint Address for Unknown Port" + portName);
}
}
/**
* Set the endpoint address for the specified port name.
*/
public void setEndpointAddress(javax.xml.namespace.QName portName, java.lang.String address) throws javax.xml.rpc.ServiceException {
setEndpointAddress(portName.getLocalPart(), address);
}
#Override
public CAdxWebServiceXmlCC getCAdxWebServiceXmlCC() throws ServiceException {
// TODO Auto-generated method stub
return null;
}
#Override
public CAdxWebServiceXmlCC getCAdxWebServiceXmlCC(URL portAddress) throws ServiceException {
// TODO Auto-generated method stub
return null;
}
}

Getting EventHubException : Connection aborted when I create TWO instances of EventHubClient

This is also not a duplicate of 'Connection aborted' error while trying to send events to Azure Event Hub using java EventHubClient API because the issue in this question was related to proxy. This is NOT an issue with my proxy settings as this code works for Singe Event hub client
My Question: Is it possible to have a Java Application which sends messages to TWO or more Event Hub Clients?
I am trying to publish/send event data to Multiple instances of Azure Event hubs.
I have provisioned TWO event hub namespaces and each namespace has its event hub.
I have in all TWO event hubs which have their own Connection Strings, SAS Keys and Namespaces and Names.
Since each event hub namespace can only support 20 Throughput units without manual intervention( service request), I am trying to find if I can send my data to Multiple Event hubs.
I can see that my code works fine for SINGLE EventHubClient. The moment, my code tries to create the second EventHubClient, I get this connection aborted exception.
I am using the sample code shared on azure's git hub at https://github.com/MicrosoftDocs/azure-docs/blob/master/articles/event-hubs/event-hubs-java-get-started-send.md
I see the below exception:
Exception in thread "main" com.microsoft.azure.eventhubs.EventHubException: connection aborted
at com.microsoft.azure.eventhubs.impl.ExceptionUtil.toException(ExceptionUtil.java:59)
at com.microsoft.azure.eventhubs.impl.MessagingFactory.onConnectionError(MessagingFactory.java:249)
at com.microsoft.azure.eventhubs.impl.ConnectionHandler.onTransportError(ConnectionHandler.java:102)
at org.apache.qpid.proton.engine.BaseHandler.handle(BaseHandler.java:191)
at org.apache.qpid.proton.engine.impl.EventImpl.dispatch(EventImpl.java:108)
at org.apache.qpid.proton.reactor.impl.ReactorImpl.dispatch(ReactorImpl.java:324)
at org.apache.qpid.proton.reactor.impl.ReactorImpl.process(ReactorImpl.java:291)
at com.microsoft.azure.eventhubs.impl.MessagingFactory$RunReactor.run(MessagingFactory.java:445)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Any pointers/inputs will be highly appreciated.
Here is the relevant code:
public class Sender {
private static final String EVENTHUB_NS1= "TT";
private static final String EVENTHUB1= "TT";
private static final String SAS_KEY_NAME1= "RootManageSharedAccessKey";
private static final String SAS_KEY_VAL1= "SECRET1";
private static final String EVENTHUB_NS2= "TT1";
private static final String EVENTHUB2= "TT1";
private static final String SAS_KEY_NAME2= "RootManageSharedAccessKey";
private static final String SAS_KEY_VAL2= "SECRET2";
private EventData getEventData(int eventDataPrefix) throws IOException, URISyntaxException {
String msgData = "<=>"+eventDataPrefix + "<=>"+"TEST MESSAGE..";
final Gson gson = new GsonBuilder().create();
byte [] data =gson.toJson(msgData).getBytes(Charset.defaultCharset());
EventData ed = EventData.create(data);
return ed;
}
public static final int MAX_BATCH_SIZE=100;
private List<EventData> getBatchOfEvents() throws IOException, URISyntaxException {
List<EventData> events = new ArrayList<>();
for(int i = 0; i < MAX_BATCH_SIZE; i ++){
events.add(getEventData(i));
}
return events;
}
private List<String> getConnectionStrings(){
List<String> connStrings = new ArrayList<>();
ConnectionStringBuilder csBldr1 = new ConnectionStringBuilder();
csBldr1.setNamespaceName(EVENTHUB_NS1);
csBldr1.setEventHubName(EVENTHUB1);
csBldr1.setSasKeyName(SAS_KEY_NAME1);
csBldr1.setSasKey(SAS_KEY_VAL1);
ConnectionStringBuilder csbldr2 = new ConnectionStringBuilder();
csbldr2.setNamespaceName(EVENTHUB_NS2);
csbldr2.setEventHubName(EVENTHUB2);
csbldr2.setSasKeyName(SAS_KEY_NAME2);
csbldr2.setSasKey(SAS_KEY_VAL2);
connStrings.add(csBldr1.toString());
connStrings.add(csbldr2.toString());
return connStrings;
}
private List<EventHubClient> getEHClients() throws IOException, EventHubException, ExecutionException, InterruptedException {
List<EventHubClient> ehClients = new ArrayList<>();
System.out.println("Starting getEhCLients..");
for( String connStr: getConnectionStrings()){
final ExecutorService executorService = Executors.newSingleThreadExecutor();
//The second iteration of for loop gives the EventHubException
EventHubClient client= EventHubClient.createSync(connStr, executorService);
ehClients.add(client);
System.out.println("EH CONNSTR::"+connStr);
}
return ehClients;
}
private void sendBatch( List<EventData> events) throws IOException, EventHubException, ExecutionException, InterruptedException {
List<EventHubClient> ehClients = getEHClients();
if( ehClients.size() <=0) {
System.out.println("NO EH CLients.. to send..");
return;
}
for(int i = 0; i < events.size();i++){
EventData data = events.get(i);
int ehClientIndex = i % ehClients.size();
EventHubClient client = ehClients.get(ehClientIndex);
client.sendSync(data);
System.out.print("MsgSent:"+ehClientIndex);
}
System.out.println("\nDone");
}
public static void main(String[] args) throws IOException, URISyntaxException, EventHubException, ExecutionException, InterruptedException {
Sender sender = new Sender();
List<EventData> events = sender.getBatchOfEvents();
sender.sendBatch(events);
}
}
Very interesting use case, I could try to reproduce from my side. My guess is that EventHubClient has some static field, which will be shared by multiple instance, this might cause your issue.
Besides that, I want to understand why use two namespace, how to about one namespace with higher throughput. One namespace is like a cluster. Actually, I'm from Spring Cloud Azure, and try to improve Java experience on Azure. Feel free to try our event hub binder. https://github.com/Microsoft/spring-cloud-azure

Custom DNS Server using Netty

I have been trying to write a custom DNS server using netty. I have used the DatagramDnsQueryDecoder to parse in the incoming DNSQuery UDP packets but I cannot figure out how to send a response to resolve a domain name. I have received the DatagramDnsQuery object from the handler but cannot find a way to initialize DatagramDnsResponse and add a test DNS record and send it back to the client through DatagramDnsResponseEncoder.
Here is what i have done so far
public class DNSListen {
public static void main(String[] args) {
final NioEventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(group)
.channel(NioDatagramChannel.class)
.handler(new ChannelInitializer<NioDatagramChannel>() {
#Override
protected void initChannel(NioDatagramChannel nioDatagramChannel) throws Exception {
nioDatagramChannel.pipeline().addLast(new DatagramDnsQueryDecoder());
nioDatagramChannel.pipeline().addLast(new DatagramDnsResponseEncoder());
nioDatagramChannel.pipeline().addLast(new DNSMessageHandler());
}
})
.option(ChannelOption.SO_BROADCAST, true);
ChannelFuture future = bootstrap.bind(53).sync();
future.channel().closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
group.shutdownGracefully();
}
}
}
here is the Handler for DNSMessages
public class DNSMessageHandler extends SimpleChannelInboundHandler<DatagramDnsQuery> {
#Override
protected void channelRead0(ChannelHandlerContext ctx, DatagramDnsQuery dnsMessage) throws Exception {
System.out.println(dnsMessage.content());
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
}
}
I get the output for multiple DNS Requests when I run this and Set the System DNS as 127.0.0.1
But I cannot find a way to send a dummy DNS Response so that the IP address is resolved for the requested domain. (I think I should initialize a DatagramDnsResponse object and write it back to the user, but is that correct?, if so how do I initialize it with a dummy IP as the resolved IP)
Am I in the wrong path, can someone please direct me to the correct path . thanks.
It's pretty easy actualy you just need an instance of DatagramDnsResponse and add a dns record with the addRecord method thats all.
Here an example for a SRV answer:
DatagramDnsResponse response = new DatagramDnsResponse(msg.recipient(), msg.sender(), msg.id());
ByteBuf buf = Unpooled.buffer();
buf.writeShort(0); // priority
buf.writeShort(0); // weight
buf.writeShort(993); // port
encodeName("my.domain.tld", buf); // target (special encoding: https://tools.ietf.org/html/rfc1101)
response.addRecord(DnsSection.ANSWER, new DefaultDnsRawRecord("_myprotocol._tcp.domain.tld." /* requested domain */, DnsRecordType.SRV, 30 /* ttl */ , buf));
ctx.writeAndFlush(response);
Edit
To encode a name use this function (I extracted it from netty):
public void encodeName(String name, ByteBuf buf) throws Exception {
if(".".equals(name)) {
buf.writeByte(0);
return;
}
final String[] labels = name.split("\\.");
for (String label : labels) {
final int labelLen = label.length();
if (labelLen == 0)
break;
buf.writeByte(labelLen);
ByteBufUtil.writeAscii(buf, label);
}
buf.writeByte(0);
}
To decode a SRV record you could use this snippet:
DnsRawRecord record = msg.recordAt(DnsSection.ANSWER, 0); //msg is a DnsResponse
if(record.type() == DnsRecordType.SRV) {
ByteBuf buf = record.content();
System.out.println("\tPriority: " + buf.readUnsignedShort());
System.out.println("\tWeight: " + buf.readUnsignedShort());
System.out.println("\tPort: " + buf.readUnsignedShort());
System.out.println("\tTarget:" + DefaultDnsRecordDecoder.decodeName(buf));
}

Not able to load application.conf from cron job in play framework 2.4

I have created a cron job that start during application restart but when i tried to create db connection i am geeting null pointer exception. I am able to create and use db from other module using same configuration.
Below is my Application.conf
db.abc.driver=com.mysql.jdbc.Driver
db.abc.url="jdbc:mysql://localhost:3306/db_name?useSSL=false"
db.abc.username=root
db.abc.password=""
db.abc.autocommit=false
db.abc.isolation=READ_COMMITTED
And code that tried to access db is
public class SchduleJob extends AbstractModule{
#Override
protected void configure() {
bind(JobOne.class)
.to(JobOneImpl.class)
.asEagerSingleton();
} }
#ImplementedBy(JobOneImpl.class)
public interface JobOne {}
#Singleton
public class JobOneImpl implements JobOne {
final ActorSystem actorSystem = ActorSystem.create("name");
final ActorRef alertActor = actorSystem.actorOf(AlertActor.props);
public JobOneImpl() {
scheduleJobs();
}
private Cancellable scheduleJobs() {
return actorSystem.scheduler().schedule(
Duration.create(0, TimeUnit.MILLISECONDS), //Initial delay 0 milliseconds
Duration.create(6, TimeUnit.MINUTES), //Frequency 30 minutes
alertActor,
"alert",
actorSystem.dispatcher(),
null
);
}
}
public class AlertActor extends UntypedActor{
public static Props props = Props.create(AlertActor.class);
final ActorSystem actorSystem = ActorSystem.create("name");
final ActorRef messageActor = actorSystem.actorOf(MessageActor.props());
#Override
public void onReceive(Object message) throws Exception {
if(message != null && message instanceof String) {
RequestDAO requestDAO = new RequestDAO();
try {
List<DBRow> rows = requestDAO.getAllRow();
} catch(Exception exception) {
exception.printStackTrace();
}
}
}
}
public class RequestDAO {
public List<DBRow> getAllRow() throws Exception {
List<DBRow> rows = new ArrayList<DBRow>();
Connection connection = null;
try {
connection = DB.getDataSource("abc").getConnection();
connection.setAutoCommit(false);
} catch(Exception exception) {
exception.printStackTrace();
if(connection != null) {
connection.rollback();
} else {
System.out.println("in else***********");
}
return null;
} finally {
if(connection != null)
connection.close();
}
return schools;
}
When i am calling method getAllRow() of RequestDAO class it's throwing
java.lang.NullPointerException
at play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:235)
at play.api.Application$$anonfun$instanceCache$1.apply(Application.scala:235)
at play.utils.InlineCache.fresh(InlineCache.scala:69)
at play.utils.InlineCache.apply(InlineCache.scala:55)
at play.api.db.DB$.db(DB.scala:22)
at play.api.db.DB$.getDataSource(DB.scala:41)
at play.api.db.DB.getDataSource(DB.scala)
at play.db.DB.getDataSource(DB.java:33)
But same code is working without cron job. What should i do to remove this error
Play uses the Typesafe config library for configuration.
I suspect your current working directory from the cron script isn't set, so it's probably not finding your application.conf (application.properties) file.
However, Config is nice in that it allows you to specify where to look for the file, either by its base name (to choose among .conf | .properties | .json extensions) or the filename including the extension on the java command line:
To specify the base name, use -Dconfig.resource=/path/to/application
To specify the full name, use -Dconfig.file=/path/to/application.properties

Categories