Runnable Jar 仅在启用调试时工作

Runnable Jar Only Working When Debugging Enabled

我有一个 XMPP 服务器,我已将其设置为发送和接收 Firebase 云消息,该服务器在测试期间运行良好,通过我的服务器代码中的以下两行打开调试:

config.setDebuggerEnabled(true);
XMPPConnection.DEBUG_ENABLED = true;

我现在想将它移到我的生产 ec2 实例中,这样做我必须将上面的 2 行代码更改为 false。进行此更改后,我的 jar 文件不再有效。

运行 来自 CMD 的罐子:

Microsoft Windows [Version 10.0.10586]
(c) 2015 Microsoft Corporation. All rights reserved.

C:\Users\Riley>cd "C:\Program Files\Java\jdk1.8.0_101\bin"

C:\Program Files\Java\jdk1.8.0_101\bin>java -jar D:\Downloads\XMPP-Chat-Server\server.jar
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.provider.UrlProviderFileInitializer initialize
INFO: Loading providers for file [classpath:META-INF/core.providers]
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.provider.ExtensionInitializer] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.ServiceDiscoveryManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.XHTMLManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.muc.MultiUserChat] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.filetransfer.FileTransferManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.LastActivityManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.commands.AdHocCommandManager] specified in smack-config.xml could not be loaded:
Sep 16, 2016 10:28:14 AM org.jivesoftware.smack.SmackConfiguration parseClassToLoad
WARNING: A startup class [org.jivesoftware.smackx.ping.PingManager] specified in smack-config.xml could not be loaded:

C:\Program Files\Java\jdk1.8.0_101\bin>

这是我的 XMPP 服务器代码:

package com.fcmserver;

/*
 * Most part of this class is copyright Google.
 * It is from https://developer.android.com/google/gcm/ccs.html
 */

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.ConnectionListener;
import org.jivesoftware.smack.PacketInterceptor;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.PacketTypeFilter;
import org.jivesoftware.smack.packet.DefaultPacketExtension;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.PacketExtension;
import org.jivesoftware.smack.provider.PacketExtensionProvider;
import org.jivesoftware.smack.provider.ProviderManager;
import org.jivesoftware.smack.util.StringUtils;
import org.json.simple.JSONValue;
import org.json.simple.parser.ParseException;
import org.xmlpull.v1.XmlPullParser;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.*;
import javax.net.ssl.SSLSocketFactory;

/**
 * Sample Smack implementation of a client for GCM Cloud Connection Server.
 *
 * For illustration purposes only.
 */
public class SmackCcsClient {

    static final String REG_ID_STORE = "gcmchat.txt";   

    static final String MESSAGE_KEY = "SM";
    Logger logger = Logger.getLogger("SmackCcsClient");

    public static final String GCM_SERVER = "fcm-xmpp.googleapis.com";
    public static final int GCM_PORT = 5235;

    public static final String GCM_ELEMENT_NAME = "gcm";
    public static final String GCM_NAMESPACE = "google:mobile:data";

    static Random random = new Random();
    XMPPConnection connection;
    ConnectionConfiguration config;

    /**
     * XMPP Packet Extension for GCM Cloud Connection Server.
     */
    class GcmPacketExtension extends DefaultPacketExtension {
        String json;

        public GcmPacketExtension(String json) {
            super(GCM_ELEMENT_NAME, GCM_NAMESPACE);
            this.json = json;
        }

        public String getJson() {
            return json;
        }

        @Override
        public String toXML() {
            return String.format("<%s xmlns=\"%s\">%s</%s>", GCM_ELEMENT_NAME,
                    GCM_NAMESPACE, json, GCM_ELEMENT_NAME);
        }

        @SuppressWarnings("unused")
        public Packet toPacket() {
            return new Message() {
                // Must override toXML() because it includes a <body>
                @Override
                public String toXML() {

                    StringBuilder buf = new StringBuilder();
                    buf.append("<message");
                    if (getXmlns() != null) {
                        buf.append(" xmlns=\"").append(getXmlns()).append("\"");
                    }
                    if (getLanguage() != null) {
                        buf.append(" xml:lang=\"").append(getLanguage())
                                .append("\"");
                    }
                    if (getPacketID() != null) {
                        buf.append(" id=\"").append(getPacketID()).append("\"");
                    }
                    if (getTo() != null) {
                        buf.append(" to=\"")
                                .append(StringUtils.escapeForXML(getTo()))
                                .append("\"");
                    }
                    if (getFrom() != null) {
                        buf.append(" from=\"")
                                .append(StringUtils.escapeForXML(getFrom()))
                                .append("\"");
                    }
                    buf.append(">");
                    buf.append(GcmPacketExtension.this.toXML());
                    buf.append("</message>");
                    return buf.toString();
                }
            };
        }
    }

    public SmackCcsClient() {
        // Add GcmPacketExtension
        ProviderManager.getInstance().addExtensionProvider(GCM_ELEMENT_NAME,
                GCM_NAMESPACE, new PacketExtensionProvider() {

                    @Override
                    public PacketExtension parseExtension(XmlPullParser parser)
                            throws Exception {
                        String json = parser.nextText();
                        GcmPacketExtension packet = new GcmPacketExtension(json);
                        return packet;
                    }
                });
    }

    /**
     * Returns a random message id to uniquely identify a message.
     *
     * <p>
     * Note: This is generated by a pseudo random number generator for
     * illustration purpose, and is not guaranteed to be unique.
     *
     */
    public String getRandomMessageId() {
        return "m-" + Long.toString(random.nextLong());
    }

    /**
     * Sends a downstream GCM message.
     */
    public void send(String jsonRequest) {
        Packet request = new GcmPacketExtension(jsonRequest).toPacket();
        connection.sendPacket(request);
    }

    /**
     * Handles an upstream data message from a device application.
     *
     * <p>
     * This sample echo server sends an echo message back to the device.
     * Subclasses should override this method to process an upstream message.
     */
    public void handleIncomingDataMessage(Map<String, Object> jsonObject) {

        String from = jsonObject.get("from").toString();

        // PackageName of the application that sent this message.
        String category = jsonObject.get("category").toString();

        // Use the packageName as the collapseKey in the echo packet
        String collapseKey = "echo:CollapseKey";
        @SuppressWarnings("unchecked")
        Map<String, String> payload = (Map<String, String>) jsonObject
                .get("data");



            String messageText = payload.get("message_text");
            String messageFrom = payload.get("message_userfrom");
            String messageTime = payload.get("message_timestamp");
            String toUser = payload.get("message_recipient");
            String id = payload.get("message_alarm_id");
            String messageType = payload.get("binder_message_type");

            payload.put("message_text", messageText);
            payload.put("message_userfrom", messageFrom);           
            payload.put("message_timestamp", messageTime);
            payload.put("message_alarm_id", id);
            payload.put("binder_message_type", messageType);

            String message = createJsonMessage(toUser, getRandomMessageId(),
                    payload, collapseKey, null, false);
            send(message);

    }

    /**
     * Handles an ACK.
     *
     * <p>
     * By default, it only logs a INFO message, but subclasses could override it
     * to properly handle ACKS.
     */
    public void handleAckReceipt(Map<String, Object> jsonObject) {
        String messageId = jsonObject.get("message_id").toString();
        String from = jsonObject.get("from").toString();
        logger.log(Level.INFO, "handleAckReceipt() from: " + from
                + ", messageId: " + messageId);
    }

    /**
     * Handles a NACK.
     *
     * <p>
     * By default, it only logs a INFO message, but subclasses could override it
     * to properly handle NACKS.
     */
    public void handleNackReceipt(Map<String, Object> jsonObject) {
        String messageId = jsonObject.get("message_id").toString();
        String from = jsonObject.get("from").toString();
        logger.log(Level.INFO, "handleNackReceipt() from: " + from
                + ", messageId: " + messageId);
    }

    /**
     * Creates a JSON encoded GCM message.
     *
     * @param to
     *            RegistrationId of the target device (Required).
     * @param messageId
     *            Unique messageId for which CCS will send an "ack/nack"
     *            (Required).
     * @param payload
     *            Message content intended for the application. (Optional).
     * @param collapseKey
     *            GCM collapse_key parameter (Optional).
     * @param timeToLive
     *            GCM time_to_live parameter (Optional).
     * @param delayWhileIdle
     *            GCM delay_while_idle parameter (Optional).
     * @return JSON encoded GCM message.
     */
    public static String createJsonMessage(String to, String messageId,
            Map<String, String> payload, String collapseKey, Long timeToLive,
            Boolean delayWhileIdle) {
        Map<String, Object> message = new HashMap<String, Object>();
        message.put("to", to);
        if (collapseKey != null) {
            message.put("collapse_key", collapseKey);
        }
        if (timeToLive != null) {
            message.put("time_to_live", timeToLive);
        }
        if (delayWhileIdle != null && delayWhileIdle) {
            message.put("delay_while_idle", true);
        }
        message.put("priority", "high");
        message.put("message_id", messageId);
        message.put("data", payload);
        return JSONValue.toJSONString(message);
    }

    /**
     * Creates a JSON encoded ACK message for an upstream message received from
     * an application.
     *
     * @param to
     *            RegistrationId of the device who sent the upstream message.
     * @param messageId
     *            messageId of the upstream message to be acknowledged to CCS.
     * @return JSON encoded ack.
     */
    public static String createJsonAck(String to, String messageId) {
        Map<String, Object> message = new HashMap<String, Object>();
        message.put("message_type", "ack");
        message.put("to", to);
        message.put("message_id", messageId);
        return JSONValue.toJSONString(message);
    }

    /**
     * Connects to GCM Cloud Connection Server using the supplied credentials.
     *
     * @param username
     *            GCM_SENDER_ID@gcm.googleapis.com
     * @param password
     *            API Key
     * @throws XMPPException
     */
    public void connect(String username, String password) throws XMPPException {
        config = new ConnectionConfiguration(GCM_SERVER, GCM_PORT);
        config.setSecurityMode(SecurityMode.enabled);
        config.setReconnectionAllowed(true);
        config.setRosterLoadedAtLogin(false);
        config.setSendPresence(false);
        config.setSocketFactory(SSLSocketFactory.getDefault());

        // NOTE: Set to true to launch a window with information about packets
        // sent and received
        config.setDebuggerEnabled(false);

        // -Dsmack.debugEnabled=true
        XMPPConnection.DEBUG_ENABLED = false;

        connection = new XMPPConnection(config);
        connection.connect();

        connection.addConnectionListener(new ConnectionListener() {

            @Override
            public void reconnectionSuccessful() {
                logger.info("Reconnecting..");
            }

            @Override
            public void reconnectionFailed(Exception e) {
                logger.log(Level.INFO, "Reconnection failed.. ", e);
            }

            @Override
            public void reconnectingIn(int seconds) {
                logger.log(Level.INFO, "Reconnecting in %d secs", seconds);
            }

            @Override
            public void connectionClosedOnError(Exception e) {
                logger.log(Level.INFO, "Connection closed on error.");
            }

            @Override
            public void connectionClosed() {
                logger.info("Connection closed.");
            }
        });

        // Handle incoming packets
        connection.addPacketListener(new PacketListener() {

            @Override
            public void processPacket(Packet packet) {
                logger.log(Level.INFO, "Received: " + packet.toXML());
                Message incomingMessage = (Message) packet;
                GcmPacketExtension gcmPacket = (GcmPacketExtension) incomingMessage
                        .getExtension(GCM_NAMESPACE);
                String json = gcmPacket.getJson();
                try {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> jsonObject = (Map<String, Object>) JSONValue
                            .parseWithException(json);

                    // present for "ack"/"nack", null otherwise
                    Object messageType = jsonObject.get("message_type");

                    if (messageType == null) {
                        // Normal upstream data message
                        handleIncomingDataMessage(jsonObject);

                        // Send ACK to CCS
                        String messageId = jsonObject.get("message_id")
                                .toString();
                        String from = jsonObject.get("from").toString();
                        String ack = createJsonAck(from, messageId);
                        send(ack);
                    } else if ("ack".equals(messageType.toString())) {
                        // Process Ack
                        handleAckReceipt(jsonObject);
                    } else if ("nack".equals(messageType.toString())) {
                        // Process Nack
                        handleNackReceipt(jsonObject);
                    } else {
                        logger.log(Level.WARNING,
                                "Unrecognized message type (%s)",
                                messageType.toString());
                    }
                } catch (ParseException e) {
                    logger.log(Level.SEVERE, "Error parsing JSON " + json, e);
                } catch (Exception e) {
                    logger.log(Level.SEVERE, "Couldn't send echo.", e);
                }
            }
        }, new PacketTypeFilter(Message.class));

        // Log all outgoing packets
        connection.addPacketInterceptor(new PacketInterceptor() {
            @Override
            public void interceptPacket(Packet packet) {
                logger.log(Level.INFO, "Sent: {0}", packet.toXML());
            }
        }, new PacketTypeFilter(Message.class));

        connection.login(username, password);
    }

    public void writeToFile(String name, String regId) throws IOException {
        Map<String, String> regIdMap = readFromFile();
        regIdMap.put(name, regId);
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(
                REG_ID_STORE, false)));
        for (Map.Entry<String, String> entry : regIdMap.entrySet()) {
            out.println(entry.getKey() + "," + entry.getValue());
        }
        out.println(name + "," + regId);
        out.close();

    }

    public Map<String, String> readFromFile() {
    Map<String, String> regIdMap = null;
    try {
        BufferedReader br = new BufferedReader(new FileReader(REG_ID_STORE));
        String regIdLine = "";
        regIdMap = new HashMap<String, String>();
        while ((regIdLine = br.readLine()) != null) {
            String[] regArr = regIdLine.split(",");
            regIdMap.put(regArr[0], regArr[1]);
        }
        br.close();
    } catch(IOException ioe) {
    }
        return regIdMap;
    }

 public static void main(String [] args) {
    final String userName = "USERNAME" + "@gcm.googleapis.com";
    final String password = "PASSWORD";

    SmackCcsClient ccsClient = new SmackCcsClient();

    try {
      ccsClient.connect(userName, password);
    } catch (XMPPException e) {
      e.printStackTrace();
    }
}
}

所以我想通了。我更改了以下代码:

public static void main(String [] args) {
    final String userName = "USERNAME" + "@gcm.googleapis.com";
    final String password = "PASSWORD";

    SmackCcsClient ccsClient = new SmackCcsClient();

    try {
      ccsClient.connect(userName, password);
    } catch (XMPPException e) {
      e.printStackTrace();
    }
}
}

以下内容:

public static void main(String [] args) {
    final String userName = "USERNAME" + "@gcm.googleapis.com";
    final String password = "PASSWORD";

    SmackCcsClient ccsClient = new SmackCcsClient();

    try {
      ccsClient.connect(userName, password);
    } catch (XMPPException e) {
      e.printStackTrace();
    }
    try {
      CountDownLatch latch = new CountDownLatch(1);
       latch.await();
} catch (InterruptedException e) {
       logger.log(Level.SEVERE, "An error occurred while latch was waiting.", e);
}

}

}
}