2015-10-04 121 views
0

我的後端java的目標是使用GCM XMPP接收移動消息。我的web應用程序有4.1.4和4.1.4。GCM XMPP - 啓動Web應用程序服務器出錯

啪的依賴關係:

<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-core</artifactId> 
    <version>4.1.4</version> 
</dependency> 
<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-tcp</artifactId> 
    <version>4.1.4</version> 
</dependency> 
<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-extensions</artifactId> 
    <version>4.1.4</version> 
</dependency> 
<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-java7</artifactId> 
    <version>4.0.1</version> 
</dependency> 

豆的XMPP連接:

@Component("CcsClientImpl") 
public class CcsClientImpl { 

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

    private static XMPPTCPConnection connection; 

    /** 
    * Indicates whether the connection is in draining state, which means that it 
    * will not accept any new downstream messages. 
    */ 
    protected static volatile boolean connectionDraining = false; 

    private static final Logger logger = LoggerFactory.getLogger("CcsClientImpl"); 

    @Value("${sender.id}") 
    private String mSenderId; 

    @Value("${server.api.key}") 
    private String mServerApiKey; 

    @Value("${gcm.xmpp.host}") 
    private String mHost; 

    @Value("${gcm.xmpp.port}") 
    private int mPort; 

    @Value("${gcm.xmpp.debuggable}") 
    private boolean mDebuggable; 

    @Autowired 
    private ProcessorFactory processorFactory; 

    //@Autowired 
    public CcsClientImpl() { 

     ProviderManager.addExtensionProvider(GCM_ELEMENT_NAME, GCM_NAMESPACE, new ExtensionElementProvider<ExtensionElement>() { 
      @Override 
      public DefaultExtensionElement parse(XmlPullParser parser,int initialDepth) throws org.xmlpull.v1.XmlPullParserException, IOException { 
       String json = parser.nextText(); 
       return new GcmPacketExtension(json); 
      } 
     }); 

     try { 
      connect(mSenderId, mServerApiKey); 
     } catch (XMPPException ex) { 
      logger.error("ERRO AO CONECTAR COM GCM XMPP", ex); 
     } catch (SmackException ex) { 
      logger.error("ERRO AO CONECTAR COM GCM XMPP", ex); 
     } catch (IOException ex) { 
      logger.error("ERRO AO CONECTAR COM GCM XMPP", ex); 
     } 
    } 

    /** 
    * Sends a downstream message to GCM. 
    * 
    * @return true if the message has been successfully sent. 
    */ 
    public boolean sendDownstreamMessage(String jsonRequest) throws 
      NotConnectedException { 
     if (!connectionDraining) { 
      send(jsonRequest); 
      return true; 
     } 
     logger.info("Dropping downstream message since the connection is draining"); 
     return false; 
    } 

    /** 
    * 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 nextMessageId() { 
     return "m-" + UUID.randomUUID().toString(); 
    } 

    /** 
    * Sends a packet with contents provided. 
    */ 
    protected void send(String jsonRequest) throws NotConnectedException { 
     Stanza request = new GcmPacketExtension(jsonRequest).toPacket(); 
     connection.sendStanza(request); 
    } 

    /// new: customized version of the standard handleIncomingDateMessage method 
    /** 
    * Handles an upstream data message from a device application. 
    */ 
    public void handleIncomingDataMessage(CcsMessage msg) { 
     if (msg.getPayload().get("action") != null) { 
      PayloadProcessor processor = processorFactory.getProcessor(msg.getPayload().get("action")); 
      processor.handleMessage(msg); 
     } 
    }  

    /** 
    * Handles an ACK. 
    * 
    * <p>Logs a INFO message, but subclasses could override it to 
    * properly handle ACKs. 
    */ 
    protected void handleAckReceipt(Map<String, Object> jsonObject) { 
     String messageId = (String) jsonObject.get("message_id"); 
     String from = (String) jsonObject.get("from"); 
     logger.info("handleAckReceipt() from: " + from + ",messageId: " + messageId); 
    } 

    /** 
    * Handles a NACK. 
    * 
    * <p>Logs a INFO message, but subclasses could override it to 
    * properly handle NACKs. 
    */ 
    protected void handleNackReceipt(Map<String, Object> jsonObject) { 
     String messageId = (String) jsonObject.get("message_id"); 
     String from = (String) jsonObject.get("from"); 
     logger.info("handleNackReceipt() from: " + from + ",messageId: " + messageId); 
    } 

    protected void handleControlMessage(Map<String, Object> jsonObject) { 
     logger.info("handleControlMessage(): " + jsonObject); 
     String controlType = (String) jsonObject.get("control_type"); 
     if ("CONNECTION_DRAINING".equals(controlType)) { 
      connectionDraining = true; 
     } else { 
      logger.info("Unrecognized control type: %s. This could happen if new features are " + "added to the CCS protocol.", 
        controlType); 
     } 
    } 

    /** 
    * Creates a JSON encoded GCM message. 
    * 
    * @param to RegistrationId of the target device (Required). 
    * @param messageId Unique messageId for which CCS sends 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("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. 
    */ 
    protected 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 senderId Your GCM project number 
    * @param apiKey API Key of your project 
    */ 
    public void connect(String senderId, String serverApiKey) 
      throws XMPPException, IOException, SmackException { 
     XMPPTCPConnectionConfiguration config = 
       XMPPTCPConnectionConfiguration.builder() 
       .setServiceName(mHost) 
       .setHost(mHost) 
       .setCompressionEnabled(false) 
       .setPort(mPort) 
       .setConnectTimeout(30000) 
       .setSecurityMode(SecurityMode.disabled) 
       .setSendPresence(false) 
           .setDebuggerEnabled(mDebuggable) 
       .setSocketFactory(SSLSocketFactory.getDefault()) 
       .build(); 

     connection = new XMPPTCPConnection(config); 

     //disable Roster as I don't think this is supported by GCM 
     Roster roster = Roster.getInstanceFor(connection); 
     roster.setRosterLoadedAtLogin(false); 

     logger.info("Connecting..."); 
     connection.connect(); 

     connection.addConnectionListener(new LoggingConnectionListener()); 

     // Handle incoming packets 
     connection.addAsyncStanzaListener(new MyStanzaListener() , new MyStanzaFilter()); 

     // Log all outgoing packets 
     connection.addPacketInterceptor(new MyStanzaInterceptor(), new MyStanzaFilter()); 

     connection.login(senderId + "@gcm.googleapis.com" , serverApiKey); 

     logger.info("Logged in: " + mSenderId); 

    } 

    private CcsMessage getMessage(Map<String, Object> jsonObject) { 
     String from = jsonObject.get("from").toString(); 

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

     // unique id of this message 
     String messageId = jsonObject.get("message_id").toString(); 

     @SuppressWarnings("unchecked") 
     Map<String, String> payload = (Map<String, String>) jsonObject.get("data"); 

     CcsMessage msg = new CcsMessage(from, category, messageId, payload); 

     return msg; 
    } 

    private class MyStanzaFilter implements StanzaFilter { 

     @Override 
     public boolean accept(Stanza arg0) { 
      // TODO Auto-generated method stub 
      if (arg0.getClass() == Stanza.class) { 
       return true; 
      } else { 
       if (arg0.getTo() != null) { 
        if (arg0.getTo().startsWith(mSenderId)) { 
         return true; 
        } 
       } 

      } 

      return false; 
     } 
    } 

    private class MyStanzaListener implements StanzaListener{ 

     @Override 
     public void processPacket(Stanza packet) { 
      logger.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 
        CcsMessage msg = getMessage(jsonObject); 

        handleIncomingDataMessage(msg); 

        // Send ACK to CCS 
        String messageId = (String) jsonObject.get("message_id"); 
        String from = (String) jsonObject.get("from"); 
        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 if ("control".equals(messageType.toString())) { 
         // Process control message 
         handleControlMessage(jsonObject); 
       } else { 
         logger.warn("Unrecognized message type (%s)", 
           messageType.toString()); 
       } 
      } catch (ParseException e) { 
       logger.info("Error parsing JSON " + json, e); 
      } catch (Exception e) { 
       logger.info("Failed to process packet", e); 
      } 
     } 

    } 

    private class MyStanzaInterceptor implements StanzaListener 
    { 
     @Override 
     public void processPacket(Stanza packet) { 
      logger.info("Sent: {0}", packet.toXML()); 
     } 

    } 


// public static void main(String[] args) throws Exception { 
//   
//  SmackCcsClient ccsClient = new SmackCcsClient(); 
// 
//  ccsClient.connect(YOUR_PROJECT_ID, YOUR_API_KEY); 
//   
//  // Send a sample hello downstream message to a device. 
//  String messageId = ccsClient.nextMessageId(); 
//  Map<String, String> payload = new HashMap<String, String>(); 
//  payload.put("Message", "Ahha, it works!"); 
//  payload.put("CCS", "Dummy Message"); 
//  payload.put("EmbeddedMessageId", messageId); 
//  String collapseKey = "sample"; 
//  Long timeToLive = 10000L; 
//  String message = createJsonMessage(YOUR_PHONE_REG_ID, messageId, payload, 
//    collapseKey, timeToLive, true); 
// 
//  ccsClient.sendDownstreamMessage(message); 
//  logger.info("Message sent."); 
//   
//  //crude loop to keep connection open for receiving messages 
//  while(true) 
//  {;} 
// } 

    /** 
    * XMPP Packet Extension for GCM Cloud Connection Server. 
    */ 
    private static final class GcmPacketExtension extends DefaultExtensionElement { 

     private final 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, 
        StringUtils.escapeForXML(json), GCM_ELEMENT_NAME); 
     } 

     public Stanza toPacket() { 
      Message message = new Message(); 
      message.addExtension(this); 
      return message; 
     } 
    } 

    private static final class LoggingConnectionListener 
      implements ConnectionListener { 

     @Override 
     public void connected(XMPPConnection xmppConnection) { 
      logger.info("Connected."); 
     } 


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

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

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

     @Override 
     public void connectionClosedOnError(Exception e) { 
      logger.info("Connection closed on error."); 
     } 

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

     @Override 
     public void authenticated(XMPPConnection arg0, boolean arg1) { 
      // TODO Auto-generated method stub 

     } 
    } 

    @PreDestroy 
    public void cleanUp() throws Exception { 
     logger.info("Bean do cliente XMPP está sendo destruído..."); 
     if (connection.isConnected()) { 
      logger.info("Conexão GCM XMPP está aberta. Desconectando..."); 
      connection.disconnect(); 
     }  
    }  

} 

當啓動tomcat的情況發生了錯誤:

Caused by: java.lang.NoClassDefFoundError: org/jivesoftware/smack/initializer/SmackAndOsgiInitializer 
    at java.lang.ClassLoader.defineClass1(Native Method) 
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760) 
    at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142) 
    at org.apache.catalina.loader.WebappClassLoaderBase.findClassInternal(WebappClassLoaderBase.java:2476) 
    at org.apache.catalina.loader.WebappClassLoaderBase.findClass(WebappClassLoaderBase.java:857) 
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1282) 
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1164) 
    at java.lang.Class.forName0(Native Method) 
    at java.lang.Class.forName(Class.java:348) 
    at org.jivesoftware.smack.SmackInitialization.loadSmackClass(SmackInitialization.java:213) 
    at org.jivesoftware.smack.SmackInitialization.parseClassesToLoad(SmackInitialization.java:193) 
    at org.jivesoftware.smack.SmackInitialization.processConfigFile(SmackInitialization.java:163) 
    at org.jivesoftware.smack.SmackInitialization.processConfigFile(SmackInitialization.java:148) 
    at org.jivesoftware.smack.SmackInitialization.<clinit>(SmackInitialization.java:116) 
    at org.jivesoftware.smack.SmackConfiguration.getVersion(SmackConfiguration.java:96) 
    at org.jivesoftware.smack.provider.ProviderManager.<clinit>(ProviderManager.java:121) 
    at br.com.soma.service.gcm.xmpp.CcsClientImpl.<init>(CcsClientImpl.java:73) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) 
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) 
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45) 
    at java.lang.reflect.Constructor.newInstance(Constructor.java:422) 
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147) 
    ... 60 more 
Caused by: java.lang.ClassNotFoundException: org.jivesoftware.smack.initializer.SmackAndOsgiInitializer 
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1313) 
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1164) 
    ... 82 more 

有人能幫助我嗎?謝謝!

+0

您是否注意到與其他所有smack- *依賴項相比,您使用的是smack-java7的不同版本?也許這是原因。我建議爲Smack版本字符串定義一個變量,並引用maven依賴項中的變量。 – Flow

+0

現在工作正常。我只是按照你的建議設置了一個變量。謝謝!! – araraujo

回答

0

現在工作正常。我只是按照你的建議設置了一個變量。謝謝!!

<properties> 
    <smack.version>4.1.4</smack.version> 
</properties> 


<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-core</artifactId> 
    <version>${smack.version}</version> 
</dependency> 
<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-tcp</artifactId> 
    <version>${smack.version}</version> 
</dependency> 
<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-extensions</artifactId> 
    <version>${smack.version}</version> 
</dependency> 
<dependency> 
    <groupId>org.igniterealtime.smack</groupId> 
    <artifactId>smack-java7</artifactId> 
    <version>${smack.version}</version> 
</dependency> 
相關問題