Package com.notnoop.apns.internal

Source Code of com.notnoop.apns.internal.Utilities

/*
* Copyright 2009, Mahmood Ali.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following disclaimer
*     in the documentation and/or other materials provided with the
*     distribution.
*   * Neither the name of Mahmood Ali. nor the names of its
*     contributors may be used to endorse or promote products derived from
*     this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.notnoop.apns.internal;

import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import com.notnoop.exceptions.InvalidSSLConfig;
import com.notnoop.exceptions.NetworkIOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class Utilities {
    private static Logger logger = LoggerFactory.getLogger(Utilities.class);

    public static final String SANDBOX_GATEWAY_HOST = "gateway.sandbox.push.apple.com";
    public static final int SANDBOX_GATEWAY_PORT = 2195;

    public static final String SANDBOX_FEEDBACK_HOST = "feedback.sandbox.push.apple.com";
    public static final int SANDBOX_FEEDBACK_PORT = 2196;

    public static final String PRODUCTION_GATEWAY_HOST = "gateway.push.apple.com";
    public static final int PRODUCTION_GATEWAY_PORT = 2195;

    public static final String PRODUCTION_FEEDBACK_HOST = "feedback.push.apple.com";
    public static final int PRODUCTION_FEEDBACK_PORT = 2196;

    public static final int MAX_PAYLOAD_LENGTH = 2048;

    private Utilities() { throw new AssertionError("Uninstantiable class"); }

    public static SSLSocketFactory newSSLSocketFactory(final InputStream cert, final String password,
         final String ksType, final String ksAlgorithm) throws InvalidSSLConfig {
        final SSLContext context = newSSLContext(cert, password, ksType, ksAlgorithm);
        return context.getSocketFactory();
    }

    public static SSLContext newSSLContext(final InputStream cert, final String password,
            final String ksType, final String ksAlgorithm) throws InvalidSSLConfig {
           try {
               final KeyStore ks = KeyStore.getInstance(ksType);
               ks.load(cert, password.toCharArray());
               return newSSLContext(ks, password, ksAlgorithm);
           } catch (final Exception e) {
               throw new InvalidSSLConfig(e);
           }
       }
   
    public static SSLContext newSSLContext(final KeyStore ks, final String password,
            final String ksAlgorithm) throws InvalidSSLConfig {
           try {
               // Get a KeyManager and initialize it
               final KeyManagerFactory kmf = KeyManagerFactory.getInstance(ksAlgorithm);
               kmf.init(ks, password.toCharArray());

               // Get a TrustManagerFactory with the DEFAULT KEYSTORE, so we have all
               // the certificates in cacerts trusted
               final TrustManagerFactory tmf = TrustManagerFactory.getInstance(ksAlgorithm);
               tmf.init((KeyStore)null);

               // Get the SSLContext to help create SSLSocketFactory
               final SSLContext sslContext = SSLContext.getInstance("TLS");
               sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
               return sslContext;
           } catch (final GeneralSecurityException e) {
               throw new InvalidSSLConfig(e);
           }
       }

    private static final Pattern pattern = Pattern.compile("[ -]");
    public static byte[] decodeHex(final String deviceToken) {
        final String hex = pattern.matcher(deviceToken).replaceAll("");

        final byte[] bts = new byte[hex.length() / 2];
        for (int i = 0; i < bts.length; i++) {
            bts[i] = (byte) (charVal(hex.charAt(2 * i)) * 16 + charVal(hex.charAt(2 * i + 1)));
        }
        return bts;
    }

    private static int charVal(final char a) {
        if ('0' <= a && a <= '9') {
            return (a - '0');
        } else if ('a' <= a && a <= 'f') {
            return (a - 'a') + 10;
        } else if ('A' <= a && a <= 'F') {
            return (a - 'A') + 10;
        } else {
            throw new RuntimeException("Invalid hex character: " + a);
        }
    }

    private static final char base[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};

    public static String encodeHex(final byte[] bytes) {
        final char[] chars = new char[bytes.length * 2];

        for (int i = 0; i < bytes.length; ++i) {
            final int b = (bytes[i]) & 0xFF;
            chars[2 * i] = base[b >>> 4];
            chars[2 * i + 1] = base[b & 0xF];
        }

        return new String(chars);
    }

    public static byte[] toUTF8Bytes(final String s) {
        try {
            return s.getBytes("UTF-8");
        } catch (final UnsupportedEncodingException e) {
            throw new RuntimeException(e);
        }
    }

    public static byte[] marshall(final byte command, final byte[] deviceToken, final byte[] payload) {
        final ByteArrayOutputStream boas = new ByteArrayOutputStream();
        final DataOutputStream dos = new DataOutputStream(boas);

        try {
            dos.writeByte(command);
            dos.writeShort(deviceToken.length);
            dos.write(deviceToken);
            dos.writeShort(payload.length);
            dos.write(payload);
            return boas.toByteArray();
        } catch (final IOException e) {
            throw new AssertionError();
        }
    }

    public static byte[] marshallEnhanced(final byte command, final int identifier,
            final int expiryTime, final byte[] deviceToken, final byte[] payload) {
        final ByteArrayOutputStream boas = new ByteArrayOutputStream();
        final DataOutputStream dos = new DataOutputStream(boas);

        try {
            dos.writeByte(command);
            dos.writeInt(identifier);
            dos.writeInt(expiryTime);
            dos.writeShort(deviceToken.length);
            dos.write(deviceToken);
            dos.writeShort(payload.length);
            dos.write(payload);
            return boas.toByteArray();
        } catch (final IOException e) {
            throw new AssertionError();
        }
    }

    public static Map<byte[], Integer> parseFeedbackStreamRaw(final InputStream in) {
        final Map<byte[], Integer> result = new HashMap<byte[], Integer>();

        final DataInputStream data = new DataInputStream(in);

        while (true) {
            try {
                final int time = data.readInt();
                final int dtLength = data.readUnsignedShort();
                final byte[] deviceToken = new byte[dtLength];
                data.readFully(deviceToken);

                result.put(deviceToken, time);
            } catch (final EOFException e) {
                break;
            } catch (final IOException e) {
                throw new RuntimeException(e);
            }
        }

        return result;
    }

    public static Map<String, Date> parseFeedbackStream(final InputStream in) {
        final Map<String, Date> result = new HashMap<String, Date>();

        final Map<byte[], Integer> raw = parseFeedbackStreamRaw(in);
        for (final Map.Entry<byte[], Integer> entry : raw.entrySet()) {
            final byte[] dtArray = entry.getKey();
            final int time = entry.getValue(); // in seconds

            final Date date = new Date(time * 1000L);    // in ms
            final String dtString = encodeHex(dtArray);
            result.put(dtString, date);
        }

        return result;
    }

    public static void close(final Closeable closeable) {
        logger.debug("close {}", closeable);

        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (final IOException e) {
            logger.debug("error while closing resource", e);
        }
    }

    public static void close(final Socket closeable) {
        logger.debug("close {}", closeable);

        try {
            if (closeable != null) {
                closeable.close();
            }
        } catch (final IOException e) {
            logger.debug("error while closing socket", e);
        }
    }

    public static void sleep(final int delay) {
        try {
            Thread.sleep(delay);
        } catch (final InterruptedException e1) {
            Thread.currentThread().interrupt();
        }
    }

    public static byte[] copyOf(final byte[] bytes) {
        final byte[] copy = new byte[bytes.length];
        System.arraycopy(bytes, 0, copy, 0, bytes.length);
        return copy;
    }

    public static byte[] copyOfRange(final byte[] original, final int from, final int to) {
        final int newLength = to - from;
        if (newLength < 0) {
            throw new IllegalArgumentException(from + " > " + to);
        }
        final byte[] copy = new byte[newLength];
        System.arraycopy(original, from, copy, 0,
                Math.min(original.length - from, newLength));
        return copy;
    }

    public static void wrapAndThrowAsRuntimeException(final Exception e) throws NetworkIOException {
        if (e instanceof IOException) {
            throw new NetworkIOException((IOException)e);
        } else if (e instanceof NetworkIOException) {
            throw (NetworkIOException)e;
        } else if (e instanceof RuntimeException) {
            throw (RuntimeException)e;
        } else {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings({"PointlessArithmeticExpression", "PointlessBitwiseExpression"})
    public static int parseBytes(final int b1, final int b2, final int b3, final int b4) {
        return  ((b1 << 3 * 8) & 0xFF000000)
              | ((b2 << 2 * 8) & 0x00FF0000)
              | ((b3 << 1 * 8) & 0x0000FF00)
              | ((b4 << 0 * 8) & 0x000000FF);
    }

    // @see http://stackoverflow.com/questions/119328/how-do-i-truncate-a-java-string-to-fit-in-a-given-number-of-bytes-once-utf-8-enc
    public static String truncateWhenUTF8(final String s, final int maxBytes) {
        int b = 0;
        for (int i = 0; i < s.length(); i++) {
            final char c = s.charAt(i);

            // ranges from http://en.wikipedia.org/wiki/UTF-8
            int skip = 0;
            int more;
            if (c <= 0x007f) {
                more = 1;
            }
            else if (c <= 0x07FF) {
                more = 2;
            } else if (c <= 0xd7ff) {
                more = 3;
            } else if (c <= 0xDFFF) {
                // surrogate area, consume next char as well
                more = 4;
                skip = 1;
            } else {
                more = 3;
            }

            if (b + more > maxBytes) {
                return s.substring(0, i);
            }
            b += more;
            i += skip;
        }
        return s;
    }

}
TOP

Related Classes of com.notnoop.apns.internal.Utilities

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.