Apple push notification services in java, linux development machine - java

I'm developing a mobile application with a mac, but it connects to a test server I'm running on linux and I'd like to enable APN on this server with a developer certificate, the question is, is it possible to install this certificate on my test server or I'll have to setup the test server on my linux machine?
To make this a little bit clearer:
My development machine: A Mac.
The test server: A linux machine running liferay 6.0.6
I want to install the development certificate on the test server so I can test push notifications.
Thanks a lot!

I know nothing about 'liferay' but this his how I setup a APN connection (on a Rails server) using the certificate. Note that you need to convert the certificate to a .pem file (using 'openssl pkcs12 -in myfile.p12 -out myfile.pem'):
##apn_cert = nil
APN_SSL_KEY_FILE = 'lib/SSLCert_Private_Key.pem'
APN_SSL_HOST = 'gateway.sandbox.push.apple.com'
# APN_SSL_HOST = 'gateway.push.apple.com'
APN_SSL_PORT = 2195
APN_SSL_PASSWORD = '<password>'
def configure_apn_cert
puts "APN Service: Configuring APN cert"
##apn_cert = File.read(File.join(RAILS_ROOT, APN_SSL_KEY_FILE))
##apn_context = OpenSSL::SSL::SSLContext.new
##apn_context.key = OpenSSL::PKey::RSA.new(##apn_cert, APN_SSL_PASSWORD)
##apn_context.cert = OpenSSL::X509::Certificate.new(##apn_cert)
end
def create_and_configure_apn_server
configure_apn_cert if not ##apn_cert
puts "APN Service: Configuring APN SOCKET and SSL connection"
#apn_socket = TCPSocket.new(APN_SSL_HOST, APN_SSL_PORT)
#apn_ssl = OpenSSL::SSL::SSLSocket.new(#apn_socket, ##apn_context)
#apn_ssl.sync = true
#apn_ssl.connect
end
def close_apn_server
#apn_ssl.close
#apn_socket.close
end
def package_build_for_apn( token, content )
"\0\0 #{token}\0#{content.length.chr}#{content}"
end
def package_send_to_apn( package )
puts "APN Service: Sending #{package}"
bytes_written = #apn_ssl.write( package )
if bytes_written != package.length then
puts "APN Service: SSL write failed"
package_to_apn_show_write( bytes_written, package)
end
end
def apn_deliver_payload( token, payload )
# Convert the device string back into a byte string
tokenBinary = Base64.decode64( token )
# Transform the payload into an APN byte string
apn_content = payload.to_hash.to_json
apn_content_len = apn_content.length
# Build the apn_package per APN specification
apn_package = "\0\0 #{tokenBinary}\0#{apn_content_len.chr}#{apn_content}"
# Actually send it.
package_send_to_apn( apn_package )
end
def package_to_apn_show_write( bytes, package)
puts "Wrote: #{bytes_written}/ Tried: #{package.length}"
puts "Package: '#{package}'"
end
def package_to_apn_debug( token, content, package )
puts "Token(#{token.length}): #{token}"
puts "Content(#{content.length}): #{content}"
puts "Package(#{package.length}): #{package}"
end

I'd like to answer my own question because it might help someone, first of all, I had a terrible confusion between the certificates I needed to generate and how to get the device token among other things.
These are the steps I went through to make this work:
Created an application ID.
Created a Certificate Signing Request using "Keychain access" and got the development certificate for push notifications which I installed using again Keychain access.
Exported the certificate as a .p12 file.
Used the notnoop java library (which is on the central maven repository) to send push notifications.
Here is a sample snippet that shows where the certificate fits in:
ApnsService service =
APNS.newService()
.withCert("/path/to/certificate.p12", "MyCertPassword")
.withSandboxDestination()
.build();
The second argument of the method is the password for the p12 file that keychain access makes you to set.
Finally to glue things, I used the [UIApplication sharedApplication] instance to register to receive push notifications and by implementing a method on the AppDelegate I get the token I needed which was in NSData format, so you need to converted into a hex string (there is sample code for that in many sites and questions on this site).
And that's it, that's the process.
Hope this helps!!

Related

Java GSS-API Service Ticket not saved in Credentials Cache using Java

I have created 2 demo Kerberos Clients using the GSS-API.
One in Python3, the second in Java.
Both clients seem to be broadly equivalent, and both "work" in that I get a service ticket that is accepted by my Java GSS-API Service Principal.
However on testing I noticed that the Python client saves the service ticket in the kerberos credentials cache, whereas the Java client does not seem to save the ticket.
I use "klist" to view the contents of the credential cache.
My clients are running on a Lubuntu 17.04 Virtual Machine, using FreeIPA as the Kerberos environment. I am using OpenJDK 8 u131.
Question 1: Does the Java GSS-API not save service tickets to the credentials cache? Or can I change my code so it does so?
Question 2: Is there any downside to the fact that the service ticket is not saved to the cache?
My assumption is that cached service tickets reduce interaction with the KDC, but comments on How to save Kerberos Service Ticket using a Windows Java client? suggest that is not the case, but this Microsoft technote says "The client does not need to go back to the KDC each time it wants access to this particular server".
Question 3: The cached service tickets from the python client vanish after some minutes - long before the expiry date. What causes them to vanish?
Python code
#!/usr/bin/python3.5
import gssapi
from io import BytesIO
server_name = 'HTTP/app-srv.acme.com#ACME.COM'
service_name = gssapi.Name(server_name)
client_ctx = gssapi.SecurityContext(name=service_name, usage='initiate')
initial_client_token = client_ctx.step()
Java Code
System.setProperty("java.security.krb5.conf","/etc/krb5.conf");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
GSSManager manager = GSSManager.getInstance();
GSSName clientName;
GSSContext context = null;
//try catch removed for brevity
GSSName serverName =
manager.createName("HTTP/app-srv.acme.com#ACME.COM", null);
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
//use default credentials
context = manager.createContext(serverName,
krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(false);
context.requestConf(false);
context.requestInteg(true);
byte[] token = new byte[0];
token = context.initSecContext(token, 0, token.length);
Edit:
While the original question focusses on the use of the Java GSS-API to build a Java Kerberos Client, GSS is not a must. I am open to other Kerberos approaches that work on Java. Right now I am experimenting with Apache Kerby kerb-client.
So far Java GSS-API seems to have 2 problems:
1) It uses the credentials cache to get the TGT (Ok), but not to cache service-tickets (Not Ok).
2) It cannot access credential caches of type KEYRING. (Confirmed by behaviour, debugging the Java runtime security classes, and by comments in that code. For the Lubuntu / FreeIPA combination I am using KEYRING was the out-of-the-box default. This won't apply to Windows, and may not apply to other Linux Kerberos combinations.
Edit 2:
The question I should have asked is:
How do I stop my KDC from being hammered for repeated SGT requests because Java GSS is not using the credentials cache.
I leave my original answer in place at the bottom, because if largely focusses on the original question.
After another round of deep debugging and testing, I have found an acceptable solution to the root problem.
Using Java GSS API with JAAS, as opposed to "pure" GSS without JAAS in my original solution makes a big difference!
Yes, existing Service Tickets (SGTs) that may be in the credentials cache are not being loaded,
nor are any newly acquired SGTs written back to the cache, however the KDC is not be constantly hammered (the real problem).
Both pure GSS, and GSS with JAAS use a client principal subject. The subject has an in-memory privateCredentials set,
which is used to store TGTs and SGTs.
The key difference is:
"pure GSS": the subject + privateCredentials is created within the GSSContext, and lives only as long as the GSSContext lives.
GSS with JAAS: the subject is created by JAAS, outside the GSSContext, and thus can live for the life of the application,
spanning many GSSContexts during the life of the application.
The first GSSContext established will query the subject's privateCredentials for a SGT, not find one,
then request a SGT from the KDC.
The SGT is added to the subject's privateCredentials, and as the subject lives longer than the GSSContext,
it is available, as is the SGT, when following GSSContexts are created. These will find the SGT in the subject's privateCredentials, and do not need to hit the KDC for a new SGT.
So seen in the light of my particular Java Fat Client, opened once and likely to run for hours, everything is ok.
The first GSSContext created will hit the KDC for a SGT which will then be used by all following GSSContexts created until the client is closed.
The credentials cache is not being used, but that does not hurt.
In the light of a much shorter lived client, reopened many many times, and perhaps in parallel,
then use / non-use of the credentials cache might be a more serious issue.
private void initJAASandGSS() {
LoginContext loginContext = null;
TextCallbackHandler cbHandler = new TextCallbackHandler();
try {
loginContext = new LoginContext("wSOXClientGSSJAASLogin", cbHandler);
loginContext.login();
mySubject = loginContext.getSubject();
} catch (LoginException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
gssManager = GSSManager.getInstance();
try {
//TODO: LAMB: This name should be got from config / built from config / serviceIdentifier
serverName = gssManager.createName("HTTP/app-srv.acme.com#ACME.COM", null);
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
} catch (GSSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private String getGSSwJAASServiceToken() {
byte[] token = null;
String encodedToken = null;
token = Subject.doAs(mySubject, new PrivilegedAction<byte[]>(){
public byte[] run(){
try{
System.setProperty("javax.security.auth.useSubjectCredsOnly","true");
GSSContext context = gssManager.createContext(serverName,
krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(false);
context.requestConf(false);
context.requestInteg(true);
byte[] ret = new byte[0];
ret = context.initSecContext(ret, 0, ret.length);
context.dispose();
return ret;
} catch(Exception e){
Log.log(Log.ERROR, e);
throw new otms.util.OTMSRuntimeException("Start Client (Kerberos) failed, cause: " + e.getMessage());
}
}
});
encodedToken = Base64.getEncoder().encodeToString(token);
return encodedToken;
}
End Edit 2: Original answer below:
Question 1: Does the Java GSS-API not save service tickets to the credentials cache? Or can I change my code so it does so?
Edit: Root Cause Analysis.
After many hours debugging the sun.security.* classes, I now understand what GSS and Java Security code is doing / not doing - at least in Java 8 u 131.
In this example we have a credential cache, of a type Java GSS can access, containing a valid Ticket Granting Ticket (TGT) and a valid Service Ticket (SGT).
1) When the client principal Subject is created, the TGT is loaded from the cache (Credentials.acquireTGTFromCache()), and stored in the privateCredentials set of the Subject. --> (OK)
Only the TGT is loaded, SGTs are NOT loaded and saved to the Subject privateCredentials. -->(NOT OK)
2) Later, deep in the GSSContext.initSecContext() process, the security code actually tries to retrieve a Service Ticket from the privateCredentials of the Subject. The relevant code is Krb5Context.initSecContext() / KrbUtils.getTicket() / SubjectComber.find()/findAux(). However as SGTs were never loaded in step 1) an SGT will not be found! Therefore a new SGT is requested from the KDC and used.
This is repeated for each Service request.
Just for fun, and strictly as a proof-of-concept hack, I added a few lines of code between the login, and the initSecContext() to parse the credentials cache, extract the credentials, convert to Krb Credentials, and add them to the Subject’s private credentials.
This done, in step 2) the existing SGT is found and used. No new SGT is requested from the KDC.
I will not post the code for this hack as it calls sun internal classes that we should not be calling, and I don’t wish to inspire anybody else to do so. Nor do I intend to use this hack as a solution.
—> The root cause problem is not that the service ticket are not SAVED to the cache; but rather
a) that SGTs are not LOADED from the credential cache to the Subject of the client principal
and
b) that there is no public API or configuration settings to do so.
This affects GSS-API both with and without JAAS.
So where does this leave me?
i) Use Java GSS-API / GSS-API with JAAS “as is”, with each SGT Request hitting the KDC —> Not good.
ii) As suggested by Samson in the comments below, use Java GSS-API only for initial login of the application, then for all further calls use an alternative security mechanism for subsequent calls (a kind of self-built kerberos-light) using tokens or cookies.
iii) Consider alternatives to GSS-API such as Apache Kerby kerb-client. This has implications outside the scope of this answer, and may well prove to be jumping from the proverbial frying pan to the fire.
I have submitted a Java Feature Request to Oracle, suggesting that SGTs should be retrieved from the cache and stored in the Subject credentials (as already the case for TGTs).
http://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8180144
Question 2: Is there any downside to the fact that the service ticket is not saved to the cache?
Using the credentials cache for Service Tickets reduces interaction between the client and the KDC. The corollary to this is that where service tickets are not cached, each request will require interaction with the KDC, which could lead to the KDC being hammered.

Vtiger +FreePBX : Call Status is not updated after call hang-up

I've integrated FreePBX with Vtiger (PBXManager),I've used this steps for integration https://wiki.vtiger.com/vtiger6/index.php/Asterisk_Integration
In my setup FreePBX and Vtiger both are on different server.
Calls are working fine but call status and other data is not updating in Vtiger. Even after call is hang-up its showing ringing in Call Status field and if I go to detail view its showing me recording URL as blank.
This is the log which I'm getting in nohup.webapp.log file
http://pastebin.com/m8ErDKt9
VtigerAsteriskConnector.properties
/*
* Copyright (C) www.vtiger.com. All rights reserved.
* #license Proprietary
*/
// Location where the application server will be running.
ServerIP = 127.0.0.1
ServerPort = 8383
// Call Recordings storage path
StorageDir = /VtigerAsteriskConnector/recordings
// Enable(true) or Disable(false) call recordings
Recording = true
// Location where the applications database files will be stored.
AsteriskAppDBPath = /VtigerAsteriskConnector/db
// Asterisk Server Details
AsteriskServerPublicIP = asterisk-server-public-ip
AsteriskServerIP = 127.0.0.1
AsteriskServerPort = 5038
AsteriskUsername = vtiger
AsteriskPassword = 5c11bea0b374299c2c70e09b4734a670
// Vtiger CRM URL
VtigerURL = http://vtigercrm.url.com
VtigerSecretKey = 167523039v54f1v677c2231
//Enable(true) or Disable(false) Asterisk Events and Database Logs in Connector
AsteriskLog = true
DatabaseLog = true
This seems related to asterisk-java library to me but I'm not sure,I've done same integration in one of my local VM and it works without any issue the only difference is in my local machine FreePBX and Vtiger both resides on same server.
I'll provide configuration files if anyone is needed.
Any suggestion and idea will be appreciated.
At current moment vtiger asterisk connector work only with asterisk 1.8
With any other version(1.4- or 11+) it not work correctly

Modbus4J Modbus RTU master

Currently I am working with the Schneider Power Logic electrical device. I want to read the data from the device and show the value in my system. So far, I discover J2mod, Jamod and Modbus4Java library. I used all modbus4java to connect and get the device's data.
Actually I still confuse whether I suppose to create Master side or Slave side. Based on my understanding, the device will be Slave and my system will be Master (1st question).
Below is the setting AT MY DEVICE. It indicate that the device in slave mode and its protocol is Modbus RTU. So, I need to create a master apps to communicate with it right which is using the ModbusRTU protocol right ? (2nd question)
Mode: Slave
Protocol: Modbus RTU
Address: 1
Baud Rate: 38400
Parity: None
Below is the code of my apps act as the Master and using the ModbusRTU protocol
public static void main(String[] args) throws ModbusTransportException, ErrorResponseException {
ModbusFactory factory = new ModbusFactory();
SerialParameters params = new SerialParameters();
params.setCommPortId("COM6");
params.setBaudRate(9600);
params.setDataBits(8);
params.setStopBits(1);
params.setParity(0);
ModbusMaster master = factory.createRtuMaster(params);
master.setTimeout(1000);
master.setRetries(0);
long start = System.currentTimeMillis();
try {
master.init();
} catch (Exception e) {
System.out.println( "Modbus Master Init Error: " + e.getMessage());
return;
}
try {
System.out.println("Reg. 1001 Value:" + master.getValue(1, RegisterRange.HOLDING_REGISTER, 3110, DataType.FOUR_BYTE_FLOAT_SWAPPED));
}
finally {
master.destroy();
}
System.out.println("Time elapsed: " + (System.currentTimeMillis() - start) + "ms");
}
This is the code that I get from the sample code provide by the Modbus4Java page. The other thing that concern me is the value of params.setCommPortId("COM6"); What other value than "COM6" that I can put there. Because basically it receive a String value. So am I able to put any String value to it ? And what is the function of this particular setCommPortID. (3rd question)
Looking at the sample code provide by the Modbus4Java page, it does not put the IP address of the device. But in my case, my device got an IP address. And the IP address only use in the Slave apps only. How should my system recognize the IP address of the device ? (4th question).
And after I run this code snippet, I got an error:
Stable Library
Native lib Version = RXTX-2.1-7
Java lib Version = RXTX-2.1-7
Modbus Master Init Error: com.serotonin.io.serial.SerialPortException: gnu.io.NoSuchPortException
Please, please and please help me. I been stuck with this almost a month. Really hope someone out there will be able to help me. Thank you in advance for any kind of help and suggestion.
I'm the maintainer for j2mod, so my answer is going to suggest you look at the test programs which are included with j2mod. You can find j2mod on SourceForge at this URL --
https://sourceforge.net/projects/j2mod/
I'm pretty good about answering questions there, but I also follow stackoverflow, so I can explain more here as well. There are a LOT of questions in here, so I apologize in advance if I've missed anything.
The Schneider device is the slave, or "server" and your application is the master or "client". Modbus is a master/slave protocol, with the master initiating all requests. Your application will be the master and responsible for making all requests of your device.
The exact communications will be provided by the device documentation. In this instance, you indicate that the device uses 38400 baud, and so forth. Those are the parameters you will use to update SerialParameters with the RXTX library (which just so happens to also be used by j2mod).
The value passed to setCommPortId() is the Windows COM port identifier - you should be able to pass any value which is associated with an actual COM port -- "COM1", "COM2", etc. Note that some USB converters change their COM port each time they are used, so you may be chasing port names.
You mentioned that your device also has an IP address. You cannot use the RTU classes and methods to access a Modbus/TCP device. The same is true for jamod and j2mod - most Modbus libraries have different classes for RTU and TCP transports (as well as ASCII and UDP, for libraries which support those other transports).

Randomly Channel.Connect.Failed error when calling to a Java server from Flex application using AMF protocol

I have a project published in the Internet that is used by thousands of users every day. Basically, I'm using a server in AmazonAWS with the server part compiled in Java 6 running in a Tomcat. I'm using AMF to publish the services and my client is built in Flex 4.6 using Flash Builder to generate the classes to connect to the AMF services. The code I'm using to connect to the services is this:
public var cpcService:RemotingServicesImpl;
private function callService():void
{
FlexGlobals.topLevelApplication.callingService=true;
encryptedSession=ResourcesUtil.buildSessionId(globalSettings.sessionId, globalSettings);
var responder:Responder=new Responder(gameStateLoaded, gameStateFailed);
var token:AsyncToken=cpcService.getGameState(encryptedSession, taskKey);
token.addResponder(responder);
}
private function gameStateFailed(ev:FaultEvent=null):void
{
DisplayUtil.trackErrorInfoEvent("FATAL - FatalError", "getGameState-" + FlexGlobals.topLevelApplication.mainView.currentState, ev, encryptedSession);
}
private function gameStateLoaded(ev:Object):void
{
// my fantastic code when everything is ok
}
Normally, everything is ok and my application is working, but some calls (like 1 every 500) are not working, I know it because in the trackErrorInfoEvent function I'm registering an event in the Google Analytics, so I know this is randomly happening. This is the error:
faultCode = "Client.Error.MessageSend"
faultDetail = "Channel.Connect.Failed error NetConnection.Call.Failed: HTTP: Failed: url: 'https://appcog.cognifit.com/messagebroker/amf'"
faultString = "Send failed"
rootCause = (null)
Of course the URL is correct and is working all times.
I have seen in some blogs that adding this line:
<add-no-cache-headers>false</add-no-cache-headers>
the problem is fixed, but I have that line in my config file and is still happening.
I have checked my server logs and I have no records for service interruptions at any time.
I really apreciate any help, thanks in advance!

Use Apple Push Notification Service through Java

Am trying to implement a Java program which sends an Apple Push Notification to an iPhone client app... Found the following library: Java APNs
Provider code:
Created the following code (from Javapns) to use in my app:
try {
PayLoad payLoad = new PayLoad();
payLoad.addAlert("My alert message");
payLoad.addBadge(45);
payLoad.addSound("default");
PushNotificationManager pushManager = PushNotificationManager.getInstance();
pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
log.warn("Initializing connectiong with APNS...");
// Connect to APNs
pushManager.initializeConnection(HOST, PORT,
"/etc/Certificates.p12", "password",
SSLConnectionHelper.KEYSTORE_TYPE_PKCS12);
Device client = pushManager.getDevice("Lambo");
// Send Push
log.warn("Sending push notification...");
PushNotificationManager.getInstance().sendNotification(client, payLoad);
}
catch (Exception e) {
throw new ApnsPushNotificationException("Unable to send push " + e);
}
When I run this app (as you can see through the Log4j statements) there's no exceptions which occur:
WARN [MyCode] Initializing connectiong with APNS...
WARN [MyCode] Sending push notification...
But my client app doesn't receive any notifications!
IDPP Registration Process:
Also, did the following on the iPhone Developer Program Portal (IDPP):
Created the APNS based SSL Certificate and Keys
Created and installed the provisioning profile
Installed the SSL Certificate and Key on the server.
Have read over the Apple Push Notification Service Guide several times and noticed a few things:
(1) On page 15, it states that the device token is not the same as the device UDID (which I am currently incorrectly passing in as the second parameter inside the PushNotificationManager.addDevice() method (see above)).
On page 17, it states:
"APNs generates a device token using information contained in the unique device certificate. The device token contains an identifier of the device. It then encrypts the device token with a token key and returns it to the device. The device returns the device token to the requesting application as an NSData object. The application then must deliver the device token to its provider in either binary or hexidecimal format."
iPhone OS Client Implementation
(2) After reading pages 33 - 34, I discovered that I didn't include the Objective-C code to have the app register with APNs.
Am not an Objective-C developer, so is this where I can recover the device code or do I have to get it from the certificate?
Where do I obtain the device token (sorry, someone else wrote the Objective-C client app and I am a Java Developer)?
Question(s):
(1) With the exception of not knowing where to get the device token and the mobile client code registration, is there anything else that I have not looked over or missed?
(2) Am I using the Javapns library the right way?
Thank you for taking the time to read this...
As a shameful self-advertising, I encourage to use java-apns library. Your code will look like:
ApnsService service =
APNS.newService()
.withCert("/etc/Certificates.p12", "password")
.withSandboxDestination() // or .withProductionDestination()
.build();
String payload =
APNS.newPayload()
.alertBody("My alert message")
.badge(45)
.sound("default")
.build();
String deviceToken = "f4201f5d8278fe39545349d0868a24a3b60ed732";
log.warn("Sending push notification...");
service.push(deviceToken, payload);
Just a little tip, in order to convert your received token into a format suitable for registration with javapns, this code will do the trick:
- (NSString *)convertTokenToDeviceID:(NSData *)token {
NSMutableString *deviceID = [NSMutableString string];
// iterate through the bytes and convert to hex
unsigned char *ptr = (unsigned char *)[token bytes];
for (NSInteger i=0; i < 32; ++i) {
[deviceID appendString:[NSString stringWithFormat:#"%02x", ptr[i]]];
}
return deviceID;
}
I tried this and I keep getting hanged when sending the notification, and nothing gets sent.
The issue stems from the following function:
public void sendNotification(Device device, PayLoad payload)
It seems that the bufferedreader has NULL
BufferedReader in =
new BufferedReader(new InputStreamReader(this.socket.getInputStream() ) );
So when this portion of the code gets hit it just hangs there in endless loop
logger.debug( "In: [" + in.readLine() + "]" );
This output is [null]
So then right after then the loops get executed:
while ( ! this.socket.isInputShutdown() ) {
while( in.ready() ) {
logger.debug("ready now");
logger.debug(in.readLine());
System.out.println( this.socket.getInputStream().read() );
}
}
The code enters the first while loop and waits for the BufferedReader in to be ready
and just keeps waiting..... ad that is your hanging
Your Java code looks solid! However, don't forget to close the connection, through PushNotificationManager.closeConnection(). It's important to cleanup after yourself.
As a side comment, I notice that you are adding the device 'iPhone' but querying for 'Lambo' afterwards. This is an indication of a bug.
The device token shown in the code is incorrect. Device tokens, currently, as 32-bit long value, which gets hexed into 64 characters. I assume that the server is failing silently when pushing the notification to invalid token!
The only way to get the device token is from the app itself. As provided by the Push Notification guide suggests, the iPhone app needs to register for notification upon launch. In the application:didRegisterForRemoteNotificationsWithDeviceToken:, the iPhone needs to send the device token to your java provider server. (For debugging purposes, you can just NSLog the device token and use it; it never changes across runs).
I would recommend that you create a server in your java provider server to receive device tokens. Set up a ServerSocket to receive connections from the iPhone and their device token (and any additional info you need) and insert the tokens in the database.
JavaPNS was recently updated to 2.0, and fixed ALL reported issues up to the release date. It does fix the issue you are describing, and using the library is MUCH simpler than it ever was (you can push a notification with a single line of code now).
You seem to be missing the token
pushManager.addDevice("iPhone", "f4201f5d8278fe39545349d0868a24a3b60ed732");
Takes id and token check:
https://github.com/o-sam-o/javapns/blob/master/src/javapns/notification/PushNotificationManager.java#L501
The only way to get a token is from the iphone app. A valid token looks something like this:
1d2d6f34 c5028bca c50df5f9 1992c912 ce7deae8 3bbe7da5 447f6a68 cfecdc0e
Regarding the comment for notnoop here:
If you are landing on this post in 2022, you'll find that the java-apns library doesn't work since 2021. Instead they recommend using pushy library.
I have tried this one just by following their example in the README file and it works really well. They have added examples for both authorisation types: by certificate or by token.

Categories