1.服务端cim-boot-server修改为idea maven工程

2.android sdk优化升级,去除mina或netty相关包的依赖
3.java sdk优化升级,去除mina或netty相关包的依赖
4.新增web sdk,可以由index.html快速启动demo
5.修正文档中一些疏漏
This commit is contained in:
远方夕阳 2019-05-13 18:15:06 +08:00
parent e9cc607776
commit abd08cdc26
487 changed files with 11626 additions and 18674 deletions

View File

@ -1,5 +1,5 @@
#### 项目介绍 #### 项目介绍
CIM是基于minanetty框架下的推送系统我们平常使用第三方的推送SDK如极光推送百度推送小米推送以及腾讯信鸽等来支撑自己的移动端的业务或许有一些用户自己实现即时通讯系统的需求那么CIM为您提供了一个解决方案或者思路目前CIM支撑 websocketandroidios桌面应用系统应用等多端接入支持目前CIM服务端使用springboot搭建仅仅拥有消息推送的功能关于数据缓存与持久化都需要使用者自己开发但是配备了比较完整的使用文档。最后希望CIM能为您带来一些价值。 CIM是基于mina或者netty框架下的推送系统我们平常使用第三方的推送SDK如极光推送百度推送小米推送以及腾讯信鸽等来支撑自己的移动端的业务或许有一些用户自己实现即时通讯系统的需求那么CIM为您提供了一个解决方案或者思路目前CIM支撑 websocketandroidios桌面应用系统应用等多端接入支持目前CIM服务端使用springboot搭建仅仅拥有消息推送的功能关于数据缓存与持久化都需要使用者自己开发但是配备了比较完整的使用文档。最后希望CIM能为您带来一些价值。
--- ---
## 相关项目 ## 相关项目
@ -14,16 +14,13 @@ CIM是基于mina和netty框架下的推送系统我们平常使用第三方
--- ---
#### 目录说明 #### 目录说明
1.cim-use-examples是各个客户端使用示例
2.cim-client-sdk 是各个客户端的SDK源码
3.cim-server-sdk 是服务端SDK源码,分为 mina和netty 两个版本,二者任选其一
4.cim-boot-server是springboot服务端工程源码,使用Idea工具开发
其中所有的sdk均为Eclipse工程打包成jar导出引入到对应的客户端或服务端工程
1. cim_for_mina目录下为mina版本实现
2. cim_for_netty目录下为netty版本实现
3. doc目录中是相关使用文档以及protubuf结构体文件
5. cim-android-sdk 是android客户端封装的的jar包
6. cim-java-sdk 是java版客户端封装的的jar包
7. cim-server-sdk 是cim-boot-server 用到的封装的jar
8. cim-boot-server是springboot服务端工程是intellij idea基于gradle构建
9. cim-client-android 是android客户端 android studio工具
10. 说明.txt是服务端环境搭建说明
#### 建议反馈 #### 建议反馈
@ -59,7 +56,18 @@ CIM是基于mina和netty框架下的推送系统我们平常使用第三方
3.消息的id字段名由mid修改为id类型由String修改为long; 3.消息的id字段名由mid修改为id类型由String修改为long;
-------------------------------------------------------------------------------------------
版本:3.7.0/时间:2019-05-13
1.服务端cim-boot-server修改为idea maven工程
2.android sdk优化升级去除mina或netty相关包的依赖
3.java sdk优化升级去除mina或netty相关包的依赖
4.新增web sdk可以由index.html快速启动demo
5.修正文档中一些疏漏

View File

@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8"?>
<module org.jetbrains.idea.maven.project.MavenProjectsManager.isMavenModule="true" type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="Spring" name="Spring">
<configuration />
</facet>
<facet type="web" name="Web">
<configuration>
<webroots />
<sourceRoots>
<root url="file://$MODULE_DIR$/src/main/java" />
<root url="file://$MODULE_DIR$/src/main/resources" />
</sourceRoots>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_8">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src/test/java" isTestSource="true" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-logging:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-classic:1.2.3" level="project" />
<orderEntry type="library" name="Maven: ch.qos.logback:logback-core:1.2.3" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.11.2" level="project" />
<orderEntry type="library" name="Maven: org.apache.logging.log4j:log4j-api:2.11.2" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:jul-to-slf4j:1.7.26" level="project" />
<orderEntry type="library" name="Maven: javax.annotation:javax.annotation-api:1.3.2" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-core:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-jcl:5.1.6.RELEASE" level="project" />
<orderEntry type="library" scope="RUNTIME" name="Maven: org.yaml:snakeyaml:1.23" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.8" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.8" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.17" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.17" level="project" />
<orderEntry type="library" name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.17" level="project" />
<orderEntry type="library" name="Maven: org.hibernate.validator:hibernate-validator:6.0.16.Final" level="project" />
<orderEntry type="library" name="Maven: javax.validation:validation-api:2.0.1.Final" level="project" />
<orderEntry type="library" name="Maven: org.jboss.logging:jboss-logging:3.3.2.Final" level="project" />
<orderEntry type="library" name="Maven: com.fasterxml:classmate:1.4.0" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-web:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-beans:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-webmvc:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-aop:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-expression:5.1.6.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.springframework.boot:spring-boot-starter-freemarker:2.1.4.RELEASE" level="project" />
<orderEntry type="library" name="Maven: org.freemarker:freemarker:2.3.28" level="project" />
<orderEntry type="library" name="Maven: org.springframework:spring-context-support:5.1.6.RELEASE" level="project" />
<orderEntry type="module-library">
<library name="Maven: com.farsunset:cim-server-sdk:3.7">
<CLASSES>
<root url="jar://$MODULE_DIR$/lib/cim-server-sdk-mina-3.7.0.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</orderEntry>
<orderEntry type="library" name="Maven: org.apache.mina:mina-core:2.0.21" level="project" />
<orderEntry type="library" name="Maven: org.slf4j:slf4j-api:1.7.26" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-handler:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-buffer:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-codec-http:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-common:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-transport:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: io.netty:netty-resolver:4.1.35.Final" level="project" />
<orderEntry type="library" name="Maven: com.google.protobuf:protobuf-java:3.7.0" level="project" />
<orderEntry type="library" name="Maven: cn.teaey.apns4j:apns4j:1.1.4" level="project" />
<orderEntry type="library" name="Maven: commons-io:commons-io:2.6" level="project" />
<orderEntry type="library" name="Maven: org.apache.commons:commons-lang3:3.8.1" level="project" />
</component>
</module>

View File

@ -0,0 +1,640 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<annotationProcessing>
<profile name="Maven default annotation processors profile" enabled="true">
<sourceOutputDir name="target/generated-sources/annotations" />
<sourceTestOutputDir name="target/generated-test-sources/test-annotations" />
<outputRelativeToContentRoot value="true" />
<module name="cim-boot-server" />
</profile>
</annotationProcessing>
<bytecodeTargetLevel>
<module name="cim-boot-server" target="1.8" />
</bytecodeTargetLevel>
</component>
<component name="Encoding">
<file url="file://$PROJECT_DIR$" charset="UTF-8" />
</component>
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="JavaDoc" enabled="true" level="WARNING" enabled_by_default="true">
<option name="TOP_LEVEL_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="INNER_CLASS_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="METHOD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="@return@param@throws or @exception" />
</value>
</option>
<option name="FIELD_OPTIONS">
<value>
<option name="ACCESS_JAVADOC_REQUIRED_FOR" value="none" />
<option name="REQUIRED_TAGS" value="" />
</value>
</option>
<option name="IGNORE_DEPRECATED" value="false" />
<option name="IGNORE_JAVADOC_PERIOD" value="true" />
<option name="IGNORE_DUPLICATED_THROWS" value="false" />
<option name="IGNORE_POINT_TO_ITSELF" value="false" />
<option name="myAdditionalJavadocTags" value="date" />
</inspection_tool>
</profile>
<version value="1.0" />
</component>
<component name="JavacSettings">
<option name="ADDITIONAL_OPTIONS_OVERRIDE">
<module name="cim-boot-server" options="-parameters" />
</option>
</component>
<component name="MavenProjectsManager">
<option name="originalFiles">
<list>
<option value="$PROJECT_DIR$/pom.xml" />
</list>
</option>
</component>
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/cim-boot-server.iml" filepath="$PROJECT_DIR$/cim-boot-server.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="libraryTable">
<library name="Maven: ch.qos.logback:logback-classic:1.2.3">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: ch.qos.logback:logback-core:1.2.3">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: cn.teaey.apns4j:apns4j:1.1.4">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/cn/teaey/apns4j/apns4j/1.1.4/apns4j-1.1.4.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/cn/teaey/apns4j/apns4j/1.1.4/apns4j-1.1.4-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/cn/teaey/apns4j/apns4j/1.1.4/apns4j-1.1.4-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml.jackson.core:jackson-annotations:2.9.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-annotations/2.9.0/jackson-annotations-2.9.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml.jackson.core:jackson-core:2.9.8">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-core/2.9.8/jackson-core-2.9.8-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml.jackson.core:jackson-databind:2.9.8">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-databind/2.9.8/jackson-databind-2.9.8-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.9.8">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/datatype/jackson-datatype-jdk8/2.9.8/jackson-datatype-jdk8-2.9.8-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.8">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/datatype/jackson-datatype-jsr310/2.9.8/jackson-datatype-jsr310-2.9.8-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml.jackson.module:jackson-module-parameter-names:2.9.8">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/jackson/module/jackson-module-parameter-names/2.9.8/jackson-module-parameter-names-2.9.8-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.fasterxml:classmate:1.4.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/classmate/1.4.0/classmate-1.4.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/classmate/1.4.0/classmate-1.4.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/fasterxml/classmate/1.4.0/classmate-1.4.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: com.google.protobuf:protobuf-java:3.7.0">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/com/google/protobuf/protobuf-java/3.7.0/protobuf-java-3.7.0.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/com/google/protobuf/protobuf-java/3.7.0/protobuf-java-3.7.0-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/com/google/protobuf/protobuf-java/3.7.0/protobuf-java-3.7.0-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: commons-io:commons-io:2.6">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.6/commons-io-2.6.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.6/commons-io-2.6-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/commons-io/commons-io/2.6/commons-io-2.6-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-buffer:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-buffer/4.1.35.Final/netty-buffer-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-buffer/4.1.35.Final/netty-buffer-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-buffer/4.1.35.Final/netty-buffer-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-codec-http:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-codec-http/4.1.35.Final/netty-codec-http-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-codec-http/4.1.35.Final/netty-codec-http-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-codec-http/4.1.35.Final/netty-codec-http-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-codec:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-codec/4.1.35.Final/netty-codec-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-codec/4.1.35.Final/netty-codec-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-codec/4.1.35.Final/netty-codec-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-common:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-common/4.1.35.Final/netty-common-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-common/4.1.35.Final/netty-common-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-common/4.1.35.Final/netty-common-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-handler:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-handler/4.1.35.Final/netty-handler-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-handler/4.1.35.Final/netty-handler-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-handler/4.1.35.Final/netty-handler-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-resolver:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-resolver/4.1.35.Final/netty-resolver-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-resolver/4.1.35.Final/netty-resolver-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-resolver/4.1.35.Final/netty-resolver-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: io.netty:netty-transport:4.1.35.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-transport/4.1.35.Final/netty-transport-4.1.35.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-transport/4.1.35.Final/netty-transport-4.1.35.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/io/netty/netty-transport/4.1.35.Final/netty-transport-4.1.35.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: javax.annotation:javax.annotation-api:1.3.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/javax/annotation/javax.annotation-api/1.3.2/javax.annotation-api-1.3.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: javax.validation:validation-api:2.0.1.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/javax/validation/validation-api/2.0.1.Final/validation-api-2.0.1.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.commons:commons-lang3:3.8.1">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.logging.log4j:log4j-api:2.11.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-api/2.11.2/log4j-api-2.11.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.logging.log4j:log4j-to-slf4j:2.11.2">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/logging/log4j/log4j-to-slf4j/2.11.2/log4j-to-slf4j-2.11.2-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.mina:mina-core:2.0.21">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/mina/mina-core/2.0.21/mina-core-2.0.21.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/mina/mina-core/2.0.21/mina-core-2.0.21-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/mina/mina-core/2.0.21/mina-core-2.0.21-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.tomcat.embed:tomcat-embed-core:9.0.17">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-core/9.0.17/tomcat-embed-core-9.0.17.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-core/9.0.17/tomcat-embed-core-9.0.17-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-core/9.0.17/tomcat-embed-core-9.0.17-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.tomcat.embed:tomcat-embed-el:9.0.17">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-el/9.0.17/tomcat-embed-el-9.0.17.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-el/9.0.17/tomcat-embed-el-9.0.17-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-el/9.0.17/tomcat-embed-el-9.0.17-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.apache.tomcat.embed:tomcat-embed-websocket:9.0.17">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.17/tomcat-embed-websocket-9.0.17.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.17/tomcat-embed-websocket-9.0.17-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/apache/tomcat/embed/tomcat-embed-websocket/9.0.17/tomcat-embed-websocket-9.0.17-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.freemarker:freemarker:2.3.28">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/freemarker/freemarker/2.3.28/freemarker-2.3.28.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/freemarker/freemarker/2.3.28/freemarker-2.3.28-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/freemarker/freemarker/2.3.28/freemarker-2.3.28-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.hibernate.validator:hibernate-validator:6.0.16.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/hibernate/validator/hibernate-validator/6.0.16.Final/hibernate-validator-6.0.16.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/hibernate/validator/hibernate-validator/6.0.16.Final/hibernate-validator-6.0.16.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/hibernate/validator/hibernate-validator/6.0.16.Final/hibernate-validator-6.0.16.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.jboss.logging:jboss-logging:3.3.2.Final">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/jboss/logging/jboss-logging/3.3.2.Final/jboss-logging-3.3.2.Final-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.slf4j:jul-to-slf4j:1.7.26">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/jul-to-slf4j/1.7.26/jul-to-slf4j-1.7.26.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/jul-to-slf4j/1.7.26/jul-to-slf4j-1.7.26-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/jul-to-slf4j/1.7.26/jul-to-slf4j-1.7.26-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.slf4j:slf4j-api:1.7.26">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/slf4j/slf4j-api/1.7.26/slf4j-api-1.7.26-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-autoconfigure:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/2.1.4.RELEASE/spring-boot-autoconfigure-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/2.1.4.RELEASE/spring-boot-autoconfigure-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-autoconfigure/2.1.4.RELEASE/spring-boot-autoconfigure-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-starter-freemarker:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-freemarker/2.1.4.RELEASE/spring-boot-starter-freemarker-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-freemarker/2.1.4.RELEASE/spring-boot-starter-freemarker-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-freemarker/2.1.4.RELEASE/spring-boot-starter-freemarker-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-starter-json:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-json/2.1.4.RELEASE/spring-boot-starter-json-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-json/2.1.4.RELEASE/spring-boot-starter-json-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-json/2.1.4.RELEASE/spring-boot-starter-json-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-starter-logging:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-logging/2.1.4.RELEASE/spring-boot-starter-logging-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-logging/2.1.4.RELEASE/spring-boot-starter-logging-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-logging/2.1.4.RELEASE/spring-boot-starter-logging-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-starter-tomcat:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-tomcat/2.1.4.RELEASE/spring-boot-starter-tomcat-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-tomcat/2.1.4.RELEASE/spring-boot-starter-tomcat-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-tomcat/2.1.4.RELEASE/spring-boot-starter-tomcat-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-starter-web:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-web/2.1.4.RELEASE/spring-boot-starter-web-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-web/2.1.4.RELEASE/spring-boot-starter-web-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter-web/2.1.4.RELEASE/spring-boot-starter-web-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot-starter:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter/2.1.4.RELEASE/spring-boot-starter-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter/2.1.4.RELEASE/spring-boot-starter-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot-starter/2.1.4.RELEASE/spring-boot-starter-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework.boot:spring-boot:2.1.4.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/boot/spring-boot/2.1.4.RELEASE/spring-boot-2.1.4.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-aop:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/5.1.6.RELEASE/spring-aop-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/5.1.6.RELEASE/spring-aop-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-aop/5.1.6.RELEASE/spring-aop-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-beans:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/5.1.6.RELEASE/spring-beans-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/5.1.6.RELEASE/spring-beans-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-beans/5.1.6.RELEASE/spring-beans-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-context-support:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context-support/5.1.6.RELEASE/spring-context-support-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context-support/5.1.6.RELEASE/spring-context-support-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context-support/5.1.6.RELEASE/spring-context-support-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-context:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/5.1.6.RELEASE/spring-context-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/5.1.6.RELEASE/spring-context-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-context/5.1.6.RELEASE/spring-context-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-core:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/5.1.6.RELEASE/spring-core-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/5.1.6.RELEASE/spring-core-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-core/5.1.6.RELEASE/spring-core-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-expression:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/5.1.6.RELEASE/spring-expression-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/5.1.6.RELEASE/spring-expression-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-expression/5.1.6.RELEASE/spring-expression-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-jcl:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-jcl/5.1.6.RELEASE/spring-jcl-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-jcl/5.1.6.RELEASE/spring-jcl-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-jcl/5.1.6.RELEASE/spring-jcl-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-web:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-web/5.1.6.RELEASE/spring-web-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-web/5.1.6.RELEASE/spring-web-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-web/5.1.6.RELEASE/spring-web-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.springframework:spring-webmvc:5.1.6.RELEASE">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-webmvc/5.1.6.RELEASE/spring-webmvc-5.1.6.RELEASE.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-webmvc/5.1.6.RELEASE/spring-webmvc-5.1.6.RELEASE-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/springframework/spring-webmvc/5.1.6.RELEASE/spring-webmvc-5.1.6.RELEASE-sources.jar!/" />
</SOURCES>
</library>
<library name="Maven: org.yaml:snakeyaml:1.23">
<CLASSES>
<root url="jar://$MAVEN_REPOSITORY$/org/yaml/snakeyaml/1.23/snakeyaml-1.23.jar!/" />
</CLASSES>
<JAVADOC>
<root url="jar://$MAVEN_REPOSITORY$/org/yaml/snakeyaml/1.23/snakeyaml-1.23-javadoc.jar!/" />
</JAVADOC>
<SOURCES>
<root url="jar://$MAVEN_REPOSITORY$/org/yaml/snakeyaml/1.23/snakeyaml-1.23-sources.jar!/" />
</SOURCES>
</library>
</component>
</project>

View File

@ -0,0 +1,321 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="bed47126-03b3-4370-a6c1-08503492974f" name="Default Changelist" comment="" />
<ignored path="$PROJECT_DIR$/out/" />
<ignored path="$PROJECT_DIR$/target/" />
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="DefaultGradleProjectSettings">
<option name="isMigrated" value="true" />
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/pom.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="506">
<caret line="23" column="18" selection-start-line="23" selection-start-column="18" selection-end-line="23" selection-end-column="18" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/api/controller/dto/BaseResult.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="264">
<caret line="34" selection-start-line="34" selection-end-line="34" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/ServerLauncher.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="396">
<caret line="49" column="41" selection-start-line="49" selection-start-column="41" selection-end-line="49" selection-end-column="41" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/src/main/resources/static/js/cim/cim.web.sdk.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="306">
<caret line="29" column="59" selection-start-line="29" selection-start-column="59" selection-end-line="29" selection-end-column="59" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>CIMWebBridge</find>
</findStrings>
<replaceStrings>
<replace>CIMPushManager</replace>
</replaceStrings>
<dirStrings>
<dir>C:\Users\Administrator\Documents\cim\cim-boot-server\src\main\resources</dir>
</dirStrings>
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/src/main/resources/static/js/cim/cim.web.sdk.js" />
</list>
</option>
</component>
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="260" />
<option name="y" value="20" />
<option name="width" value="1400" />
<option name="height" value="1000" />
</component>
<component name="ProjectView">
<navigator proportions="" version="1">
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="PackagesPane" />
<pane id="Scope" />
<pane id="ProjectPane">
<subPane>
<expand>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="java" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="java" type="462c0819:PsiDirectoryNode" />
<item name="cim" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="resources" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="resources" type="462c0819:PsiDirectoryNode" />
<item name="static" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="resources" type="462c0819:PsiDirectoryNode" />
<item name="static" type="462c0819:PsiDirectoryNode" />
<item name="js" type="462c0819:PsiDirectoryNode" />
</path>
<path>
<item name="cim-boot-server" type="b2602c69:ProjectViewProjectNode" />
<item name="cim-boot-server" type="462c0819:PsiDirectoryNode" />
<item name="src" type="462c0819:PsiDirectoryNode" />
<item name="main" type="462c0819:PsiDirectoryNode" />
<item name="resources" type="462c0819:PsiDirectoryNode" />
<item name="static" type="462c0819:PsiDirectoryNode" />
<item name="js" type="462c0819:PsiDirectoryNode" />
<item name="cim" type="462c0819:PsiDirectoryNode" />
</path>
</expand>
<select />
</subPane>
</pane>
</panes>
</component>
<component name="PropertiesComponent">
<property name="RequestMappingsPanelOrder0" value="0" />
<property name="RequestMappingsPanelOrder1" value="1" />
<property name="RequestMappingsPanelWidth0" value="75" />
<property name="RequestMappingsPanelWidth1" value="75" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="aspect.path.notification.shown" value="true" />
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="nodejs_interpreter_path.stuck_in_default_project" value="undefined stuck path" />
<property name="nodejs_npm_path_reset_for_default_project" value="true" />
<property name="settings.editor.selected.configurable" value="configurable.group.appearance" />
</component>
<component name="RecentsManager">
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\Users\Administrator\Documents\cim\cim-boot-server\cim-boot-server\cim-boot-server" />
<recent name="C:\Users\Administrator\Documents\cim\cim-boot-server\cim-boot-server\cim-boot-server\src" />
</key>
</component>
<component name="RunDashboard">
<option name="ruleStates">
<list>
<RuleState>
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
</RuleState>
<RuleState>
<option name="name" value="StatusDashboardGroupingRule" />
</RuleState>
</list>
</option>
</component>
<component name="RunManager">
<configuration name="ServerLauncher" type="SpringBootApplicationConfigurationType" factoryName="Spring Boot" temporary="true" nameIsGenerated="true">
<module name="cim-boot-server" />
<extension name="coverage">
<pattern>
<option name="PATTERN" value="com.farsunset.cim.*" />
<option name="ENABLED" value="true" />
</pattern>
</extension>
<option name="SPRING_BOOT_MAIN_CLASS" value="com.farsunset.cim.ServerLauncher" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<recent_temporary>
<list>
<item itemvalue="Spring Boot.ServerLauncher" />
</list>
</recent_temporary>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="bed47126-03b3-4370-a6c1-08503492974f" name="Default Changelist" comment="" />
<created>1557734989980</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1557734989980</updated>
<workItem from="1557734991214" duration="96000" />
<workItem from="1557735150926" duration="502000" />
<workItem from="1557738240090" duration="289000" />
<workItem from="1557740865016" duration="686000" />
</task>
<servers />
</component>
<component name="TimeTrackingManager">
<option name="totallyTimeSpent" value="1573000" />
</component>
<component name="ToolWindowManager">
<frame x="-8" y="-8" width="1936" height="1056" extended-state="6" />
<layout>
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.2553305" />
<window_info id="Structure" order="1" side_tool="true" weight="0.25" />
<window_info id="Designer" order="2" />
<window_info id="UI Designer" order="3" />
<window_info id="Favorites" order="4" side_tool="true" />
<window_info id="Web" order="5" side_tool="true" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info anchor="bottom" id="Run" order="2" weight="0.32936078" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="FindBugs-IDEA" order="7" />
<window_info anchor="bottom" id="Spring" order="8" />
<window_info anchor="bottom" id="Terminal" order="9" />
<window_info anchor="bottom" id="Docker" order="10" show_stripe_button="false" />
<window_info anchor="bottom" id="Event Log" order="11" side_tool="true" />
<window_info anchor="bottom" id="Messages" order="12" />
<window_info anchor="bottom" id="Java Enterprise" order="13" />
<window_info anchor="bottom" id="Database Changes" order="14" />
<window_info anchor="bottom" id="Version Control" order="15" />
<window_info anchor="right" id="Commander" internal_type="SLIDING" order="0" type="SLIDING" weight="0.4" />
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
<window_info anchor="right" id="Maven" order="3" />
<window_info anchor="right" id="Palette" order="4" />
<window_info anchor="right" id="Yobatis" order="5" />
<window_info anchor="right" id="Database" order="6" />
<window_info anchor="right" id="Palette&#9;" order="7" />
<window_info anchor="right" id="Bean Validation" order="8" />
</layout>
</component>
<component name="TypeScriptGeneratedFilesManager">
<option name="version" value="1" />
</component>
<component name="editorHistoryManager">
<entry file="file://$PROJECT_DIR$/pom.xml">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="506">
<caret line="23" column="18" selection-start-line="23" selection-start-column="18" selection-end-line="23" selection-end-column="18" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/api/controller/dto/BaseResult.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="264">
<caret line="34" selection-start-line="34" selection-end-line="34" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/main/java/com/farsunset/cim/ServerLauncher.java">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="396">
<caret line="49" column="41" selection-start-line="49" selection-start-column="41" selection-end-line="49" selection-end-column="41" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/src/main/resources/static/js/cim/cim.web.sdk.js">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="306">
<caret line="29" column="59" selection-start-line="29" selection-start-column="59" selection-end-line="29" selection-end-column="59" />
<folding>
<element signature="n#!!doc" expanded="true" />
</folding>
</state>
</provider>
</entry>
</component>
<component name="masterDetails">
<states>
<state key="ProjectJDKs.UI">
<settings>
<last-edited>1.8</last-edited>
<splitter-proportions>
<option name="proportions">
<list>
<option value="0.2" />
</list>
</option>
</splitter-proportions>
</settings>
</state>
</states>
</component>
</project>

140
cim-boot-server/pom.xml Normal file
View File

@ -0,0 +1,140 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.farsunset</groupId>
<artifactId>cim-boot-server</artifactId>
<version>1.0.0</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
<relativePath/>
</parent>
<properties>
<java.version>1.8</java.version>
<netty.version>4.1.35.Final</netty.version>
<mina.version>2.0.21</mina.version>
<protobuf.version>3.7.0</protobuf.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>com.farsunset</groupId>
<artifactId>cim-server-sdk</artifactId>
<version>3.7</version>
<scope>system</scope>
<!-- mina 、netty版本 sdk任选其一-->
<systemPath>${project.basedir}/lib/cim-server-sdk-mina-3.7.0.jar</systemPath>
</dependency>
<!--- ##################使用mina版本SDK时的配置 start ##################-->
<dependency>
<groupId>org.apache.mina</groupId>
<artifactId>mina-core</artifactId>
<version>${mina.version}</version>
</dependency>
<!--- ##################使用mina版本SDK时的配置 end ##################-->
<!--- ##################使用netty本SDK时的配置 start ##################-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-handler</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-buffer</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-common</artifactId>
<version>${netty.version}</version>
</dependency>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-transport</artifactId>
<version>${netty.version}</version>
</dependency>
<!--- ##################使用netty本SDK时的配置 end ##################-->
<dependency>
<groupId>com.google.protobuf</groupId>
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>cn.teaey.apns4j</groupId>
<artifactId>apns4j</artifactId>
<version>1.1.4</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<name>Spring Releases</name>
<url>https://repo.spring.io/release</url>
</repository>
</repositories>
</project>

View File

@ -6,6 +6,7 @@ import java.util.HashMap;
import javax.annotation.PostConstruct; import javax.annotation.PostConstruct;
import javax.annotation.Resource; import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
@ -16,6 +17,7 @@ import com.farsunset.cim.handler.SessionClosedHandler;
import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor; import com.farsunset.cim.sdk.server.handler.CIMNioSocketAcceptor;
import com.farsunset.cim.sdk.server.handler.CIMRequestHandler; import com.farsunset.cim.sdk.server.handler.CIMRequestHandler;
import com.farsunset.cim.sdk.server.model.SentBody; import com.farsunset.cim.sdk.server.model.SentBody;
import com.farsunset.cim.service.CIMSessionService;
import com.farsunset.cim.sdk.server.model.CIMSession; import com.farsunset.cim.sdk.server.model.CIMSession;
@Configuration @Configuration
@ -55,6 +57,17 @@ public class CIMConfig implements CIMRequestHandler {
return nioSocketAcceptor; return nioSocketAcceptor;
} }
/**
*
* @param memorySessionService 默认使用内存管理方案
* @return
*/
@Bean("cimSessionService")
public CIMSessionService getCIMSessionService(@Qualifier("memorySessionService") CIMSessionService cimSessionService) {
return cimSessionService;
}
@Override @Override
public void process(CIMSession session, SentBody body) { public void process(CIMSession session, SentBody body) {

View File

@ -21,12 +21,9 @@
*/ */
package com.farsunset.cim; package com.farsunset.cim;
import java.lang.reflect.Modifier;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration; import org.springframework.boot.autoconfigure.jmx.JmxAutoConfiguration;
@ -36,11 +33,6 @@ import org.springframework.boot.autoconfigure.webservices.WebServicesAutoConfigu
import org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration; import org.springframework.boot.autoconfigure.websocket.reactive.WebSocketReactiveAutoConfiguration;
import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration; import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketMessagingAutoConfiguration;
import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration; import org.springframework.boot.autoconfigure.websocket.servlet.WebSocketServletAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.http.converter.json.GsonHttpMessageConverter;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
/** /**
* *
@ -59,21 +51,7 @@ import com.google.gson.GsonBuilder;
JacksonAutoConfiguration.class }) JacksonAutoConfiguration.class })
public class ServerLauncher { public class ServerLauncher {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(ServerLauncher.class, args); SpringApplication.run(ServerLauncher.class, args);
} }
@Bean
@ConditionalOnMissingBean
public GsonHttpMessageConverter gsonHttpMessageConverter(Gson gson) {
GsonHttpMessageConverter converter = new GsonHttpMessageConverter();
gson = new GsonBuilder()
.excludeFieldsWithModifiers(Modifier.PROTECTED | Modifier.TRANSIENT | Modifier.FINAL | Modifier.STATIC)
.create();
converter.setGson(gson);
return converter;
}
} }

View File

@ -35,9 +35,9 @@ public class NavigationController {
return model; return model;
} }
@RequestMapping(value = "/webclient/main.action", method = RequestMethod.GET) @RequestMapping(value = "/webclient", method = RequestMethod.GET)
public ModelAndView webclient(ModelAndView model) { public ModelAndView webclient(ModelAndView model) {
model.setViewName("console/webclient/main"); model.setViewName("console/webclient/index");
return model; return model;
} }

View File

@ -34,11 +34,11 @@ import com.farsunset.cim.service.CIMSessionService;
public class SessionController { public class SessionController {
@Resource @Resource
private CIMSessionService memorySessionService; private CIMSessionService cimSessionService;
@RequestMapping(value = "/list.action") @RequestMapping(value = "/list")
public String list(Model model) { public String list(Model model) {
model.addAttribute("sessionList", memorySessionService.list()); model.addAttribute("sessionList", cimSessionService.list());
return "console/session/manage"; return "console/session/manage";
} }
} }

View File

@ -51,7 +51,7 @@ public class BindHandler implements CIMRequestHandler {
protected final Logger logger = LoggerFactory.getLogger(BindHandler.class); protected final Logger logger = LoggerFactory.getLogger(BindHandler.class);
@Resource @Resource
private CIMSessionService memorySessionService; private CIMSessionService cimSessionService;
@Value("${server.host}") @Value("${server.host}")
private String host; private String host;
@ -80,7 +80,7 @@ public class BindHandler implements CIMRequestHandler {
/* /*
* 由于客户端断线服务端可能会无法获知的情况客户端重连时需要关闭旧的连接 * 由于客户端断线服务端可能会无法获知的情况客户端重连时需要关闭旧的连接
*/ */
CIMSession oldSession = memorySessionService.get(account); CIMSession oldSession = cimSessionService.get(account);
/* /*
* 如果是账号已经在另一台终端登录则让另一个终端下线 * 如果是账号已经在另一台终端登录则让另一个终端下线
@ -100,7 +100,7 @@ public class BindHandler implements CIMRequestHandler {
closeQuietly(oldSession); closeQuietly(oldSession);
} }
memorySessionService.save(newSession); cimSessionService.save(newSession);
} catch (Exception e) { } catch (Exception e) {

View File

@ -48,7 +48,7 @@ public class SessionClosedHandler implements CIMRequestHandler {
protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class); protected final Logger logger = LoggerFactory.getLogger(SessionClosedHandler.class);
@Resource @Resource
private CIMSessionService memorySessionService; private CIMSessionService cimSessionService;
public void process(CIMSession ios, SentBody message) { public void process(CIMSession ios, SentBody message) {
Object quietly = ios.getAttribute(CIMConstant.KEY_QUIETLY_CLOSE); Object quietly = ios.getAttribute(CIMConstant.KEY_QUIETLY_CLOSE);
@ -61,7 +61,7 @@ public class SessionClosedHandler implements CIMRequestHandler {
return; return;
} }
CIMSession oldSession = memorySessionService.get(account.toString()); CIMSession oldSession = cimSessionService.get(account.toString());
if (oldSession == null || oldSession.isApnsOpend()) { if (oldSession == null || oldSession.isApnsOpend()) {
return; return;
@ -69,7 +69,7 @@ public class SessionClosedHandler implements CIMRequestHandler {
oldSession.setState(CIMSession.STATE_DISABLED); oldSession.setState(CIMSession.STATE_DISABLED);
oldSession.setNid(null); oldSession.setNid(null);
memorySessionService.save(oldSession); cimSessionService.save(oldSession);
} }
} }

View File

@ -44,7 +44,7 @@ public class DefaultMessagePusher implements CIMMessagePusher {
private String host; private String host;
@Resource @Resource
private CIMSessionService memorySessionService; private CIMSessionService cimSessionService;
@ -58,7 +58,7 @@ public class DefaultMessagePusher implements CIMMessagePusher {
* @param msg * @param msg
*/ */
public void push(Message message) { public void push(Message message) {
CIMSession session = memorySessionService.get(message.getReceiver()); CIMSession session = cimSessionService.get(message.getReceiver());
if(session == null) { if(session == null) {
return; return;

View File

@ -25,5 +25,5 @@ import com.farsunset.cim.sdk.server.model.Message;
public interface ApnsService { public interface ApnsService {
void push( Message message, String deviceToken); void push(Message message, String deviceToken);
} }

View File

@ -46,6 +46,7 @@ public class ClusterSessionServiceImpl implements CIMSessionService {
@Override @Override
public void save(CIMSession session) { public void save(CIMSession session) {
} }
@Override @Override

View File

@ -42,6 +42,10 @@ public class MemorySessionServiceImpl implements CIMSessionService {
@Override @Override
public void save(CIMSession session) { public void save(CIMSession session) {
if(session.getState() == CIMSession.STATE_DISABLED ) {
remove(session.getAccount());
return;
}
sessionMap.put(session.getAccount(), session); sessionMap.put(session.getAccount(), session);
} }

View File

@ -2,13 +2,13 @@
<div id="_main_nav" class="ui-vnav"> <div id="_main_nav" class="ui-vnav">
<ul class="ui-nav-inner"> <ul class="ui-nav-inner">
<li style="height: 50px;text-align: center;margin-top: 10px;"> <li style="height: 50px;text-align: center;margin-top: 10px;">
<a type="button" target="_blank" href="/webclient/main.action" class="btn btn-danger" > <a type="button" target="_blank" href="/webclient" class="btn btn-danger" >
<span class="glyphicon glyphicon-globe"></span> WEB版本 <span class="glyphicon glyphicon-globe"></span> WEB版本
</a> </a>
</li> </li>
<li style="border-bottom: 1px solid #D1D6DA;"></li> <li style="border-bottom: 1px solid #D1D6DA;"></li>
<li class="ui-item" id="sessionMenu"> <li class="ui-item" id="sessionMenu">
<a href="/console/session/list.action"> <a href="/console/session/list">
<img src="/image/icon/online.svg" style="margin-top:-2px;" width="24px" height="24px"/> <img src="/image/icon/online.svg" style="margin-top:-2px;" width="24px" height="24px"/>
<span class="ui-text"><@spring.message "module.console.menu.onlineuser"/></span> <span class="ui-text"><@spring.message "module.console.menu.onlineuser"/></span>
</a> </a>

View File

@ -65,7 +65,7 @@ function doSendMessage(){
<#list sessionList as cimsession> <#list sessionList as cimsession>
<tr style="height: 50px;"> <tr style="height: 50px;">
<td>${cimsession.account! }</td> <td>${cimsession.account! }</td>
<td>${cimsession.nid!}</td> <td><#if cimsession.nid??>${cimsession.nid}</#if></td>
<td>${cimsession.channel! }</td> <td>${cimsession.channel! }</td>
<td>${cimsession.deviceId! }</td> <td>${cimsession.deviceId! }</td>
<td>${cimsession.deviceModel! }</td> <td>${cimsession.deviceModel! }</td>

View File

@ -16,12 +16,13 @@
</head> </head>
<script type="text/javascript"> <script>
/***********************************推送配置开始**************************/
/** 当socket连接成功回调 **/ /** 当socket连接成功回调 **/
function onConnectionSuccessed(){ function onConnectionSuccessed(){
CIMWebBridge.bindAccount($('#account').val()); CIMPushManager.bindAccount($('#account').val());
} }
/** 当收到请求回复时候回调 **/ /** 当收到请求回复时候回调 **/
@ -60,6 +61,25 @@
$("#messageList").append("<div class='alert alert-info' >"+message.content+"</div>"); $("#messageList").append("<div class='alert alert-info' >"+message.content+"</div>");
} }
/***********************************推送配置结束**************************/
/***********************************业务配置开始**************************/
function doLogin(){
if($.trim($('#account').val()) =='' ){
return;
}
showProcess('正在接入请稍后......');
/**登录成功后创建连接****/
CIMPushManager.connection();
}
$(document).ready(function(){ $(document).ready(function(){
$('#LoginDialog').fadeIn(); $('#LoginDialog').fadeIn();
$('#LoginDialog').addClass("in"); $('#LoginDialog').addClass("in");
@ -93,12 +113,50 @@
} }
} }
/***********************************业务配置结束**************************/
</script> </script>
<body style="width: 600px;"> <body style="width: 600px;">
<#include "loginDialog.html">
<#include "messageDialog.html">
<div class="modal fade" id="LoginDialog" tabindex="-1" role="dialog" data-backdrop="static">
<div class="modal-dialog" style="width: 400px;margin: 64px auto;">
<div class="modal-content" >
<div class="modal-body" style="padding:0px;" >
<div style="height:200px;text-align: center; background: #5FA0D3; color: #ffffff; border: 0px; border-top-left-radius: 4px; border-top-right-radius: 4px;">
<img src="/image/icon.png" style="height: 72px;width: 72px;margin-top:40px;"/>
<div style="margin-top: 20px; color: #ffffff;font-size: 16px;">请输入一个帐号用于登录,随后接收推送消息</div>
</div>
<div class="input-group" style="margin-top: 30px;margin-left:10px;margin-right:10px;margin-bottom:30px;">
<span class="input-group-addon"><span class="glyphicon glyphicon-user" aria-hidden="true"></span></span>
<input type="text" class="form-control" id="account" maxlength="32" placeholder="帐号(数字或者英文字母)"
style="display: inline; width: 100%; height: 50px;" />
</div>
</div>
<div class="modal-footer" style="text-align: center;">
<a type="button" class="btn btn-success btn-lg" onclick="doLogin()"
style="width: 300px;">登录</a>
</div>
</div>
</div>
</div>
<!-- 消息提示页面 -->
<div class="modal fade" data-backdrop="static" id="MessageDialog" tabindex="-1" role="dialog" >
<div class="modal-dialog" style="width: 600px;margin: 30px auto;">
<div class="modal-content" >
<div class="modal-header" style="text-align: center;">
<span style="float: left;">请在管理页面推送一条消息</span>
<span style="float: right;color: #4caf50;">当前帐号:<span id="current_account"></span></span>
</div>
<div class="modal-body" id="messageList" style="min-height: 600px;" >
</div>
</div>
</div>
</div>
</body> </body>
</html> </html>

View File

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -1,9 +1,14 @@
var CIM_URI="ws://127.0.0.1:23456";// 修改为服务器的真实IP /*CIM服务器IP*/
var CIM_HOST = "127.0.0.1";
/*CIM服务端口*/
var CIM_PORT = 23456;
var CIM_URI="ws://"+CIM_HOST+":"+CIM_PORT;
var CMD_HEARTBEAT_RESPONSE = new Uint8Array([67,82]); var CMD_HEARTBEAT_RESPONSE = new Uint8Array([67,82]);
var SDK_VERSION = "1.0.0"; var SDK_VERSION = "1.0.0";
var SDK_CHANNEL = "browser"; var SDK_CHANNEL = "browser";
var APP_PACKAGE = "com.farsunset.cim"; var APP_PACKAGE = "com.farsunset.cim";
const ACTION_999 = "999";//特殊的消息类型,代表被服务端强制下线 var ACTION_999 = "999";//特殊的消息类型,代表被服务端强制下线
var DATA_HEADER_LENGTH = 3; var DATA_HEADER_LENGTH = 3;
var C_H_RS = 0; var C_H_RS = 0;
@ -14,18 +19,18 @@ var REPLYBODY = 4;
var socket; var socket;
var manualStop = false; var manualStop = false;
var CIMWebBridge = new Object(); var CIMPushManager = {};
CIMWebBridge.connection = function(){ CIMPushManager.connection = function(){
manualStop = false; manualStop = false;
window.localStorage.account = ''; window.localStorage.account = '';
socket = new WebSocket(CIM_URI); socket = new WebSocket(CIM_URI);
socket.binaryType = 'arraybuffer'; socket.binaryType = 'arraybuffer';
socket.onopen = CIMWebBridge.innerOnConnectionSuccessed; socket.onopen = CIMPushManager.innerOnConnectionSuccessed;
socket.onmessage = CIMWebBridge.innerOnMessageReceived; socket.onmessage = CIMPushManager.innerOnMessageReceived;
socket.onclose = CIMWebBridge.innerOnConnectionClosed; socket.onclose = CIMPushManager.innerOnConnectionClosed;
}; };
CIMWebBridge.bindAccount = function(account){ CIMPushManager.bindAccount = function(account){
window.localStorage.account = account; window.localStorage.account = account;
@ -45,32 +50,32 @@ CIMWebBridge.bindAccount = function(account){
body.getDataMap().set("packageName", APP_PACKAGE); body.getDataMap().set("packageName", APP_PACKAGE);
body.getDataMap().set("deviceId", deviceId); body.getDataMap().set("deviceId", deviceId);
body.getDataMap().set("device", browser.name); body.getDataMap().set("device", browser.name);
CIMWebBridge.sendRequest(body); CIMPushManager.sendRequest(body);
}; };
CIMWebBridge.stop = function(){ CIMPushManager.stop = function(){
manualStop = true; manualStop = true;
socket.close(); socket.close();
}; };
CIMWebBridge.resume = function(){ CIMPushManager.resume = function(){
manualStop = false; manualStop = false;
CIMWebBridge.connection(); CIMPushManager.connection();
}; };
CIMWebBridge.innerOnConnectionSuccessed = function(){ CIMPushManager.innerOnConnectionSuccessed = function(){
var account = window.localStorage.account; var account = window.localStorage.account;
if(account == '' || account == undefined){ if(account == '' || account == undefined){
onConnectionSuccessed(); onConnectionSuccessed();
}else{ }else{
CIMWebBridge.bindAccount(account); CIMPushManager.bindAccount(account);
} }
}; };
CIMWebBridge.innerOnMessageReceived = function(e){ CIMPushManager.innerOnMessageReceived = function(e){
var data = new Uint8Array(e.data); var data = new Uint8Array(e.data);
var type = data[0]; var type = data[0];
@ -79,7 +84,7 @@ CIMWebBridge.innerOnMessageReceived = function(e){
* 收到服务端发来的心跳请求立即回复响应否则服务端会在10秒后断开连接 * 收到服务端发来的心跳请求立即回复响应否则服务端会在10秒后断开连接
*/ */
if(type == S_H_RQ){ if(type == S_H_RQ){
CIMWebBridge.sendHeartbeatResponse(); CIMPushManager.sendHeartbeatResponse();
return; return;
} }
@ -114,16 +119,16 @@ CIMWebBridge.innerOnMessageReceived = function(e){
} }
}; };
CIMWebBridge.innerOnConnectionClosed = function(e){ CIMPushManager.innerOnConnectionClosed = function(e){
if(!manualStop){ if(!manualStop){
var time = Math.floor(Math.random()*(30-15+1)+15); var time = Math.floor(Math.random()*(30-15+1)+15);
setTimeout(function(){ setTimeout(function(){
CIMWebBridge.connection(); CIMPushManager.connection();
},time); },time);
} }
}; };
CIMWebBridge.sendRequest = function(body){ CIMPushManager.sendRequest = function(body){
var data = body.serializeBinary(); var data = body.serializeBinary();
var header = buildHeader(SENTBODY,data.length); var header = buildHeader(SENTBODY,data.length);
@ -133,7 +138,7 @@ CIMWebBridge.sendRequest = function(body){
socket.send(protubuf); socket.send(protubuf);
}; };
CIMWebBridge.sendHeartbeatResponse = function(){ CIMPushManager.sendHeartbeatResponse = function(){
var data = CMD_HEARTBEAT_RESPONSE; var data = CMD_HEARTBEAT_RESPONSE;
var header = buildHeader(C_H_RS,data.length); var header = buildHeader(C_H_RS,data.length);
var protubuf = new Uint8Array(data.length + header.length); var protubuf = new Uint8Array(data.length + header.length);

View File

@ -2,8 +2,6 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="libs/log4j-1.2.17.jar"/>
<classpathentry kind="lib" path="libs/mina-core-2.0.16.jar"/>
<classpathentry kind="lib" path="C:/Program Files/Android/android-sdk-windows/platforms/android-26/android.jar"/> <classpathentry kind="lib" path="C:/Program Files/Android/android-sdk-windows/platforms/android-26/android.jar"/>
<classpathentry kind="lib" path="libs/protobuf-java-3.7.0.jar"/> <classpathentry kind="lib" path="libs/protobuf-java-3.7.0.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>

View File

@ -0,0 +1,501 @@
/**
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************************
* *
* Website : http://www.farsunset.com *
* *
***************************************************************************************
*/
package com.farsunset.cim.sdk.android;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import com.farsunset.cim.sdk.android.coder.CIMLogger;
import com.farsunset.cim.sdk.android.coder.ClientMessageDecoder;
import com.farsunset.cim.sdk.android.coder.ClientMessageEncoder;
import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.exception.SessionClosedException;
import com.farsunset.cim.sdk.android.model.HeartbeatRequest;
import com.farsunset.cim.sdk.android.model.HeartbeatResponse;
import com.farsunset.cim.sdk.android.model.Message;
import com.farsunset.cim.sdk.android.model.ReplyBody;
import com.farsunset.cim.sdk.android.model.SentBody;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Handler;
import android.util.ArrayMap;
/**
* 连接服务端管理cim核心处理类管理连接以及消息处理
*
* @author 3979434@qq.com
*/
class CIMConnectorManager {
private final int READ_BUFFER_SIZE = 2048;
private final int WRITE_BUFFER_SIZE = 1024;
private final int READ_IDLE_TIME = 120 * 1000;//
private final int HEARBEAT_TIME_OUT = (READ_IDLE_TIME + 10) * 1000;// 收到服务端心跳请求超时时间 毫秒
private final String KEY_LAST_HEART_TIME = "KEY_LAST_HEART_TIME";
private Selector selector;
private SocketChannel socketChannel ;
private Context context;
private static CIMConnectorManager manager;
private CIMLogger logger = CIMLogger.getLogger();
private ByteBuffer readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
private ArrayMap<String, Object> attr = new ArrayMap<>();
private ExecutorService workerExecutor = Executors.newFixedThreadPool(1);
private ExecutorService bossExecutor = Executors.newFixedThreadPool(1);
private final AtomicBoolean CONNECTING_FLAG = new AtomicBoolean(false) ;
private ClientMessageEncoder messageEncoder = new ClientMessageEncoder();
private ClientMessageDecoder messageDecoder = new ClientMessageDecoder();
private CIMConnectorManager(Context ctx) {
context = ctx;
makeNioConnector();
}
private void makeNioConnector() {
try {
if(socketChannel == null || !socketChannel.isOpen()) {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.setOption(StandardSocketOptions.SO_RCVBUF,READ_BUFFER_SIZE);
socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, WRITE_BUFFER_SIZE);
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
socketChannel.setOption(StandardSocketOptions.TCP_NODELAY,true);
}
if(selector == null || !selector.isOpen()) {
selector = Selector.open();
}
selector.wakeup();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}catch(Exception e) {
}
}
public synchronized static CIMConnectorManager getManager(Context context) {
if (manager == null) {
manager = new CIMConnectorManager(context);
}
return manager;
}
public void connect(final String host, final int port) {
if (!isNetworkConnected(context)) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED);
context.sendBroadcast(intent);
return;
}
boolean isConnected = isConnected();
if (CONNECTING_FLAG.get() || isConnected) {
return;
}
CONNECTING_FLAG.set(true);
if(!socketChannel.isOpen() ||!selector.isOpen()) {
makeNioConnector();
}
bossExecutor.execute(new Runnable() {
@Override
public void run() {
final InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
logger.startConnect(remoteAddress);
CIMCacheManager.putBoolean(context, CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
try {
socketChannel.connect(remoteAddress);
}catch(Exception e){
closeSession();
return;
}
workerExecutor.execute(new Runnable() {
@Override
public void run() {
while (socketChannel.isOpen()) {
try {
selector.select();
for(SelectionKey key : selector.selectedKeys()){
if (key.isConnectable() && socketChannel.finishConnect()) {
handelConnectionEvent();
continue;
}
if (key.isReadable()) {
handelReadEvent();
}
}
} catch (Exception e) {
if(e instanceof ConnectException) {
handleConnectFailure(remoteAddress);
}else {
closeSession();
}
}
}
}
});
}
});
}
Handler idleHandler = new Handler() {
public void handleMessage(android.os.Message m) {
sessionIdle();
}
};
private void handelConnectionEvent() throws Exception {
CONNECTING_FLAG.set(false);
socketChannel.register(selector, SelectionKey.OP_READ);
sessionCreated();
idleHandler.sendEmptyMessageDelayed(0, READ_IDLE_TIME);
}
private void handelReadEvent() throws Exception {
idleHandler.removeCallbacksAndMessages(null);
idleHandler.sendEmptyMessageDelayed(0, READ_IDLE_TIME);
int result = 0;
while((result = socketChannel.read(readBuffer)) > 0) {
if(readBuffer.position() == readBuffer.capacity()) {
extemdByteBuffer();
}
}
if(result == -1) {
closeSession();
return;
}
readBuffer.position(0);
Object message = messageDecoder.doDecode(readBuffer);
if(message == null) {
return;
}
logger.messageReceived(socketChannel,message);
if(isRequest(message)) {
send(getResponse());
return;
}
this.messageReceived(message);
}
private void extemdByteBuffer() {
ByteBuffer newBuffer = ByteBuffer.allocate(readBuffer.capacity() + READ_BUFFER_SIZE / 2);
readBuffer.position(0);
newBuffer.put(readBuffer);
readBuffer.clear();
readBuffer = newBuffer;
}
private void handleConnectFailure(InetSocketAddress remoteAddress) {
CONNECTING_FLAG.set(false);
long interval = CIMConstant.RECONN_INTERVAL_TIME - (5 * 1000 - new Random().nextInt(15 * 1000));
logger.connectFailure(remoteAddress, interval);
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED);
intent.putExtra("interval", interval);
context.sendBroadcast(intent);
}
public void send(final SentBody body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
boolean isSuccessed = false;
String exceptionName = SessionClosedException.class.getSimpleName();
if (isConnected()) {
try {
ByteBuffer buffer = messageEncoder.encode(body);
int result = 0;
while(buffer.hasRemaining()){
result += socketChannel.write(buffer);
}
isSuccessed = result > 0;
} catch (IOException e) {
exceptionName = e.getClass().getSimpleName();
closeSession();
}
}
if (!isSuccessed) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_FAILED);
intent.putExtra(Exception.class.getName(), exceptionName);
intent.putExtra(SentBody.class.getName(), body);
context.sendBroadcast(intent);
}else {
messageSent(body);
}
}
});
}
public void send(final HeartbeatResponse body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
try {
socketChannel.write(messageEncoder.encode(body));
messageSent(body);
} catch (IOException e) {
closeSession();
}
}
});
}
public void sessionCreated() throws Exception {
logger.sessionCreated(socketChannel);
setLastHeartbeatTime();
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_SUCCESSED);
context.sendBroadcast(intent);
}
public void sessionClosed() {
readBuffer.clear();
if(readBuffer.capacity() > READ_BUFFER_SIZE) {
readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
}
attr.clear();
logger.sessionClosed(socketChannel);
closeSelector();
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED);
context.sendBroadcast(intent);
}
public void sessionIdle() {
logger.sessionIdle(socketChannel);
/**
* 用于解决wifi情况下偶而路由器与服务器断开连接时客户端并没及时收到关闭事件 导致这样的情况下当前连接无效也不会重连的问题
*
*/
long lastHeartbeatTime = getLastHeartbeatTime();
if (System.currentTimeMillis() - lastHeartbeatTime >= HEARBEAT_TIME_OUT) {
closeSession();
}
}
public void messageReceived(Object obj) {
if (obj instanceof Message) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED);
intent.putExtra(Message.class.getName(), (Message) obj);
context.sendBroadcast(intent);
}
if (obj instanceof ReplyBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED);
intent.putExtra(ReplyBody.class.getName(), (ReplyBody) obj);
context.sendBroadcast(intent);
}
}
public void messageSent(Object message) {
logger.messageSent(socketChannel, message);
if (message instanceof SentBody) {
Intent intent = new Intent();
intent.setPackage(context.getPackageName());
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_SUCCESSED);
intent.putExtra(SentBody.class.getName(), (SentBody) message);
context.sendBroadcast(intent);
}
}
private void setLastHeartbeatTime() {
attr.put(KEY_LAST_HEART_TIME, System.currentTimeMillis());
}
private long getLastHeartbeatTime() {
long time = 0;
Object value = attr.get(KEY_LAST_HEART_TIME);
if (value != null) {
time = Long.parseLong(value.toString());
}
return time;
}
public static boolean isNetworkConnected(Context context) {
try {
ConnectivityManager nw = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = nw.getActiveNetworkInfo();
return networkInfo != null;
} catch (Exception e) {
}
return false;
}
public HeartbeatResponse getResponse() {
return HeartbeatResponse.getInstance();
}
public boolean isRequest(Object data) {
setLastHeartbeatTime();
return data instanceof HeartbeatRequest;
}
public void destroy() {
closeSession();
closeSelector();
}
public boolean isConnected() {
return socketChannel != null && socketChannel.isConnected();
}
public void closeSession() {
try {
socketChannel.close();
} catch (IOException ignore) {
}finally {
this.sessionClosed();
}
}
public void closeSelector() {
if (selector != null) {
try {
selector.close();
} catch (IOException ignore) {
}
}
}
}

View File

@ -78,8 +78,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
*/ */
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED)) { if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED)) {
long interval = intent.getLongExtra("interval", CIMConstant.RECONN_INTERVAL_TIME); long interval = intent.getLongExtra("interval", CIMConstant.RECONN_INTERVAL_TIME);
String exceptionName = intent.getStringExtra(Exception.class.getName()); onConnectionFailed(interval);
onConnectionFailed(exceptionName, interval);
} }
/* /*
@ -149,7 +148,7 @@ public abstract class CIMEventBroadcastReceiver extends BroadcastReceiver {
onConnectionClosed(); onConnectionClosed();
} }
private void onConnectionFailed(String exceptionName, long reinterval) { private void onConnectionFailed(long reinterval) {
if (CIMConnectorManager.isNetworkConnected(context)) { if (CIMConnectorManager.isNetworkConnected(context)) {
onConnectionFailed(); onConnectionFailed();

View File

@ -38,8 +38,8 @@ import android.os.Message;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import com.farsunset.cim.sdk.android.coder.CIMLogger;
import com.farsunset.cim.sdk.android.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.filter.CIMLoggingFilter;
import com.farsunset.cim.sdk.android.model.SentBody; import com.farsunset.cim.sdk.android.model.SentBody;
/** /**
@ -140,7 +140,7 @@ public class CIMPushService extends Service {
if (CIMPushManager.ACTION_SET_LOGGER_EANABLE.equals(action)) { if (CIMPushManager.ACTION_SET_LOGGER_EANABLE.equals(action)) {
boolean enable = intent.getBooleanExtra(KEY_LOGGER_ENABLE, true); boolean enable = intent.getBooleanExtra(KEY_LOGGER_ENABLE, true);
CIMLoggingFilter.getLogger().debugMode(enable); CIMLogger.getLogger().debugMode(enable);
} }
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
@ -174,14 +174,14 @@ public class CIMPushService extends Service {
private void handleKeepAlive() { private void handleKeepAlive() {
if (manager.isConnected()) { if (manager.isConnected()) {
CIMLoggingFilter.getLogger().connectState(true); CIMLogger.getLogger().connectState(true);
return; return;
} }
boolean isManualStop = CIMCacheManager.getBoolean(getApplicationContext(), CIMCacheManager.KEY_MANUAL_STOP); boolean isManualStop = CIMCacheManager.getBoolean(getApplicationContext(), CIMCacheManager.KEY_MANUAL_STOP);
boolean isDestroyed = CIMCacheManager.getBoolean(getApplicationContext(), CIMCacheManager.KEY_CIM_DESTROYED); boolean isDestroyed = CIMCacheManager.getBoolean(getApplicationContext(), CIMCacheManager.KEY_CIM_DESTROYED);
CIMLoggingFilter.getLogger().connectState(false, isManualStop, isDestroyed); CIMLogger.getLogger().connectState(false, isManualStop, isDestroyed);
CIMPushManager.connect(this, 0); CIMPushManager.connect(this, 0);

View File

@ -19,14 +19,11 @@
* * * *
*************************************************************************************** ***************************************************************************************
*/ */
package com.farsunset.cim.sdk.android.filter; package com.farsunset.cim.sdk.android.coder;
import java.io.IOException;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.channels.SocketChannel;
import org.apache.mina.core.filterchain.IoFilterAdapter;
import org.apache.mina.core.session.IdleStatus;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.core.write.WriteRequest;
import android.util.Log; import android.util.Log;
@ -34,82 +31,59 @@ import android.util.Log;
/** /**
* 日志打印添加session 的id和ip address * 日志打印添加session 的id和ip address
*/ */
public class CIMLoggingFilter extends IoFilterAdapter { public class CIMLogger {
private final static String TAG = "CIM"; private final static String TAG = "CIM";
private boolean debug = true; private boolean debug = true;
public static CIMLoggingFilter getLogger() { public static CIMLogger getLogger() {
return LoggerHolder.logger; return LoggerHolder.logger;
} }
private CIMLoggingFilter() { private CIMLogger() {
} }
private static class LoggerHolder{ private static class LoggerHolder{
private static CIMLoggingFilter logger = new CIMLoggingFilter(); private static CIMLogger logger = new CIMLogger();
} }
public void debugMode(boolean mode) { public void debugMode(boolean mode) {
debug = mode; debug = mode;
} }
@Override public void messageReceived(SocketChannel session, Object message) {
public void exceptionCaught(NextFilter nextFilter, IoSession session, Throwable cause) {
if(debug) {
Log.d(TAG,String.format("EXCEPTION" + getSessionInfo(session) + "\n%s", cause.getClass().getName()));
}
session.closeOnFlush();
}
@Override
public void messageReceived(NextFilter nextFilter, IoSession session, Object message) {
if(debug) { if(debug) {
Log.i(TAG,String.format("RECEIVED" + getSessionInfo(session) + "\n%s", message)); Log.i(TAG,String.format("RECEIVED" + getSessionInfo(session) + "\n%s", message));
} }
nextFilter.messageReceived(session, message);
} }
@Override public void messageSent(SocketChannel session, Object message) {
public void messageSent(NextFilter nextFilter, IoSession session, WriteRequest writeRequest) {
if(debug) { if(debug) {
Log.i(TAG,String.format("SENT" + getSessionInfo(session) + "\n%s", writeRequest.getOriginalRequest().getMessage())); Log.i(TAG,String.format("SENT" + getSessionInfo(session) + "\n%s", message));
} }
nextFilter.messageSent(session, writeRequest);
} }
@Override public void sessionCreated( SocketChannel session) throws Exception {
public void sessionCreated(NextFilter nextFilter, IoSession session) throws Exception {
nextFilter.sessionCreated(session);
}
@Override
public void sessionOpened(NextFilter nextFilter, IoSession session) throws Exception {
if(debug) { if(debug) {
Log.i(TAG,"OPENED" + getSessionInfo(session)); Log.i(TAG,"OPENED" + getSessionInfo(session));
} }
nextFilter.sessionOpened(session);
} }
@Override public void sessionIdle( SocketChannel session) {
public void sessionIdle(NextFilter nextFilter, IoSession session, IdleStatus status) {
if(debug) { if(debug) {
Log.i(TAG,"IDLE " + status.toString().toUpperCase() + getSessionInfo(session)); Log.d(TAG,"IDLE READ" + getSessionInfo(session));
} }
nextFilter.sessionIdle(session, status);
} }
@Override public void sessionClosed( SocketChannel session) {
public void sessionClosed(NextFilter nextFilter, IoSession session) {
if(debug) { if(debug) {
Log.i(TAG,"CLOSED" + getSessionInfo(session)); Log.w(TAG,"CLOSED ID = " + session.hashCode());
} }
nextFilter.sessionClosed(session);
} }
public void connectFailure(InetSocketAddress remoteAddress,long interval) { public void connectFailure(InetSocketAddress remoteAddress,long interval) {
if(debug) { if(debug) {
Log.i(TAG,"CONNECT FAILURE TRY RECONNECT AFTER " + interval +"ms"); Log.d(TAG,"CONNECT FAILURE TRY RECONNECT AFTER " + interval +"ms");
} }
} }
@ -121,30 +95,36 @@ public class CIMLoggingFilter extends IoFilterAdapter {
public void connectState(boolean isConnected) { public void connectState(boolean isConnected) {
if(debug) { if(debug) {
Log.i(TAG,"CONNECTED:" + isConnected); Log.d(TAG,"CONNECTED:" + isConnected);
} }
} }
public void connectState(boolean isConnected,boolean isManualStop,boolean isDestroyed) { public void connectState(boolean isConnected,boolean isManualStop,boolean isDestroyed) {
if(debug) { if(debug) {
Log.i(TAG,"CONNECTED:" + isConnected + " STOPED:"+isManualStop+ " DESTROYED:"+isDestroyed); Log.d(TAG,"CONNECTED:" + isConnected + " STOPED:"+isManualStop+ " DESTROYED:"+isDestroyed);
} }
} }
private String getSessionInfo(IoSession session) { private String getSessionInfo(SocketChannel session) {
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
if (session == null) { if (session == null) {
return ""; return "";
} }
builder.append(" ["); builder.append(" [");
builder.append("id:").append(session.getId()); builder.append("id:").append(session.hashCode());
if (session.getLocalAddress() != null) { try {
builder.append(" L:").append(session.getLocalAddress().toString()); if (session.getLocalAddress() != null) {
builder.append(" L:").append(session.getLocalAddress().toString());
}
} catch (Exception ignore) {
} }
if (session.getRemoteAddress() != null) { try {
builder.append(" R:").append(session.getRemoteAddress().toString()); if (session.getRemoteAddress() != null) {
builder.append(" R:").append(session.getRemoteAddress().toString());
}
} catch (Exception ignore) {
} }
builder.append("]"); builder.append("]");
return builder.toString(); return builder.toString();

View File

@ -19,12 +19,11 @@
* * * *
*************************************************************************************** ***************************************************************************************
*/ */
package com.farsunset.cim.sdk.android.filter; package com.farsunset.cim.sdk.android.coder;
import java.nio.ByteBuffer;
import org.apache.mina.core.buffer.IoBuffer;
import org.apache.mina.core.session.IoSession;
import org.apache.mina.filter.codec.CumulativeProtocolDecoder;
import org.apache.mina.filter.codec.ProtocolDecoderOutput;
import com.farsunset.cim.sdk.android.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.HeartbeatRequest; import com.farsunset.cim.sdk.android.model.HeartbeatRequest;
@ -37,17 +36,16 @@ import com.google.protobuf.InvalidProtocolBufferException;
/** /**
* 客户端消息解码 * 客户端消息解码
*/ */
public class ClientMessageDecoder extends CumulativeProtocolDecoder { public class ClientMessageDecoder {
@Override public Object doDecode(ByteBuffer iobuffer) throws Exception {
public boolean doDecode(IoSession iosession, IoBuffer iobuffer, ProtocolDecoderOutput out) throws Exception {
/** /**
* 消息头3位 * 消息头3位
*/ */
if (iobuffer.remaining() < CIMConstant.DATA_HEADER_LENGTH) { if (iobuffer.remaining() < CIMConstant.DATA_HEADER_LENGTH) {
return false; return null;
} }
iobuffer.mark(); iobuffer.mark();
@ -62,18 +60,16 @@ public class ClientMessageDecoder extends CumulativeProtocolDecoder {
// 如果消息体没有接收完整则重置读取等待下一次重新读取 // 如果消息体没有接收完整则重置读取等待下一次重新读取
if (conetnLength > iobuffer.remaining()) { if (conetnLength > iobuffer.remaining()) {
iobuffer.reset(); iobuffer.reset();
return false; return null;
} }
byte[] dataBytes = new byte[conetnLength]; byte[] dataBytes = new byte[conetnLength];
iobuffer.get(dataBytes, 0, conetnLength); iobuffer.get(dataBytes, 0, conetnLength);
Object message = mappingMessageObject(dataBytes, conetnType); iobuffer.position(0);
if (message != null) {
out.write(message); return mappingMessageObject(dataBytes, conetnType);
}
return true;
} }
private Object mappingMessageObject(byte[] bytes, byte type) throws InvalidProtocolBufferException { private Object mappingMessageObject(byte[] bytes, byte type) throws InvalidProtocolBufferException {

View File

@ -19,29 +19,30 @@
* * * *
*************************************************************************************** ***************************************************************************************
*/ */
package com.farsunset.cim.sdk.android.filter; package com.farsunset.cim.sdk.android.coder;
import java.nio.ByteBuffer;
import com.farsunset.cim.sdk.android.constant.CIMConstant; import com.farsunset.cim.sdk.android.constant.CIMConstant;
import com.farsunset.cim.sdk.android.model.Protobufable; import com.farsunset.cim.sdk.android.model.Protobufable;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
/** /**
* 客户端消息发送前进行编码,可在此加密消息 * 客户端消息发送前进行编码
*
*/ */
public class ClientMessageEncoder extends MessageToByteEncoder<Protobufable> { public class ClientMessageEncoder {
@Override public ByteBuffer encode(Object object) {
protected void encode(ChannelHandlerContext ctx, Protobufable message, ByteBuf out) throws Exception {
Protobufable data = (Protobufable) message; Protobufable data = (Protobufable) object;
byte[] byteArray = data.getByteArray(); byte[] byteArray = data.getByteArray();
out.writeBytes(createHeader(data.getType(), byteArray.length)); ByteBuffer iobuffer = ByteBuffer.allocate(byteArray.length + CIMConstant.DATA_HEADER_LENGTH);
out.writeBytes(byteArray);
iobuffer.put(createHeader(data.getType(), byteArray.length));
iobuffer.put(byteArray);
iobuffer.flip();
return iobuffer;
} }

View File

@ -61,9 +61,6 @@ public interface CIMConstant {
String CLIENT_LOGOUT = "client_logout"; String CLIENT_LOGOUT = "client_logout";
@Deprecated
String CLIENT_PULL_MESSAGE = "client_pull_message";
} }
public static interface MessageAction { public static interface MessageAction {

View File

@ -2,10 +2,8 @@
<classpath> <classpath>
<classpathentry kind="src" path="src"/> <classpathentry kind="src" path="src"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="lib" path="libs/log4j.jar"/>
<classpathentry kind="lib" path="libs/slf4j-api-1.7.5.jar"/> <classpathentry kind="lib" path="libs/slf4j-api-1.7.5.jar"/>
<classpathentry kind="lib" path="libs/slf4j-nop-1.7.5.jar"/> <classpathentry kind="lib" path="libs/slf4j-nop-1.7.5.jar"/>
<classpathentry kind="lib" path="libs/mina-core-2.0.16.jar"/>
<classpathentry kind="lib" path="libs/protobuf-java-3.7.0.jar"/> <classpathentry kind="lib" path="libs/protobuf-java-3.7.0.jar"/>
<classpathentry kind="output" path="bin"/> <classpathentry kind="output" path="bin"/>
</classpath> </classpath>

View File

@ -0,0 +1,490 @@
/**
* Copyright 2013-2019 Xia Jun(3979434@qq.com).
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
***************************************************************************************
* *
* Website : http://www.farsunset.com *
* *
***************************************************************************************
*/
package com.farsunset.cim.sdk.client;
import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.StandardSocketOptions;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.HashMap;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import com.farsunset.cim.sdk.client.coder.CIMLogger;
import com.farsunset.cim.sdk.client.coder.ClientMessageDecoder;
import com.farsunset.cim.sdk.client.coder.ClientMessageEncoder;
import com.farsunset.cim.sdk.client.constant.CIMConstant;
import com.farsunset.cim.sdk.client.exception.SessionClosedException;
import com.farsunset.cim.sdk.client.model.HeartbeatRequest;
import com.farsunset.cim.sdk.client.model.HeartbeatResponse;
import com.farsunset.cim.sdk.client.model.Intent;
import com.farsunset.cim.sdk.client.model.Message;
import com.farsunset.cim.sdk.client.model.ReplyBody;
import com.farsunset.cim.sdk.client.model.SentBody;
/**
* 连接服务端管理cim核心处理类管理连接以及消息处理
*
* @author 3979434@qq.com
*/
class CIMConnectorManager {
private final int READ_BUFFER_SIZE = 2048;
private final int WRITE_BUFFER_SIZE = 1024;
private final int READ_IDLE_TIME = 120 * 1000;//
private final int HEARBEAT_TIME_OUT = (READ_IDLE_TIME + 10) * 1000;// 收到服务端心跳请求超时时间 毫秒
private final String KEY_LAST_HEART_TIME = "KEY_LAST_HEART_TIME";
private Selector selector;
private SocketChannel socketChannel ;
private static CIMConnectorManager manager;
private CIMLogger logger = CIMLogger.getLogger();
private ByteBuffer readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
private HashMap<String, Object> attr = new HashMap<>();
private ExecutorService eventExecutor = Executors.newFixedThreadPool(1);
private ExecutorService workerExecutor = Executors.newFixedThreadPool(1);
private ExecutorService bossExecutor = Executors.newFixedThreadPool(1);
private final AtomicBoolean CONNECTING_FLAG = new AtomicBoolean(false) ;
private ClientMessageEncoder messageEncoder = new ClientMessageEncoder();
private ClientMessageDecoder messageDecoder = new ClientMessageDecoder();
private Timer idleHandler = new Timer();;
private ReadIdleTask idleTask = new ReadIdleTask();;
private CIMConnectorManager() {
makeNioConnector();
}
private void makeNioConnector() {
try {
if(socketChannel == null || !socketChannel.isOpen()) {
socketChannel = SocketChannel.open();
socketChannel.configureBlocking(false);
socketChannel.setOption(StandardSocketOptions.SO_RCVBUF,READ_BUFFER_SIZE);
socketChannel.setOption(StandardSocketOptions.SO_SNDBUF, WRITE_BUFFER_SIZE);
socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
socketChannel.setOption(StandardSocketOptions.TCP_NODELAY,true);
}
if(selector == null || !selector.isOpen()) {
selector = Selector.open();
}
selector.wakeup();
socketChannel.register(selector, SelectionKey.OP_CONNECT);
}catch(Exception e) {
}
}
public synchronized static CIMConnectorManager getManager() {
if (manager == null) {
manager = new CIMConnectorManager();
}
return manager;
}
public void connect(final String host, final int port) {
if (CONNECTING_FLAG.get() || isConnected()) {
return;
}
CONNECTING_FLAG.set(true);
if(!socketChannel.isOpen() ||!selector.isOpen()) {
makeNioConnector();
}
bossExecutor.execute(new Runnable() {
@Override
public void run() {
final InetSocketAddress remoteAddress = new InetSocketAddress(host, port);
logger.startConnect(remoteAddress);
CIMCacheManager.getInstance().putBoolean(CIMCacheManager.KEY_CIM_CONNECTION_STATE, false);
try {
socketChannel.connect(remoteAddress);
}catch(Exception e) {
closeSession();
return;
}
workerExecutor.execute(new Runnable() {
@Override
public void run() {
while (socketChannel.isOpen()) {
try {
selector.select();
for(SelectionKey key : selector.selectedKeys()){
if (key.isConnectable() && socketChannel.finishConnect()) {
handelConnectionEvent();
continue;
}
if (key.isReadable()) {
handelReadEvent();
}
}
} catch (Exception e) {
if(e instanceof ConnectException) {
handleConnectFailure(remoteAddress);
}else {
closeSession();
}
}
}
}
});
}
});
}
private void handelConnectionEvent() throws Exception {
CONNECTING_FLAG.set(false);
socketChannel.register(selector, SelectionKey.OP_READ);
sessionCreated();
idleHandler.schedule(idleTask = new ReadIdleTask(), READ_IDLE_TIME);
}
private void handelReadEvent() throws Exception {
if(idleTask != null) {
idleTask.cancel();
}
idleHandler.schedule(idleTask = new ReadIdleTask(), READ_IDLE_TIME);
int result = 0;
while((result = socketChannel.read(readBuffer)) > 0) {
if(readBuffer.position() == readBuffer.capacity()) {
extemdByteBuffer();
}
}
if(result == -1) {
closeSession();
return;
}
readBuffer.position(0);
Object message = messageDecoder.doDecode(readBuffer);
if(message == null) {
return;
}
logger.messageReceived(socketChannel,message);
if(isRequest(message)) {
send(getResponse());
return;
}
this.messageReceived(message);
}
private void extemdByteBuffer() {
ByteBuffer newBuffer = ByteBuffer.allocate(readBuffer.capacity() + READ_BUFFER_SIZE / 2);
readBuffer.position(0);
newBuffer.put(readBuffer);
readBuffer.clear();
readBuffer = newBuffer;
}
private void handleConnectFailure(InetSocketAddress remoteAddress) {
CONNECTING_FLAG.set(false);
long interval = CIMConstant.RECONN_INTERVAL_TIME - (5 * 1000 - new Random().nextInt(15 * 1000));
logger.connectFailure(remoteAddress, interval);
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED);
intent.putExtra("interval", interval);
sendBroadcast(intent);
}
public void send(final SentBody body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
boolean isSuccessed = false;
String exceptionName = SessionClosedException.class.getSimpleName();
if (isConnected()) {
try {
ByteBuffer buffer = messageEncoder.encode(body);
int result = 0;
while(buffer.hasRemaining()){
result += socketChannel.write(buffer);
}
isSuccessed = result > 0;
} catch (IOException e) {
exceptionName = e.getClass().getSimpleName();
closeSession();
}
}
if (!isSuccessed) {
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_FAILED);
intent.putExtra(Exception.class.getName(), exceptionName);
intent.putExtra(SentBody.class.getName(), body);
sendBroadcast(intent);
}else {
messageSent(body);
}
}
});
}
public void send(final HeartbeatResponse body) {
bossExecutor.execute(new Runnable() {
@Override
public void run() {
try {
socketChannel.write(messageEncoder.encode(body));
messageSent(body);
} catch (IOException e) {
closeSession();
}
}
});
}
public void sessionCreated() throws Exception {
logger.sessionCreated(socketChannel);
setLastHeartbeatTime();
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_SUCCESSED);
sendBroadcast(intent);
}
public void sessionClosed() {
readBuffer.clear();
if(readBuffer.capacity() > READ_BUFFER_SIZE) {
readBuffer = ByteBuffer.allocate(READ_BUFFER_SIZE);
}
attr.clear();
logger.sessionClosed(socketChannel);
closeSelector();
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_CONNECTION_CLOSED);
sendBroadcast(intent);
}
public void sessionIdle() {
logger.sessionIdle(socketChannel);
/**
* 用于解决wifi情况下偶而路由器与服务器断开连接时客户端并没及时收到关闭事件 导致这样的情况下当前连接无效也不会重连的问题
*
*/
long lastHeartbeatTime = getLastHeartbeatTime();
if (System.currentTimeMillis() - lastHeartbeatTime >= HEARBEAT_TIME_OUT) {
closeSession();
}
}
public void messageReceived(Object obj) {
if (obj instanceof Message) {
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_MESSAGE_RECEIVED);
intent.putExtra(Message.class.getName(), (Message) obj);
sendBroadcast(intent);
}
if (obj instanceof ReplyBody) {
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_REPLY_RECEIVED);
intent.putExtra(ReplyBody.class.getName(), (ReplyBody) obj);
sendBroadcast(intent);
}
}
public void messageSent(Object message) {
logger.messageSent(socketChannel, message);
if (message instanceof SentBody) {
Intent intent = new Intent();
intent.setAction(CIMConstant.IntentAction.ACTION_SENT_SUCCESSED);
intent.putExtra(SentBody.class.getName(), (SentBody) message);
sendBroadcast(intent);
}
}
private void setLastHeartbeatTime() {
attr.put(KEY_LAST_HEART_TIME, System.currentTimeMillis());
}
private long getLastHeartbeatTime() {
long time = 0;
Object value = attr.get(KEY_LAST_HEART_TIME);
if (value != null) {
time = Long.parseLong(value.toString());
}
return time;
}
public HeartbeatResponse getResponse() {
return HeartbeatResponse.getInstance();
}
public boolean isRequest(Object data) {
setLastHeartbeatTime();
return data instanceof HeartbeatRequest;
}
public void destroy() {
closeSession();
closeSelector();
}
public boolean isConnected() {
return socketChannel != null && socketChannel.isConnected();
}
public void closeSession() {
try {
socketChannel.close();
} catch (IOException ignore) {
}finally {
this.sessionClosed();
}
}
public void closeSelector() {
if (selector != null) {
try {
selector.close();
} catch (IOException ignore) {
}
}
}
private void sendBroadcast(final Intent intent) {
eventExecutor.execute(new Runnable() {
@Override
public void run() {
CIMEventBroadcastReceiver.getInstance().onReceive(intent);
}
});
}
private class ReadIdleTask extends TimerTask{
@Override
public void run() {
sessionIdle();
}
}
}

View File

@ -26,7 +26,7 @@ import java.util.Timer;
import java.util.TimerTask; import java.util.TimerTask;
import com.farsunset.cim.sdk.client.constant.CIMConstant; import com.farsunset.cim.sdk.client.constant.CIMConstant;
import com.farsunset.cim.sdk.client.exception.SessionDisconnectedException; import com.farsunset.cim.sdk.client.exception.SessionClosedException;
import com.farsunset.cim.sdk.client.model.Intent; import com.farsunset.cim.sdk.client.model.Intent;
import com.farsunset.cim.sdk.client.model.Message; import com.farsunset.cim.sdk.client.model.Message;
import com.farsunset.cim.sdk.client.model.ReplyBody; import com.farsunset.cim.sdk.client.model.ReplyBody;
@ -66,7 +66,7 @@ public class CIMEventBroadcastReceiver {
*/ */
if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED)) { if (intent.getAction().equals(CIMConstant.IntentAction.ACTION_CONNECTION_FAILED)) {
long interval = intent.getLongExtra("interval", CIMConstant.RECONN_INTERVAL_TIME); long interval = intent.getLongExtra("interval", CIMConstant.RECONN_INTERVAL_TIME);
onInnerConnectionFailed((Exception) intent.getExtra(Exception.class.getName()), interval); onInnerConnectionFailed(interval);
} }
/* /*
@ -129,11 +129,11 @@ public class CIMEventBroadcastReceiver {
} }
private void onInnerConnectionFailed(Exception e, long interval) { private void onInnerConnectionFailed(long interval) {
connectionHandler.schedule(new ConnectionTask(), interval); connectionHandler.schedule(new ConnectionTask(), interval);
listener.onConnectionFailed(e); listener.onConnectionFailed();
} }
private void onInnerConnectionSuccessed() { private void onInnerConnectionSuccessed() {
@ -163,7 +163,7 @@ public class CIMEventBroadcastReceiver {
e.printStackTrace(); e.printStackTrace();
// 与服务端端开链接重新连接 // 与服务端端开链接重新连接
if (e instanceof SessionDisconnectedException) { if (e instanceof SessionClosedException) {
CIMPushManager.connect(); CIMPushManager.connect();
} else { } else {
// 发送失败 重新发送 // 发送失败 重新发送

View File

@ -60,7 +60,7 @@ public interface CIMEventListener {
* 当服务器连接失败的时候回调 * 当服务器连接失败的时候回调
* *
*/ */
void onConnectionFailed(Exception e); void onConnectionFailed();
/** /**
* 监听器在容器里面的排序值越大则越先接收 * 监听器在容器里面的排序值越大则越先接收

View File

@ -38,7 +38,7 @@ public class CIMListenerManager {
private static ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>(); private static ArrayList<CIMEventListener> cimListeners = new ArrayList<CIMEventListener>();
private static CIMMessageReceiveComparator comparator = new CIMMessageReceiveComparator(); private static CIMMessageReceiveComparator comparator = new CIMMessageReceiveComparator();
protected static final Logger logger = LoggerFactory.getLogger(CIMListenerManager.class); private static final Logger LOGGER = LoggerFactory.getLogger(CIMListenerManager.class);
public static void registerMessageListener(CIMEventListener listener) { public static void registerMessageListener(CIMEventListener listener) {
@ -80,9 +80,9 @@ public class CIMListenerManager {
} }
} }
public static void notifyOnConnectionFailed(Exception e) { public static void notifyOnConnectionFailed() {
for (CIMEventListener listener : cimListeners) { for (CIMEventListener listener : cimListeners) {
listener.onConnectionFailed(e); listener.onConnectionFailed();
} }
} }
@ -92,7 +92,7 @@ public class CIMListenerManager {
public static void logListenersName() { public static void logListenersName() {
for (CIMEventListener listener : cimListeners) { for (CIMEventListener listener : cimListeners) {
logger.debug("#######" + listener.getClass().getName() + "#######"); LOGGER.debug("#######" + listener.getClass().getName() + "#######");
} }
} }

Some files were not shown because too many files have changed in this diff Show More