From 32540dec5829147c2cbff1d88a8a9ab511ce08c0 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Tue, 17 Oct 2023 15:07:37 -0300 Subject: [PATCH 1/2] Removedjavapns module Issue: 102760 --- javapns/pom.xml | 37 -- javapns/src/main/java/javapns/Push.java | 242 ------- .../javapns/communication/AppleServer.java | 32 - .../communication/AppleServerBasicImpl.java | 53 -- .../ConnectionToAppleServer.java | 250 ------- .../communication/KeystoreManager.java | 113 ---- .../ServerTrustingTrustManager.java | 28 - .../InvalidCertificateChainException.java | 27 - .../InvalidKeystoreFormatException.java | 27 - .../InvalidKeystorePasswordException.java | 27 - .../src/main/java/javapns/devices/Device.java | 68 -- .../java/javapns/devices/DeviceFactory.java | 44 -- .../exceptions/DuplicateDeviceException.java | 34 - .../exceptions/NullDeviceTokenException.java | 35 - .../devices/exceptions/NullIdException.java | 34 - .../exceptions/UnknownDeviceException.java | 35 - .../implementations/basic/BasicDevice.java | 118 ---- .../basic/BasicDeviceFactory.java | 106 --- .../javapns/feedback/AppleFeedbackServer.java | 24 - .../AppleFeedbackServerBasicImpl.java | 73 -- .../feedback/ConnectionToFeedbackServer.java | 32 - .../feedback/FeedbackServiceManager.java | 181 ----- .../notification/AppleNotificationServer.java | 24 - .../AppleNotificationServerBasicImpl.java | 73 -- .../ConnectionToNotificationServer.java | 32 - .../NewsstandNotificationPayload.java | 68 -- .../java/javapns/notification/Payload.java | 337 ---------- .../notification/PayloadPerDevice.java | 41 -- .../notification/PushNotificationManager.java | 627 ------------------ .../notification/PushNotificationPayload.java | 300 --------- .../notification/PushedNotification.java | 265 -------- .../javapns/notification/ResponsePacket.java | 106 --- .../notification/ResponsePacketReader.java | 116 ---- .../PayloadAlertAlreadyExistsException.java | 29 - .../PayloadMaxSizeExceededException.java | 37 -- ...yloadMaxSizeProbablyExceededException.java | 40 -- .../notification/management/APNPayload.java | 40 -- .../management/CalDAVPayload.java | 40 -- .../CalendarSubscriptionPayload.java | 39 -- .../notification/management/EmailPayload.java | 70 -- .../notification/management/LDAPPayload.java | 60 -- .../management/MobileConfigPayload.java | 48 -- .../management/PasswordPolicyPayload.java | 71 -- .../management/RemovalPasswordPayload.java | 21 - .../management/RestrictionsPayload.java | 51 -- .../notification/management/SCEPPayload.java | 76 --- .../notification/management/VPNPayload.java | 39 -- .../management/WebClipPayload.java | 29 - .../notification/management/WiFiPayload.java | 32 - .../NotificationProgressListener.java | 24 - .../transmission/NotificationThread.java | 277 -------- .../transmission/NotificationThreads.java | 315 --------- pom.xml | 1 - 53 files changed, 4948 deletions(-) delete mode 100644 javapns/pom.xml delete mode 100644 javapns/src/main/java/javapns/Push.java delete mode 100644 javapns/src/main/java/javapns/communication/AppleServer.java delete mode 100644 javapns/src/main/java/javapns/communication/AppleServerBasicImpl.java delete mode 100644 javapns/src/main/java/javapns/communication/ConnectionToAppleServer.java delete mode 100644 javapns/src/main/java/javapns/communication/KeystoreManager.java delete mode 100644 javapns/src/main/java/javapns/communication/ServerTrustingTrustManager.java delete mode 100644 javapns/src/main/java/javapns/communication/exceptions/InvalidCertificateChainException.java delete mode 100644 javapns/src/main/java/javapns/communication/exceptions/InvalidKeystoreFormatException.java delete mode 100644 javapns/src/main/java/javapns/communication/exceptions/InvalidKeystorePasswordException.java delete mode 100644 javapns/src/main/java/javapns/devices/Device.java delete mode 100644 javapns/src/main/java/javapns/devices/DeviceFactory.java delete mode 100644 javapns/src/main/java/javapns/devices/exceptions/DuplicateDeviceException.java delete mode 100644 javapns/src/main/java/javapns/devices/exceptions/NullDeviceTokenException.java delete mode 100644 javapns/src/main/java/javapns/devices/exceptions/NullIdException.java delete mode 100644 javapns/src/main/java/javapns/devices/exceptions/UnknownDeviceException.java delete mode 100644 javapns/src/main/java/javapns/devices/implementations/basic/BasicDevice.java delete mode 100644 javapns/src/main/java/javapns/devices/implementations/basic/BasicDeviceFactory.java delete mode 100644 javapns/src/main/java/javapns/feedback/AppleFeedbackServer.java delete mode 100644 javapns/src/main/java/javapns/feedback/AppleFeedbackServerBasicImpl.java delete mode 100644 javapns/src/main/java/javapns/feedback/ConnectionToFeedbackServer.java delete mode 100644 javapns/src/main/java/javapns/feedback/FeedbackServiceManager.java delete mode 100644 javapns/src/main/java/javapns/notification/AppleNotificationServer.java delete mode 100644 javapns/src/main/java/javapns/notification/AppleNotificationServerBasicImpl.java delete mode 100644 javapns/src/main/java/javapns/notification/ConnectionToNotificationServer.java delete mode 100644 javapns/src/main/java/javapns/notification/NewsstandNotificationPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/Payload.java delete mode 100644 javapns/src/main/java/javapns/notification/PayloadPerDevice.java delete mode 100644 javapns/src/main/java/javapns/notification/PushNotificationManager.java delete mode 100644 javapns/src/main/java/javapns/notification/PushNotificationPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/PushedNotification.java delete mode 100644 javapns/src/main/java/javapns/notification/ResponsePacket.java delete mode 100644 javapns/src/main/java/javapns/notification/ResponsePacketReader.java delete mode 100644 javapns/src/main/java/javapns/notification/exceptions/PayloadAlertAlreadyExistsException.java delete mode 100644 javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeExceededException.java delete mode 100644 javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeProbablyExceededException.java delete mode 100644 javapns/src/main/java/javapns/notification/management/APNPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/CalDAVPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/CalendarSubscriptionPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/EmailPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/LDAPPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/MobileConfigPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/PasswordPolicyPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/RemovalPasswordPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/RestrictionsPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/SCEPPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/VPNPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/WebClipPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/management/WiFiPayload.java delete mode 100644 javapns/src/main/java/javapns/notification/transmission/NotificationProgressListener.java delete mode 100644 javapns/src/main/java/javapns/notification/transmission/NotificationThread.java delete mode 100644 javapns/src/main/java/javapns/notification/transmission/NotificationThreads.java diff --git a/javapns/pom.xml b/javapns/pom.xml deleted file mode 100644 index 52d695ebd..000000000 --- a/javapns/pom.xml +++ /dev/null @@ -1,37 +0,0 @@ - - - 4.0.0 - - - com.genexus - parent - ${revision}${changelist} - - - javapns - JavaPNS - - - - ${project.groupId} - gxcommon - ${project.version} - - - org.json - json - 20230618 - - - org.bouncycastle - bcprov-jdk18on - 1.75 - - - - - javapns - - diff --git a/javapns/src/main/java/javapns/Push.java b/javapns/src/main/java/javapns/Push.java deleted file mode 100644 index eaee6fe49..000000000 --- a/javapns/src/main/java/javapns/Push.java +++ /dev/null @@ -1,242 +0,0 @@ -package javapns; - -import java.util.*; - -import javapns.devices.*; -import javapns.devices.implementations.basic.*; -import javapns.feedback.*; -import javapns.notification.*; - -/** - *

Main class for easily interacting with the Apple Push Notification System

- * - *

This is the best starting point for pushing simple or custom notifications, - * or for contacting the Feedback Service to cleanup your list of devices.

- * - *

The javapns library also includes more advanced options such as - * multithreaded transmission, special payloads, JPA-support, and more. - * See the library's documentation at http://code.google.com/p/javapns/ - * for more information.

- * - * @author Sylvain Pedneault - */ -public class Push { - - /** - * Push a simple alert to one or more devices. - * - * @param message the alert message to push. - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List alert(String message, Object keystore, String password, boolean production, String... tokens) { - return payload(PushNotificationPayload.alert(message), keystore, password, production, tokens); - } - - - /** - * Push a simple badge number to one or more devices. - * - * @param badge the badge number to push. - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List badge(int badge, Object keystore, String password, boolean production, String... tokens) { - return payload(PushNotificationPayload.badge(badge), keystore, password, production, tokens); - } - - - /** - * Push a simple sound name to one or more devices. - * - * @param sound the sound name (stored in the client app) to push. - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List sound(String sound, Object keystore, String password, boolean production, String... tokens) { - return payload(PushNotificationPayload.sound(sound), keystore, password, production, tokens); - } - - - /** - * Push a notification combining an alert, a badge and a sound. - * - * @param message the alert message to push (set to null to skip). - * @param badge the badge number to push (set to -1 to skip). - * @param sound the sound name to push (set to null to skip). - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List combined(String message, int badge, String sound, Object keystore, String password, boolean production, String... tokens) { - return payload(PushNotificationPayload.combined(message, badge, sound), keystore, password, production, tokens); - } - - - /** - * Push a content-available notification for Newsstand. - * - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List contentAvailable(Object keystore, String password, boolean production, String... tokens) { - return payload(NewsstandNotificationPayload.contentAvailable(), keystore, password, production, tokens); - } - - - /** - * Push a preformatted payload. - * This is a convenience method for passing a List of tokens instead of an array. - * - * @param payload a simple or complex payload to push. - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List payload(Payload payload, Object keystore, String password, boolean production, List tokens) { - return payload(payload, keystore, password, production, tokens.toArray(new String[0])); - } - - - /** - * Push a preformatted payload. - * - * @param payload a simple or complex payload to push. - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param tokens one or more device tokens to push to. - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List payload(Payload payload, Object keystore, String password, boolean production, String... tokens) { - List devices = new Vector(); - if (payload == null) return devices; - PushNotificationManager pushManager = new PushNotificationManager(); - try { - AppleNotificationServer server = new AppleNotificationServerBasicImpl(keystore, password, production); - pushManager.initializeConnection(server); - for (String token : tokens) { - Device device = new BasicDevice(token); - PushedNotification notification = pushManager.sendNotification(device, payload, false); - devices.add(notification); - } - } catch (Exception e) { - System.out.println("Error pushing notification(s):"); - e.printStackTrace(); - } finally { - try { - pushManager.stopConnection(); - } catch (Exception e) { - } - } - return devices; - } - - - /** - * Push a different preformatted payload for each device. - * This is a convenience method for passing a List of PayloadPerDevice instead of an array. - * - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param payloadDevicePairs a list of joint payloads and devices to push - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List payloads(Object keystore, String password, boolean production, List payloadDevicePairs) { - return payloads(keystore, password, production, payloadDevicePairs.toArray(new PayloadPerDevice[0])); - } - - - /** - * Push a different preformatted payload for each device. - * - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @param payloadDevicePairs a list of joint payloads and devices to push - * @return a list of pushed notifications, each with details on transmission results and error (if any) - */ - public static List payloads(Object keystore, String password, boolean production, PayloadPerDevice... payloadDevicePairs) { - List devices = new Vector(); - if (payloadDevicePairs == null) return devices; - PushNotificationManager pushManager = new PushNotificationManager(); - try { - AppleNotificationServer server = new AppleNotificationServerBasicImpl(keystore, password, production); - pushManager.initializeConnection(server); - for (PayloadPerDevice ppd : payloadDevicePairs) { - Device device = ppd.getDevice(); - Payload payload = ppd.getPayload(); - PushedNotification notification = pushManager.sendNotification(device, payload, false); - devices.add(notification); - } - } catch (Exception e) { - System.out.println("Error pushing notification(s):"); - e.printStackTrace(); - } finally { - try { - pushManager.stopConnection(); - } catch (Exception e) { - } - } - return devices; - } - - - /** - *

Retrieve a list of devices that should be removed from future notification lists.

- * - *

Devices in this list are ones that you previously tried to push a notification to, - * but to which Apple could not actually deliver because the device user has either - * opted out of notifications, has uninstalled your application, or some other conditions.

- * - *

Important: Apple's Feedback Service always resets its list of inactive devices - * after each time you contact it. Calling this method twice will not return the same - * list of devices!

- * - *

Please be aware that Apple does not specify precisely when a device will be listed - * by the Feedback Service. More specifically, it is unlikely that the device will - * be listed immediately if you uninstall the application during testing. It might - * get listed after some number of notifications couldn't reach it, or some amount of - * time has elapsed, or a combination of both.

- * - *

Further more, if you are using Apple's sandbox servers, the Feedback Service will - * probably not list your device if you uninstalled your app and it was the last one - * on your device that was configured to receive notifications from the sandbox. - * See the library's wiki for more information.

- * - * @param keystore a PKCS12 keystore provided by Apple (File, InputStream, byte[] or String for a file path) - * @param password the keystore's password. - * @param production true to use Apple's production servers, false to use the sandbox servers. - * @return a list of devices that are inactive. - */ - public static List feedback(Object keystore, String password, boolean production) { - List devices = new Vector(); - try { - FeedbackServiceManager feedbackManager = new FeedbackServiceManager(); - AppleFeedbackServer server = new AppleFeedbackServerBasicImpl(keystore, password, production); - devices.addAll(feedbackManager.getDevices(server)); - } catch (Exception e) { - System.out.println("Error pushing notification(s):"); - e.printStackTrace(); - } - return devices; - } - -} diff --git a/javapns/src/main/java/javapns/communication/AppleServer.java b/javapns/src/main/java/javapns/communication/AppleServer.java deleted file mode 100644 index b033d1f6d..000000000 --- a/javapns/src/main/java/javapns/communication/AppleServer.java +++ /dev/null @@ -1,32 +0,0 @@ -package javapns.communication; - -import java.io.*; - -/** - * Common interface of all classes representing a connection to any Apple server. - * Use AppleNotificationServer and AppleFeedbackServer interfaces for specific connections. - * - * @author Sylvain Pedneault - */ -public interface AppleServer { - - /** - * Returns a stream to a keystore. - * @return an InputStream - */ - public InputStream getKeystoreStream(); - - - /** - * Returns the keystore's password. - * @return a password matching the keystore - */ - public String getKeystorePassword(); - - /** - * Returns the format used to produce the keystore (typically PKCS12). - * @return a valid keystore format identifier - */ - public String getKeystoreType(); - -} diff --git a/javapns/src/main/java/javapns/communication/AppleServerBasicImpl.java b/javapns/src/main/java/javapns/communication/AppleServerBasicImpl.java deleted file mode 100644 index fe3aa3ac4..000000000 --- a/javapns/src/main/java/javapns/communication/AppleServerBasicImpl.java +++ /dev/null @@ -1,53 +0,0 @@ -package javapns.communication; - -import java.io.*; - -/** - * A basic and abstract implementation of the AppleServer interface - * intended to facilitate rapid deployment. - * - * @author Sylvain Pedneault - */ -public abstract class AppleServerBasicImpl implements AppleServer { - - private final Object keystore; - private final String password; - private final String type; - - - /** - * Constructs a AppleServerBasicImpl object. - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param type The keystore type (typically PKCS12) - * @throws FileNotFoundException - */ - public AppleServerBasicImpl(Object keystore, String password, String type) throws FileNotFoundException { - //this.input = KeystoreManager.streamKeystore(keystore); - this.keystore = keystore; - this.password = password; - this.type = type; - } - - - public InputStream getKeystoreStream() { - try { - return KeystoreManager.streamKeystore(keystore); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } - } - - - public String getKeystorePassword() { - return password; - } - - - public String getKeystoreType() { - return type; - } - -} diff --git a/javapns/src/main/java/javapns/communication/ConnectionToAppleServer.java b/javapns/src/main/java/javapns/communication/ConnectionToAppleServer.java deleted file mode 100644 index 85fbe41cc..000000000 --- a/javapns/src/main/java/javapns/communication/ConnectionToAppleServer.java +++ /dev/null @@ -1,250 +0,0 @@ -package javapns.communication; - -import java.io.*; -import java.net.*; -import java.security.*; -import java.security.cert.*; - -import javax.net.ssl.*; - -import org.bouncycastle.jce.provider.*; -import com.genexus.diagnostics.core.*; -/** - *

Class representing an abstract connection to an Apple server

- * - * Communication protocol differences between Notification and Feedback servers are - * implemented in {@link javapns.notification.ConnectionToNotificationServer} and {@link javapns.feedback.ConnectionToFeedbackServer}. - * - * @author Sylvain Pedneault - */ -public abstract class ConnectionToAppleServer { - - protected static final ILogger logger = LogManager.getLogger(ConnectionToAppleServer.class); - - /* The algorithm used by KeyManagerFactory */ - private static final String ALGORITHM = ((Security.getProperty("ssl.KeyManagerFactory.algorithm") == null) ? "sunx509" : Security.getProperty("ssl.KeyManagerFactory.algorithm")); - - /* The protocol used to create the SSLSocket */ - private static final String PROTOCOL = "TLS"; - - /* PKCS12 */ - public static final String KEYSTORE_TYPE_PKCS12 = "PKCS12"; - /* JKS */ - public static final String KEYSTORE_TYPE_JKS = "JKS"; - - static { - Security.addProvider(new BouncyCastleProvider()); - } - - private KeyStore keyStore; - private SSLSocketFactory socketFactory; - private AppleServer server; - - - /** - * Builds a connection to an Apple server. - * - * @param server - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws IOException - * @throws Exception - */ - public ConnectionToAppleServer(AppleServer server) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, Exception { - this.server = server; - - this.keyStore = KeystoreManager.loadKeystore(server); - } - - - public AppleServer getServer() { - return server; - } - - - public KeyStore getKeystore() throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, Exception { - return keyStore; - // return KeystoreManager.loadKeystore(server); - } - - - public void setKeystore(KeyStore ks) { - this.keyStore = ks; - } - - - /** - * Generic SSLSocketFactory builder - * - * @param trustManagers - * @return SSLSocketFactory - * @throws Exception - */ - protected SSLSocketFactory createSSLSocketFactoryWithTrustManagers(TrustManager[] trustManagers) throws Exception { - - logger.debug("Creating SSLSocketFactory"); - // Get a KeyManager and initialize it - KeyStore keystore = getKeystore(); - KeyManagerFactory kmf = KeyManagerFactory.getInstance(ALGORITHM); - try { - char[] password = KeystoreManager.getKeystorePasswordForSSL(server); - kmf.init(keystore, password); - } catch (Exception e) { - e = KeystoreManager.getSimplerSSLException(e); - throw e; - } - - // Get the SSLContext to help create SSLSocketFactory - SSLContext sslc = SSLContext.getInstance(PROTOCOL); - sslc.init(kmf.getKeyManagers(), trustManagers, null); - - return sslc.getSocketFactory(); - } - - - public abstract String getServerHost(); - - - public abstract int getServerPort(); - - - /** - * Return a SSLSocketFactory for creating sockets to communicate with Apple. - * - * @return SSLSocketFactory - * @throws KeyStoreException - * @throws NoSuchProviderException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws IOException - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws Exception - */ - public SSLSocketFactory createSSLSocketFactory() throws KeyStoreException, NoSuchProviderException, CertificateException, NoSuchAlgorithmException, IOException, UnrecoverableKeyException, KeyManagementException, Exception { - return createSSLSocketFactoryWithTrustManagers(new TrustManager[] { new ServerTrustingTrustManager() }); - } - - - public SSLSocketFactory getSSLSocketFactory() throws Exception { - if (socketFactory == null) socketFactory = createSSLSocketFactory(); - return socketFactory; - } - - - /** - * Create a SSLSocket which will be used to send data to Apple - * @return the SSLSocket - * @throws Exception - * @throws FileNotFoundException - */ - public SSLSocket getSSLSocket() throws Exception { - SSLSocketFactory socketFactory = getSSLSocketFactory(); - logger.debug("Creating SSLSocket to " + getServerHost() + ":" + getServerPort()); - - try { - if (isProxySet()) { - return tunnelThroughProxy(socketFactory); - } else { - return (SSLSocket) socketFactory.createSocket(getServerHost(), getServerPort()); - } - } catch (Exception e) { - throw e; - } - } - - - private boolean isProxySet() { - String httpsHost = System.getProperty("https.proxyHost"); - boolean isSet = httpsHost != null && httpsHost.length() > 0; - return isSet; - } - - - private SSLSocket tunnelThroughProxy(SSLSocketFactory socketFactory) throws UnknownHostException, IOException { - SSLSocket socket; - - // If a proxy was set, tunnel through the proxy to create the connection - String tunnelHost = System.getProperty("https.proxyHost"); - Integer tunnelPort = Integer.getInteger("https.proxyPort").intValue(); - - Socket tunnel = new Socket(tunnelHost, tunnelPort); - doTunnelHandshake(tunnel, getServerHost(), getServerPort()); - - /* overlay the tunnel socket with SSL */ - socket = (SSLSocket) socketFactory.createSocket(tunnel, getServerHost(), getServerPort(), true); - - /* register a callback for handshaking completion event */ - socket.addHandshakeCompletedListener(new HandshakeCompletedListener() { - public void handshakeCompleted(HandshakeCompletedEvent event) { - logger.debug("Handshake finished!"); - logger.debug("\t CipherSuite:" + event.getCipherSuite()); - logger.debug("\t SessionId " + event.getSession()); - logger.debug("\t PeerHost " + event.getSession().getPeerHost()); - } - }); - - return socket; - } - - - private void doTunnelHandshake(Socket tunnel, String host, int port) throws IOException { - - OutputStream out = tunnel.getOutputStream(); - - String msg = "CONNECT " + host + ":" + port + " HTTP/1.0\n" + "User-Agent: BoardPad Server" + "\r\n\r\n"; - byte b[] = null; - try { //We really do want ASCII7 -- the http protocol doesn't change with locale. - b = msg.getBytes("ASCII7"); - } catch (UnsupportedEncodingException ignored) { //If ASCII7 isn't there, something serious is wrong, but Paranoia Is Good (tm) - b = msg.getBytes(); - } - out.write(b); - out.flush(); - - // We need to store the reply so we can create a detailed error message to the user. - byte reply[] = new byte[200]; - int replyLen = 0; - int newlinesSeen = 0; - boolean headerDone = false; //Done on first newline - - InputStream in = tunnel.getInputStream(); - - while (newlinesSeen < 2) { - int i = in.read(); - if (i < 0) { - throw new IOException("Unexpected EOF from proxy"); - } - if (i == '\n') { - headerDone = true; - ++newlinesSeen; - } else if (i != '\r') { - newlinesSeen = 0; - if (!headerDone && replyLen < reply.length) { - reply[replyLen++] = (byte) i; - } - } - } - - /* - * Converting the byte array to a string is slightly wasteful - * in the case where the connection was successful, but it's - * insignificant compared to the network overhead. - */ - String replyStr; - try { - replyStr = new String(reply, 0, replyLen, "ASCII7"); - } catch (UnsupportedEncodingException ignored) { - replyStr = new String(reply, 0, replyLen); - } - - /* We check for Connection Established because our proxy returns HTTP/1.1 instead of 1.0 */ - if (replyStr.toLowerCase().indexOf("200 connection established") == -1) { - throw new IOException("Unable to tunnel through. Proxy returns \"" + replyStr + "\""); - } - - /* tunneling Handshake was successful! */ - } - -} diff --git a/javapns/src/main/java/javapns/communication/KeystoreManager.java b/javapns/src/main/java/javapns/communication/KeystoreManager.java deleted file mode 100644 index 7eeae891b..000000000 --- a/javapns/src/main/java/javapns/communication/KeystoreManager.java +++ /dev/null @@ -1,113 +0,0 @@ -package javapns.communication; - -import java.io.*; -import java.security.*; -import java.security.cert.*; - -import javapns.communication.exceptions.*; - -/** - * Class responsible for dealing with keystores. - * - * @author Sylvain Pedneault - */ -class KeystoreManager { - - /** - * Loads a keystore. - * - * @param server The server the keystore is intended for - * @return A loaded keystore - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws IOException - * @throws Exception - */ - public static KeyStore loadKeystore(AppleServer server) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, Exception { - return loadKeystore(server, server.getKeystoreStream()); - } - - - /** - * Loads a keystore. - * - * @param server The server the keystore is intended for - * @param keystore The keystore to load (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @return A loaded keystore - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws IOException - * @throws Exception - */ - public static KeyStore loadKeystore(AppleServer server, Object keystore) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, Exception { - synchronized (server) { - InputStream keystoreStream = streamKeystore(keystore); - //System.out.println("Loading keystore from "+keystore+" synchronized on "+server); - KeyStore keyStore; - try { - keyStore = KeyStore.getInstance(server.getKeystoreType()); - try { - char[] password = KeystoreManager.getKeystorePasswordForSSL(server); - keyStore.load(keystoreStream, password); - } catch (Exception e) { - e = getSimplerSSLException(e); - throw e; - } - } finally { - try { - keystoreStream.close(); - } catch (Exception e) { - } - } - return keyStore; - } - } - - - static char[] getKeystorePasswordForSSL(AppleServer server) { - String password = server.getKeystorePassword(); - if (password == null) password = ""; - // if (password != null && password.length() == 0) password = null; - char[] passchars = password != null ? password.toCharArray() : null; - return passchars; - } - - - static Exception getSimplerSSLException(Exception e) { - if (e != null) { - String msg = e.toString(); - if (msg.contains("javax.crypto.BadPaddingException")) { - return new InvalidKeystorePasswordException(); - } - if (msg.contains("DerInputStream.getLength(): lengthTag=127, too big")) { - return new InvalidKeystoreFormatException(); - } - if (msg.contains("java.lang.ArithmeticException: / by zero") || msg.contains("java.security.UnrecoverableKeyException: Get Key failed: / by zero")) { - return new InvalidKeystorePasswordException("Blank passwords not supported (#38). You must create your keystore with a non-empty password."); - } - } - return e; - } - - - /** - * Given an object representing a keystore, returns an actual stream for that keystore. - * Allows you to provide an actual keystore as an InputStream or a byte[] array, - * or a reference to a keystore file as a File object or a String path. - * - * - * @param keystore InputStream, File, byte[] or String (as a file path) - * @return A stream to the keystore. - * @throws FileNotFoundException - */ - public static InputStream streamKeystore(Object keystore) throws FileNotFoundException { - if (keystore instanceof InputStream) return (InputStream) keystore; - else if (keystore instanceof File) return new BufferedInputStream(new FileInputStream((File) keystore)); - else if (keystore instanceof String) return new BufferedInputStream(new FileInputStream((String) keystore)); - else if (keystore instanceof byte[]) return new ByteArrayInputStream((byte[]) keystore); - else throw new IllegalArgumentException("Unsupported keystore reference: " + keystore); - } - -} diff --git a/javapns/src/main/java/javapns/communication/ServerTrustingTrustManager.java b/javapns/src/main/java/javapns/communication/ServerTrustingTrustManager.java deleted file mode 100644 index 5888c3f80..000000000 --- a/javapns/src/main/java/javapns/communication/ServerTrustingTrustManager.java +++ /dev/null @@ -1,28 +0,0 @@ -package javapns.communication; - -import java.security.cert.*; - -import javax.net.ssl.*; - -/** - * A trust manager that automatically trusts all servers. - * Used to avoid having handshake errors with Apple's sandbox servers. - * - * @author Sylvain Pedneault - */ -class ServerTrustingTrustManager implements X509TrustManager { - - public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { - throw new CertificateException("Client is not trusted."); - } - - - public void checkServerTrusted(X509Certificate[] chain, String authType) { - // trust all servers - } - - - public X509Certificate[] getAcceptedIssuers() { - return null;//new X509Certificate[0]; - } -} \ No newline at end of file diff --git a/javapns/src/main/java/javapns/communication/exceptions/InvalidCertificateChainException.java b/javapns/src/main/java/javapns/communication/exceptions/InvalidCertificateChainException.java deleted file mode 100644 index 89d9ad09b..000000000 --- a/javapns/src/main/java/javapns/communication/exceptions/InvalidCertificateChainException.java +++ /dev/null @@ -1,27 +0,0 @@ -package javapns.communication.exceptions; - -/** - * Thrown when we try to contact Apple with an invalid keystore or certificate chain. - * @author Sylvain Pedneault - * - */ -@SuppressWarnings("serial") -public class InvalidCertificateChainException extends Exception { - - /** - * Constructor - */ - public InvalidCertificateChainException() { - super("Invalid certificate chain! Verify that the keystore you provided was produced according to specs..."); - } - - - /** - * Constructor with custom message - * @param message - */ - public InvalidCertificateChainException(String message) { - super("Invalid certificate chain (" + message + ")! Verify that the keystore you provided was produced according to specs..."); - } - -} diff --git a/javapns/src/main/java/javapns/communication/exceptions/InvalidKeystoreFormatException.java b/javapns/src/main/java/javapns/communication/exceptions/InvalidKeystoreFormatException.java deleted file mode 100644 index de3d03320..000000000 --- a/javapns/src/main/java/javapns/communication/exceptions/InvalidKeystoreFormatException.java +++ /dev/null @@ -1,27 +0,0 @@ -package javapns.communication.exceptions; - -/** - * Thrown when we try to contact Apple with an invalid keystore format. - * @author Sylvain Pedneault - * - */ -@SuppressWarnings("serial") -public class InvalidKeystoreFormatException extends Exception { - - /** - * Constructor - */ - public InvalidKeystoreFormatException() { - super("Invalid keystore format! Make sure it is PKCS12..."); - } - - - /** - * Constructor with custom message - * @param message - */ - public InvalidKeystoreFormatException(String message) { - super(message); - } - -} diff --git a/javapns/src/main/java/javapns/communication/exceptions/InvalidKeystorePasswordException.java b/javapns/src/main/java/javapns/communication/exceptions/InvalidKeystorePasswordException.java deleted file mode 100644 index 3eddc9207..000000000 --- a/javapns/src/main/java/javapns/communication/exceptions/InvalidKeystorePasswordException.java +++ /dev/null @@ -1,27 +0,0 @@ -package javapns.communication.exceptions; - -/** - * Thrown when we try to contact Apple with an invalid password for the keystore. - * @author Sylvain Pedneault - * - */ -@SuppressWarnings("serial") -public class InvalidKeystorePasswordException extends Exception { - - /** - * Constructor - */ - public InvalidKeystorePasswordException() { - super("Invalid keystore password! Verify settings for connecting to Apple..."); - } - - - /** - * Constructor with custom message - * @param message - */ - public InvalidKeystorePasswordException(String message) { - super(message); - } - -} diff --git a/javapns/src/main/java/javapns/devices/Device.java b/javapns/src/main/java/javapns/devices/Device.java deleted file mode 100644 index e79582621..000000000 --- a/javapns/src/main/java/javapns/devices/Device.java +++ /dev/null @@ -1,68 +0,0 @@ -package javapns.devices; - -import java.sql.*; - -/** - * This is the common interface for all Devices. - * It allows the DeviceFactory to support multiple - * implementations of Device (in-memory, JPA-backed, etc.) - * - * @author Sylvain Pedneault - */ -public interface Device { - - /** - * An id representing a particular device. - * - * Note that this is a local reference to the device, - * which is not related to the actual device UUID or - * other device-specific identification. Most of the - * time, this deviceId should be the same as the token. - * - * @return the device id - */ - public String getDeviceId(); - - - /** - * A device token. - * - * @return the device token - */ - public String getToken(); - - - /** - * - * @return the last register - */ - public Timestamp getLastRegister(); - - - /** - * An id representing a particular device. - * - * Note that this is a local reference to the device, - * which is not related to the actual device UUID or - * other device-specific identification. Most of the - * time, this deviceId should be the same as the token. - * - * @param id the device id - */ - public void setDeviceId(String id); - - - /** - * Set the device token - * @param token - */ - public void setToken(String token); - - - /** - * - * @param lastRegister the last register - */ - public void setLastRegister(Timestamp lastRegister); - -} \ No newline at end of file diff --git a/javapns/src/main/java/javapns/devices/DeviceFactory.java b/javapns/src/main/java/javapns/devices/DeviceFactory.java deleted file mode 100644 index 09de963eb..000000000 --- a/javapns/src/main/java/javapns/devices/DeviceFactory.java +++ /dev/null @@ -1,44 +0,0 @@ -package javapns.devices; - -import javapns.devices.exceptions.*; - -/** - * This is the common interface for all DeviceFactories. - * It allows the PushNotificationManager to support multiple - * implementations of DeviceFactory (in-memory, JPA-backed, etc.) - * - * @author Sylvain Pedneault - */ -public interface DeviceFactory { - - /** - * Add a device to the map - * @param id The local device id - * @param token The device token - * @return The device created - * @throws DuplicateDeviceException - * @throws NullIdException - * @throws NullDeviceTokenException - */ - public Device addDevice(String id, String token) throws DuplicateDeviceException, NullIdException, NullDeviceTokenException, Exception; - - - /** - * Get a device according to his id - * @param id The local device id - * @return The device - * @throws UnknownDeviceException - * @throws NullIdException - */ - public Device getDevice(String id) throws UnknownDeviceException, NullIdException; - - - /** - * Remove a device - * @param id The local device id - * @throws UnknownDeviceException - * @throws NullIdException - */ - public void removeDevice(String id) throws UnknownDeviceException, NullIdException; - -} \ No newline at end of file diff --git a/javapns/src/main/java/javapns/devices/exceptions/DuplicateDeviceException.java b/javapns/src/main/java/javapns/devices/exceptions/DuplicateDeviceException.java deleted file mode 100644 index 6bfb26a39..000000000 --- a/javapns/src/main/java/javapns/devices/exceptions/DuplicateDeviceException.java +++ /dev/null @@ -1,34 +0,0 @@ -package javapns.devices.exceptions; - -/** - * Thrown when a Device already exist and we try to add it a second time - * @author Maxime Peron - */ -@SuppressWarnings("serial") -public class DuplicateDeviceException extends Exception{ - - /* Custom message for this exception */ - private String message; - - /** - * Constructor - */ - public DuplicateDeviceException(){ - this.message = "Client already exists"; - } - - /** - * Constructor with custom message - * @param message - */ - public DuplicateDeviceException(String message){ - this.message = message; - } - - /** - * String representation - */ - public String toString(){ - return this.message; - } -} diff --git a/javapns/src/main/java/javapns/devices/exceptions/NullDeviceTokenException.java b/javapns/src/main/java/javapns/devices/exceptions/NullDeviceTokenException.java deleted file mode 100644 index 2da7a5fc9..000000000 --- a/javapns/src/main/java/javapns/devices/exceptions/NullDeviceTokenException.java +++ /dev/null @@ -1,35 +0,0 @@ -package javapns.devices.exceptions; - -/** - * Thrown when the given token is null - * @author Maxime Peron - * - */ -@SuppressWarnings("serial") -public class NullDeviceTokenException extends Exception{ - - /* Custom message for this exception */ - private String message; - - /** - * Constructor - */ - public NullDeviceTokenException(){ - this.message = "Client already exists"; - } - - /** - * Constructor with custom message - * @param message - */ - public NullDeviceTokenException(String message){ - this.message = message; - } - - /** - * String representation - */ - public String toString(){ - return this.message; - } -} diff --git a/javapns/src/main/java/javapns/devices/exceptions/NullIdException.java b/javapns/src/main/java/javapns/devices/exceptions/NullIdException.java deleted file mode 100644 index 998ac8949..000000000 --- a/javapns/src/main/java/javapns/devices/exceptions/NullIdException.java +++ /dev/null @@ -1,34 +0,0 @@ -package javapns.devices.exceptions; - -/** - * Thrown when the given id is null - * @author Maxime Peron - */ -@SuppressWarnings("serial") -public class NullIdException extends Exception{ - - /* Custom message for this exception */ - private String message; - - /** - * Constructor - */ - public NullIdException(){ - this.message = "Client already exists"; - } - - /** - * Constructor with custom message - * @param message - */ - public NullIdException(String message){ - this.message = message; - } - - /** - * String representation - */ - public String toString(){ - return this.message; - } -} diff --git a/javapns/src/main/java/javapns/devices/exceptions/UnknownDeviceException.java b/javapns/src/main/java/javapns/devices/exceptions/UnknownDeviceException.java deleted file mode 100644 index 92b17b5eb..000000000 --- a/javapns/src/main/java/javapns/devices/exceptions/UnknownDeviceException.java +++ /dev/null @@ -1,35 +0,0 @@ -package javapns.devices.exceptions; - -/** - * Thrown when we try to retrieve a device that doesn't exist - * @author Maxime Peron - * - */ -@SuppressWarnings("serial") -public class UnknownDeviceException extends Exception{ - - /* Custom message for this exception */ - private String message; - - /** - * Constructor - */ - public UnknownDeviceException(){ - this.message = "Unknown client"; - } - - /** - * Constructor with custom message - * @param message - */ - public UnknownDeviceException(String message){ - this.message = message; - } - - /** - * String representation - */ - public String toString(){ - return this.message; - } -} diff --git a/javapns/src/main/java/javapns/devices/implementations/basic/BasicDevice.java b/javapns/src/main/java/javapns/devices/implementations/basic/BasicDevice.java deleted file mode 100644 index bf98ec3df..000000000 --- a/javapns/src/main/java/javapns/devices/implementations/basic/BasicDevice.java +++ /dev/null @@ -1,118 +0,0 @@ -package javapns.devices.implementations.basic; - -import java.sql.Timestamp; - -import javapns.devices.*; - -/** - * This class is used to represent a Device (iPhone) - * @author Maxime Peron - * - */ -public class BasicDevice implements Device { - - /* - * An id representing a particular device. - * - * Note that this is a local reference to the device, - * which is not related to the actual device UUID or - * other device-specific identification. Most of the - * time, this deviceId should be the same as the token. - */ - private String deviceId; - - /* The device token given by Apple Server, hexadecimal form, 64bits length */ - private String token; - - /* The last time a device registered */ - private Timestamp lastRegister; - - - /** - * Default constructor. - * @param token The device token - */ - public BasicDevice(String token) throws Exception { - super(); - this.deviceId = token; - this.token = token; - this.lastRegister = new Timestamp(System.currentTimeMillis()); - - validateTokenFormat(token); - - } - - public static void validateTokenFormat(String token) throws IllegalArgumentException { - if (token==null) { - throw new IllegalArgumentException("Device Token is null, and not the required 64 bytes..."); - } - if (token.getBytes().length != 64) { - //throw new IllegalArgumentException("Device Token has a length of [" + token.getBytes().length + "] and not the required 64 bytes!"); - } - } - - /** - * Constructor - * @param id The device id - * @param token The device token - */ - public BasicDevice(String id, String token, Timestamp register) throws Exception { - super(); - this.deviceId = id; - this.token = token; - this.lastRegister = register; - - validateTokenFormat(token); - - } - - - /** - * Getter - * @return the device id - */ - public String getDeviceId() { - return deviceId; - } - - - /** - * Getter - * @return the device token - */ - public String getToken() { - return token; - } - - - /** - * Getter - * @return the last register - */ - public Timestamp getLastRegister() { - return lastRegister; - } - - - /** - * Setter - * @param id the device id - */ - public void setDeviceId(String id) { - this.deviceId = id; - } - - /** - * Setter the device token - * @param token - */ - public void setToken(String token) { - this.token = token; - } - - - public void setLastRegister(Timestamp lastRegister) { - this.lastRegister = lastRegister; - } - -} diff --git a/javapns/src/main/java/javapns/devices/implementations/basic/BasicDeviceFactory.java b/javapns/src/main/java/javapns/devices/implementations/basic/BasicDeviceFactory.java deleted file mode 100644 index b8c29e7a1..000000000 --- a/javapns/src/main/java/javapns/devices/implementations/basic/BasicDeviceFactory.java +++ /dev/null @@ -1,106 +0,0 @@ -package javapns.devices.implementations.basic; - -import java.sql.*; -import java.util.*; - -import javapns.devices.*; -import javapns.devices.exceptions.*; -import javapns.notification.*; - -import org.apache.commons.lang.*; -import com.genexus.diagnostics.core.*; - -/** - * This class implements an in-memory DeviceFactory (backed by a Map). - * Since this class does not persist Device objects, it should not be used in a production environment. - * - * NB : Future Improvement : - * - Add a method to find a device knowing his token - * - Add a method to update a device (timestamp or token) - * - method to compare two devices, and replace when the device token has changed - * - * @author Maxime Peron - * - */ -public class BasicDeviceFactory implements DeviceFactory { - - protected static final ILogger logger = PushNotificationManager.logger; - - /* A map containing all the devices, identified with their id */ - private Map devices; - - /* synclock */ - private static final Object synclock = new Object(); - - - /** - * Constructs a VolatileDeviceFactory - */ - public BasicDeviceFactory() { - this.devices = new HashMap(); - } - - - /** - * Add a device to the map - * @param id The device id - * @param token The device token - * @throws DuplicateDeviceException - * @throws NullIdException - * @throws NullDeviceTokenException - */ - public Device addDevice(String id, String token) throws DuplicateDeviceException, NullIdException, NullDeviceTokenException, Exception { - if ((id == null) || (id.trim().equals(""))) { - throw new NullIdException(); - } else if ((token == null) || (token.trim().equals(""))) { - throw new NullDeviceTokenException(); - } else { - if (!this.devices.containsKey(id)) { - token = StringUtils.deleteWhitespace(token); - BasicDevice device = new BasicDevice(id, token, new Timestamp(Calendar.getInstance().getTime().getTime())); - this.devices.put(id, device); - return device; - } else { - throw new DuplicateDeviceException(); - } - } - } - - - /** - * Get a device according to his id - * @param id The device id - * @return The device - * @throws UnknownDeviceException - * @throws NullIdException - */ - public Device getDevice(String id) throws UnknownDeviceException, NullIdException { - if ((id == null) || (id.trim().equals(""))) { - throw new NullIdException(); - } else { - if (this.devices.containsKey(id)) { - return this.devices.get(id); - } else { - throw new UnknownDeviceException(); - } - } - } - - - /** - * Remove a device - * @param id The device id - * @throws UnknownDeviceException - * @throws NullIdException - */ - public void removeDevice(String id) throws UnknownDeviceException, NullIdException { - if ((id == null) || (id.trim().equals(""))) { - throw new NullIdException(); - } - if (this.devices.containsKey(id)) { - this.devices.remove(id); - } else { - throw new UnknownDeviceException(); - } - } -} diff --git a/javapns/src/main/java/javapns/feedback/AppleFeedbackServer.java b/javapns/src/main/java/javapns/feedback/AppleFeedbackServer.java deleted file mode 100644 index a99f55bdb..000000000 --- a/javapns/src/main/java/javapns/feedback/AppleFeedbackServer.java +++ /dev/null @@ -1,24 +0,0 @@ -package javapns.feedback; - -import javapns.communication.*; - -/** - * Interface representing a connection to an Apple Feedback Server - * - * @author Sylvain Pedneault - */ -public interface AppleFeedbackServer extends AppleServer { - - public static final String PRODUCTION_HOST = "feedback.push.apple.com"; - public static final int PRODUCTION_PORT = 2196; - - public static final String DEVELOPMENT_HOST = "feedback.sandbox.push.apple.com"; - public static final int DEVELOPMENT_PORT = 2196; - - - public String getFeedbackServerHost(); - - - public int getFeedbackServerPort(); - -} diff --git a/javapns/src/main/java/javapns/feedback/AppleFeedbackServerBasicImpl.java b/javapns/src/main/java/javapns/feedback/AppleFeedbackServerBasicImpl.java deleted file mode 100644 index bc1ca833d..000000000 --- a/javapns/src/main/java/javapns/feedback/AppleFeedbackServerBasicImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -package javapns.feedback; - -import java.io.*; - -import javapns.communication.*; - -/** - * Basic implementation of the AppleFeedbackServer interface, - * intended to facilitate rapid deployment. - * - * @author Sylvain Pedneault - */ -public class AppleFeedbackServerBasicImpl extends AppleServerBasicImpl implements AppleFeedbackServer { - - private String host; - private int port; - - - /** - * Communication settings for interacting with Apple's default production or sandbox feedback server. - * This constructor uses the recommended keystore type "PCKS12". - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param production true to use Apple's production servers, false to use the sandbox - * @throws FileNotFoundException - */ - public AppleFeedbackServerBasicImpl(Object keystore, String password, boolean production) throws FileNotFoundException { - this(keystore, password, ConnectionToAppleServer.KEYSTORE_TYPE_PKCS12, production); - } - - - /** - * Communication settings for interacting with Apple's default production or sandbox feedback server. - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param type The keystore's type - * @param production true to use Apple's production servers, false to use the sandbox - * @throws FileNotFoundException - */ - public AppleFeedbackServerBasicImpl(Object keystore, String password, String type, boolean production) throws FileNotFoundException { - this(keystore, password, type, production ? PRODUCTION_HOST : DEVELOPMENT_HOST, production ? PRODUCTION_PORT : DEVELOPMENT_PORT); - } - - - /** - * Communication settings for interacting with a specific Apple Push Notification Feedback Server. - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param type The keystore's type - * @param host A specific APNS host - * @param port A specific APNS port - * @throws FileNotFoundException - */ - public AppleFeedbackServerBasicImpl(Object keystore, String password, String type, String host, int port) throws FileNotFoundException { - super(keystore, password, type); - this.host = host; - this.port = port; - } - - - public String getFeedbackServerHost() { - return host; - } - - - public int getFeedbackServerPort() { - return port; - } - -} diff --git a/javapns/src/main/java/javapns/feedback/ConnectionToFeedbackServer.java b/javapns/src/main/java/javapns/feedback/ConnectionToFeedbackServer.java deleted file mode 100644 index c423617ef..000000000 --- a/javapns/src/main/java/javapns/feedback/ConnectionToFeedbackServer.java +++ /dev/null @@ -1,32 +0,0 @@ -package javapns.feedback; - -import java.io.*; -import java.security.*; -import java.security.cert.*; - -import javapns.communication.*; - -/** - * Class representing a connection to a specific Feedback Server. - * - * @author Sylvain Pedneault - */ -public class ConnectionToFeedbackServer extends ConnectionToAppleServer { - - public ConnectionToFeedbackServer(AppleFeedbackServer feedbackServer) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, Exception { - super(feedbackServer); - } - - - @Override - public String getServerHost() { - return ((AppleFeedbackServer) getServer()).getFeedbackServerHost(); - } - - - @Override - public int getServerPort() { - return ((AppleFeedbackServer) getServer()).getFeedbackServerPort(); - } - -} diff --git a/javapns/src/main/java/javapns/feedback/FeedbackServiceManager.java b/javapns/src/main/java/javapns/feedback/FeedbackServiceManager.java deleted file mode 100644 index 7c1bbfb08..000000000 --- a/javapns/src/main/java/javapns/feedback/FeedbackServiceManager.java +++ /dev/null @@ -1,181 +0,0 @@ -package javapns.feedback; - -import java.io.*; -import java.security.*; -import java.security.cert.*; -import java.util.*; - -import javapns.devices.*; -import javapns.devices.exceptions.*; -import javapns.devices.implementations.basic.*; -import javax.net.ssl.*; - -import com.genexus.diagnostics.core.*; - - -/** - * Class for interacting with a specific Feedback Service. - * - * @author kljajo, dgardon, Sylvain Pedneault - * - */ -public class FeedbackServiceManager { - - protected static final ILogger logger = LogManager.getLogger(FeedbackServiceManager.class); - - /* Length of the tuple sent by Apple */ - private static final int FEEDBACK_TUPLE_SIZE = 38; - - private boolean proxySet = false; - - private DeviceFactory deviceFactory; - - - /** - * Constructs a FeedbackServiceManager with a supplied DeviceFactory. - */ - public FeedbackServiceManager(DeviceFactory deviceFactory) { - this.setDeviceFactory(deviceFactory); - } - - - /** - * Constructs a FeedbackServiceManager with a default basic DeviceFactory. - */ - public FeedbackServiceManager() { - this.setDeviceFactory(new BasicDeviceFactory()); - } - - - /** - * Retrieve all devices which have un-installed the application w/Path to keystore - * - * @param server Connection information for the Apple server - * @return List of Devices - * @throws IOException - * @throws FileNotFoundException - * @throws CertificateException - * @throws NoSuchAlgorithmException - * @throws KeyStoreException - * @throws KeyManagementException - * @throws UnrecoverableKeyException - */ - /** - */ - public LinkedList getDevices(AppleFeedbackServer server) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, NoSuchProviderException, Exception { - // logger.debug( "Retrieving Devices from Host: [" + appleHost + "] Port: [" + applePort + "] with KeyStorePath [" + keyStorePath + "]/[" + keyStoreType + "]" ); - // Create the connection and open a socket - ConnectionToFeedbackServer connectionHelper = new ConnectionToFeedbackServer(server); - SSLSocket socket = connectionHelper.getSSLSocket(); - - return getDevices(socket); - } - - - /** - * Retrieves the list of devices from an established SSLSocket. - * - * @param socket - * @return Devices - * @throws Exception - * @throws NullDeviceTokenException - * @throws NullIdException - * @throws DuplicateDeviceException - */ - private LinkedList getDevices(SSLSocket socket) throws Exception { - - // Compute - LinkedList listDev = null; - try { - InputStream socketStream = socket.getInputStream(); - - // Read bytes - byte[] b = new byte[1024]; - ByteArrayOutputStream message = new ByteArrayOutputStream(); - int nbBytes = 0; - // socketStream.available can return 0 - // http://forums.sun.com/thread.jspa?threadID=5428561 - while ((nbBytes = socketStream.read(b, 0, 1024)) != -1) { - message.write(b, 0, nbBytes); - } - - listDev = new LinkedList(); - byte[] listOfDevices = message.toByteArray(); - int nbTuples = listOfDevices.length / FEEDBACK_TUPLE_SIZE; - logger.debug("Found: [" + nbTuples + "]"); - for (int i = 0; i < nbTuples; i++) { - int offset = i * FEEDBACK_TUPLE_SIZE; - - // Build date - int index = 0; - int firstByte = 0; - int secondByte = 0; - int thirdByte = 0; - int fourthByte = 0; - long anUnsignedInt = 0; - - firstByte = (0x000000FF & ((int) listOfDevices[offset])); - secondByte = (0x000000FF & ((int) listOfDevices[offset + 1])); - thirdByte = (0x000000FF & ((int) listOfDevices[offset + 2])); - fourthByte = (0x000000FF & ((int) listOfDevices[offset + 3])); - index = index + 4; - anUnsignedInt = ((long) (firstByte << 24 | secondByte << 16 | thirdByte << 8 | fourthByte)) & 0xFFFFFFFFL; - - // Build device token length - int deviceTokenLength = listOfDevices[offset + 4] << 8 | listOfDevices[offset + 5]; - - // Build device token - String deviceToken = ""; - int octet = 0; - for (int j = 0; j < 32; j++) { - octet = (0x000000FF & ((int) listOfDevices[offset + 6 + j])); - deviceToken = deviceToken.concat(String.format("%02x", octet)); - } - - // Build device and add to list - /* Create a basic device, as we do not want to go through the factory and create a device in the actual database... */ - Device device = new BasicDevice(deviceToken); - listDev.add(device); - logger.info("FeedbackManager retrieves one device : " + new Date(anUnsignedInt * 1000) + ";" + deviceTokenLength + ";" + deviceToken + "."); - } - - // Close the socket and return the list - - } catch (Exception e) { - logger.debug("Caught exception fetching devices from Feedback Service"); - throw e; - } - - finally { - socket.close(); - } - return listDev; - } - - - /** - * Set the proxy if needed - * @param host the proxyHost - * @param port the proxyPort - */ - public void setProxy(String host, String port) { - this.proxySet = true; - - System.setProperty("http.proxyHost", host); - System.setProperty("http.proxyPort", port); - - System.setProperty("https.proxyHost", host); - System.setProperty("https.proxyPort", port); - } - - - public void setDeviceFactory(DeviceFactory deviceFactory) { - this.deviceFactory = deviceFactory; - } - - - public DeviceFactory getDeviceFactory() { - return deviceFactory; - } - -} diff --git a/javapns/src/main/java/javapns/notification/AppleNotificationServer.java b/javapns/src/main/java/javapns/notification/AppleNotificationServer.java deleted file mode 100644 index 9fe85d45a..000000000 --- a/javapns/src/main/java/javapns/notification/AppleNotificationServer.java +++ /dev/null @@ -1,24 +0,0 @@ -package javapns.notification; - -import javapns.communication.*; - -/** - * Interface representing a connection to an Apple Notification Server - * - * @author Sylvain Pedneault - */ -public interface AppleNotificationServer extends AppleServer { - - public static final String PRODUCTION_HOST = "gateway.push.apple.com"; - public static final int PRODUCTION_PORT = 2195; - - public static final String DEVELOPMENT_HOST = "gateway.sandbox.push.apple.com"; - public static final int DEVELOPMENT_PORT = 2195; - - - public String getNotificationServerHost(); - - - public int getNotificationServerPort(); - -} diff --git a/javapns/src/main/java/javapns/notification/AppleNotificationServerBasicImpl.java b/javapns/src/main/java/javapns/notification/AppleNotificationServerBasicImpl.java deleted file mode 100644 index faa52fe5c..000000000 --- a/javapns/src/main/java/javapns/notification/AppleNotificationServerBasicImpl.java +++ /dev/null @@ -1,73 +0,0 @@ -package javapns.notification; - -import java.io.*; - -import javapns.communication.*; - -/** - * Basic implementation of the AppleNotificationServer interface, - * intended to facilitate rapid deployment. - * - * @author Sylvain Pedneault - */ -public class AppleNotificationServerBasicImpl extends AppleServerBasicImpl implements AppleNotificationServer { - - private String host; - private int port; - - - /** - * Communication settings for interacting with Apple's default production or sandbox notification server. - * This constructor uses the recommended keystore type "PCKS12". - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param production true to use Apple's production servers, false to use the sandbox - * @throws FileNotFoundException - */ - public AppleNotificationServerBasicImpl(Object keystore, String password, boolean production) throws FileNotFoundException { - this(keystore, password, ConnectionToAppleServer.KEYSTORE_TYPE_PKCS12, production); - } - - - /** - * Communication settings for interacting with Apple's default production or sandbox notification server. - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param type The keystore's type - * @param production true to use Apple's production servers, false to use the sandbox - * @throws FileNotFoundException - */ - public AppleNotificationServerBasicImpl(Object keystore, String password, String type, boolean production) throws FileNotFoundException { - this(keystore, password, type, production ? PRODUCTION_HOST : DEVELOPMENT_HOST, production ? PRODUCTION_PORT : DEVELOPMENT_PORT); - } - - - /** - * Communication settings for interacting with a specific Apple Push Notification Server. - * - * @param keystore The keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password The keystore's password - * @param type The keystore's type - * @param host A specific APNS host - * @param port A specific APNS port - * @throws FileNotFoundException - */ - public AppleNotificationServerBasicImpl(Object keystore, String password, String type, String host, int port) throws FileNotFoundException { - super(keystore, password, type); - this.host = host; - this.port = port; - } - - - public String getNotificationServerHost() { - return host; - } - - - public int getNotificationServerPort() { - return port; - } - -} diff --git a/javapns/src/main/java/javapns/notification/ConnectionToNotificationServer.java b/javapns/src/main/java/javapns/notification/ConnectionToNotificationServer.java deleted file mode 100644 index 330d9c6e5..000000000 --- a/javapns/src/main/java/javapns/notification/ConnectionToNotificationServer.java +++ /dev/null @@ -1,32 +0,0 @@ -package javapns.notification; - -import java.io.*; -import java.security.*; -import java.security.cert.*; - -import javapns.communication.*; - -/** - * Connection details specific to the Notification Service. - * - * @author Sylvain Pedneault - */ -public class ConnectionToNotificationServer extends ConnectionToAppleServer { - - public ConnectionToNotificationServer(AppleNotificationServer server) throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException, Exception { - super(server); - } - - - @Override - public String getServerHost() { - return ((AppleNotificationServer) getServer()).getNotificationServerHost(); - } - - - @Override - public int getServerPort() { - return ((AppleNotificationServer) getServer()).getNotificationServerPort(); - } - -} diff --git a/javapns/src/main/java/javapns/notification/NewsstandNotificationPayload.java b/javapns/src/main/java/javapns/notification/NewsstandNotificationPayload.java deleted file mode 100644 index d5bd87f65..000000000 --- a/javapns/src/main/java/javapns/notification/NewsstandNotificationPayload.java +++ /dev/null @@ -1,68 +0,0 @@ -package javapns.notification; - -import org.json.*; - -/** - * A Newsstand-specific payload compatible with the Apple Push Notification Service. - * - * @author Sylvain Pedneault - */ -public class NewsstandNotificationPayload extends Payload { - - /** - * Create a pre-defined payload with a content-available property set to 1. - * - * @return a ready-to-send newsstand payload - */ - public static NewsstandNotificationPayload contentAvailable() { - NewsstandNotificationPayload payload = complex(); - try { - payload.addContentAvailable(); - } catch (JSONException e) { - } - return payload; - } - - - /** - * Create an empty payload which you can configure later (most users should not use this). - * This method is usually used to create complex or custom payloads. - * Note: the payload actually contains the default "aps" - * dictionary required by Newsstand. - * - * @return a blank payload that can be customized - */ - private static NewsstandNotificationPayload complex() { - NewsstandNotificationPayload payload = new NewsstandNotificationPayload(); - return payload; - } - - /* The application Dictionnary */ - private JSONObject apsDictionary; - - - /** - * Create a default payload with a blank "aps" dictionary. - */ - NewsstandNotificationPayload() { - super(); - this.apsDictionary = new JSONObject(); - try { - JSONObject payload = getPayload(); - payload.put("aps", this.apsDictionary); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - - void addContentAvailable() throws JSONException { - addContentAvailable(1); - } - - - void addContentAvailable(int contentAvailable) throws JSONException { - this.apsDictionary.put("content-available", contentAvailable); - } - -} diff --git a/javapns/src/main/java/javapns/notification/Payload.java b/javapns/src/main/java/javapns/notification/Payload.java deleted file mode 100644 index 0c5552c98..000000000 --- a/javapns/src/main/java/javapns/notification/Payload.java +++ /dev/null @@ -1,337 +0,0 @@ -package javapns.notification; - -import java.util.*; - -import javapns.devices.*; -import javapns.notification.exceptions.*; - -import org.json.*; - -import com.genexus.diagnostics.core.*; - -/** - * Abstract class representing a payload that can be transmitted to Apple. - * - * By default, this class has no payload content at all. Subclasses are - * responsible for imposing specific content based on the specifications - * they are intended to implement (such as the 'aps' dictionnary for APS - * payloads). - * - * @author Sylvain Pedneault - */ -public abstract class Payload { - - /* Character encoding specified by Apple documentation */ - private static final String DEFAULT_CHARACTER_ENCODING = "UTF-8"; - - protected static final ILogger logger = LogManager.getLogger(DeviceFactory.class); - - /* The root Payload */ - private JSONObject payload; - - /* Character encoding to use for streaming the payload (should be UTF-8) */ - private String characterEncoding = DEFAULT_CHARACTER_ENCODING; - - /* Number of seconds after which this payload should expire */ - private int expiry = 1 * 24 * 60 * 60; - - private boolean payloadSizeEstimatedWhenAdding = false; - - - /** - * Constructor, instantiate the the root JSONObject - */ - public Payload() { - super(); - this.payload = new JSONObject(); - } - - - public JSONObject getPayload() { - return this.payload; - } - - - /** - * Add a custom dictionnary with a string value - * @param name - * @param value - * @throws JSONException - */ - public void addCustomDictionary(String name, String value) throws JSONException { - logger.debug("Adding custom Dictionary [" + name + "] = [" + value + "]"); - put(name, value, payload, false); - } - - - /** - * Add a custom dictionnary with a int value - * @param name - * @param value - * @throws JSONException - */ - public void addCustomDictionary(String name, int value) throws JSONException { - logger.debug("Adding custom Dictionary [" + name + "] = [" + value + "]"); - put(name, value, payload, false); - } - - - /** - * Add a custom dictionnary with multiple values - * @param name - * @param values - * @throws JSONException - */ - public void addCustomDictionary(String name, List values) throws JSONException { - logger.debug("Adding custom Dictionary [" + name + "] = (list)"); - put(name, values, payload, false); - } - - - /** - * Get the string representation - */ - public String toString() { - return this.payload.toString(); - } - - - /** - * Get this payload as a byte array using the preconfigured character encoding. - * - * @return byte[] bytes ready to be streamed directly to Apple servers - */ - public byte[] getPayloadAsBytes() throws Exception { - byte[] payload = getPayloadAsBytesUnchecked(); - validateMaximumPayloadSize(payload.length); - return payload; - } - - - /** - * Get this payload as a byte array using the preconfigured character encoding. - * This method does NOT check if the payload exceeds the maximum payload length. - * - * @return byte[] bytes ready to be streamed directly to Apple servers (but that might exceed the maximum size limit) - */ - private byte[] getPayloadAsBytesUnchecked() throws Exception { - byte[] bytes = null; - try { - bytes = toString().getBytes(characterEncoding); - } catch (Exception ex) { - bytes = toString().getBytes(); - } - return bytes; - } - - - /** - * Get the number of bytes that the payload will occupy when streamed. - * - * @return a number of bytes - * @throws Exception - */ - public int getPayloadSize() throws Exception { - return getPayloadAsBytesUnchecked().length; - } - - - /** - * Check if the payload exceeds the maximum size allowed. - * The maximum size allowed is returned by the getMaximumPayloadSize() method. - * - * @return true if the payload exceeds the maximum size allowed, false otherwise - */ - private boolean isPayloadTooLong() { - try { - byte[] bytes = getPayloadAsBytesUnchecked(); - if (bytes.length > getMaximumPayloadSize()) return true; - } catch (Exception e) { - } - return false; - } - - - /** - * Estimate the size that this payload will take after adding a given property. - * For performance reasons, this estimate is not as reliable as actually adding - * the property and checking the payload size afterwards. - * - * Currently works well with strings and numbers. - * - * @param propertyName the name of the property to use for calculating the estimation - * @param propertyValue the value of the property to use for calculating the estimation - * @return an estimated payload size if the property were to be added to the payload - */ - public int estimatePayloadSizeAfterAdding(String propertyName, Object propertyValue) { - try { - int maximumPayloadSize = getMaximumPayloadSize(); - int currentPayloadSize = getPayloadAsBytesUnchecked().length; - int estimatedSize = currentPayloadSize; - if (propertyName != null && propertyValue != null) { - estimatedSize += 5; // "":"" - estimatedSize += propertyName.getBytes(getCharacterEncoding()).length; - int estimatedValueSize = 0; - - if (propertyValue instanceof String || propertyValue instanceof Number) estimatedValueSize = propertyValue.toString().getBytes(getCharacterEncoding()).length; - - estimatedSize += estimatedValueSize; - } - return estimatedSize; - } catch (Exception e) { - try { - return getPayloadSize(); - } catch (Exception e1) { - return 0; - } - } - } - - - /** - * Validate if the estimated payload size after adding a given property will be allowed. - * For performance reasons, this estimate is not as reliable as actually adding - * the property and checking the payload size afterwards. - * - * @param propertyName the name of the property to use for calculating the estimation - * @param propertyValue the value of the property to use for calculating the estimation - * @return true if the payload size is not expected to exceed the maximum allowed, false if it might be too big - */ - public boolean isEstimatedPayloadSizeAllowedAfterAdding(String propertyName, Object propertyValue) { - int maximumPayloadSize = getMaximumPayloadSize(); - int estimatedPayloadSize = estimatePayloadSizeAfterAdding(propertyName, propertyValue); - boolean estimatedToBeAllowed = estimatedPayloadSize <= maximumPayloadSize; - return estimatedToBeAllowed; - } - - - /** - * Validate that the payload does not exceed the maximum size allowed. - * If the limit is exceeded, a PayloadMaxSizeExceededException is thrown. - * - * @param currentPayloadSize the total size of the payload in bytes - * @throws PayloadMaxSizeExceededException if the payload exceeds the maximum size allowed - */ - private void validateMaximumPayloadSize(int currentPayloadSize) throws PayloadMaxSizeExceededException { - int maximumPayloadSize = getMaximumPayloadSize(); - if (currentPayloadSize > maximumPayloadSize) { - throw new PayloadMaxSizeExceededException(maximumPayloadSize, currentPayloadSize); - } - } - - - /** - * Puts a property in a JSONObject, while possibly checking for estimated payload size violation. - * - * @param propertyName the name of the property to use for calculating the estimation - * @param propertyValue the value of the property to use for calculating the estimation - * @param object the JSONObject to put the property in - * @param opt true to use putOpt, false to use put - * @throws JSONException - */ - protected void put(String propertyName, Object propertyValue, JSONObject object, boolean opt) throws JSONException { - try { - if (isPayloadSizeEstimatedWhenAdding()) { - int maximumPayloadSize = getMaximumPayloadSize(); - int estimatedPayloadSize = estimatePayloadSizeAfterAdding(propertyName, propertyValue); - boolean estimatedToExceed = estimatedPayloadSize > maximumPayloadSize; - if (estimatedToExceed) throw new PayloadMaxSizeProbablyExceededException(maximumPayloadSize, estimatedPayloadSize); - } - } catch (PayloadMaxSizeProbablyExceededException e) { - throw e; - } catch (Exception e) { - - } - if (opt) object.putOpt(propertyName, propertyValue); - else object.put(propertyName, propertyValue); - } - - - /** - * Indicates if payload size is estimated and controlled when adding properties (default is false). - * - * @return true to throw an exception if the estimated size is too big when adding a property, false otherwise - */ - public boolean isPayloadSizeEstimatedWhenAdding() { - return payloadSizeEstimatedWhenAdding; - } - - - /** - * Indicate if payload size should be estimated and controlled when adding properties (default is false). - * @param checked true to throw an exception if the estimated size is too big when adding a property, false otherwise - */ - public void setPayloadSizeEstimatedWhenAdding(boolean checked) { - this.payloadSizeEstimatedWhenAdding = checked; - } - - - /** - * Return the maximum payload size in bytes. - * By default, this method returns Integer.MAX_VALUE. - * Subclasses should override this method to provide their own limit. - * - * @return the maximum payload size in bytes - */ - public int getMaximumPayloadSize() { - return Integer.MAX_VALUE; - } - - - /** - * Changes the character encoding for streaming the payload. - * Character encoding is preset to UTF-8, as Apple documentation specifies. - * Therefore, unless you are working on a special project, you should leave it as is. - * - * @param characterEncoding a valid character encoding that String.getBytes(encoding) will accept - */ - public void setCharacterEncoding(String characterEncoding) { - this.characterEncoding = characterEncoding; - } - - - /** - * Returns the character encoding that will be used by getPayloadAsBytes(). - * Default is UTF-8, as per Apple documentation. - * - * @return a character encoding - */ - public String getCharacterEncoding() { - return characterEncoding; - } - - - /** - * Set the number of seconds after which this payload should expire. - * Default is one (1) day. - * - * @param seconds - */ - public void setExpiry(int seconds) { - this.expiry = seconds; - } - - - /** - * Return the number of seconds after which this payload should expire. - * - * @return a number of seconds - */ - public int getExpiry() { - return expiry; - } - - - /** - * Enables a special simulation mode which causes the library to behave - * as usual *except* that at the precise point where the payload would - * actually be streamed out to Apple, it is not. - * - * @return the same payload - */ - public Payload asSimulationOnly() { - setExpiry(919191); - return this; - } - -} diff --git a/javapns/src/main/java/javapns/notification/PayloadPerDevice.java b/javapns/src/main/java/javapns/notification/PayloadPerDevice.java deleted file mode 100644 index 7a1b7a805..000000000 --- a/javapns/src/main/java/javapns/notification/PayloadPerDevice.java +++ /dev/null @@ -1,41 +0,0 @@ -package javapns.notification; - -import javapns.devices.*; -import javapns.devices.implementations.basic.*; - -/** - * A one-to-one link between a payload and device. - * Provides support for a typical payload-per-device scenario. - * - * @author Sylvain Pedneault - */ -public class PayloadPerDevice { - - private Payload payload; - private Device device; - - - public PayloadPerDevice(Payload payload, String token) throws Exception { - super(); - this.payload = payload; - this.device = new BasicDevice(token); - } - - - public PayloadPerDevice(Payload payload, Device device) { - super(); - this.payload = payload; - this.device = device; - } - - - public Payload getPayload() { - return payload; - } - - - public Device getDevice() { - return device; - } - -} diff --git a/javapns/src/main/java/javapns/notification/PushNotificationManager.java b/javapns/src/main/java/javapns/notification/PushNotificationManager.java deleted file mode 100644 index 764d350e8..000000000 --- a/javapns/src/main/java/javapns/notification/PushNotificationManager.java +++ /dev/null @@ -1,627 +0,0 @@ -package javapns.notification; - -import java.io.*; -import java.net.*; -import java.nio.*; -import java.security.*; -import java.security.cert.*; -import java.util.*; - -import javapns.communication.*; -import javapns.communication.exceptions.*; -import javapns.devices.*; -import javapns.devices.exceptions.*; -import javapns.devices.implementations.basic.*; - -import javax.net.ssl.*; - -import com.genexus.diagnostics.core.*; -/** - * The main class used to send notification and handle a connection to Apple SSLServerSocket. - * This class is not multi-threaded. One instance per thread must be created. - * - * @author Maxime Pilon - * @author Sylvain Pedneault - * @author Others... - */ -public class PushNotificationManager { - - /* - * Number of milliseconds to use as socket timeout. - * Set to -1 to leave the timeout to its default setting. - */ - private int sslSocketTimeout = 30 * 1000; - - public static final ILogger logger = LogManager.getLogger(PushNotificationManager.class); - - /* Default retries for a connection */ - private static final int DEFAULT_RETRIES = 3; - - /* Special identifier that tells the manager to generate a sequential identifier for each payload pushed */ - private static final int SEQUENTIAL_IDENTIFIER = -1; - - /* Connection helper */ - private ConnectionToAppleServer connectionToAppleServer; - - /* The always connected SSLSocket */ - private SSLSocket socket; - - /* Default retry attempts */ - private int retryAttempts = DEFAULT_RETRIES; - - private int nextMessageIdentifier = 1; - - /* - * To circumvent an issue with invalid server certificates, - * set to true to use a trust manager that will always accept - * server certificates, regardless of their validity. - */ - private boolean trustAllServerCertificates = true; - - private boolean proxySet = false; - - /* The DeviceFactory to use with this PushNotificationManager */ - private DeviceFactory deviceFactory; - - private LinkedHashMap pushedNotifications = new LinkedHashMap(); - - - /** - * Constructs a PushNotificationManager with a default DeviceFactory; - * Must allow the device factory to be replaced later, to support IoC. - */ - public PushNotificationManager() { - deviceFactory = new BasicDeviceFactory(); - } - - - /** - * Constructs a PushNotificationManager using a supplied DeviceFactory - * @param deviceManager - */ - public PushNotificationManager(DeviceFactory deviceManager) { - this.deviceFactory = deviceManager; - } - - - /** - * Initialize the connection and create a SSLSocket - * @param server The Apple Server to connect to. - * @throws Exception - */ - public void initializeConnection(AppleNotificationServer server) throws Exception { - this.connectionToAppleServer = new ConnectionToNotificationServer(server); - this.socket = connectionToAppleServer.getSSLSocket(); - logger.debug("Initialized Connection to Host: [" + server.getNotificationServerHost() + "] Port: [" + server.getNotificationServerPort() + "]: " + socket); - } - - - public void initializePreviousConnection() throws Exception { - initializeConnection((AppleNotificationServer) this.connectionToAppleServer.getServer()); - } - - - public void restartConnection(AppleNotificationServer server) throws Exception { - stopConnection(); - initializeConnection(server); - } - - - private void restartPreviousConnection() throws Exception { - try { - logger.debug("Closing connection to restart previous one"); - this.socket.close(); - } catch (Exception e) { - /* Do not complain if connection is already closed... */ - } - initializePreviousConnection(); - } - - - /** - * Read and process any pending error-responses, and then close the connection. - * - * @throws IOException - */ - public void stopConnection() throws Exception { - processedFailedNotifications(); - try { - logger.debug("Closing connection"); - this.socket.close(); - } catch (Exception e) { - /* Do not complain if connection is already closed... */ - } - } - - - private int processedFailedNotifications() throws Exception { - logger.debug("Reading responses"); - int responsesReceived = ResponsePacketReader.processResponses(this); - while (responsesReceived > 0) { - PushedNotification skippedNotification = null; - List notificationsToResend = new ArrayList(); - boolean foundFirstFail = false; - for (PushedNotification notification : pushedNotifications.values()) { - if (foundFirstFail || !notification.isSuccessful()) { - if (foundFirstFail) notificationsToResend.add(notification); - else { - foundFirstFail = true; - skippedNotification = notification; - } - } - } - pushedNotifications.clear(); - int toResend = notificationsToResend.size(); - logger.debug("Found " + toResend + " notifications that must be re-sent"); - if (toResend > 0) { - logger.debug("Restarting connection to resend notifications"); - restartPreviousConnection(); - for (PushedNotification pushedNotification : notificationsToResend) { - sendNotification(pushedNotification, false); - } - } - int remaining = responsesReceived = ResponsePacketReader.processResponses(this); - if (remaining == 0) { - logger.debug("No notifications remaining to be resent"); - return 0; - } - } - return responsesReceived; - } - - - /** - * Send a notification to a single device and close the connection. - * - * @param device the device to be notified - * @param payload the payload to send - * @return a pushed notification with details on transmission result and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - * @throws Exception - */ - public PushedNotification sendNotification(Device device, Payload payload) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - return sendNotification(device, payload, true); - } - - - /** - * Send a notification to a multiple devices in a single connection and close the connection. - * - * @param payload the payload to send - * @param devices the device to be notified - * @return a list of pushed notifications, each with details on transmission results and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - * @throws Exception - */ - public List sendNotifications(Payload payload, List devices) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - List notifications = new Vector(); - for (Device device : devices) - notifications.add(sendNotification(device, payload, false, SEQUENTIAL_IDENTIFIER)); - stopConnection(); - return notifications; - } - - - /** - * Send a notification to a multiple devices in a single connection and close the connection. - * - * @param payload the payload to send - * @param devices the device to be notified - * @return a list of pushed notifications, each with details on transmission results and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - * @throws Exception - */ - public List sendNotifications(Payload payload, Device... devices) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - List notifications = new Vector(); - for (Device device : devices) - notifications.add(sendNotification(device, payload, false, SEQUENTIAL_IDENTIFIER)); - stopConnection(); - return notifications; - } - - - /** - * Send a notification (Payload) to the given device - * - * @param device the device to be notified - * @param payload the payload to send - * @param closeAfter indicates if the connection should be closed after the payload has been sent - * @return a pushed notification with details on transmission result and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - */ - public PushedNotification sendNotification(Device device, Payload payload, boolean closeAfter) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - return sendNotification(device, payload, closeAfter, SEQUENTIAL_IDENTIFIER); - } - - - /** - * Send a notification (Payload) to the given device - * - * @param device the device to be notified - * @param payload the payload to send - * @param identifier a unique identifier which will match any error reported later (if any) - * @return a pushed notification with details on transmission result and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - */ - public PushedNotification sendNotification(Device device, Payload payload, int identifier) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - return sendNotification(device, payload, false, identifier); - } - - - /** - * Send a notification (Payload) to the given device - * - * @param device the device to be notified - * @param payload the payload to send - * @param closeAfter indicates if the connection should be closed after the payload has been sent - * @param identifier a unique identifier which will match any error reported later (if any) - * @return a pushed notification with details on transmission result and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - * @return TransmissionEnvelope an object that encapsulates all message transmission results - */ - public PushedNotification sendNotification(Device device, Payload payload, boolean closeAfter, int identifier) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - PushedNotification pushedNotification = new PushedNotification(device, payload, identifier); - sendNotification(pushedNotification, closeAfter); - return pushedNotification; - } - - - /** - * Actual action of sending a notification - * - * @param notification the ready-to-push notification - * @param closeAfter indicates if the connection should be closed after the payload has been sent - * @return a pushed notification with details on transmission result and error (if any) - * @throws UnrecoverableKeyException - * @throws KeyManagementException - * @throws KeyStoreException - * @throws NoSuchAlgorithmException - * @throws CertificateException - * @throws FileNotFoundException - * @throws IOException - * @return TransmissionEnvelope an object that encapsulates all message transmission results - */ - private void sendNotification(PushedNotification notification, boolean closeAfter) throws UnrecoverableKeyException, KeyManagementException, KeyStoreException, NoSuchAlgorithmException, CertificateException, FileNotFoundException, IOException, Exception { - try { - Device device = notification.getDevice(); - Payload payload = notification.getPayload(); - if (notification.getIdentifier() <= 0) notification.setIdentifier(newMessageIdentifier()); - if (!pushedNotifications.containsKey(notification.getIdentifier())) pushedNotifications.put(notification.getIdentifier(), notification); - int identifier = notification.getIdentifier(); - - String token = device.getToken(); - // even though the BasicDevice constructor validates the token, we revalidate it in case we were passed another implementation of Device - BasicDevice.validateTokenFormat(token); - // PushedNotification pushedNotification = new PushedNotification(device, payload); - byte[] bytes = getMessage(token, payload, identifier, notification); - // pushedNotifications.put(pushedNotification.getIdentifier(), pushedNotification); - - /* Special simulation mode to skip actual streaming of message */ - boolean simulationMode = payload.getExpiry() == 919191; - - boolean success = false; - - BufferedReader in = new BufferedReader(new InputStreamReader(this.socket.getInputStream())); - int socketTimeout = getSslSocketTimeout(); - if (socketTimeout > 0) this.socket.setSoTimeout(socketTimeout); - notification.setTransmissionAttempts(0); - // Keep trying until we have a success - while (!success) { - try { - logger.debug("Attempting to send notification: " + payload.toString() + ""); - logger.debug(" to device: " + token + ""); - notification.addTransmissionAttempt(); - try { - if (!simulationMode) { - this.socket.getOutputStream().write(bytes); - } else { - logger.debug("* Simulation only: would have streamed " + bytes.length + "-bytes message now.."); - } - } catch (Exception e) { - if (e != null) { - if (e.toString().contains("certificate_unknown")) { - throw new InvalidCertificateChainException(e.getMessage()); - } - } - throw e; - } - logger.debug("Flushing"); - this.socket.getOutputStream().flush(); - success = true; - logger.debug("Notification sent on " + notification.getLatestTransmissionAttempt()); - notification.setTransmissionCompleted(true); - - } catch (IOException e) { - // throw exception if we surpassed the valid number of retry attempts - if (notification.getTransmissionAttempts() >= retryAttempts) { - logger.error("Attempt to send Notification failed and beyond the maximum number of attempts permitted"); - notification.setTransmissionCompleted(false); - notification.setException(e); - logger.error("Delivery error", e); - throw e; - - } else { - logger.info("Attempt failed (" + e.getMessage() + ")... trying again"); - //Try again - try { - this.socket.close(); - } catch (Exception e2) { - // do nothing - } - this.socket = connectionToAppleServer.getSSLSocket(); - if (socketTimeout > 0) this.socket.setSoTimeout(socketTimeout); - } - } - } - } catch (Exception ex) { - notification.setException(ex); - logger.error("Delivery error", ex); - try { - if (closeAfter) { - logger.error("Closing connection after error"); - stopConnection(); - } - } catch (Exception e) { - } - } - } - - - /** - * Add a device - * @param id The device id - * @param token The device token - * @throws DuplicateDeviceException - * @throws NullDeviceTokenException - * @throws NullIdException - */ - public void addDevice(String id, String token) throws DuplicateDeviceException, NullIdException, NullDeviceTokenException, Exception { - logger.debug("Adding Token [" + token + "] to Device [" + id + "]"); - deviceFactory.addDevice(id, token); - } - - - /** - * Get a device according to his id - * @param id The device id - * @return The device - * @throws UnknownDeviceException - * @throws NullIdException - */ - public Device getDevice(String id) throws UnknownDeviceException, NullIdException { - logger.debug("Getting Token from Device [" + id + "]"); - return deviceFactory.getDevice(id); - } - - - /** - * Remove a device - * @param id The device id - * @throws UnknownDeviceException - * @throws NullIdException - */ - public void removeDevice(String id) throws UnknownDeviceException, NullIdException { - logger.debug("Removing Token from Device [" + id + "]"); - deviceFactory.removeDevice(id); - } - - - /** - * Set the proxy if needed - * @param host the proxyHost - * @param port the proxyPort - */ - public void setProxy(String host, String port) { - proxySet = true; - - System.setProperty("http.proxyHost", host); - System.setProperty("http.proxyPort", port); - - System.setProperty("https.proxyHost", host); - System.setProperty("https.proxyPort", port); - } - - - /** - * Compose the Raw Interface that will be sent through the SSLSocket - * A notification message is - * COMMAND | TOKENLENGTH | DEVICETOKEN | PAYLOADLENGTH | PAYLOAD - * NEW! - * COMMAND | !Identifier! | !Expiry! | TOKENLENGTH| DEVICETOKEN | PAYLOADLENGTH | PAYLOAD - * See page 30 of Apple Push Notification Service Programming Guide - * @param deviceToken the deviceToken - * @param payload the payload - * @param message - * @return the byteArray to write to the SSLSocket OutputStream - * @throws IOException - */ - private byte[] getMessage(String deviceToken, Payload payload, int identifier, PushedNotification message) throws IOException, Exception { - logger.debug("Building Raw message from deviceToken and payload"); - - /* To test with a corrupted or invalid token, uncomment following line*/ - //deviceToken = deviceToken.substring(0,10); - - // First convert the deviceToken (in hexa form) to a binary format - /*byte[] deviceTokenAsBytes = new byte[deviceToken.length() / 2]; - deviceToken = deviceToken.toUpperCase(); - int j = 0; - for (int i = 0; i < deviceToken.length(); i += 2) { - String t = deviceToken.substring(i, i + 2); - int tmp = Integer.parseInt(t, 16); - deviceTokenAsBytes[j++] = (byte) tmp; - }*/ - - byte[] deviceTokenAsBytes = com.genexus.util.Codecs.base64Decode(deviceToken.getBytes()); - - // Create the ByteArrayOutputStream which will contain the raw interface - byte[] payloadAsBytes = payload.getPayloadAsBytes(); - int size = (Byte.SIZE / Byte.SIZE) + (Character.SIZE / Byte.SIZE) + deviceTokenAsBytes.length + (Character.SIZE / Byte.SIZE) + payloadAsBytes.length; - ByteArrayOutputStream bao = new ByteArrayOutputStream(size); - - // Write command to ByteArrayOutputStream - // 0 = simple - // 1 = enhanced - byte b = 1; - bao.write(b); - - // 4 bytes identifier (which will match any error packet received later on) - bao.write(intTo4ByteArray(identifier)); - message.setIdentifier(identifier); - - // 4 bytes - int requestedExpiry = payload.getExpiry(); - if (requestedExpiry <= 0) { - bao.write(intTo4ByteArray(requestedExpiry)); - message.setExpiry(0); - } else { - long ctime = System.currentTimeMillis(); - long ttl = requestedExpiry * 1000; // time-to-live in milliseconds - Long expiryDateInSeconds = ((ctime + ttl) / 1000L); - bao.write(intTo4ByteArray(expiryDateInSeconds.intValue())); - message.setExpiry(ctime + ttl); - } - - // Write the TokenLength as a 16bits unsigned int, in big endian - int tl = deviceTokenAsBytes.length; - bao.write((byte) ((tl & 0xFF00) >> 8)); - bao.write((byte) (tl & 0xFF)); - - // Write the Token in bytes - bao.write(deviceTokenAsBytes); - - // Write the PayloadLength as a 16bits unsigned int, in big endian - int pl = payloadAsBytes.length; - int s1 = (pl & 0xFF00) >> 8; - int s2 = pl & 0xFF; - bao.write(s1); - bao.write(s2); - - // Finally write the Payload - bao.write(payloadAsBytes); - - logger.debug("Built raw message ID " + identifier); - - // Return the ByteArrayOutputStream as a Byte Array - return bao.toByteArray(); - } - - - /** - * Get the number of retry attempts - * @return int - */ - public int getRetryAttempts() { - return this.retryAttempts; - } - - - private static final byte[] intTo4ByteArray(int value) { - return ByteBuffer.allocate(4).putInt(value).array(); - } - - - /** - * Set the number of retry attempts - * @param retryAttempts - */ - public void setRetryAttempts(int retryAttempts) { - this.retryAttempts = retryAttempts; - } - - - /** - * Sets the DeviceFactory used by this PushNotificationManager. - * Usually useful for dependency injection. - * @param deviceFactory an object implementing DeviceFactory - */ - public void setDeviceFactory(DeviceFactory deviceFactory) { - this.deviceFactory = deviceFactory; - } - - - /** - * Returns the DeviceFactory used by this PushNotificationManager. - * @return the DeviceFactory in use - */ - public DeviceFactory getDeviceFactory() { - return deviceFactory; - } - - - public void setSslSocketTimeout(int sslSocketTimeout) { - this.sslSocketTimeout = sslSocketTimeout; - } - - - public int getSslSocketTimeout() { - return sslSocketTimeout; - } - - - public void setTrustAllServerCertificates(boolean trustAllServerCertificates) { - this.trustAllServerCertificates = trustAllServerCertificates; - } - - - public boolean isTrustAllServerCertificates() { - return trustAllServerCertificates; - } - - - /** - * Return a new sequential message identifier. - * - * @return a message identifier unique to this PushNotificationManager - */ - private int newMessageIdentifier() { - int id = nextMessageIdentifier; - nextMessageIdentifier++; - return id; - } - - - public Socket getActiveSocket() { - return socket; - } - - - public Map getPushedNotifications() { - return pushedNotifications; - } -} diff --git a/javapns/src/main/java/javapns/notification/PushNotificationPayload.java b/javapns/src/main/java/javapns/notification/PushNotificationPayload.java deleted file mode 100644 index 5fa1926b8..000000000 --- a/javapns/src/main/java/javapns/notification/PushNotificationPayload.java +++ /dev/null @@ -1,300 +0,0 @@ -package javapns.notification; - -import java.util.*; - -import javapns.notification.exceptions.*; - -import org.json.*; - -/** - * A payload compatible with the Apple Push Notification Service. - * - * @author Maxime Peron - * @author Sylvain Pedneault - */ -public class PushNotificationPayload extends Payload { - - /* Maximum total length (serialized) of a payload */ - private static final int MAXIMUM_PAYLOAD_LENGTH = 256; - - - /** - * Create a pre-defined payload with a simple alert message. - * - * @param message the alert's message - * @return a ready-to-send payload - */ - public static Payload alert(String message) { - PushNotificationPayload payload = complex(); - try { - payload.addAlert(message); - } catch (JSONException e) { - } - return payload; - } - - - /** - * Create a pre-defined payload with a badge. - * - * @param badge the badge - * @return a ready-to-send payload - */ - public static Payload badge(int badge) { - PushNotificationPayload payload = complex(); - try { - payload.addBadge(badge); - } catch (JSONException e) { - } - return payload; - } - - - /** - * Create a pre-defined payload with a sound name. - * - * @param sound the name of the sound - * @return a ready-to-send payload - */ - public static Payload sound(String sound) { - PushNotificationPayload payload = complex(); - try { - payload.addSound(sound); - } catch (JSONException e) { - } - return payload; - } - - - /** - * Create a pre-defined payload with a simple alert message, a badge and a sound. - * - * @param message the alert message - * @param badge the badge - * @param sound the name of the sound - * @return a ready-to-send payload - */ - public static Payload combined(String message, int badge, String sound) { - PushNotificationPayload payload = complex(); - try { - if (message != null) payload.addAlert(message); - if (badge >= 0) payload.addBadge(badge); - if (sound != null) payload.addSound(sound); - } catch (JSONException e) { - } - return payload; - } - - - /** - * Create an empty payload which you can configure later. - * This method is usually used to create complex or custom payloads. - * Note: the payload actually contains the default "aps" - * dictionary required by APNS. - * - * @return a blank payload that can be customized - */ - public static PushNotificationPayload complex() { - PushNotificationPayload payload = new PushNotificationPayload(); - return payload; - } - - /* The application Dictionnary */ - private JSONObject apsDictionary; - - - /** - * Create a default payload with a blank "aps" dictionary. - */ - public PushNotificationPayload() { - super(); - this.apsDictionary = new JSONObject(); - try { - JSONObject payload = getPayload(); - if (!payload.has("aps")) payload.put("aps", this.apsDictionary); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - - /** - * Create a payload and immediately add an alert message, a badge and a sound. - * - * @param alert the alert message - * @param badge the badge - * @param sound the name of the sound - * @throws JSONException - */ - public PushNotificationPayload(String alert, int badge, String sound) throws JSONException { - this(); - if (alert != null) addAlert(alert); - addBadge(badge); - if (sound != null) addSound(sound); - } - - - /** - * Add a badge. - * - * @param badge a badge number - * @throws JSONException - */ - public void addBadge(int badge) throws JSONException { - logger.debug("Adding badge [" + badge + "]"); - put("badge", badge, this.apsDictionary, true); - } - - - /** - * Add a sound. - * - * @param sound the name of a sound - * @throws JSONException - */ - public void addSound(String sound) throws JSONException { - logger.debug("Adding sound [" + sound + "]"); - put("sound", sound, this.apsDictionary, true); - } - - - /** - * Add a simple alert message. - * Note: you cannot add a simple and a custom alert in the same payload. - * - * @param alertMessage the alert's message - * @throws JSONException - */ - public void addAlert(String alertMessage) throws JSONException { - String previousAlert = getCompatibleProperty("alert", String.class, "A custom alert (\"%s\") was already added to this payload"); - logger.debug("Adding alert [" + alertMessage + "]" + (previousAlert != null ? " replacing previous alert [" + previousAlert + "]" : "")); - put("alert", alertMessage, this.apsDictionary, false); - } - - - /** - * Get the custom alert object, creating it if it does not yet exist. - * - * @return the JSON object defining the custom alert - * @throws JSONException if a simple alert has already been added to this payload - */ - private JSONObject getOrAddCustomAlert() throws JSONException { - JSONObject alert = getCompatibleProperty("alert", JSONObject.class, "A simple alert (\"%s\") was already added to this payload"); - if (alert == null) { - alert = new JSONObject(); - put("alert", alert, this.apsDictionary, false); - } - return alert; - } - - - /** - * Get the value of a given property, but only if it is of the expected class. - * If the value exists but is of a different class than expected, an - * exception is thrown. - * - * This method simply invokes the other getCompatibleProperty method with the root aps dictionary. - * - * - * @param the property value's class - * @param propertyName the name of the property to get - * @param expectedClass the property value's expected (required) class - * @param exceptionMessage the exception message to throw if the value is not of the expected class - * @return the property's value - * @throws JSONException - */ - private T getCompatibleProperty(String propertyName, Class expectedClass, String exceptionMessage) throws JSONException { - return getCompatibleProperty(propertyName, expectedClass, exceptionMessage, this.apsDictionary); - } - - - /** - * Get the value of a given property, but only if it is of the expected class. - * If the value exists but is of a different class than expected, an - * exception is thrown. - * - * This method is useful for properly supporting properties that can have a simple - * or complex value (such as "alert") - * - * @param the property value's class - * @param propertyName the name of the property to get - * @param expectedClass the property value's expected (required) class - * @param exceptionMessage the exception message to throw if the value is not of the expected class - * @param dictionary the dictionary where to get the property from - * @return the property's value - * @throws JSONException - */ - @SuppressWarnings("unchecked") - private T getCompatibleProperty(String propertyName, Class expectedClass, String exceptionMessage, JSONObject dictionary) throws JSONException { - Object propertyValue = null; - try { - propertyValue = dictionary.get(propertyName); - } catch (Exception e) { - } - if (propertyValue == null) return null; - if (propertyValue.getClass().equals(expectedClass)) return (T) propertyValue; - try { - exceptionMessage = String.format(exceptionMessage, propertyValue); - } catch (Exception e) { - } - throw new PayloadAlertAlreadyExistsException(exceptionMessage); - - } - - - /** - * Create a custom alert (if none exist) and add a body to the custom alert. - * - * @param body the body of the alert - * @throws JSONException if the custom alert cannot be added because a simple alert already exists - */ - public void addCustomAlertBody(String body) throws JSONException { - put("body", body, getOrAddCustomAlert(), false); - } - - - /** - * Create a custom alert (if none exist) and add a custom text for the right button of the popup. - * - * @param actionLocKey - * @throws JSONException if the custom alert cannot be added because a simple alert already exists - */ - public void addCustomAlertActionLocKey(String actionLocKey) throws JSONException { - put("action-loc-key", actionLocKey, getOrAddCustomAlert(), false); - } - - - /** - * Create a custom alert (if none exist) and add a loc-key parameter. - * - * @param locKey - * @throws JSONException if the custom alert cannot be added because a simple alert already exists - */ - public void addCustomAlertLocKey(String locKey) throws JSONException { - put("loc-key", locKey, getOrAddCustomAlert(), false); - } - - - /** - * Create a custom alert (if none exist) and add sub-parameters for the loc-key parameter. - * - * @param args - * @throws JSONException if the custom alert cannot be added because a simple alert already exists - */ - public void addCustomAlertLocArgs(List args) throws JSONException { - put("loc-args", args, getOrAddCustomAlert(), false); - } - - - /** - * Return the maximum payload size in bytes. - * For APNS payloads, this method returns 256. - * - * @return the maximum payload size in bytes (256) - */ - @Override - public int getMaximumPayloadSize() { - return MAXIMUM_PAYLOAD_LENGTH; - } - -} diff --git a/javapns/src/main/java/javapns/notification/PushedNotification.java b/javapns/src/main/java/javapns/notification/PushedNotification.java deleted file mode 100644 index 3ac4135d1..000000000 --- a/javapns/src/main/java/javapns/notification/PushedNotification.java +++ /dev/null @@ -1,265 +0,0 @@ -package javapns.notification; - -import java.util.*; - -import javapns.devices.*; - -/** - *

An object representing the result of a push notification to a specific payload to a single device.

- * - *

If Apple's Push Notification Service returned an error-response packet, it is linked to the related PushedNotification - * so you can find out what the actual error was.

- * - * @author Sylvain Pedneault - */ -public class PushedNotification { - - private Payload payload; - private Device device; - private ResponsePacket response; - - private int identifier; - private long expiry; - private int transmissionAttempts; - private boolean transmissionCompleted; - - private Exception exception; - - protected PushedNotification(Device device, Payload payload) { - this.device = device; - this.payload = payload; - } - - - protected PushedNotification(Device device, Payload payload, int identifier) { - this.device = device; - this.payload = payload; - this.identifier = identifier; - } - - - /** - * Returns the payload that was pushed. - * - * @return the payload that was pushed - */ - public Payload getPayload() { - return payload; - } - - - protected void setPayload(Payload payload) { - this.payload = payload; - } - - - /** - * Returns the device that the payload was pushed to. - * @return the device that the payload was pushed to - */ - public Device getDevice() { - return device; - } - - - protected void setDevice(Device device) { - this.device = device; - } - - - /** - * Returns the connection-unique identifier referred to by - * error-response packets. - * - * @return a connection-unique identifier - */ - public int getIdentifier() { - return identifier; - } - - - protected void setIdentifier(int identifier) { - this.identifier = identifier; - } - - - /** - * Returns the expiration date of the push notification. - * - * @return the expiration date of the push notification. - */ - public long getExpiry() { - return expiry; - } - - - protected void setExpiry(long expiry) { - this.expiry = expiry; - } - - - protected void setTransmissionAttempts(int transmissionAttempts) { - this.transmissionAttempts = transmissionAttempts; - } - - - protected void addTransmissionAttempt() { - transmissionAttempts++; - } - - - /** - * Returns the number of attempts that have been made to transmit the notification. - * @return a number of attempts - */ - public int getTransmissionAttempts() { - return transmissionAttempts; - } - - - /** - * Returns a human-friendly description of the number of attempts made to transmit the notification. - * @return a human-friendly description of the number of attempts made to transmit the notification - */ - public String getLatestTransmissionAttempt() { - if (transmissionAttempts == 0) return "no attempt yet"; - switch (transmissionAttempts) { - case 0: - return "no attempt yet"; - case 1: - return "first attempt"; - case 2: - return "second attempt"; - case 3: - return "third attempt"; - case 4: - return "fourth attempt"; - default: - return "attempt #" + transmissionAttempts; - } - } - - - protected void setTransmissionCompleted(boolean completed) { - this.transmissionCompleted = completed; - } - - - /** - * Indicates if the notification has been streamed successfully to Apple's server. - * This does not indicate if an error-response was received or not, but simply - * that the library successfully completed the transmission of the notification to - * Apple's server. - * @return true if the notification was successfully streamed to Apple, false otherwise - */ - public boolean isTransmissionCompleted() { - return transmissionCompleted; - } - - - protected void setResponse(ResponsePacket response) { - this.response = response; - } - - - /** - * If a response packet regarding this notification was received, - * this method returns it. Otherwise it returns null. - * - * @return a response packet, if one was received for this notification - */ - public ResponsePacket getResponse() { - return response; - } - - - /** - *

Returns true if no response packet was received for this notification, - * or if one was received but is not an error-response (ie command 8), - * or if one was received but its status is 0 (no error occurred).

- * - *

Returns false if an error-response packet is attached and has - * a non-zero status code.

- * - *

Make sure you use the Feedback Service to cleanup your list of - * invalid device tokens, as Apple's documentation says.

- * - * @return true if push was successful, false otherwise - */ - public boolean isSuccessful() { - if (!transmissionCompleted) return false; - if (response == null) return true; - if (response.getCommand() != 8) return true; - if (response.getStatus() == 0) return true; - return false; - } - - - /** - * Filters a list of pushed notifications and returns only the ones that were successful. - * - * @param notifications a list of pushed notifications - * @return a filtered list containing only notifications that were succcessful - */ - public static List findSuccessfulNotifications(List notifications) { - List filteredList = new Vector(); - for (PushedNotification notification : notifications) { - if (notification.isSuccessful()) filteredList.add(notification); - } - return filteredList; - } - - - /** - * Filters a list of pushed notifications and returns only the ones that failed. - * - * @param notifications a list of pushed notifications - * @return a filtered list containing only notifications that were not successful - */ - public static List findFailedNotifications(List notifications) { - List filteredList = new Vector(); - for (PushedNotification notification : notifications) { - if (!notification.isSuccessful()) { - filteredList.add(notification); - } - } - return filteredList; - } - - - /** - * Returns a human-friendly description of this pushed notification. - */ - @Override - public String toString() { - StringBuilder msg = new StringBuilder(); - msg.append("[" + identifier + "]"); - msg.append(transmissionCompleted ? " transmitted " + payload + " on " + getLatestTransmissionAttempt() : " not transmitted"); - msg.append(" to token " + device.getToken().substring(0, 5) + ".." + device.getToken().substring(59, 64)); - if (response != null) { - msg.append(" " + response.getMessage()); - } - return msg.toString(); - } - - - public void updateTo(PushedNotification repushedNotification) { - // this.setIdentifier(repushedNotification.getIdentifier()); - ResponsePacket newResponse = repushedNotification.getResponse(); - System.out.println(response + " >>> " + newResponse); - if (newResponse != null) this.setResponse(newResponse); - this.setTransmissionAttempts(repushedNotification.getTransmissionAttempts()); - this.setTransmissionCompleted(repushedNotification.isTransmissionCompleted()); - } - - - public void setException(Exception exception) { - this.exception = exception; - } - - - public Exception getException() { - return exception; - } - -} diff --git a/javapns/src/main/java/javapns/notification/ResponsePacket.java b/javapns/src/main/java/javapns/notification/ResponsePacket.java deleted file mode 100644 index c717ca846..000000000 --- a/javapns/src/main/java/javapns/notification/ResponsePacket.java +++ /dev/null @@ -1,106 +0,0 @@ -package javapns.notification; - -/** - * A response packet, as described in Apple's enhanced notification format. - * - * @author Sylvain Pedneault - */ -public class ResponsePacket { - - private int command; - private int status; - private int identifier; - - - protected ResponsePacket() { - } - - - protected ResponsePacket(int command, int status, int identifier) { - this.command = command; - this.status = status; - this.identifier = identifier; - } - - - protected void linkToPushedNotification(PushNotificationManager notificationManager) { - PushedNotification notification = null; - try { - notification = notificationManager.getPushedNotifications().get(identifier); - if (notification != null) { - notification.setResponse(this); - } - } catch (Exception e) { - } - } - - - /** - * Returns the response's command number. It should be 8 for all error responses. - * - * @return the response's command number (which should be 8) - */ - public int getCommand() { - return command; - } - - - protected void setCommand(int command) { - this.command = command; - } - - - /** - * Returns the response's status code (see getMessage() for a human-friendly status message instead). - * - * @return the response's status code - */ - public int getStatus() { - return status; - } - - - protected void setStatus(int status) { - this.status = status; - } - - - /** - * Returns the response's identifier, which matches the pushed notification's. - * - * @return the response's identifier - */ - public int getIdentifier() { - return identifier; - } - - - protected void setIdentifier(int identifier) { - this.identifier = identifier; - } - - - /** - * Returns a humand-friendly error message, as documented by Apple. - * - * @return a humand-friendly error message - */ - public String getMessage() { - if (command == 8) { - String prefix = "APNS: ["+identifier+"] "; //APNS ERROR FOR MESSAGE ID #" + identifier + ": "; - if (status == 0) return prefix + "No errors encountered"; - if (status == 1) return prefix + "Processing error"; - if (status == 2) return prefix + "Missing device token"; - if (status == 3) return prefix + "Missing topic"; - if (status == 4) return prefix + "Missing payload"; - if (status == 5) return prefix + "Invalid token size"; - if (status == 6) return prefix + "Invalid topic size"; - if (status == 7) return prefix + "Invalid payload size"; - if (status == 8) return prefix + "Invalid token"; - if (status == 255) return prefix + "None (unknown)"; - return prefix + "Undocumented status code: " + status; - } - return "APNS: Undocumented response command: " + command; - } - -} diff --git a/javapns/src/main/java/javapns/notification/ResponsePacketReader.java b/javapns/src/main/java/javapns/notification/ResponsePacketReader.java deleted file mode 100644 index 5af9ed617..000000000 --- a/javapns/src/main/java/javapns/notification/ResponsePacketReader.java +++ /dev/null @@ -1,116 +0,0 @@ -package javapns.notification; - -import java.io.*; -import java.net.*; -import java.util.*; - -/** - * Class for reading response packets from an APNS connection. - * See Apple's documentation on enhanced notification format. - * - * @author Sylvain Pedneault - */ -class ResponsePacketReader { - - /* The number of seconds to wait for a response */ - private static final int TIMEOUT = 5 * 1000; - - - /** - * Read response packets from the current APNS connection and process them. - * - * @param notificationManager - * @return the number of response packets received and processed - */ - public static int processResponses(PushNotificationManager notificationManager) { - List responses = readResponses(notificationManager.getActiveSocket()); - handleResponses(responses, notificationManager); - return responses.size(); - } - - - /** - * Read raw response packets from the provided socket. - * - * Note: this method automatically sets the socket's timeout - * to TIMEOUT, so not to block the socket's input stream. - * - * @param socket - * @return - */ - private static List readResponses(Socket socket) { - List responses = new Vector(); - int previousTimeout = 0; - try { - /* Set socket timeout to avoid getting stuck on read() */ - try { - previousTimeout = socket.getSoTimeout(); - socket.setSoTimeout(TIMEOUT); - } catch (Exception e) { - } - InputStream input = socket.getInputStream(); - while (true) { - ResponsePacket packet = readResponsePacketData(input); - if (packet != null) responses.add(packet); - else break; - } - - } catch (Exception e) { - /* Ignore exception, as we are expecting timeout exceptions because Apple might not reply anything */ - //System.out.println(e); - } - /* Reset socket timeout, just in case */ - try { - socket.setSoTimeout(previousTimeout); - } catch (Exception e) { - } - //System.out.println("Received "+responses.size()+" response packets"); - return responses; - } - - - private static void handleResponses(List responses, PushNotificationManager notificationManager) { - Map envelopes = notificationManager.getPushedNotifications(); - for (ResponsePacket response : responses) { - response.linkToPushedNotification(notificationManager); - handleResponse(response, notificationManager); - } - } - - - private static ResponsePacket readResponsePacketData(InputStream input) throws IOException { - int command = input.read(); - if (command < 0) return null; - int status = input.read(); - if (status < 0) return null; - - int identifier_byte1 = input.read(); - if (identifier_byte1 < 0) return null; - int identifier_byte2 = input.read(); - if (identifier_byte2 < 0) return null; - int identifier_byte3 = input.read(); - if (identifier_byte3 < 0) return null; - int identifier_byte4 = input.read(); - if (identifier_byte4 < 0) return null; - int identifier = (identifier_byte1 << 24) + (identifier_byte2 << 16) + (identifier_byte3 << 8) + (identifier_byte4); - return new ResponsePacket(command, status, identifier); - } - - - @Deprecated - private static void handleResponse(ResponsePacket response, PushNotificationManager notificationManager) { - //System.out.println("Received response packet: " + response.getMessage()); - if (response.getCommand() == 8) handleErrorResponse(response, notificationManager); - } - - - @Deprecated - private static void handleErrorResponse(ResponsePacket response, PushNotificationManager notificationManager) { - //System.out.println("Received error-response packet: " + response.getMessage()); - // ErrorResponseListener listener = notificationManager.getErrorResponseListener(); - // if (listener != null) { - // listener.handleError(response, notificationManager); - // } - } - -} diff --git a/javapns/src/main/java/javapns/notification/exceptions/PayloadAlertAlreadyExistsException.java b/javapns/src/main/java/javapns/notification/exceptions/PayloadAlertAlreadyExistsException.java deleted file mode 100644 index 1249b8633..000000000 --- a/javapns/src/main/java/javapns/notification/exceptions/PayloadAlertAlreadyExistsException.java +++ /dev/null @@ -1,29 +0,0 @@ -package javapns.notification.exceptions; - -import org.json.*; - -/** - * Thrown when a payload exceeds the maximum size allowed. - * @author Sylvain Pedneault - * - */ -@SuppressWarnings("serial") -public class PayloadAlertAlreadyExistsException extends JSONException { - - /** - * Default constructor - */ - public PayloadAlertAlreadyExistsException() { - super("Payload alert already exists"); - } - - - /** - * Constructor with custom message - * @param message - */ - public PayloadAlertAlreadyExistsException(String message) { - super(message); - } - -} diff --git a/javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeExceededException.java b/javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeExceededException.java deleted file mode 100644 index 486d2f792..000000000 --- a/javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeExceededException.java +++ /dev/null @@ -1,37 +0,0 @@ -package javapns.notification.exceptions; - -/** - * Thrown when a payload exceeds the maximum size allowed. - * @author Sylvain Pedneault - * - */ -@SuppressWarnings("serial") -public class PayloadMaxSizeExceededException extends Exception { - - /** - * Default constructor - */ - public PayloadMaxSizeExceededException() { - super("Total payload size exceeds allowed limit"); - } - - - public PayloadMaxSizeExceededException(int maxSize) { - super(String.format("Total payload size exceeds allowed limit (%s bytes max)", maxSize)); - } - - - public PayloadMaxSizeExceededException(int maxSize, int currentSize) { - super(String.format("Total payload size exceeds allowed limit (payload is %s bytes, limit is %s)", currentSize, maxSize)); - } - - - /** - * Constructor with custom message - * @param message - */ - public PayloadMaxSizeExceededException(String message) { - super(message); - } - -} diff --git a/javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeProbablyExceededException.java b/javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeProbablyExceededException.java deleted file mode 100644 index 1ec6ca577..000000000 --- a/javapns/src/main/java/javapns/notification/exceptions/PayloadMaxSizeProbablyExceededException.java +++ /dev/null @@ -1,40 +0,0 @@ -package javapns.notification.exceptions; - -import org.json.*; - -/** - * Thrown when a payload is expected to exceed the maximum size allowed after adding a given property. - * Invoke payload.setPayloadSizeEstimatedWhenAdding(false) to disable this automatic checking. - * - * @author Sylvain Pedneault - */ -@SuppressWarnings("serial") -public class PayloadMaxSizeProbablyExceededException extends JSONException { - - /** - * Default constructor - */ - public PayloadMaxSizeProbablyExceededException() { - super("Total payload size will most likely exceed allowed limit"); - } - - - public PayloadMaxSizeProbablyExceededException(int maxSize) { - super(String.format("Total payload size will most likely exceed allowed limit (%s bytes max)", maxSize)); - } - - - public PayloadMaxSizeProbablyExceededException(int maxSize, int estimatedSize) { - super(String.format("Total payload size will most likely exceed allowed limit (estimated to become %s bytes, limit is %s)", estimatedSize, maxSize)); - } - - - /** - * Constructor with custom message - * @param message - */ - public PayloadMaxSizeProbablyExceededException(String message) { - super(message); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/APNPayload.java b/javapns/src/main/java/javapns/notification/management/APNPayload.java deleted file mode 100644 index 61388a6a2..000000000 --- a/javapns/src/main/java/javapns/notification/management/APNPayload.java +++ /dev/null @@ -1,40 +0,0 @@ -package javapns.notification.management; - -import java.util.*; - -import org.json.*; - -/** - * An MDM payload for APN (Access Point Name). - * - * @author Sylvain Pedneault - */ -public class APNPayload extends MobileConfigPayload { - - public APNPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, Map defaultsData, String defaultsDomainName, Map[] apns, String apn, String username) throws JSONException { - super(payloadVersion, "com.apple.apn.managed", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("DefaultsData", defaultsData); - payload.put("defaultsDomainName", defaultsDomainName); - for (Map apnsEntry : apns) - payload.put("apns", apnsEntry); - payload.put("apn", apn); - payload.put("username", username); - } - - - public void setPassword(APNPayload value) throws JSONException { - getPayload().put("password", value); - } - - - public void setProxy(String value) throws JSONException { - getPayload().put("proxy", value); - } - - - public void setProxyPort(int value) throws JSONException { - getPayload().put("proxyPort", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/CalDAVPayload.java b/javapns/src/main/java/javapns/notification/management/CalDAVPayload.java deleted file mode 100644 index 8d6e90fd8..000000000 --- a/javapns/src/main/java/javapns/notification/management/CalDAVPayload.java +++ /dev/null @@ -1,40 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for CalDAV. - * - * @author Sylvain Pedneault - */ -public class CalDAVPayload extends MobileConfigPayload { - - public CalDAVPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String calDAVHostName, String calDAVUsername, boolean calDAVUseSSL) throws JSONException { - super(payloadVersion, "com.apple.caldav.account", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("CalDAVHostName", calDAVHostName); - payload.put("CalDAVUsername", calDAVUsername); - payload.put("CalDAVUseSSL", calDAVUseSSL); - } - - - public void setCalDAVAccountDescription(String value) throws JSONException { - getPayload().put("CalDAVAccountDescription", value); - } - - - public void setCalDAVPassword(String value) throws JSONException { - getPayload().put("CalDAVPassword", value); - } - - - public void setCalDAVPort(int value) throws JSONException { - getPayload().put("CalDAVPort", value); - } - - - public void setCalDAVPrincipalURL(String value) throws JSONException { - getPayload().put("CalDAVPrincipalURL", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/CalendarSubscriptionPayload.java b/javapns/src/main/java/javapns/notification/management/CalendarSubscriptionPayload.java deleted file mode 100644 index db91a801a..000000000 --- a/javapns/src/main/java/javapns/notification/management/CalendarSubscriptionPayload.java +++ /dev/null @@ -1,39 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for CalendarSubscription. - * - * @author Sylvain Pedneault - */ -public class CalendarSubscriptionPayload extends MobileConfigPayload { - - public CalendarSubscriptionPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String subCalAccountHostName, boolean subCalAccountUseSSL) throws JSONException { - super(payloadVersion, "com.apple.caldav.account", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("SubCalAccountHostName", subCalAccountHostName); - payload.put("SubCalAccountUseSSL", subCalAccountUseSSL); - } - - - public void setSubCalAccountDescription(String value) throws JSONException { - getPayload().put("SubCalAccountDescription", value); - } - - - public void setSubCalAccountUsername(String value) throws JSONException { - getPayload().put("SubCalAccountUsername", value); - } - - - public void setSubCalAccountPassword(String value) throws JSONException { - getPayload().put("SubCalAccountPassword", value); - } - - - public void setSubCalAccountUseSSL(boolean value) throws JSONException { - getPayload().put("SubCalAccountUseSSL", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/EmailPayload.java b/javapns/src/main/java/javapns/notification/management/EmailPayload.java deleted file mode 100644 index d0fd2d593..000000000 --- a/javapns/src/main/java/javapns/notification/management/EmailPayload.java +++ /dev/null @@ -1,70 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for Email. - * - * @author Sylvain Pedneault - */ -public class EmailPayload extends MobileConfigPayload { - - public EmailPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String emailAccountType, String emailAddress, String incomingMailServerAuthentication, String incomingMailServerHostName, String incomingMailServerUsername, String outgoingMailServerAuthentication, String outgoingMailServerHostName, String outgoingMailServerUsername) throws JSONException { - super(payloadVersion, "com.apple.mail.managed", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("EmailAccountType", emailAccountType); - payload.put("EmailAddress", emailAddress); - payload.put("IncomingMailServerAuthentication", incomingMailServerAuthentication); - payload.put("IncomingMailServerHostName", incomingMailServerHostName); - payload.put("IncomingMailServerUsername", incomingMailServerUsername); - payload.put("OutgoingMailServerAuthentication", outgoingMailServerAuthentication); - payload.put("OutgoingMailServerHostName", outgoingMailServerHostName); - payload.put("OutgoingMailServerUsername", outgoingMailServerUsername); - } - - - public void setEmailAccountDescription(String value) throws JSONException { - getPayload().put("EmailAccountDescription", value); - } - - - public void setEmailAccountName(String value) throws JSONException { - getPayload().put("EmailAccountName", value); - } - - - public void setIncomingMailServerPortNumber(int value) throws JSONException { - getPayload().put("IncomingMailServerPortNumber", value); - } - - - public void setIncomingMailServerUseSSL(boolean value) throws JSONException { - getPayload().put("IncomingMailServerUseSSL", value); - } - - - public void setIncomingPassword(String value) throws JSONException { - getPayload().put("IncomingPassword", value); - } - - - public void setOutgoingPassword(String value) throws JSONException { - getPayload().put("OutgoingPassword", value); - } - - - public void setOutgoingPasswwordSameAsIncomingPassword(boolean value) throws JSONException { - getPayload().put("OutgoingPasswwordSameAsIncomingPassword", value); - } - - - public void setOutgoingMailServerPortNumber(int value) throws JSONException { - getPayload().put("OutgoingMailServerPortNumber", value); - } - - - public void setOutgoingMailServerUseSSL(boolean value) throws JSONException { - getPayload().put("OutgoingMailServerUseSSL", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/LDAPPayload.java b/javapns/src/main/java/javapns/notification/management/LDAPPayload.java deleted file mode 100644 index 651f1a5b8..000000000 --- a/javapns/src/main/java/javapns/notification/management/LDAPPayload.java +++ /dev/null @@ -1,60 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for LDAP. - * - * @author Sylvain Pedneault - */ -public class LDAPPayload extends MobileConfigPayload { - - public LDAPPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String ldapAccountHostName, boolean ldapAccountUseSSL) throws JSONException { - super(payloadVersion, "com.apple.webClip.managed", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("LDAPAccountHostName", ldapAccountHostName); - payload.put("LDAPAccountUseSSL", ldapAccountUseSSL); - } - - - public void setLDAPAccountDescription(boolean value) throws JSONException { - getPayload().put("LDAPAccountDescription", value); - } - - - public void setLDAPAccountUserName(boolean value) throws JSONException { - getPayload().put("LDAPAccountUserName", value); - } - - - public void setLDAPAccountPassword(boolean value) throws JSONException { - getPayload().put("LDAPAccountPassword", value); - } - - - public JSONObject addSearchSettings(String ldapSearchSettingSearchBase, String ldapSearchSettingScope) throws JSONException { - return addSearchSettings(ldapSearchSettingSearchBase, ldapSearchSettingScope, null); - } - - - public JSONObject addSearchSettings(String ldapSearchSettingSearchBase, int ldapSearchSettingScope) throws JSONException { - return addSearchSettings(ldapSearchSettingSearchBase, ldapSearchSettingScope, null); - } - - - public JSONObject addSearchSettings(String ldapSearchSettingSearchBase, int ldapSearchSettingScope, String ldapSearchSettingDescription) throws JSONException { - return addSearchSettings(ldapSearchSettingSearchBase, ldapSearchSettingScope == 0 ? "LDAPSearchSettingScopeBase" : ldapSearchSettingScope == 1 ? "LDAPSearchSettingScopeBase" : "LDAPSearchSettingScopeSubtree", ldapSearchSettingDescription); - } - - - public JSONObject addSearchSettings(String ldapSearchSettingSearchBase, String ldapSearchSettingScope, String ldapSearchSettingDescription) throws JSONException { - JSONObject payload = getPayload(); - JSONObject searchSettings = new JSONObject(); - payload.put("LDAPSearchSettings", searchSettings); - searchSettings.put("LDAPSearchSettingSearchBase", ldapSearchSettingSearchBase); - searchSettings.put("LDAPSearchSettingScope", ldapSearchSettingScope); - if (ldapSearchSettingDescription != null) searchSettings.put("LDAPSearchSettingDescription", ldapSearchSettingDescription); - return searchSettings; - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/MobileConfigPayload.java b/javapns/src/main/java/javapns/notification/management/MobileConfigPayload.java deleted file mode 100644 index 1dcb40b0d..000000000 --- a/javapns/src/main/java/javapns/notification/management/MobileConfigPayload.java +++ /dev/null @@ -1,48 +0,0 @@ -package javapns.notification.management; - -import javapns.notification.*; - -import org.json.*; - -/** - * A payload template compatible with Apple Mobile Device Management's Config Payload specification (beta version). - * - * @author Sylvain Pedneault - */ -public abstract class MobileConfigPayload extends Payload { - - private static long serialuuid = 10000000; - - - private static String generateUUID() { - return System.nanoTime() + "." + (++serialuuid); - } - - - public MobileConfigPayload(int payloadVersion, String payloadType, String payloadOrganization, String payloadIdentifier, String payloadDisplayName) throws JSONException { - this(payloadVersion, generateUUID(), payloadType, payloadOrganization, payloadIdentifier, payloadDisplayName); - } - - - public MobileConfigPayload(int payloadVersion, String payloadUUID, String payloadType, String payloadOrganization, String payloadIdentifier, String payloadDisplayName) throws JSONException { - super(); - JSONObject payload = getPayload(); - payload.put("PayloadVersion", payloadVersion); - payload.put("PayloadUUID", payloadUUID); - payload.put("PayloadType", payloadType); - payload.put("PayloadOrganization", payloadOrganization); - payload.put("PayloadIdentifier", payloadIdentifier); - payload.put("PayloadDisplayName", payloadDisplayName); - } - - - public void setPayloadDescription(String description) throws JSONException { - getPayload().put("PayloadDescription", description); - } - - - public void setPayloadRemovalDisallowed(boolean disallowed) throws JSONException { - getPayload().put("PayloadRemovalDisallowed", disallowed); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/PasswordPolicyPayload.java b/javapns/src/main/java/javapns/notification/management/PasswordPolicyPayload.java deleted file mode 100644 index 0f755be14..000000000 --- a/javapns/src/main/java/javapns/notification/management/PasswordPolicyPayload.java +++ /dev/null @@ -1,71 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for PasswordPolicy. - * - * @author Sylvain Pedneault - */ -public class PasswordPolicyPayload extends MobileConfigPayload { - - public PasswordPolicyPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName) throws JSONException { - super(payloadVersion, "com.apple.mobiledevice.passwordpolicy", payloadOrganization, payloadIdentifier, payloadDisplayName); - } - - - public void setAllowSimple(boolean value) throws JSONException { - getPayload().put("allowSimple", value); - } - - - public void setForcePIN(boolean value) throws JSONException { - getPayload().put("forcePIN", value); - } - - - public void setMaxFailedAttempts(int value) throws JSONException { - getPayload().put("maxFailedAttempts", value); - } - - - public void setMaxInactivity(int value) throws JSONException { - getPayload().put("maxInactivity", value); - } - - - public void setMaxPINAgeInDays(int value) throws JSONException { - getPayload().put("maxPINAgeInDays", value); - } - - - public void setMinComplexChars(int value) throws JSONException { - getPayload().put("minComplexChars", value); - } - - - public void setMinLength(int value) throws JSONException { - getPayload().put("minLength", value); - } - - - public void setRequireAlphanumeric(boolean value) throws JSONException { - getPayload().put("requireAlphanumeric", value); - } - - - public void setPinHistory(int value) throws JSONException { - getPayload().put("pinHistory", value); - } - - - public void setManualFetchingWhenRoaming(boolean value) throws JSONException { - getPayload().put("manualFetchingWhenRoaming", value); - } - - - public void setMaxGracePeriod(int value) throws JSONException { - getPayload().put("maxGracePeriod", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/RemovalPasswordPayload.java b/javapns/src/main/java/javapns/notification/management/RemovalPasswordPayload.java deleted file mode 100644 index 9fc987a94..000000000 --- a/javapns/src/main/java/javapns/notification/management/RemovalPasswordPayload.java +++ /dev/null @@ -1,21 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for RemovalPassword. - * - * @author Sylvain Pedneault - */ -public class RemovalPasswordPayload extends MobileConfigPayload { - - public RemovalPasswordPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName) throws JSONException { - super(payloadVersion, "com.apple.profileRemovalPassword", payloadOrganization, payloadIdentifier, payloadDisplayName); - } - - - public void setRemovalPasword(String value) throws JSONException { - getPayload().put("RemovalPassword", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/RestrictionsPayload.java b/javapns/src/main/java/javapns/notification/management/RestrictionsPayload.java deleted file mode 100644 index 4e187b24b..000000000 --- a/javapns/src/main/java/javapns/notification/management/RestrictionsPayload.java +++ /dev/null @@ -1,51 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for Restrictions. - * - * @author Sylvain Pedneault - */ -public class RestrictionsPayload extends MobileConfigPayload { - - public RestrictionsPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName) throws JSONException { - super(payloadVersion, "com.apple.applicationaccess", payloadOrganization, payloadIdentifier, payloadDisplayName); - } - - - public void setAllowAppInstallation(boolean value) throws JSONException { - getPayload().put("allowAppInstallation", value); - } - - - public void setAllowCamera(boolean value) throws JSONException { - getPayload().put("allowCamera", value); - } - - - public void setAllowExplicitContent(boolean value) throws JSONException { - getPayload().put("allowExplicitContent", value); - } - - - public void setAllowScreenShot(boolean value) throws JSONException { - getPayload().put("allowScreenShot", value); - } - - - public void setAllowYouTube(boolean value) throws JSONException { - getPayload().put("allowYouTube", value); - } - - - public void setAllowiTunes(boolean value) throws JSONException { - getPayload().put("allowAppInstallation", value); - } - - - public void setAllowSafari(boolean value) throws JSONException { - getPayload().put("allowSafari", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/SCEPPayload.java b/javapns/src/main/java/javapns/notification/management/SCEPPayload.java deleted file mode 100644 index 32b9b1a3b..000000000 --- a/javapns/src/main/java/javapns/notification/management/SCEPPayload.java +++ /dev/null @@ -1,76 +0,0 @@ -package javapns.notification.management; - -import java.util.*; - -import org.json.*; - -/** - * An MDM payload for SCEP (Simple Certificate Enrollment Protocol). - * - * @author Sylvain Pedneault - */ -public class SCEPPayload extends MobileConfigPayload { - - public SCEPPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String url) throws JSONException { - super(payloadVersion, "com.apple.encrypted-profile-service", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("URL", url); - } - - - public void setName(String value) throws JSONException { - getPayload().put("Name", value); - } - - - public void setSubject(String value) throws JSONException { - String[] parts = value.split("/"); - List list = new ArrayList(); - for (String part : parts) { - String[] subparts = value.split("="); - list.add(subparts); - } - String[][] subject = list.toArray(new String[0][0]); - setSubject(subject); - } - - - public void setSubject(String[][] value) throws JSONException { - getPayload().put("Subject", value); - } - - - public void setChallenge(String value) throws JSONException { - getPayload().put("Challenge", value); - } - - - public void setKeysize(int value) throws JSONException { - getPayload().put("Keysize", value); - } - - - public void setKeyType(String value) throws JSONException { - getPayload().put("Key Type", value); - } - - - public void setKeyUsage(int value) throws JSONException { - getPayload().put("Key Usage", value); - } - - - public JSONObject addSubjectAltName() throws JSONException { - JSONObject object = new JSONObject(); - getPayload().put("SubjectAltName", object); - return object; - } - - - public JSONObject addGetCACaps() throws JSONException { - JSONObject object = new JSONObject(); - getPayload().put("GetCACaps", object); - return object; - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/VPNPayload.java b/javapns/src/main/java/javapns/notification/management/VPNPayload.java deleted file mode 100644 index f9535ba1e..000000000 --- a/javapns/src/main/java/javapns/notification/management/VPNPayload.java +++ /dev/null @@ -1,39 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for VPN. - * - * @author Sylvain Pedneault - */ -public class VPNPayload extends MobileConfigPayload { - - public static final String VPNTYPE_L2TP = "L2TP"; - public static final String VPNTYPE_PPTP = "PPTP"; - public static final String VPNTYPE_IPSec = "IPSec"; - - - public VPNPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String userDefinedName, boolean overridePrimary, String vpnType) throws JSONException { - super(payloadVersion, "com.apple.vpn.managed", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("UserDefinedName", userDefinedName); - payload.put("OverridePrimary", overridePrimary); - payload.put("VPNType", vpnType); - } - - - public JSONObject addPPP() throws JSONException { - JSONObject object = new JSONObject(); - getPayload().put("PPP", object); - return object; - } - - - public JSONObject addIPSec() throws JSONException { - JSONObject object = new JSONObject(); - getPayload().put("IPSec", object); - return object; - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/WebClipPayload.java b/javapns/src/main/java/javapns/notification/management/WebClipPayload.java deleted file mode 100644 index 4b191db79..000000000 --- a/javapns/src/main/java/javapns/notification/management/WebClipPayload.java +++ /dev/null @@ -1,29 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for WebClip. - * - * @author Sylvain Pedneault - */ -public class WebClipPayload extends MobileConfigPayload { - - public WebClipPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String url, String label) throws JSONException { - super(payloadVersion, "com.apple.webClip.managed", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("URL", url); - payload.put("Label", label); - } - - - public void setIcon(Object data) throws JSONException { - getPayload().put("Icon", data); - } - - - public void setIsRemovable(boolean value) throws JSONException { - getPayload().put("IsRemovable", value); - } - -} diff --git a/javapns/src/main/java/javapns/notification/management/WiFiPayload.java b/javapns/src/main/java/javapns/notification/management/WiFiPayload.java deleted file mode 100644 index 038683363..000000000 --- a/javapns/src/main/java/javapns/notification/management/WiFiPayload.java +++ /dev/null @@ -1,32 +0,0 @@ -package javapns.notification.management; - -import org.json.*; - -/** - * An MDM payload for Wi-Fi. - * - * @author Sylvain Pedneault - */ -public class WiFiPayload extends MobileConfigPayload { - - public WiFiPayload(int payloadVersion, String payloadOrganization, String payloadIdentifier, String payloadDisplayName, String SSID_STR, boolean hiddenNetwork, String encryptionType) throws JSONException { - super(payloadVersion, "com.apple.wifi.managed", payloadOrganization, payloadIdentifier, payloadDisplayName); - JSONObject payload = getPayload(); - payload.put("SSID_STR", SSID_STR); - payload.put("HIDDEN_NETWORK", hiddenNetwork); - payload.put("EncryptionType", encryptionType); - } - - - public void setPassword(String value) throws JSONException { - getPayload().put("Password", value); - } - - - public JSONObject addEAPClientConfiguration() throws JSONException { - JSONObject object = new JSONObject(); - getPayload().put("EAPClientConfiguration", object); - return object; - } - -} diff --git a/javapns/src/main/java/javapns/notification/transmission/NotificationProgressListener.java b/javapns/src/main/java/javapns/notification/transmission/NotificationProgressListener.java deleted file mode 100644 index 30ea436dd..000000000 --- a/javapns/src/main/java/javapns/notification/transmission/NotificationProgressListener.java +++ /dev/null @@ -1,24 +0,0 @@ -package javapns.notification.transmission; - -/** - *

An event listener for monitoring progress of NotificationThreads

- * - * @author Sylvain Pedneault - */ -public interface NotificationProgressListener { - - public void eventAllThreadsStarted(NotificationThreads notificationThreads); - - - public void eventThreadStarted(NotificationThread notificationThread); - - - public void eventThreadFinished(NotificationThread notificationThread); - - - public void eventConnectionRestarted(NotificationThread notificationThread); - - - public void eventAllThreadsFinished(NotificationThreads notificationThreads); - -} diff --git a/javapns/src/main/java/javapns/notification/transmission/NotificationThread.java b/javapns/src/main/java/javapns/notification/transmission/NotificationThread.java deleted file mode 100644 index ceda2efa6..000000000 --- a/javapns/src/main/java/javapns/notification/transmission/NotificationThread.java +++ /dev/null @@ -1,277 +0,0 @@ -package javapns.notification.transmission; - -import java.util.*; - -import javapns.devices.*; -import javapns.notification.*; - -/** - *

Pushes a payload to a large number of devices in a single separate thread

- * - *

No more than {@code maxNotificationsPerConnection} are pushed over a single connection. - * When that maximum is reached, the connection is restarted automatically and push continues. - * This is intended to avoid an undocumented notification-per-connection limit observed - * occasionnally with Apple servers.

- * - *

Usage: once a NotificationThread is created, invoke {@code start()} to push the payload to all devices in a separate thread.

- * - *

To run this code unthreaded, invoke {@code run()} directly (rarely used).

- * - * @author Sylvain Pedneault - */ -public class NotificationThread extends Thread { - - private static final int DEFAULT_MAXNOTIFICATIONSPERCONNECTION = 200; - - private PushNotificationManager notificationManager; - private AppleNotificationServer server; - private Payload payload; - private List devices; - private int maxNotificationsPerConnection = DEFAULT_MAXNOTIFICATIONSPERCONNECTION; - private long sleepBetweenNotifications = 0; - private NotificationProgressListener listener; - private int threadNumber = 1; - private int nextMessageIdentifier = 1; - private List notifications = new Vector(); - - - /** - * Create a grouped thread for pushing notifications to a list of devices - * and coordinating with a parent NotificationThreads object. - * - * @param threads - * @param notificationManager - * @param server - * @param payload - * @param devices - */ - public NotificationThread(NotificationThreads threads, PushNotificationManager notificationManager, AppleNotificationServer server, Payload payload, List devices) { - super(threads, "javapns notification thread (" + devices.size() + ")"); - this.notificationManager = notificationManager == null ? new PushNotificationManager() : notificationManager; - this.server = server; - this.payload = payload; - this.devices = devices; - } - - - /** - * Create a grouped thread for pushing notifications to an array of devices - * and coordinating with a parent NotificationThreads object. - * - * @param threads - * @param notificationManager - * @param server - * @param payload - * @param devices - */ - public NotificationThread(NotificationThreads threads, PushNotificationManager notificationManager, AppleNotificationServer server, Payload payload, Device... devices) { - this(threads, notificationManager, server, payload, Arrays.asList(devices)); - } - - - /** - * Create a standalone thread for pushing notifications to a list of devices. - * - * @param notificationManager - * @param server - * @param payload - * @param devices - */ - public NotificationThread(PushNotificationManager notificationManager, AppleNotificationServer server, Payload payload, List devices) { - this(null, notificationManager, server, payload, devices); - } - - - /** - * Create a standalone thread for pushing notifications to an array of devices. - * - * @param notificationManager - * @param server - * @param payload - * @param devices - */ - public NotificationThread(PushNotificationManager notificationManager, AppleNotificationServer server, Payload payload, Device... devices) { - this(notificationManager, server, payload, Arrays.asList(devices)); - } - - - public void run() { - int total = devices.size(); - if (listener != null) listener.eventThreadStarted(this); - try { - notificationManager.initializeConnection(server); - for (int i = 0; i < total; i++) { - Device device = devices.get(i); - int message = newMessageIdentifier(); - PushedNotification notification = notificationManager.sendNotification(device, payload, false, message); - notifications.add(notification); - if (sleepBetweenNotifications > 0) sleep(sleepBetweenNotifications); - if (i != 0 && i % maxNotificationsPerConnection == 0) { - if (listener != null) listener.eventConnectionRestarted(this); - notificationManager.restartConnection(server); - } - } - notificationManager.stopConnection(); - } catch (Exception e) { - e.printStackTrace(); - } - if (listener != null) listener.eventThreadFinished(this); - /* Also notify the parent NotificationThreads, so that it can determine when all threads have finished working */ - if (getThreadGroup() instanceof NotificationThreads) ((NotificationThreads) getThreadGroup()).threadFinished(this); - } - - - /** - * Set a maximum number of notifications that should be streamed over a continuous connection - * to an Apple server. When that maximum is reached, the thread automatically closes and - * reopens a fresh new connection to the server and continues streaming notifications. - * - * Default is 200 (recommended). - * - * @param maxNotificationsPerConnection - */ - public void setMaxNotificationsPerConnection(int maxNotificationsPerConnection) { - this.maxNotificationsPerConnection = maxNotificationsPerConnection; - } - - - public int getMaxNotificationsPerConnection() { - return maxNotificationsPerConnection; - } - - - /** - * Set a delay the thread should sleep between each notification. - * This is sometimes useful when communication with Apple servers is - * unreliable and notifications are streaming too fast. - * - * Default is 0. - * - * @param milliseconds - */ - public void setSleepBetweenNotifications(long milliseconds) { - this.sleepBetweenNotifications = milliseconds; - } - - - public long getSleepBetweenNotifications() { - return sleepBetweenNotifications; - } - - - public void setDevices(List devices) { - this.devices = devices; - } - - - public List getDevices() { - return devices; - } - - - /** - * Get the number of devices that this thread pushes to. - * - * @return the number of devices registered with this thread - */ - public int size() { - return devices.size(); - } - - - /** - * Provide an event listener which will be notified of this thread's progress. - * - * @param listener any object implementing the NotificationProgressListener interface - */ - public void setListener(NotificationProgressListener listener) { - this.listener = listener; - } - - - public NotificationProgressListener getListener() { - return listener; - } - - - /** - * Set the thread number so that generated message identifiers can be made - * unique across all threads. - * - * @param threadNumber - */ - protected void setThreadNumber(int threadNumber) { - this.threadNumber = threadNumber; - } - - - /** - * Return the thread number assigned by the parent NotificationThreads object, if any. - * - * @return the unique number assigned to this thread by the parent group - */ - public int getThreadNumber() { - return threadNumber; - } - - - /** - * Return a new sequential message identifier. - * - * @return a message identifier unique to all NotificationThread objects - */ - public int newMessageIdentifier() { - return (threadNumber << 24) | nextMessageIdentifier++; - } - - - /** - * Returns the first message identifier generated by this thread. - * - * @return a message identifier unique to all NotificationThread objects - */ - public int getFirstMessageIdentifier() { - return (threadNumber << 24) | 1; - } - - - /** - * Returns the last message identifier generated by this thread. - * - * @return a message identifier unique to all NotificationThread objects - */ - public int getLastMessageIdentifier() { - return (threadNumber << 24) | devices.size(); - } - - - /** - * Returns list of all notifications pushed by this thread (successful or not). - * - * @return a list of pushed notifications - */ - public List getPushedNotifications() { - return notifications; - } - - - /** - * Returns list of all notifications that this thread attempted to push but that failed. - * - * @return a list of failed notifications - */ - public List getFailedNotifications() { - return PushedNotification.findFailedNotifications(getPushedNotifications()); - } - - - /** - * Returns list of all notifications that this thread attempted to push and succeeded. - * - * @return a list of failed notifications - */ - public List getSuccessfulNotifications() { - return PushedNotification.findSuccessfulNotifications(getPushedNotifications()); - } - -} diff --git a/javapns/src/main/java/javapns/notification/transmission/NotificationThreads.java b/javapns/src/main/java/javapns/notification/transmission/NotificationThreads.java deleted file mode 100644 index 608477e6a..000000000 --- a/javapns/src/main/java/javapns/notification/transmission/NotificationThreads.java +++ /dev/null @@ -1,315 +0,0 @@ -package javapns.notification.transmission; - -import java.util.*; - -import javapns.devices.*; -import javapns.notification.*; - -/** - *

Pushes a payload to a large number of devices using multiple threads

- * - *

The list of devices is spread evenly into multiple {@link javapns.notification.transmission.NotificationThread}s.

- * - *

Usage: once a NotificationThreads is created, invoke {@code start()} to start all {@link javapns.notification.transmission.NotificationThread} threads.

- *

You can provide a {@link javapns.notification.transmission.NotificationProgressListener} to receive events about the work being done.

- - * @author Sylvain Pedneault - */ -public class NotificationThreads extends ThreadGroup { - - private List threads = new Vector(); - private NotificationProgressListener listener; - private int threadsRunning = 0; - private Object finishPoint = new Object(); - - - /** - * Create the specified number of notification threads and spread the devices evenly between the threads. - * - * @param server the server to push to - * @param payload the payload to push - * @param devices a very large list of devices - * @param numberOfThreads the number of threads to create to share the work - */ - public NotificationThreads(AppleNotificationServer server, Payload payload, List devices, int numberOfThreads) { - super("javapns notification threads (" + numberOfThreads + " threads)"); - for (List deviceGroup : groupDevices(devices, numberOfThreads)) - threads.add(new NotificationThread(this, new PushNotificationManager(), server, payload, deviceGroup)); - } - - - /** - * Create the specified number of notification threads and spread the devices evenly between the threads. - * Internally, this constructor uses a AppleNotificationServerBasicImpl to encapsulate the provided keystore, password and production parameters. - * - * @param keystore the keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password the keystore's password - * @param production true to use Apple's production servers, false to use the sandbox - * @param payload the payload to push - * @param devices a very large list of devices - * @param numberOfThreads the number of threads to create to share the work - * @throws Exception - */ - public NotificationThreads(Object keystore, String password, boolean production, Payload payload, List devices, int numberOfThreads) throws Exception { - this(new AppleNotificationServerBasicImpl(keystore, password, production), payload, devices, numberOfThreads); - } - - - /** - * Spread the devices evenly between the provided threads. - * - * @param server the server to push to - * @param payload the payload to push - * @param devices a very large list of devices - * @param threads a list of pre-built threads - */ - public NotificationThreads(AppleNotificationServer server, Payload payload, List devices, List threads) { - super("javapns notification threads (" + threads.size() + " threads)"); - this.threads = threads; - List> groups = groupDevices(devices, threads.size()); - for (int i = 0; i < groups.size(); i++) - threads.get(i).setDevices(groups.get(i)); - } - - - /** - * Spread the devices evenly between the provided threads. - * Internally, this constructor uses a AppleNotificationServerBasicImpl to encapsulate the provided keystore, password and production parameters. - * - * @param keystore the keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password the keystore's password - * @param production true to use Apple's production servers, false to use the sandbox - * @param payload the payload to push - * @param devices a very large list of devices - * @param threads a list of pre-built threads - * @throws Exception - */ - public NotificationThreads(Object keystore, String password, boolean production, Payload payload, List devices, List threads) throws Exception { - this(new AppleNotificationServerBasicImpl(keystore, password, production), payload, devices, threads); - } - - - /** - * Use the provided threads which should already each have their group of devices to work with. - * - * @param server the server to push to - * @param payload the payload to push - * @param threads a list of pre-built threads - */ - public NotificationThreads(AppleNotificationServer server, Payload payload, List threads) { - super("javapns notification threads (" + threads.size() + " threads)"); - this.threads = threads; - } - - - /** - * Use the provided threads which should already each have their group of devices to work with. - * Internally, this constructor uses a AppleNotificationServerBasicImpl to encapsulate the provided keystore, password and production parameters. - * - * @param keystore the keystore to use (can be a File, an InputStream, a String for a file path, or a byte[] array) - * @param password the keystore's password - * @param production true to use Apple's production servers, false to use the sandbox - * @param payload the payload to push - * @param threads a list of pre-built threads - * @throws Exception - */ - public NotificationThreads(Object keystore, String password, boolean production, Payload payload, List threads) throws Exception { - this(new AppleNotificationServerBasicImpl(keystore, password, production), payload, threads); - } - - - /** - * Create group of devices ready to be dispatched to worker threads. - * - * @param devices a large list of devices - * @param threads the number of threads to group devices for - * @return - */ - private static List> groupDevices(List devices, int threads) { - List> groups = new Vector>(threads); - int total = devices.size(); - int devicesPerThread = (total / threads); - if (total % threads > 0) devicesPerThread++; - //System.out.println("Making "+threads+" groups of "+devicesPerThread+" devices out of "+total+" devices in total"); - for (int i = 0; i < threads; i++) { - int firstDevice = i * devicesPerThread; - if (firstDevice >= total) break; - int lastDevice = firstDevice + devicesPerThread - 1; - if (lastDevice >= total) lastDevice = total - 1; - lastDevice++; - //System.out.println("Grouping together "+(lastDevice-firstDevice)+" devices (#"+firstDevice+" to "+lastDevice+")"); - List threadDevices = devices.subList(firstDevice, lastDevice); - groups.add(threadDevices); - } - return groups; - } - - - /** - * Start all notification threads. - * - * This method returns immediately, as all threads start working on their own. - * To wait until all threads are finished, use the waitForAllThreads() method. - */ - public final synchronized NotificationThreads start() { - if (threadsRunning > 0) throw new IllegalStateException("NotificationThreads already started (" + threadsRunning + " still running)"); - assignThreadsNumbers(); - for (NotificationThread thread : threads) { - threadsRunning++; - thread.start(); - } - if (listener != null) listener.eventAllThreadsStarted(this); - return this; - } - - - /** - * Configure in all threads the maximum number of notifications per connection. - * - * As soon as a thread reaches that maximum, it will automatically close the connection, - * initialize a new connection and continue pushing more notifications. - * - * @param notifications the maximum number of notifications that threads will push in a single connection (default is 200) - */ - public void setMaxNotificationsPerConnection(int notifications) { - for (NotificationThread thread : threads) - thread.setMaxNotificationsPerConnection(notifications); - } - - - /** - * Configure in all threads the number of milliseconds that threads should wait between each notification. - * - * This feature is intended to alleviate intense resource usage that can occur when - * sending large quantities of notifications very quickly. - - * @param milliseconds the number of milliseconds threads should sleep between individual notifications (default is 0) - */ - public void setSleepBetweenNotifications(long milliseconds) { - for (NotificationThread thread : threads) - thread.setSleepBetweenNotifications(milliseconds); - } - - - /** - * Get a list of threads created to push notifications. - * - * @return a list of threads - */ - public List getThreads() { - return threads; - } - - - /** - * Get the progress listener, if any is attached. - * @return a progress listener - */ - public NotificationProgressListener getListener() { - return listener; - } - - - /** - * Attach an event listener to this object as well as all linked threads. - * - * @param listener - */ - public void setListener(NotificationProgressListener listener) { - this.listener = listener; - for (NotificationThread thread : threads) - thread.setListener(listener); - } - - - /** - * Worker threads invoke this method as soon as they have completed their work. - * This method tracks the number of threads still running, allowing us - * to detect when ALL threads have finished. - * - * When all threads are done working, this method fires an AllThreadsFinished - * event to the attached listener (if one is present) and wakes up any - * object that is waiting for the waitForAllThreads() method to return. - * - * @param notificationThread - */ - protected void threadFinished(NotificationThread notificationThread) { - threadsRunning--; - if (threadsRunning == 0) { - if (listener != null) listener.eventAllThreadsFinished(this); - try { - synchronized (finishPoint) { - finishPoint.notifyAll(); - } - } catch (Exception e) { - } - } - } - - - /** - * Wait for all threads to complete their work. - * - * This method blocks and returns only when all threads are done. - * - * @throws InterruptedException - */ - public void waitForAllThreads() throws InterruptedException { - try { - synchronized (finishPoint) { - finishPoint.wait(); - } - } catch (IllegalMonitorStateException e) { - /* All threads are most likely already done, so we ignore this */ - } - } - - - /** - * Assign unique numbers to worker threads. - * Thread numbers allow each thread to generate message identifiers that - * are unique to all threads in the group. - */ - private void assignThreadsNumbers() { - int t = 1; - for (NotificationThread thread : threads) - thread.setThreadNumber(t++); - } - - - /** - * Get a list of all notifications pushed by all threads. - * - * @return a list of pushed notifications - */ - public List getPushedNotifications() { - int capacity = 0; - for (NotificationThread thread : threads) - capacity += thread.getPushedNotifications().size(); - List all = new Vector(capacity); - for (NotificationThread thread : threads) - all.addAll(thread.getPushedNotifications()); - return all; - } - - - /** - * Get a list of all notifications that all threads attempted to push but that failed. - * - * @return a list of failed notifications - */ - public List getFailedNotifications() { - return PushedNotification.findFailedNotifications(getPushedNotifications()); - } - - - /** - * Get a list of all notifications that all threads attempted to push and succeeded. - * - * @return a list of successful notifications - */ - public List getSuccessfulNotifications() { - return PushedNotification.findSuccessfulNotifications(getPushedNotifications()); - } - -} diff --git a/pom.xml b/pom.xml index 7b9143275..7a9973d0b 100644 --- a/pom.xml +++ b/pom.xml @@ -93,7 +93,6 @@ gxmaps gxoffice gxsearch - javapns android gxgeospatial gxodata From 3b7fe2f95f2c7ee1acd048cb3c9727bfbb8bcec1 Mon Sep 17 00:00:00 2001 From: tomas-sexenian Date: Tue, 17 Oct 2023 15:21:24 -0300 Subject: [PATCH 2/2] Remove javapns dependency from java's pom.xml --- java/pom.xml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/java/pom.xml b/java/pom.xml index 3910c4f4e..50b250f30 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -34,11 +34,6 @@ gxmail ${project.version} - - ${project.groupId} - javapns - ${project.version} - org.apache.commons commons-collections4