[
  {
    "path": ".gitignore",
    "content": "*.class\n\n# Package Files #\n*.jar\n*.war\n*.ear\n.svn\n/target\n*.svn-base\n.myeclipse/\n.idea/\nJgFramework.iml\n"
  },
  {
    "path": "LICENSE",
    "content": "Apache License\n                           Version 2.0, January 2004\n                        http://www.apache.org/licenses/\n\n   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n   1. Definitions.\n\n      \"License\" shall mean the terms and conditions for use, reproduction,\n      and distribution as defined by Sections 1 through 9 of this document.\n\n      \"Licensor\" shall mean the copyright owner or entity authorized by\n      the copyright owner that is granting the License.\n\n      \"Legal Entity\" shall mean the union of the acting entity and all\n      other entities that control, are controlled by, or are under common\n      control with that entity. For the purposes of this definition,\n      \"control\" means (i) the power, direct or indirect, to cause the\n      direction or management of such entity, whether by contract or\n      otherwise, or (ii) ownership of fifty percent (50%) or more of the\n      outstanding shares, or (iii) beneficial ownership of such entity.\n\n      \"You\" (or \"Your\") shall mean an individual or Legal Entity\n      exercising permissions granted by this License.\n\n      \"Source\" form shall mean the preferred form for making modifications,\n      including but not limited to software source code, documentation\n      source, and configuration files.\n\n      \"Object\" form shall mean any form resulting from mechanical\n      transformation or translation of a Source form, including but\n      not limited to compiled object code, generated documentation,\n      and conversions to other media types.\n\n      \"Work\" shall mean the work of authorship, whether in Source or\n      Object form, made available under the License, as indicated by a\n      copyright notice that is included in or attached to the work\n      (an example is provided in the Appendix below).\n\n      \"Derivative Works\" shall mean any work, whether in Source or Object\n      form, that is based on (or derived from) the Work and for which the\n      editorial revisions, annotations, elaborations, or other modifications\n      represent, as a whole, an original work of authorship. For the purposes\n      of this License, Derivative Works shall not include works that remain\n      separable from, or merely link (or bind by name) to the interfaces of,\n      the Work and Derivative Works thereof.\n\n      \"Contribution\" shall mean any work of authorship, including\n      the original version of the Work and any modifications or additions\n      to that Work or Derivative Works thereof, that is intentionally\n      submitted to Licensor for inclusion in the Work by the copyright owner\n      or by an individual or Legal Entity authorized to submit on behalf of\n      the copyright owner. For the purposes of this definition, \"submitted\"\n      means any form of electronic, verbal, or written communication sent\n      to the Licensor or its representatives, including but not limited to\n      communication on electronic mailing lists, source code control systems,\n      and issue tracking systems that are managed by, or on behalf of, the\n      Licensor for the purpose of discussing and improving the Work, but\n      excluding communication that is conspicuously marked or otherwise\n      designated in writing by the copyright owner as \"Not a Contribution.\"\n\n      \"Contributor\" shall mean Licensor and any individual or Legal Entity\n      on behalf of whom a Contribution has been received by Licensor and\n      subsequently incorporated within the Work.\n\n   2. Grant of Copyright License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      copyright license to reproduce, prepare Derivative Works of,\n      publicly display, publicly perform, sublicense, and distribute the\n      Work and such Derivative Works in Source or Object form.\n\n   3. Grant of Patent License. Subject to the terms and conditions of\n      this License, each Contributor hereby grants to You a perpetual,\n      worldwide, non-exclusive, no-charge, royalty-free, irrevocable\n      (except as stated in this section) patent license to make, have made,\n      use, offer to sell, sell, import, and otherwise transfer the Work,\n      where such license applies only to those patent claims licensable\n      by such Contributor that are necessarily infringed by their\n      Contribution(s) alone or by combination of their Contribution(s)\n      with the Work to which such Contribution(s) was submitted. If You\n      institute patent litigation against any entity (including a\n      cross-claim or counterclaim in a lawsuit) alleging that the Work\n      or a Contribution incorporated within the Work constitutes direct\n      or contributory patent infringement, then any patent licenses\n      granted to You under this License for that Work shall terminate\n      as of the date such litigation is filed.\n\n   4. Redistribution. You may reproduce and distribute copies of the\n      Work or Derivative Works thereof in any medium, with or without\n      modifications, and in Source or Object form, provided that You\n      meet the following conditions:\n\n      (a) You must give any other recipients of the Work or\n          Derivative Works a copy of this License; and\n\n      (b) You must cause any modified files to carry prominent notices\n          stating that You changed the files; and\n\n      (c) You must retain, in the Source form of any Derivative Works\n          that You distribute, all copyright, patent, trademark, and\n          attribution notices from the Source form of the Work,\n          excluding those notices that do not pertain to any part of\n          the Derivative Works; and\n\n      (d) If the Work includes a \"NOTICE\" text file as part of its\n          distribution, then any Derivative Works that You distribute must\n          include a readable copy of the attribution notices contained\n          within such NOTICE file, excluding those notices that do not\n          pertain to any part of the Derivative Works, in at least one\n          of the following places: within a NOTICE text file distributed\n          as part of the Derivative Works; within the Source form or\n          documentation, if provided along with the Derivative Works; or,\n          within a display generated by the Derivative Works, if and\n          wherever such third-party notices normally appear. The contents\n          of the NOTICE file are for informational purposes only and\n          do not modify the License. You may add Your own attribution\n          notices within Derivative Works that You distribute, alongside\n          or as an addendum to the NOTICE text from the Work, provided\n          that such additional attribution notices cannot be construed\n          as modifying the License.\n\n      You may add Your own copyright statement to Your modifications and\n      may provide additional or different license terms and conditions\n      for use, reproduction, or distribution of Your modifications, or\n      for any such Derivative Works as a whole, provided Your use,\n      reproduction, and distribution of the Work otherwise complies with\n      the conditions stated in this License.\n\n   5. Submission of Contributions. Unless You explicitly state otherwise,\n      any Contribution intentionally submitted for inclusion in the Work\n      by You to the Licensor shall be under the terms and conditions of\n      this License, without any additional terms or conditions.\n      Notwithstanding the above, nothing herein shall supersede or modify\n      the terms of any separate license agreement you may have executed\n      with Licensor regarding such Contributions.\n\n   6. Trademarks. This License does not grant permission to use the trade\n      names, trademarks, service marks, or product names of the Licensor,\n      except as required for reasonable and customary use in describing the\n      origin of the Work and reproducing the content of the NOTICE file.\n\n   7. Disclaimer of Warranty. Unless required by applicable law or\n      agreed to in writing, Licensor provides the Work (and each\n      Contributor provides its Contributions) on an \"AS IS\" BASIS,\n      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or\n      implied, including, without limitation, any warranties or conditions\n      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A\n      PARTICULAR PURPOSE. You are solely responsible for determining the\n      appropriateness of using or redistributing the Work and assume any\n      risks associated with Your exercise of permissions under this License.\n\n   8. Limitation of Liability. In no event and under no legal theory,\n      whether in tort (including negligence), contract, or otherwise,\n      unless required by applicable law (such as deliberate and grossly\n      negligent acts) or agreed to in writing, shall any Contributor be\n      liable to You for damages, including any direct, indirect, special,\n      incidental, or consequential damages of any character arising as a\n      result of this License or out of the use or inability to use the\n      Work (including but not limited to damages for loss of goodwill,\n      work stoppage, computer failure or malfunction, or any and all\n      other commercial damages or losses), even if such Contributor\n      has been advised of the possibility of such damages.\n\n   9. Accepting Warranty or Additional Liability. While redistributing\n      the Work or Derivative Works thereof, You may choose to offer,\n      and charge a fee for, acceptance of support, warranty, indemnity,\n      or other liability obligations and/or rights consistent with this\n      License. However, in accepting such obligations, You may act only\n      on Your own behalf and on Your sole responsibility, not on behalf\n      of any other Contributor, and only if You agree to indemnify,\n      defend, and hold each Contributor harmless for any liability\n      incurred by, or claims asserted against, such Contributor by reason\n      of your accepting any such warranty or additional liability.\n\n   END OF TERMS AND CONDITIONS\n\n   APPENDIX: How to apply the Apache License to your work.\n\n      To apply the Apache License to your work, attach the following\n      boilerplate notice, with the fields enclosed by brackets \"{}\"\n      replaced with your own identifying information. (Don't include\n      the brackets!)  The text should be enclosed in the appropriate\n      comment syntax for the file format. We also recommend that a\n      file or class name and description of purpose be included on the\n      same \"printed page\" as the copyright notice for easier\n      identification within third-party archives.\n\n   Copyright {yyyy} {name of copyright owner}\n\n   Licensed under the Apache License, Version 2.0 (the \"License\");\n   you may not use this file except in compliance with the License.\n   You may obtain a copy of the License at\n\n       http://www.apache.org/licenses/LICENSE-2.0\n\n   Unless required by applicable law or agreed to in writing, software\n   distributed under the License is distributed on an \"AS IS\" BASIS,\n   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n   See the License for the specific language governing permissions and\n   limitations under the License.\n\n"
  },
  {
    "path": "README.md",
    "content": "JgFramework\n===========\n\n基于Netty的强大的游戏服务器框架\n\n特点\n===\n~~~\n1、使用netty作为底层，性能得到保障\n2、支持socket和websocket2种连接模式，可以自由选择\n3、简单实用的路由，方便handler开发\n4、异步无锁的数据同步\n5、spring+Hibernia的自动注入和事务管理\n6、mysql数据库的读写分离以及对多数据库的读写支持\n7、传输数据的多样化，可以自用实现接口来实现不同的传输数据类型，现在使用的是json\n8、框架自带了认证服务和管理服务，有简单的管理命令，需要telnet连接到端口（默认38080）\n9、方便的ip段限制功能\n10、方便设置心跳检查\n11、登录方和服务端之间的认证，可通过实际接口来完成，默认使用的rsa加密传输认证码\n12、性能优良的排队系统\n13、丰富的工具类：memcache、redis等\n14、基本游戏模块的抽象\n~~~\n\n性能测试\n======\n##### *测试信息*\n~~~\ncpu : AMD A10\n内存 : 8G\n测试项目 : https://github.com/bupt1987/JgWeb   \n测试脚本 : src/test/java/client/TestWebSocket.java\n测试方式 : 自压\n~~~\n##### *测试结果*\n~~~\n在100个登录用户，每个用户在登录完成，再init操作之后，每个用户发送100000个请求，   \n得到每秒处理请求数在3.5W左右。\n~~~\n\n欢迎加入\n======\n如果对该系统有兴趣可以发邮件至 bupt1987@gmail.com 一起探讨，欢迎加入\n\n\n例子\n===\n见：https://github.com/bupt1987/JgWeb\n"
  },
  {
    "path": "default_applicationContext.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<beans xmlns=\"http://www.springframework.org/schema/beans\"\n\txmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:p=\"http://www.springframework.org/schema/p\"\n\txmlns:aop=\"http://www.springframework.org/schema/aop\" xmlns:tx=\"http://www.springframework.org/schema/tx\"\n\txmlns:context=\"http://www.springframework.org/schema/context\"\n\txsi:schemaLocation=\"http://www.springframework.org/schema/beans \n\t\t\thttp://www.springframework.org/schema/beans/spring-beans-3.1.xsd\n\t\t\thttp://www.springframework.org/schema/tx \n         \thttp://www.springframework.org/schema/tx/spring-tx-3.1.xsd\n          \thttp://www.springframework.org/schema/context \n          \thttp://www.springframework.org/schema/context/spring-context-3.1.xsd \n          \thttp://www.springframework.org/schema/aop \n          \thttp://www.springframework.org/schema/aop/spring-aop-3.1.xsd\">\n          \t\n    <!-- 注解 -->\n\t<context:annotation-config/>\n\t<!-- 扫描包 -->\n\t<context:component-scan base-package=\"com.zhaidaosi.game.server.sdm\"/>\n\t<!-- 代理 -->\n\t<aop:aspectj-autoproxy/>\n\t\n\t<context:property-placeholder location=\"classpath*:jdbc.properties\" />\n\n\t<!-- bonecp连接池配置 -->\n\t<bean id=\"parentDataSource\" class=\"com.jolbox.bonecp.BoneCPDataSource\" destroy-method=\"close\"/>\n\n\n\t<!-- jgframework 主数据源-->  \n    <bean id=\"jgframeworkMasterDataSource\" parent=\"parentDataSource\">\n        <property name=\"driverClass\" value=\"${jgframework.master.jdbc.driverClassName}\" />  \n        <property name=\"jdbcUrl\" value=\"${jgframework.master.jdbc.url}\" />  \n        <property name=\"username\" value=\"${jgframework.master.jdbc.username}\" />  \n        <property name=\"password\" value=\"${jgframework.master.jdbc.password}\" />\n        <property name=\"partitionCount\" value=\"${jgframework.master.jdbc.partitionCount}\"/>\n\t\t<property name=\"maxConnectionsPerPartition\" value=\"${jgframework.master.jdbc.maxConnectionsPerPartition}\"/>\n\t\t<property name=\"minConnectionsPerPartition\" value=\"${jgframework.master.jdbc.minConnectionsPerPartition}\"/>\n\t\t<property name=\"poolName\" value=\"jgframework-master-pool\"/>\n\t\t<property name=\"lazyInit\" value=\"true\"/>\n    </bean>\n    <!-- jgframework 从数据源-->  \n    <bean id=\"jgframeworkSlaveDataSource\" parent=\"parentDataSource\">  \n        <property name=\"driverClass\" value=\"${jgframework.slave.jdbc.driverClassName}\" />  \n        <property name=\"jdbcUrl\" value=\"${jgframework.slave.jdbc.url}\" />  \n        <property name=\"username\" value=\"${jgframework.slave.jdbc.username}\" />  \n        <property name=\"password\" value=\"${jgframework.slave.jdbc.password}\"/>\n        <property name=\"partitionCount\" value=\"${jgframework.slave.jdbc.partitionCount}\"/>\n\t\t<property name=\"maxConnectionsPerPartition\" value=\"${jgframework.slave.jdbc.maxConnectionsPerPartition}\"/>\n\t\t<property name=\"minConnectionsPerPartition\" value=\"${jgframework.slave.jdbc.minConnectionsPerPartition}\"/> \n\t\t<property name=\"poolName\" value=\"jgframework-slave-pool\"/>\n    </bean>\t\n    \n    <!-- cronweb 主数据源-->  \n    <bean id=\"cronwebMasterDataSource\" parent=\"parentDataSource\">\n        <property name=\"driverClass\" value=\"${cronweb.master.jdbc.driverClassName}\" />  \n        <property name=\"jdbcUrl\" value=\"${cronweb.master.jdbc.url}\" />  \n        <property name=\"username\" value=\"${cronweb.master.jdbc.username}\" />  \n        <property name=\"password\" value=\"${cronweb.master.jdbc.password}\" />\n        <property name=\"partitionCount\" value=\"${cronweb.master.jdbc.partitionCount}\"/>\n\t\t<property name=\"maxConnectionsPerPartition\" value=\"${cronweb.master.jdbc.maxConnectionsPerPartition}\"/>\n\t\t<property name=\"minConnectionsPerPartition\" value=\"${cronweb.master.jdbc.minConnectionsPerPartition}\"/>\n\t\t<property name=\"poolName\" value=\"cronweb-master-pool\"/>\n\t\t<property name=\"lazyInit\" value=\"true\"/>\n    </bean> \n    <!-- cronweb 从数据源-->  \n    <bean id=\"cronwebSlaveDataSource\" parent=\"parentDataSource\">  \n        <property name=\"driverClass\" value=\"${cronweb.slave.jdbc.driverClassName}\" />  \n        <property name=\"jdbcUrl\" value=\"${cronweb.slave.jdbc.url}\" />  \n        <property name=\"username\" value=\"${cronweb.slave.jdbc.username}\" />  \n        <property name=\"password\" value=\"${cronweb.slave.jdbc.password}\"/>\n        <property name=\"partitionCount\" value=\"${cronweb.slave.jdbc.partitionCount}\"/>\n\t\t<property name=\"maxConnectionsPerPartition\" value=\"${cronweb.slave.jdbc.maxConnectionsPerPartition}\"/>\n\t\t<property name=\"minConnectionsPerPartition\" value=\"${cronweb.slave.jdbc.minConnectionsPerPartition}\"/> \n\t\t<property name=\"poolName\" value=\"cronweb-slave-pool\"/>\n    </bean>\n\n\t<bean id=\"dataSource\" class=\"com.zhaidaosi.game.jgframework.common.spring.DynamicDataSource\">  \n        <property name=\"targetDataSources\">  \n            <map key-type=\"java.lang.String\">  \n                <entry key=\"cronweb-master\" value-ref=\"cronwebMasterDataSource\" />\n                <entry key=\"cronweb-slave\" value-ref=\"cronwebSlaveDataSource\" /> \n                <entry key=\"jgframework-master\" value-ref=\"jgframeworkMasterDataSource\" />\n                <entry key=\"jgframework-slave\" value-ref=\"jgframeworkSlaveDataSource\" /> \n            </map>  \n        </property>  \n        <property name=\"defaultTargetDataSource\" ref=\"jgframeworkSlaveDataSource\" />  \n        <property name=\"defaultDatabase\" value=\"jgframework\"/>\n    </bean> \n    \n\t\n\t<!-- 自己定义的扫描模型类 -->\n\t<bean id=\"sessionFactory\" class=\"com.zhaidaosi.game.jgframework.common.spring.AnnotationSessionFactoryBeanEx\">\n\t\t<property name=\"dataSource\" ref=\"dataSource\"/>\n\t\t<property name=\"hibernateProperties\">\n\t\t\t<props>\n\t\t\t\t<prop key=\"hibernate.dialect\">org.hibernate.dialect.MySQLInnoDBDialect</prop>\n\t\t\t\t<prop key=\"hibernate.show_sql\">false</prop>\n    \t\t\t<prop key=\"hibernate.hbm2ddl.auto\">none</prop><!-- update -->\n\t\t\t</props>\n\t\t</property>\n\t\t<property name=\"annotatedClassesLocations\">  \n            <list>  \n                <value>classpath*:com/zhaidaosi/game/server/sdm/model/*.class</value>  \n            </list>  \n        </property>\n\t</bean>\n\n\t<bean id=\"hibernateTemplate\" class=\"org.springframework.orm.hibernate3.HibernateTemplate\">\n\t\t<property name=\"sessionFactory\">\n\t\t\t<ref bean=\"sessionFactory\" />\n\t\t</property>\n\t</bean>\n\n\t<!-- 定义事务管理器 -->\n\t<bean id=\"txManager\"\n\t\tclass=\"org.springframework.orm.hibernate3.HibernateTransactionManager\">\n\t\t<property name=\"sessionFactory\" ref=\"sessionFactory\" />\n\t</bean>\n\n\t<!-- 加载事务驱动 -->\n\t<tx:annotation-driven transaction-manager=\"txManager\"/>\n\t<tx:advice id=\"txAdvice\" transaction-manager=\"txManager\">\n\t\t<tx:attributes>\n\t\t\t<tx:method name=\"total*\" read-only=\"true\" propagation=\"SUPPORTS\"/>\n\t\t\t<tx:method name=\"find*\" read-only=\"true\" propagation=\"SUPPORTS\"/>\n\t\t\t<tx:method name=\"save*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"add*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"delete*\" propagation=\"REQUIRED\" />\n\t\t\t<tx:method name=\"update*\" propagation=\"REQUIRED\" />\n\t\t</tx:attributes>\n\t</tx:advice>\n\t\n\t<!-- 切换数据库 -->\n\t<bean id=\"dataSourceAdvice\" class=\"com.zhaidaosi.game.jgframework.common.spring.DataSourceAdvice\" />\n\t<aop:config>\n\t\t<aop:pointcut id=\"bussinessService\" expression=\"execution(public * com.zhaidaosi.game.server.sdm.service..*.*(..))\" />\n\t\t<aop:advisor pointcut-ref=\"bussinessService\" advice-ref=\"dataSourceAdvice\" />\n\t\t<aop:advisor pointcut-ref=\"bussinessService\" advice-ref=\"txAdvice\" />\n\t</aop:config>\n\t\n\t<aop:config>\n\t\t<aop:pointcut id=\"frameworkbussinessService\" expression=\"execution(public * com.zhaidaosi.game.jgframework.common.sdm.BaseService.*(..))\" />\n\t\t<aop:advisor pointcut-ref=\"frameworkbussinessService\" advice-ref=\"dataSourceAdvice\" />\n\t\t<aop:advisor pointcut-ref=\"frameworkbussinessService\" advice-ref=\"txAdvice\" />\n\t</aop:config>\n\t\n\t<!-- service beans -->\n\t<!-- scope=\"prototype\"  -->\n\t<bean id=\"CronModelService\" class=\"com.zhaidaosi.game.server.sdm.service.CronModelService\"/>\n\t<bean id=\"UserService\" class=\"com.zhaidaosi.game.server.sdm.service.UserService\"/>\n\t\n</beans>"
  },
  {
    "path": "default_jgframework.properties",
    "content": "#must input\nbase.package.name=com.zhaidaosi.game.server\n\n#run mode : debug, product default : debug\nrun.mode=debug\n\n#timezone\ntime.zone=Asia/Shanghai\n\n#charset default : UTF-8\ncharset=UTF-8\n\n#true or false default : true\nuseSpring=true\n\n#memcache default : 127.0.0.1:11211,1\nmemcache.servers=127.0.0.1:11211,1\nmemcache.keyPrefix=jg-\n\n#manager default : 38080\nmanager.port=38080\n#default : 127.0.0.1\nmanager.allowIps=127.0.0.1;10.10.2.1-10.10.2.254\n#default : admin\nmanager.user=admin\n#default : admin\nmanager.password=admin\n\n#service\n#default : 127.0.0.1\nservice.ips=127.0.0.1\n#default : 28080\nservice.port=28080\n#syncPeriod need > 3 miao default : 60\nservice.syncPeriod=60\n#default : 0\nservice.threadCount=0\n#default : 60\nservice.heartbeatTime=60\n#socket or websocket\n#default : websocket\nservice.mode=websocket\n#max login user default : 0 \nservice.maxLoginUser=0\n\n#auth\n#default : 18080\nauth.port=18080\n#default : 0\nauth.threadCount=0\nauth.handler=auth.\n\n\n#des key\n#default : 1234567890!@#$qweasd\ndes.key=1234567890!@#$qweasd\n\n#rsa keys\nrsa.publicKey=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCifAl6RlbG1PVOowZJ2niVlijq9FC19jEIaA2WVm+En64roRsTjlWpAKOfYBHIwEYWvI7rObyobTIPyOkBOCx5Sbopq2ME7FUQEwI2IeEBGHwnIBPzkhTEt9kMT88g8hZRBV6D/p6J8Z1u2WU0q88Xpd4o7VDxFRmGUTSePOGcjQIDAQAB\nrsa.privateKey=MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKJ8CXpGVsbU9U6jBknaeJWWKOr0ULX2MQhoDZZWb4SfriuhGxOOVakAo59gEcjARha8jus5vKhtMg/I6QE4LHlJuimrYwTsVRATAjYh4QEYfCcgE/OSFMS32QxPzyDyFlEFXoP+nonxnW7ZZTSrzxel3ijtUPEVGYZRNJ484ZyNAgMBAAECgYA3SHCJE8mOmQJloP4Qvq5sZszBNCMJ5hvEunJ1Bi+nNhUybvwhaTon6DnDjhI+9XxjXABcdCaGP7DawgbVDWHDzjgQG0xQle2ryrZFa0thgQDYM4iraMgxMN/5kTXD9DlZcf871N0DeI8dTpxJhVMcM5d95sml6pJxxqwyzABiAQJBAO1rvTpHS6OgDVRpHV4HksyEcKETEayVknAIbTGP3VH3L4X50CpwOwPsvaHi5sENkSEA2JtKj0qF0CbP3sAdDcECQQCvMxhuq2V+dRyMkFLot3YZbMffr2dJi6o4XwxDtI/nhHzS5bQIzKX7L1m8ZJ0GR6CSjZ6X+LBRW6h3tLTsNdnNAkANsK+5o5DN/5WlL2Z9HIyvdFeWQiY7wGgwQ5wgRn5pkopP/Gave8c7Y7RPmGjb6u9aatUSp0r57hthkYzzoPlBAkBG6sfZBEfxCDamL0VgLeMAJ6hAQx/sBTzB1LeCMHSPonFkbNaTOUN2iZQpThDBmfzFVc38dg3o4NEwo1UYyDOBAkAsfnopb+Msp8pMBw7mcX/CeCXNIVpBNWSLtT0AssDf9ofaQ+bIsFIsy2GaPt/UuZmltXgTP5J3iWqFIKQDRstH\n\n\n"
  },
  {
    "path": "pom.xml",
    "content": "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n         xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd\">\n    <modelVersion>4.0.0</modelVersion>\n\n    <groupId>JgFramework</groupId>\n    <artifactId>JgFramework</artifactId>\n    <version>0.0.1-SNAPSHOT</version>\n    <packaging>jar</packaging>\n\n    <name>JgFramework</name>\n    <url>http://maven.apache.org</url>\n\n    <properties>\n        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>\n    </properties>\n\n    <repositories>\n        <repository>\n            <id>jboss-releases</id>\n            <url>https://repository.jboss.org/nexus/content/repositories/releases/</url>\n        </repository>\n    </repositories>\n\n    <build>\n        <plugins>\n            <plugin>\n                <groupId>org.apache.maven.plugins</groupId>\n                <artifactId>maven-compiler-plugin</artifactId>\n                <version>2.3.2</version>\n                <configuration>\n                    <source>1.7</source>\n                    <target>1.7</target>\n                </configuration>\n            </plugin>\n        </plugins>\n    </build>\n\n    <dependencies>\n        <dependency>\n            <groupId>io.netty</groupId>\n            <artifactId>netty-all</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>com.alibaba</groupId>\n            <artifactId>fastjson</artifactId>\n            <scope>compile</scope>\n        </dependency>\n        <dependency>\n            <groupId>org.jboss.marshalling</groupId>\n            <artifactId>jboss-marshalling</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>com.google.protobuf</groupId>\n            <artifactId>protobuf-java</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>javax.activation</groupId>\n            <artifactId>activation</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.osgi.core</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.apache.felix</groupId>\n            <artifactId>org.osgi.compendium</artifactId>\n            <scope>compile</scope>\n            <exclusions>\n                <exclusion>\n                    <artifactId>javax.servlet</artifactId>\n                    <groupId>org.apache.felix</groupId>\n                </exclusion>\n                <exclusion>\n                    <artifactId>org.osgi.foundation</artifactId>\n                    <groupId>org.apache.felix</groupId>\n                </exclusion>\n            </exclusions>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.slf4j</groupId>\n            <artifactId>slf4j-api</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>commons-logging</groupId>\n            <artifactId>commons-logging</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.jboss.logging</groupId>\n            <artifactId>jboss-logging-spi</artifactId>\n            <scope>compile</scope>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>log4j</groupId>\n            <artifactId>log4j</artifactId>\n            <scope>compile</scope>\n            <exclusions>\n                <exclusion>\n                    <artifactId>mail</artifactId>\n                    <groupId>javax.mail</groupId>\n                </exclusion>\n                <exclusion>\n                    <artifactId>jms</artifactId>\n                    <groupId>javax.jms</groupId>\n                </exclusion>\n                <exclusion>\n                    <artifactId>jmxtools</artifactId>\n                    <groupId>com.sun.jdmk</groupId>\n                </exclusion>\n                <exclusion>\n                    <artifactId>jmxri</artifactId>\n                    <groupId>com.sun.jmx</groupId>\n                </exclusion>\n            </exclusions>\n            <optional>true</optional>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate</groupId>\n            <artifactId>hibernate-annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate</groupId>\n            <artifactId>hibernate-commons-annotations</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate</groupId>\n            <artifactId>hibernate-entitymanager</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.hibernate</groupId>\n            <artifactId>hibernate-validator</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>javax.persistence</groupId>\n            <artifactId>persistence-api</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cglib</groupId>\n            <artifactId>cglib</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>javassist</groupId>\n            <artifactId>javassist</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>antlr</groupId>\n            <artifactId>antlr</artifactId>\n        </dependency>\n        <!--<dependency>-->\n        <!--<groupId>org.hibernate</groupId>-->\n        <!--<artifactId>hibernate</artifactId>-->\n        <!--</dependency>-->\n        <dependency>\n            <groupId>javax.transaction</groupId>\n            <artifactId>jta</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>net.sf.ehcache</groupId>\n            <artifactId>ehcache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>dom4j</groupId>\n            <artifactId>dom4j</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>c3p0</groupId>\n            <artifactId>c3p0</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>jboss</groupId>\n            <artifactId>jboss-cache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.jboss.cache</groupId>\n            <artifactId>jbosscache-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>opensymphony</groupId>\n            <artifactId>oscache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>proxool</groupId>\n            <artifactId>proxool</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>swarmcache</groupId>\n            <artifactId>swarmcache</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-httpclient</groupId>\n            <artifactId>commons-httpclient</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-core</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aop</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-asm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-aspects</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-beans</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-context-support</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-expression</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-instrument</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-jdbc</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-orm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.springframework</groupId>\n            <artifactId>spring-tx</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>aopalliance</groupId>\n            <artifactId>aopalliance</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>asm</groupId>\n            <artifactId>asm</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>org.aspectj</groupId>\n            <artifactId>aspectjweaver</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>cglib</groupId>\n            <artifactId>cglib-nodep</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-codec</groupId>\n            <artifactId>commons-codec</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-dbcp</groupId>\n            <artifactId>commons-dbcp</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-pool</groupId>\n            <artifactId>commons-pool</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.jolbox</groupId>\n            <artifactId>bonecp-provider</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>mysql</groupId>\n            <artifactId>mysql-connector-java</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-beanutils</groupId>\n            <artifactId>commons-beanutils</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>commons-collections</groupId>\n            <artifactId>commons-collections</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.whalin</groupId>\n            <artifactId>Memcached-Java-Client</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>com.google.guava</groupId>\n            <artifactId>guava</artifactId>\n        </dependency>\n        <dependency>\n            <groupId>redis.clients</groupId>\n            <artifactId>jedis</artifactId>\n            <type>jar</type>\n            <scope>compile</scope>\n        </dependency>\n    </dependencies>\n    <dependencyManagement>\n        <dependencies>\n            <dependency>\n                <groupId>io.netty</groupId>\n                <artifactId>netty-all</artifactId>\n                <version>4.0.33.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.marshalling</groupId>\n                <artifactId>jboss-marshalling</artifactId>\n                <version>1.4.0.Final</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.protobuf</groupId>\n                <artifactId>protobuf-java</artifactId>\n                <version>2.5.0</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.activation</groupId>\n                <artifactId>activation</artifactId>\n                <version>1.1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.osgi.core</artifactId>\n                <version>1.4.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.apache.felix</groupId>\n                <artifactId>org.osgi.compendium</artifactId>\n                <version>1.4.0</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-api</artifactId>\n                <version>1.6.4</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-logging</groupId>\n                <artifactId>commons-logging</artifactId>\n                <version>1.1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.logging</groupId>\n                <artifactId>jboss-logging-spi</artifactId>\n                <version>2.1.2.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>log4j</groupId>\n                <artifactId>log4j</artifactId>\n                <version>1.2.16</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hibernate</groupId>\n                <artifactId>hibernate-annotations</artifactId>\n                <version>3.4.0.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hibernate</groupId>\n                <artifactId>hibernate-commons-annotations</artifactId>\n                <version>3.1.0.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hibernate</groupId>\n                <artifactId>hibernate-entitymanager</artifactId>\n                <version>3.4.0.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>org.hibernate</groupId>\n                <artifactId>hibernate-validator</artifactId>\n                <version>3.1.0.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>javax.persistence</groupId>\n                <artifactId>persistence-api</artifactId>\n                <version>1.0</version>\n            </dependency>\n            <dependency>\n                <groupId>cglib</groupId>\n                <artifactId>cglib</artifactId>\n                <version>2.2</version>\n            </dependency>\n            <dependency>\n                <groupId>javassist</groupId>\n                <artifactId>javassist</artifactId>\n                <version>3.9.0.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>antlr</groupId>\n                <artifactId>antlr</artifactId>\n                <version>2.7.6</version>\n            </dependency>\n            <!--<dependency>-->\n            <!--<groupId>org.hibernate</groupId>-->\n            <!--<artifactId>hibernate</artifactId>-->\n            <!--<version>3.3.2.GA</version>-->\n            <!--</dependency>-->\n            <dependency>\n                <groupId>javax.transaction</groupId>\n                <artifactId>jta</artifactId>\n                <version>1.1</version>\n            </dependency>\n            <dependency>\n                <groupId>net.sf.ehcache</groupId>\n                <artifactId>ehcache</artifactId>\n                <version>1.2.3</version>\n            </dependency>\n            <dependency>\n                <groupId>org.slf4j</groupId>\n                <artifactId>slf4j-log4j12</artifactId>\n                <version>1.6.4</version>\n            </dependency>\n            <dependency>\n                <groupId>dom4j</groupId>\n                <artifactId>dom4j</artifactId>\n                <version>1.6.1</version>\n            </dependency>\n            <dependency>\n                <groupId>c3p0</groupId>\n                <artifactId>c3p0</artifactId>\n                <version>0.9.1</version>\n            </dependency>\n            <dependency>\n                <groupId>jboss</groupId>\n                <artifactId>jboss-cache</artifactId>\n                <version>1.4.1.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>org.jboss.cache</groupId>\n                <artifactId>jbosscache-core</artifactId>\n                <version>3.1.0.GA</version>\n            </dependency>\n            <dependency>\n                <groupId>opensymphony</groupId>\n                <artifactId>oscache</artifactId>\n                <version>2.1</version>\n            </dependency>\n            <dependency>\n                <groupId>proxool</groupId>\n                <artifactId>proxool</artifactId>\n                <version>0.8.3</version>\n            </dependency>\n            <dependency>\n                <groupId>swarmcache</groupId>\n                <artifactId>swarmcache</artifactId>\n                <version>1.0RC2</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-httpclient</groupId>\n                <artifactId>commons-httpclient</artifactId>\n                <version>3.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-core</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-aop</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-asm</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-aspects</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-beans</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-context-support</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-expression</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-instrument</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-jdbc</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-orm</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>org.springframework</groupId>\n                <artifactId>spring-tx</artifactId>\n                <version>3.1.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>aopalliance</groupId>\n                <artifactId>aopalliance</artifactId>\n                <version>1.0</version>\n            </dependency>\n            <dependency>\n                <groupId>asm</groupId>\n                <artifactId>asm</artifactId>\n                <version>3.1</version>\n            </dependency>\n            <dependency>\n                <groupId>org.aspectj</groupId>\n                <artifactId>aspectjweaver</artifactId>\n                <version>1.6.9</version>\n            </dependency>\n            <dependency>\n                <groupId>cglib</groupId>\n                <artifactId>cglib-nodep</artifactId>\n                <version>2.2</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-codec</groupId>\n                <artifactId>commons-codec</artifactId>\n                <version>1.8</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-dbcp</groupId>\n                <artifactId>commons-dbcp</artifactId>\n                <version>1.4</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-pool</groupId>\n                <artifactId>commons-pool</artifactId>\n                <version>1.5.3</version>\n            </dependency>\n            <dependency>\n                <groupId>com.jolbox</groupId>\n                <artifactId>bonecp-provider</artifactId>\n                <version>0.7.1.RELEASE</version>\n            </dependency>\n            <dependency>\n                <groupId>mysql</groupId>\n                <artifactId>mysql-connector-java</artifactId>\n                <version>5.1.26</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-beanutils</groupId>\n                <artifactId>commons-beanutils</artifactId>\n                <version>1.7.0</version>\n            </dependency>\n            <dependency>\n                <groupId>commons-collections</groupId>\n                <artifactId>commons-collections</artifactId>\n                <version>3.1</version>\n            </dependency>\n            <dependency>\n                <groupId>com.whalin</groupId>\n                <artifactId>Memcached-Java-Client</artifactId>\n                <version>3.0.2</version>\n            </dependency>\n            <dependency>\n                <groupId>com.google.guava</groupId>\n                <artifactId>guava</artifactId>\n                <version>r09</version>\n            </dependency>\n            <dependency>\n                <groupId>com.alibaba</groupId>\n                <artifactId>fastjson</artifactId>\n                <version>1.2.12</version>\n            </dependency>\n            <dependency>\n                <groupId>redis.clients</groupId>\n                <artifactId>jedis</artifactId>\n                <version>2.0.0</version>\n            </dependency>\n        </dependencies>\n    </dependencyManagement>\n</project>\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/Boot.java",
    "content": "package com.zhaidaosi.game.jgframework;\n\nimport com.zhaidaosi.game.jgframework.common.BaseIp;\nimport com.zhaidaosi.game.jgframework.common.BaseRunTimer;\nimport com.zhaidaosi.game.jgframework.common.BaseString;\nimport com.zhaidaosi.game.jgframework.common.cache.BaseLocalCached;\nimport com.zhaidaosi.game.jgframework.common.encrpt.BaseDes;\nimport com.zhaidaosi.game.jgframework.common.encrpt.BaseRsa;\nimport com.zhaidaosi.game.jgframework.common.spring.ServiceManager;\nimport com.zhaidaosi.game.jgframework.connector.AuthConnector;\nimport com.zhaidaosi.game.jgframework.connector.ManagerConnector;\nimport com.zhaidaosi.game.jgframework.connector.ServiceConnector;\nimport com.zhaidaosi.game.jgframework.model.action.ActionManager;\nimport com.zhaidaosi.game.jgframework.model.area.AreaManager;\nimport com.zhaidaosi.game.jgframework.model.entity.BasePlayerFactory;\nimport com.zhaidaosi.game.jgframework.model.entity.IBasePlayerFactory;\nimport com.zhaidaosi.game.jgframework.session.SessionManager;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Properties;\nimport java.util.TimeZone;\n\npublic class Boot {\n\n    public static String BASE_PACKAGE_NAME;\n    public static String SDM_BASE_PACKAGE_NAME;\n    public static String SERVER_RSYNC_PACKAGE_PATH;\n    public static String SERVER_HANDLER_PACKAGE_PATH;\n\n    private static final Logger log = LoggerFactory.getLogger(Boot.class);\n    private final static String SERVER_PROPERTIES = \"jgframework.properties\";\n    private final static String ALL_STRING = \"all\";\n    private final static String SERVICE_STRING = \"service\";\n    private final static String AUTH_STRING = \"auth\";\n    private static String actionPackage;\n    private static String areaPackage;\n    private static int servicePort = 28080;\n    private static String serviceMode = ServiceConnector.MODE_WEB_SOCKET;\n    private static long serviceSyncPeriod = 60000;\n    private static int serviceThreadCount = 0;\n    private static int serviceHeartbeatTime = 60;\n    private static int serviceMaxLoginUser = 0;\n    private static ArrayList<String> serviceIps = new ArrayList<>();\n    private static int authPort = 18080;\n    private static int authThreadCount = 0;\n    private static String authHandler;\n    private static boolean debug = true;\n    private static ArrayList<String> memcacheServers = new ArrayList<>();\n    private static String memcacheKeyPrefix = \"jg-\";\n    private static Charset charset = Charset.forName(\"UTF-8\");\n    private static int managerPort = 38080;\n    private static ArrayList<Long[]> managerAllowIps = new ArrayList<>();\n    private static String managerUser = \"admin\";\n    private static String managerPassword = \"admin\";\n    private static ServiceConnector serviceConnector = null;\n    private static ManagerConnector managerConnector = null;\n    private static AuthConnector authConnector = null;\n    private static String args = null;\n    private static IBasePlayerFactory playerFactory = new BasePlayerFactory();\n    private static boolean useSpring = true;\n\n    private static boolean init = false;\n\n    /**\n     * 初始化参数\n     * @return\n     */\n    private static boolean init() {\n        if (init) {\n            return true;\n        }\n        boolean error = false;\n        try {\n            Properties pps = new Properties();\n            pps.load(Boot.class.getClassLoader().getResourceAsStream(SERVER_PROPERTIES));\n\n            BASE_PACKAGE_NAME = pps.getProperty(\"base.package.name\");\n            if (BaseString.isEmpty(BASE_PACKAGE_NAME)) {\n                error = true;\n                log.error(\"base.package.name 必须填写\");\n            }\n            SDM_BASE_PACKAGE_NAME = BASE_PACKAGE_NAME + \".sdm\";\n            SERVER_RSYNC_PACKAGE_PATH = BASE_PACKAGE_NAME + \".rsync\";\n            SERVER_HANDLER_PACKAGE_PATH = BASE_PACKAGE_NAME + \".handler\";\n\n            //设置默认时间\n            if (!BaseString.isEmpty(pps.getProperty(\"time.zone\"))) {\n                TimeZone.setDefault(TimeZone.getTimeZone(pps.getProperty(\"time.zone\")));\n            }\n\n            //是否使用spring\n            if (!BaseString.isEmpty(pps.getProperty(\"useSpring\"))) {\n                useSpring = pps.getProperty(\"useSpring\").equals(\"true\");\n            }\n\n            //设置运行模式\n            debug = \"debug\".equals(pps.getProperty(\"run.mode\"));\n\n            if (debug) {\n                BaseRunTimer.toActive();\n            }\n            if (ALL_STRING.equals(args) || SERVICE_STRING.equals(args)) {\n                //service端\n                if (!BaseString.isEmpty(pps.getProperty(\"service.port\"))) {\n                    servicePort = Integer.valueOf(pps.getProperty(\"service.port\"));\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"service.mode\"))) {\n                    serviceMode = pps.getProperty(\"service.mode\");\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"service.threadCount\"))) {\n                    serviceThreadCount = Integer.valueOf(pps.getProperty(\"service.threadCount\"));\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"service.syncPeriod\"))) {\n                    serviceSyncPeriod = Integer.valueOf(pps.getProperty(\"service.syncPeriod\"));\n                    if (serviceSyncPeriod < 3) {\n                        error = true;\n                        log.error(\"service.syncPeriod 必须大于3秒\");\n                    }\n                    serviceSyncPeriod = serviceSyncPeriod * 1000;\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"service.heartbeatTime\"))) {\n                    serviceHeartbeatTime = Integer.valueOf(pps.getProperty(\"service.heartbeatTime\"));\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"service.maxLoginUser\"))) {\n                    serviceMaxLoginUser = Integer.valueOf(pps.getProperty(\"service.maxLoginUser\"));\n                }\n            }\n\n            if (ALL_STRING.equals(args) || AUTH_STRING.equals(args)) {\n                //auth端\n                if (!BaseString.isEmpty(pps.getProperty(\"service.ips\"))) {\n                    Collections.addAll(serviceIps, pps.getProperty(\"service.ips\").split(\";\"));\n                } else {\n                    error = true;\n                    log.error(\"service.ips 必须填写\");\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"auth.port\"))) {\n                    authPort = Integer.valueOf(pps.getProperty(\"auth.port\"));\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"auth.threadCount\"))) {\n                    authThreadCount = Integer.valueOf(pps.getProperty(\"auth.threadCount\"));\n                }\n                if (!BaseString.isEmpty(pps.getProperty(\"auth.handler\"))) {\n                    authHandler = pps.getProperty(\"auth.handler\");\n                } else {\n                    error = true;\n                    log.error(\"auth.handler 必须填写\");\n                }\n            }\n\n            //manager端\n            if (!BaseString.isEmpty(pps.getProperty(\"manager.port\"))) {\n                managerPort = Integer.valueOf(pps.getProperty(\"manager.port\"));\n            }\n            if (!BaseString.isEmpty(pps.getProperty(\"manager.user\"))) {\n                managerUser = pps.getProperty(\"manager.user\");\n            }\n            if (!BaseString.isEmpty(pps.getProperty(\"manager.password\"))) {\n                managerPassword = pps.getProperty(\"manager.password\");\n            }\n            String[] ips;\n            if (!BaseString.isEmpty(pps.getProperty(\"manager.allowIps\"))) {\n                ips = pps.getProperty(\"manager.allowIps\").split(\";\");\n            } else {\n                ips = new String[]{\"127.0.0.1\"};\n            }\n            setManagerAllowIps(ips);\n\n            //memcache\n            if (!BaseString.isEmpty(pps.getProperty(\"memcache.servers\"))) {\n                Collections.addAll(memcacheServers, pps.getProperty(\"memcache.servers\").split(\";\"));\n            } else {\n                memcacheServers.add(\"127.0.0.1:11211,1\");\n            }\n            if (!BaseString.isEmpty(pps.getProperty(\"memcache.keyPrefix\"))) {\n                memcacheKeyPrefix = pps.getProperty(\"memcache.keyPrefix\");\n            }\n\n            //des密钥\n            if (!BaseString.isEmpty(pps.getProperty(\"des.key\"))) {\n                BaseDes.setDesKey(pps.getProperty(\"des.key\"));\n            }\n            //rsa密钥\n            if (!BaseString.isEmpty(pps.getProperty(\"rsa.publicKey\")) && !BaseString.isEmpty(pps.getProperty(\"rsa.privateKey\"))) {\n                BaseRsa.init(pps.getProperty(\"rsa.publicKey\"), pps.getProperty(\"rsa.privateKey\"));\n            }\n            //系统字符集\n            if (!BaseString.isEmpty(pps.getProperty(\"charset\"))) {\n                charset = Charset.forName(pps.getProperty(\"charset\"));\n            }\n\n        } catch (Exception e) {\n            error = true;\n            log.error(\"系统启动失败\", e);\n        }\n        if (!error) {\n            init = true;\n        }\n        return init;\n    }\n\n    /**\n     * 设置允许ip段\n     * @param ips\n     */\n    private static void setManagerAllowIps(String[] ips) {\n        for (String ip : ips) {\n            managerAllowIps.add(BaseIp.stringToIp(ip));\n        }\n    }\n\n    /**\n     * 设置扫描action的包路径，例如：com.zhaidaosi.game.server.model.action\n     * @param actionPackage\n     */\n    public static void setActionPackage(String actionPackage) {\n        Boot.actionPackage = actionPackage;\n    }\n\n    /**\n     * 设置扫描area的包路径，例如：com.zhaidaosi.game.server.model.area\n     * @param areaPackage\n     */\n    public static void setAreaPackage(String areaPackage) {\n        Boot.areaPackage = areaPackage;\n    }\n\n    /**\n     * 获取player的工厂，默认是BasePlayerFactory\n     * @return\n     */\n    public static IBasePlayerFactory getPlayerFactory() {\n        return playerFactory;\n    }\n\n    /**\n     * 设置player的工厂，默认是BasePlayerFactory\n     * @param playerFactory\n     */\n    public static void setPlayerFactory(IBasePlayerFactory playerFactory) {\n        Boot.playerFactory = playerFactory;\n    }\n\n    /**\n     * 设置mc的前缀\n     * @return\n     */\n    public static String getMemcacheKeyPrefix() {\n        return memcacheKeyPrefix;\n    }\n\n    /**\n     * 获取service的连接对象\n     * @return\n     */\n    public static ServiceConnector getServiceConnector() {\n        return serviceConnector;\n    }\n\n    /**\n     * 获取auth的连接对象\n     * @return\n     */\n    public static AuthConnector getAuthConnector() {\n        return authConnector;\n    }\n\n    /**\n     * 获取manager服务端口\n     * @return\n     */\n    public static int getManagerPort() {\n        return managerPort;\n    }\n\n    /**\n     * 获取manager允许访问的ip段\n     * @return\n     */\n    public static ArrayList<Long[]> getManagerAllowIps() {\n        return managerAllowIps;\n    }\n\n    /**\n     * 获取manager的登录用户\n     * @return\n     */\n    public static String getManagerUser() {\n        return managerUser;\n    }\n\n    /**\n     * 获取manager的用户密码\n     * @return\n     */\n    public static String getManagerPassword() {\n        return managerPassword;\n    }\n\n\n    /**\n     * 获取默认字符集\n     * @return\n     */\n    public static Charset getCharset() {\n        return charset;\n    }\n\n    /**\n     * service服务器工作线程数\n     * @return\n     */\n    public static int getServiceThreadCount() {\n        return serviceThreadCount;\n    }\n\n    /**\n     * 认证服务器工作线程数\n     * @return\n     */\n    public static int getAuthThreadCount() {\n        return authThreadCount;\n    }\n\n    /**\n     * 返回所有的memcache配置\n     * @return\n     */\n    public static ArrayList<String> getMemcacheServers() {\n        return memcacheServers;\n    }\n\n    /**\n     * 返回所有service服务器ip\n     * @return\n     */\n    public static ArrayList<String> getServiceIps() {\n        return serviceIps;\n    }\n\n    /**\n     * 返回认证服务的所有handler\n     * @return\n     */\n    public static String getAuthHandler() {\n        return authHandler;\n    }\n\n    /**\n     * 返回服务器端口\n     * @return\n     */\n    public static int getServicePort() {\n        return servicePort;\n    }\n\n    /**\n     * 返回service服务器个数\n     * @return\n     */\n    public static int getServiceCount() {\n        return serviceIps.size();\n    }\n\n    /**\n     * 返回service的同步间隔\n     * @return\n     */\n    public static long getServiceSyncPeriod() {\n        return serviceSyncPeriod;\n    }\n\n    /**\n     * 获取心跳检查时间\n     * @return\n     */\n    public static int getServiceHeartbeatTime() {\n        return serviceHeartbeatTime;\n    }\n\n    /**\n     * 通过ip返回service的连接地址\n     * @param ip\n     * @return\n     */\n    public static String getServiceAddress(String ip) {\n        if (serviceMode.equals(ServiceConnector.MODE_SOCKET)) {\n            return ip + \":\" + servicePort;\n        } else {\n            return \"ws://\" + ip + \":\" + servicePort + ServiceConnector.WEB_SOCKET_PATH;\n        }\n    }\n\n    /**\n     * 是否开启debug模式\n     * @return\n     */\n    public static boolean getDebug() {\n        return debug;\n    }\n\n\n    /**\n     * 重启服务\n     */\n    public static void restart() {\n        stop();\n        start();\n    }\n\n    /**\n     * 停止服务\n     */\n    public static void stop() {\n        BaseLocalCached.cancelTimer();\n        if (authConnector != null) {\n            authConnector.stop();\n        }\n        if (serviceConnector != null) {\n            serviceConnector.stop();\n        }\n        if (managerConnector != null) {\n            managerConnector.stop();\n        }\n    }\n\n    /**\n     * 启动服务\n     */\n    public static void start() {\n        start(Boot.args);\n    }\n\n    /**\n     * 启动服务\n     * @param args ALL_STRING,SERVICE_STRING,AUTH_STRING\n     */\n    public static void start(String args) {\n        if (Boot.args == null) {\n            Boot.args = args == null ? ALL_STRING : args;\n        }\n        if (!Boot.ALL_STRING.equals(Boot.args) && !Boot.SERVICE_STRING.equals(Boot.args) & !Boot.AUTH_STRING.equals(Boot.args)) {\n            Boot.args = args = ALL_STRING;\n        }\n\n        //初始化参数\n        if (init()) {\n            //加载spring\n            if (useSpring) {\n                ServiceManager.init();\n            }\n            //开启本地缓存清理任务\n            BaseLocalCached.startTimer();\n            //加载路由\n            Router.init();\n\n            if (args == null || args.equals(ALL_STRING) || args.equals(SERVICE_STRING)) {\n                //加载动作\n                ActionManager.initAction(actionPackage);\n                //加载区域\n                AreaManager.initArea(areaPackage);\n\n                if (serviceMaxLoginUser > 0) {\n                    SessionManager.setMaxUser(serviceMaxLoginUser);\n                } else {\n                    serviceMaxLoginUser = 0;\n                }\n\n                if (serviceConnector == null) {\n                    serviceConnector = new ServiceConnector(servicePort, serviceSyncPeriod, serviceMode);\n                }\n                serviceConnector.start();\n\n                if (managerConnector == null) {\n                    managerConnector = new ManagerConnector(managerPort);\n                }\n                managerConnector.start();\n\n            }\n            if (args == null || args.equals(ALL_STRING) || args.equals(AUTH_STRING)) {\n                if (authConnector == null) {\n                    authConnector = new AuthConnector(authPort);\n                }\n                authConnector.start();\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/Router.java",
    "content": "package com.zhaidaosi.game.jgframework;\n\nimport com.zhaidaosi.game.jgframework.common.BaseFile;\nimport com.zhaidaosi.game.jgframework.common.BaseRunTimer;\nimport com.zhaidaosi.game.jgframework.common.BaseString;\nimport com.zhaidaosi.game.jgframework.handler.BaseHandler;\nimport com.zhaidaosi.game.jgframework.handler.IBaseHandler;\nimport com.zhaidaosi.game.jgframework.message.IBaseMessage;\nimport com.zhaidaosi.game.jgframework.message.InMessage;\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\nimport io.netty.channel.Channel;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.HashMap;\nimport java.util.Set;\n\npublic class Router {\n\n    private static final Logger log = LoggerFactory.getLogger(Router.class);\n    private static HashMap<String, IBaseHandler> handlers = new HashMap<>();\n    private static final String classSuffix = \"Handler\";\n    public static final String ERROR_HANDLERNAME = \"_error_\";\n    public static final String HEART_HANDLERNAME = \"_heart_\";\n    public static final String WAIT_HANDLERNAME = \"_wait_\";\n\n    /**\n     * 初始化handler\n     */\n    public static void init() {\n        Set<Class<?>> classes = BaseFile.getClasses(Boot.SERVER_HANDLER_PACKAGE_PATH, classSuffix, true);\n\n        for (Class<?> c : classes) {\n            String className = c.getName();\n            IBaseHandler handler;\n            try {\n                handler = (IBaseHandler) c.newInstance();\n                // 只取Handler前面部分\n                String handlerName = className.replace(Boot.SERVER_HANDLER_PACKAGE_PATH + \".\", \"\").replace(classSuffix, \"\").toLowerCase();\n                handler.setHandlerName(handlerName);\n                handlers.put(handlerName, handler);\n                log.info(\"handler类 : \" + className + \" 加载完成\");\n            } catch (InstantiationException | IllegalAccessException e) {\n                log.error(\"handler类 : \" + className + \" 加载失败\", e);\n            }\n        }\n    }\n\n    /**\n     * 运行handler\n     * @param im\n     * @param ch\n     * @return\n     * @throws Exception\n     */\n    public static IBaseMessage run(InMessage im, Channel ch) throws Exception {\n        long startTime = 0;\n        if (BaseRunTimer.isActive()) {\n            startTime = System.currentTimeMillis();\n        }\n        IBaseMessage rs = null;\n        String handlerName = im.getH();\n        if (!BaseString.isEmpty(handlerName)) {\n            try {\n                if (handlerName.equals(HEART_HANDLERNAME)) {\n                    rs = BaseHandler.doHeart();\n                    rs.setH(HEART_HANDLERNAME);\n                } else {\n                    IBaseHandler handler = handlers.get(handlerName);\n                    if (handler == null) {\n                        rs = OutMessage.showError(\"handler不存在\", 21000);\n                    } else {\n                        rs = handler.run(im, ch);\n                    }\n                    if (rs != null) {\n                        rs.setH(handlerName);\n                    }\n                }\n            } finally {\n                if (BaseRunTimer.isActive()) {\n                    long runningTime = System.currentTimeMillis() - startTime;\n                    BaseRunTimer.addTimer(\"Handler : \" + handlerName + \" run \" + runningTime + \" ms\");\n                }\n            }\n        } else {\n            rs = OutMessage.showError(\"handler不能为空\", 20000);\n            rs.setH(ERROR_HANDLERNAME);\n        }\n        return rs;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseAvlTree.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport java.util.AbstractSet;\nimport java.util.Iterator;\nimport java.util.Random;\n\n/**\n * 平衡二叉搜索（排序）树\n */\npublic class BaseAvlTree<E extends Comparable<E>> extends AbstractSet<E> {\n    private Entry<E> root;//根节点\n    private int size;//树节点个数\n\n    private static class Entry<E> {\n        E elem;//数据域\n        Entry<E> parent;//父节点\n        Entry<E> left;//左节点\n        Entry<E> right;//右节点\n        /*\n         * 树的平衡因子，等号表示左子树和右子树有同样的高度。如果L，左子树比右子树高1。如果为R，则意味着右\n         * 子树比左高1。刚创建时是平衡的，所以为=\n         *             50\n         *             /R\\\n         *            20  80\n         *            /L  /R\\\n         *           10  70 100\n         *           =   =  /=\\\n         *                 92 103\n         *                 =  =\n         */\n        char balanceFactor = '=';\n\n        //构造函数只有两个参数，左右节点是调用add方法时设置\n        public Entry(E elem, Entry<E> parent) {\n            this.elem = elem;\n            this.parent = parent;\n        }\n    }\n\n    private class TreeIterator implements Iterator<E> {\n\n        private Entry<E> lastReturned = null;\n        private Entry<E> next;\n\n        TreeIterator() {\n\n            next = root;\n            if (next != null)\n                while (next.left != null)\n                    next = next.left;\n\n        }\n\n        public boolean hasNext() {\n\n            return next != null;\n\n        }\n\n        public E next() {\n\n            lastReturned = next;\n            next = successor(next);\n            return lastReturned.elem;\n\n        }\n\n        public void remove() {\n\n            if (lastReturned != null && lastReturned.left != null)\n                next = lastReturned;\n            deleteEntry(lastReturned);\n            lastReturned = null;\n\n        }\n    }\n\n    /**\n     * 左旋转：结果就是将p移到它的左子节点的位置，而p的右子节点被移到该元素原来位置\n     * @param p 旋转元素\n     */\n    private void rotateLeft(Entry<E> p) {\n        /*\n\t\t* 围绕50左旋转:\n\t\t*p → 50                 90\n\t\t*     \\                 /\\\n\t\t* r → 90      →       50 100\n\t\t*      \\\n\t\t*     100\n\t\t* \n\t\t* 围绕80左旋转:r的左子树变成p的右子树。因为位于r的左子树上的任意一个元素值大于p且小于r，所以r的左子\n\t\t* 树可以成为p的右子树这是没有问题的。其实上面也发生了同样的现象，只是r的左子树为空罢了\n\t\t*  p → 80                  90\n\t\t*      /\\                  /\\ \n\t\t*     60 90 ← r     →     80 120\n\t\t*        /\\               /\\   /\n\t\t*      85 120           60 85 100\n\t\t*          /\n\t\t*         100\n\t\t* \n\t\t* 围绕80在更大范围内旋转：元素不是围绕树的根旋转。旋转前后的树都是二叉搜索树。且被旋转元素80上的所\n\t\t* 有元素在旋转中不移动（50、30、20、40这四个元素还是原来位置）\n\t\t*       50                         50\n\t\t*       / \\                        / \\\n\t\t*     30   80 ← p                 30  90\n\t\t*     /\\   /\\                     /\\  / \\\n\t\t*   20 40 60 90 ← r      →      20 40 80 120\n\t\t*            /\\                       /\\   /\n\t\t*           85 120                  60 85 100\n\t\t*              /\n\t\t*             100\n\t\t* \n\t\t* 节点数据结构:\n\t\t*  +------------------+\n\t\t*  | elem | p | l | r |\n\t\t*  +------------------+\n\t\t*  \n\t\t*    +------------------+\n\t\t*    | 50 |NULL|NULL| r |\n\t\t*    +------------------+\n\t\t*                 ↖⑥ ↘④\n\t\t*         +---------------+\n\t\t*         |80| p | l  | r |   ← p \n\t\t*         +---------------+\n\t\t*         ↗       ↙     ↖③ ↘①      \n\t\t*  +----------------+ +---------------+\n\t\t*  |60| p |NULL|NULL| |90| p |  l | r |   ← r\n\t\t*  +----------------+ +---------------+\n\t\t*                     ↗②       ↙⑤    ↖↘ \n\t\t*              +----------------+ +---------------+\n\t\t*              |85| p |NULL|NULL| |90| p | l |NULL|\n\t\t*              +----------------+ +---------------+\n\t\t*                                  ↗      ↙  \n\t\t*                           +-----------------+\n\t\t*                           |100| p |NULL|NULL|\n\t\t*                           +-----------------+\n\t\t*/\n\n        Entry<E> r = p.right;//旋转元素的右子节点\n        //把旋转元素的右子节点的左子节点接到旋转元素的右子树\n        p.right = r.left;//①\n        //如果旋转元素的右子节点存在左子节点的话，同时修改该节点的父节指针指向\n        if (r.left != null) {\n            //把旋转元素的右子节点的左子节点的父设置成旋转元素\n            r.left.parent = p;//②\n        }\n        //将旋转元素的右子节点的父设置成旋转元素的父，这里有可以p为根节点，那么旋转后p就成根节点\n        r.parent = p.parent;//③\n\n        //如果旋转元素为根元素，则旋转后，旋转元素的右子节点r将成为根节点\n        if (p.parent == null) {\n            root = r;\n        }//否则p不是根节点，如果p是他父节点的左节点时\n        else if (p.parent.left == p) {\n            //让p的父节点的左指针指向r\n            p.parent.left = r;\n        }//否则如果p是他父节点的右节点时\n        else {\n            //让p的父节点的右指针指向r\n            p.parent.right = r;//④\n        }\n        //让旋转元素的左节点指向旋转元素p\n        r.left = p;//⑤\n        //让旋转元素的父节点指向旋转元素右节点r\n        p.parent = r;//⑥\n    }\n\n    /**\n     * 右旋转：结果就是将p移到它的右子节点的位置，而p的左子节点被移到该元素原来位置\n     * 与左旋转是完全对称的，将左旋转中的lef与rigth互换即可得到，这里就不详细解释了\n     * @param p 旋转元素\n     */\n    private void rotateRight(Entry<E> p) {\n\n\t\t/*\n\t\t* 围绕100右旋转:\n\t\t*  p → 100              90\n\t\t*       /               /\\\n\t\t* l → 90      →       50 100\n\t\t*     /\n\t\t*    50\n\t\t* \n\t\t* 围绕80右旋转:l的右子树变成p的左子树。因为位于l的右子树上的任意一个元素值小于p且小于l，所以l的右\n\t\t* 子树可以成为p的左子树这是没有问题的。其实上面也发生了同样的现象，只是l的右子树为空罢了\n\t\t* \n\t\t*  p → 80                  60\n\t\t*      /\\                  /\\ \n\t\t* l → 60 90         →     50 80\n\t\t*     /\\                   \\  /\\\n\t\t*    50 70                55 70 90   \n\t\t*     \\   \n\t\t*     55\n\t\t*/\n\n        Entry<E> l = p.left;\n        p.left = l.right;\n        if (l.right != null) {\n            l.right.parent = p;\n        }\n        l.parent = p.parent;\n\n        if (p.parent == null) {\n            root = l;\n        } else if (p.parent.right == p) {\n            p.parent.right = l;\n        } else {\n            p.parent.left = l;\n        }\n        l.right = p;\n        p.parent = l;\n    }\n\n    /**\n     * BaseAVLTree类的add方法类似于BinSerrchTree类的add方法，但是沿着根向下前进到插入点时，需记录这样一个被插\n     * 入Entry对象最近的祖先：该祖先的平衡因子balanceFactor值是L或R(即不歼)，且让ancestor指向这个祖先节\n     * 点，该祖先节有什么用呢，从ancestor的子开始到新增节点路径上的所有祖先节点都是平衡，这些祖先节点会因为\n     * 新增节点而变得不平衡了，需要重新调整平衡因子，这个分界点在调整平衡因子时非常有用\n     *\n     * @param elem 要新增元素的数据域\n     * @return boolean\n     */\n    public boolean add(E elem) {\n        //如果树为空，则直接插入\n        if (root == null) {\n            root = new Entry<E>(elem, null);\n            size++;\n            return true;\n        } else {\n            Entry<E> tmp = root;//新增节点的父节点，从根节点下面开始找插入点\n            Entry<E> ancestor = null;//平衡因子不为 = 的最近祖先节点\n            int comp; //比较结果\n            while (true) {//死循环，直接找到插入点退出循环\n                comp = elem.compareTo(tmp.elem);\n                //如果已存在该元素，则直接返回失败\n                if (comp == 0) {\n                    return false;\n                }\n\n                //记录不平衡的祖先节点\n                if (tmp.balanceFactor != '=') {\n                    //如果哪个祖先节点不平衡，则记录，当循环完后，ancestor指向的就是最近一个\n                    //不平衡的祖先节点\n                    ancestor = tmp;\n                }\n\n                //如果小于当前比较节点，则在其左边插入\n                if (comp < 0) {\n\n                    //如果左子树不为空，继续循环在左边找插入点\n                    if (tmp.left != null) {\n                        tmp = tmp.left;\n                    } else {//否则插入\n                        tmp.left = new Entry<E>(elem, tmp);\n                        //插入后要进行平衡调整\n                        fixAfterInsertion(ancestor, tmp.left);\n                        size++;\n                        return true;\n                    }\n                } else {//在右边插入\n\n                    //如果右子树不为空，继续循环在右边找插入点\n                    if (tmp.right != null) {\n                        tmp = tmp.right;\n                    } else {//否则插入\n                        tmp.right = new Entry<E>(elem, tmp);\n                        //插入后要进行平衡调整\n                        fixAfterInsertion(ancestor, tmp.right);\n                        size++;\n                        return true;\n                    }\n                }\n\n            }\n        }\n    }\n\n    /**\n     * 当新增节点后，会改变某些节点的平衡因子，所以添加节点后需重新调整平衡因子\n     *\n     * 根据前人们的分析与研究，可分为6种情况\n     *\n     * @param ancestor 新增元素的最近一个不平衡的祖先节点\n     * @param inserted 新增元素\n     */\n    protected void fixAfterInsertion(Entry<E> ancestor, Entry<E> inserted) {\n        E elem = inserted.elem;\n\n        if (ancestor == null) {\n\t\t\t/*\n\t\t\t * 情况1：ancestor的值为null，即被插入Entry对象的每个祖先的平衡因子都是 =，此时新增节点后\n\t\t\t * ，树的高度不会发生变化，所以不需要旋转，我们要作的就是调整从根节点到插入节点的路径上的所有\n\t\t\t * 节点的平衡因子罢了\n\t\t\t * \n\t\t\t *                       新增55后调整\n\t\t\t *             50            →           50\n\t\t\t *             /=\\                       /R\\\n\t\t\t *           25   70                   25   70\n\t\t\t *          /=\\   /=\\                 /=\\   /L\\\n\t\t\t *         15 30 60 90               15 30 60 90\n\t\t\t *         =  =  =   =               =  =  /L =\n\t\t\t *                                        55\n\t\t\t *                                        =\n\t\t\t */\n            //根节点的平衡因子我们单独拿出来调整，因为adjustPath的参数好比是一个开区间，它不包括两头参数\n            //本身，而是从nserted.paraent开始到to的子节点为止，所以需单独调整，其他分支也一样\n            if (elem.compareTo(root.elem) < 0) {\n                root.balanceFactor = 'L';\n            } else {\n                root.balanceFactor = 'R';\n            }\n            //再调用adjustPath方法调整新增节点的父节点到root的某子节点路径上的所有祖先节点的\n            //平衡因子\n            adjustPath(root, inserted);\n        } else if ((ancestor.balanceFactor == 'L' && elem.compareTo(ancestor.elem) > 0)\n                || (ancestor.balanceFactor == 'R' && elem.compareTo(ancestor.elem) < 0)) {\n\t\t\t/*\n\t\t\t * 情况2：\n\t\t\t * ancestor.balanceFactor的值为 L，且在ancestor对象的右子树插入，或ancestor.balanceFac\n\t\t\t * tor的值为 R，且在ancestor对象的左子树插入，这两插入方式都不会引起树的高度发生变化，所以我们\n\t\t\t * 也不需要旋转，直接调整平衡因子即可\n\t\t\t *                      新增55后调整\n\t\t\t *  ancestor → 50           →              50\n\t\t\t *            /L\\                         /=\\\n\t\t\t *          25   70                     25   70\n\t\t\t *         /R\\   /=\\                   /R\\   /L\\\n\t\t\t *        15 30 60 90                 15 30 60 90\n\t\t\t *           /L                          /L /L\n\t\t\t *          28                          28 55\n\t\t\t *                      新增28后调整\n\t\t\t *  ancestor → 50            →             50\n\t\t\t *            /R\\                         /=\\\n\t\t\t *          25   70                     25   70\n\t\t\t *         /=\\   /L\\                   /R\\   /L\\\n\t\t\t *        15 30 60 90                 15 30 60 90\n\t\t\t *              /L                       /L /L\n\t\t\t *             55                       28 55\n\t\t\t */\n            //先设置ancestor的平衡因子为 平衡\n            ancestor.balanceFactor = '=';\n            //然后按照一般策略对inserted与ancestor间的元素进行调整\n            adjustPath(ancestor, inserted);\n        } else if (ancestor.balanceFactor == 'R'\n                && elem.compareTo(ancestor.right.elem) > 0) {\n\t\t\t/*\n\t\t\t * 情况3：\n\t\t\t * ancestor.balanceFactor的值为 R，并且被插入的Entry位于ancestor的右子树的右子树上， 此\n\t\t\t * 种情况下会引起树的不平衡，所以先需绕ancestor进行旋转，再进行平衡因子的调整\n\t\t\t *\n\t\t\t * 新增93                          先调整因子再绕70左旋\n\t\t\t *   →         50                    →           50\n\t\t\t *            /R\\                                /R\\\n\t\t\t *          25   70  ← ancestor                25  90\n\t\t\t *         /L    /R\\                          /L   /=\\\n\t\t\t *        15    60 90                        15  70   98\n\t\t\t *        =     =  /=\\                       =  /=\\   /L\n\t\t\t *                80  98                       60 80 93\n\t\t\t *                =   /=                       =  =  =\n\t\t\t *                   93\n\t\t\t *                   =\n\t\t\t */\n            ancestor.balanceFactor = '=';\n            //围绕ancestor执行一次左旋\n            rotateLeft(ancestor);\n            //再调整ancestor.paraent（90）到新增节点路径上祖先节点平衡\n            adjustPath(ancestor.parent, inserted);\n        } else if (ancestor.balanceFactor == 'L'\n                && elem.compareTo(ancestor.left.elem) < 0) {\n\t\t\t/*\n\t\t\t * 情况4：\n\t\t\t * ancestor.balanceFactor的值为 L，并且被插入的Entry位于ancestor的左子树的左子树上，\n\t\t\t * 此种情况下会引起树的不平衡，所以先需绕ancestor进行旋转，再进行平衡因子的调整\n\t\t\t * \n\t\t\t * 新增13                         先调整因子再绕50右旋\n\t\t\t *   →         50 ← ancestor        →            20\n\t\t\t *            /L\\                                /=\\\n\t\t\t *          20   70                            10   50\n\t\t\t *         /=\\   /=\\                          /R\\   /=\\\n\t\t\t *        10 30 60 90                        5  15 30  70\n\t\t\t *       /=\\ /=\\=  =                         = /L /=\\  /=\\\n\t\t\t *      5 15 25 35                            13 25 35 60 90\n\t\t\t *      = /= = =                              =  =  =  =  = \n\t\t\t *       13         \n\t\t\t *       =        \n\t\t\t */\n            ancestor.balanceFactor = '=';\n            //围绕ancestor执行一次右旋\n            rotateRight(ancestor);\n            //再调整ancestor.paraent（20）到新增节点路径上祖先节点平衡\n            adjustPath(ancestor.parent, inserted);\n        } else if (ancestor.balanceFactor == 'L'\n                && elem.compareTo(ancestor.left.elem) > 0) {\n\t\t\t/*\n\t\t\t * 情况5：\n\t\t\t * ancestor.balanceFactor的值为 L，并且被插入的Entry位于ancestor的左子树的右子树上。此\n\t\t\t * 种情况也会导致树不平衡，此种与第6种一样都需要执行两次旋转（执行一次绕ancestor的左子节点左\n\t\t\t * 旋，接着执行一次绕ancestor执行一次右旋）后，树才平衡，最后还需调用 左-右旋 专有方法进行平衡\n\t\t\t * 因子的调整\n\t\t\t */\n            rotateLeft(ancestor.left);\n            rotateRight(ancestor);\n            //旋转后调用 左-右旋 专有方法进行平衡因子的调整\n            adjustLeftRigth(ancestor, inserted);\n        } else if (ancestor.balanceFactor == 'R'\n                && elem.compareTo(ancestor.right.elem) < 0) {\n\n\t\t\t/*\n\t\t\t * 情况6：\n\t\t\t * ancestor.balanceFactor的值为 R，并且被插入的Entry位于ancestor的右子树的 左子树上，此\n\t\t\t * 种情况也会导致树不平衡，此种与第5种一样都需要执行两次旋转（执行一次绕ancestor的右子节点右旋\n\t\t\t * ，接着执行一次绕ancestor执行一次左旋）后，树才平衡，最后还需调用 右-左旋 专有方法进行平衡因\n\t\t\t * 子的调整\n\t\t\t */\n            rotateRight(ancestor.right);\n            rotateLeft(ancestor);\n            //旋转后调用 右-左旋 专有方法进行平衡因子的调整\n            adjustRigthLeft(ancestor, inserted);\n        }\n    }\n\n\n    /**\n     * 调整指定路径上的节点的平衡因子\n     *\n     * 注，指定的路径上的所有节点一定是平衡的，因此如果被插入元素小于某个祖先节点，\n     * 则这个祖先节点新的平衡因子是 L，反之为 R。\n     *\n     * @param inserted 从哪里元素开始向上调整，但不包括该，即从父开始）\n     * @param to 直到哪个元素结束,但不包括该元素，一般传进来的为ancestor\n     */\n    protected void adjustPath(Entry<E> to, Entry<E> inserted) {\n        E elem = inserted.elem;\n        Entry<E> tmp = inserted.parent;\n        //从新增节点的父节点开始向上回溯调整，直到结尾节点to止\n        while (tmp != to) {\n\t\t\t/*\n\t\t\t * 插入30，则在25右边插入，这样父节点平衡会被打破，右子树就会比左子树高1，所以平衡因子为R；祖\n\t\t\t * 先节点50的平衡因子也被打破，因为在50的左子树上插入的，所以对50来说，左子树会比右子树高1，所\n\t\t\t * 以其平衡因子为L\n\t\t\t *    50                      50\n\t\t\t *    /=\\       插入30        /L\\\n\t\t\t *   25  70       →         25  70\n\t\t\t *   =   =                   R\\  =\n\t\t\t *                            30\n\t\t\t *                            = \n\t\t\t */\n            //如果新增元素比祖先节点小，则是在祖先节点的左边插入，则自然该祖先的左比右子树会高1\n            if (elem.compareTo(tmp.elem) < 0) {\n\n                tmp.balanceFactor = 'L';\n            } else {\n                //否则会插到右边，那么祖先节点的右就会比左子树高1\n                tmp.balanceFactor = 'R';\n            }\n            tmp = tmp.parent;//再调整祖先的祖先\n        }\n    }\n\n    /**\n     * 进行 左-右旋转 后平衡因子调整\n     * 分三种情况\n     * @param ancestor\n     * @param inserted\n     */\n    protected void adjustLeftRigth(Entry<E> ancestor, Entry<E> inserted) {\n        E elem = inserted.elem;\n        if (ancestor.parent == inserted) {\n\t\t\t/*\n\t\t\t * 第1种，新增的节点在旋转完成后为ancestor父节点情况：\n\t\t\t * \n\t\t\t * 新增40                          绕30左旋                绕50右旋\n\t\t\t *   →      50 ← ancestor         →         50         →\n\t\t\t *          /L                              /L         \n\t\t\t *         30                              40  \n\t\t\t *         =\\                             /=\n\t\t\t *          40                           30\n\t\t\t *          =                            =\n\t\t\t *          \n\t\t\t *                    调整平衡因子\n\t\t\t *          40            →            40\n\t\t\t *          /=\\                        /=\\\n\t\t\t *         30 50                      30 50\n\t\t\t *         =  L                       =   =\n\t\t\t *         \n\t\t\t * 注，这里的 左-右旋 是在fixAfterInsertion方法中的第5种情况中完成的，在这里只是平衡因子的\n\t\t\t * 调整，图是为了好说明问题而放在这个方法中的，下面的两个分支也是一样      \n\t\t\t */\n            ancestor.balanceFactor = '=';\n        } else if (elem.compareTo(ancestor.parent.elem) < 0) {\n\t\t\t/*\n\t\t\t * 第2种，新增的节点在旋转完成后为不为ancestor父节点，且新增节点比旋转后ancestor的父节点要小\n\t\t\t * 的情况\n\t\t\t * \n\t\t\t * 由于插入元素(35)比旋转后ancestor(50)的父节点(40)要小， 所以新增节点会在其左子树中\n\t\t\t * \n\t\t\t * 新增35                         绕20左旋\n\t\t\t *   →      50 ← ancestor        →                 50\n\t\t\t *          /L\\                                    /L\\\n\t\t\t *        20   90                                40   90\n\t\t\t *       /=\\   /=\\                              /=\\   /=\\\n\t\t\t *     10  40 70  100                          20 45 70 100\n\t\t\t *    /=\\  /=\\=   =                            /=\\    \n\t\t\t *   5  15 30 45                              10  30   \n\t\t\t *   =  =  =\\ =                              /=\\   =\\\n\t\t\t *          35                              5  15   35\n\t\t\t *          =                               =  =    =\n\t\t\t *          \n\t\t\t *  绕50右旋                      调整平衡因子\n\t\t\t *     →        40                →                40\n\t\t\t *              /=\\                                /=\\\n\t\t\t *             20  50                            20   50\n\t\t\t *            /=\\  /L\\                          /=\\   /R\\\n\t\t\t *          10 30 45 90                        10 30 45  90\n\t\t\t *         /=\\  =\\   /=\\                      /=\\  R\\    /=\\\n\t\t\t *        5  15  35 70 100                   5  15  35  70  100\n\t\t\t *        =  =   =  =  =                     =  =   =   =   =\n\t\t\t *          \n\t\t\t */\n            ancestor.balanceFactor = 'R';\n            //调整ancestor兄弟节点到插入点路径上节点平衡因子\n            adjustPath(ancestor.parent.left, inserted);\n        } else {\n\t\t\t/*\n\t\t\t * 第2种，新增的节点在旋转完成后为不为ancestor父节点，且新增节点比旋转后ancestor的父节点要大的\n\t\t\t * 情况\n\t\t\t * \n\t\t\t * 由于插入元素(42)比旋转后ancestor(50)的父节点(40)要大，所以新增节点会在其右子树中\n\t\t\t * \n\t\t\t * 新增42                           绕20左旋\n\t\t\t *   →      50 ← ancestor          →               50\n\t\t\t *          /L\\                                    /L\\\n\t\t\t *        20   90                                40   90\n\t\t\t *       /=\\   /=\\                              /=\\    /=\\\n\t\t\t *     10  40 70  100                          20  45 70 100\n\t\t\t *    /=\\  /=\\=   =                           /=\\  /=\n\t\t\t *   5  15 30 45                             10 30 42  \n\t\t\t *   =  =  =  /=                             /=\\=  =\n\t\t\t *           42                             5  15   \n\t\t\t *           =                              =  =    \n\t\t\t *          \n\t\t\t * 绕50右旋                        调整平衡因子\n\t\t\t *   →          40                 →               40\n\t\t\t *              /=\\                                /=\\\n\t\t\t *             20  50                            20   50\n\t\t\t *            /=\\  /L\\                          /L\\   /=\\\n\t\t\t *          10 30 45 90                        10 30 45  90\n\t\t\t *         /=\\   /=  /=\\                      /=\\    /L  /=\\\n\t\t\t *        5  15 42  70 100                    5 15  42  70 100\n\t\t\t *        =  =  =   =  =                      =  =  =   =  =\n\t\t\t *          \n\t\t\t */\n            ancestor.parent.left.balanceFactor = 'L';\n\n            ancestor.balanceFactor = '=';\n            //调整ancestor节点到插入点路径上节点平衡因子\n            adjustPath(ancestor, inserted);\n        }\n    }\n\n    /**\n     * 进行 右-左旋转 后平衡因子调整\n     *\n     * 与adjustLeftRigth方法一样，也有三种情况，这两个方法是对称的\n     * @param ancestor\n     * @param inserted\n     */\n    protected void adjustRigthLeft(Entry<E> ancestor, Entry<E> inserted) {\n        E elem = inserted.elem;\n        if (ancestor.parent == inserted) {\n\t\t\t/*\n\t\t\t * 第1种，新增的节点在旋转完成后为ancestor父节点情况： \n\t\t\t * \n\t\t\t * 新增40                          绕50右旋                绕30左旋 \n\t\t\t *   →       30 ← ancestor        →        30          →\n\t\t\t *           R\\                            R\\         \n\t\t\t *            50                            40  \n\t\t\t *           /=                              =\\\n\t\t\t *          40                                50\n\t\t\t *          =                                 =\n\t\t\t *          \n\t\t\t *          40         调整平衡因子         40\n\t\t\t *          /=\\           →            /=\\\n\t\t\t *         30 50                      30  50\n\t\t\t *         R  =                       =   =\n\t\t\t *         \n\t\t\t * 注，这里的 右-左旋 是在fixAfterInsertion方法中的第6种情况中完成的，这里只是 平衡因子的调\n\t\t\t * 整，图是为了好说明问题而放在这个方法中的，下面的两个分支也是一样      \n\t\t\t */\n            ancestor.balanceFactor = '=';\n        } else if (elem.compareTo(ancestor.parent.elem) > 0) {\n\t\t\t/*\n\t\t\t * 第2种，新增的节点在旋转完成后为不为ancestor父节点，且新增节点比旋转后\n\t\t\t * ancestor的父节点要大的情况\n\t\t\t * \n\t\t\t * 由于插入元素(73)比旋转后ancestor(50)的父节点(70)要大， 所以新增节点会\n\t\t\t * 在其右子树中\n\t\t\t * \n\t\t\t * 新增73                          绕90右旋\n\t\t\t *   →       50 ← ancestor       →                  50\n\t\t\t *          /R\\                                    /R\\\n\t\t\t *        20   90                                20   70\n\t\t\t *       /=\\   /=\\                              /=\\   /=\\\n\t\t\t *     10  40 70  95                          10  40 65 90\n\t\t\t *     =   = /=\\  /=\\                         =   =  =  /=\\ \n\t\t\t *          65 75 93 97                                75  95\n\t\t\t *          =  /= =  =                                 /=  /=\\\n\t\t\t *            73                                      73  93 97\n\t\t\t *            =    \n\t\t\t *                          \n\t\t\t * 绕50左旋                       调整平衡因子\n\t\t\t *   →          70                →                70\n\t\t\t *              /=\\                                /=\\\n\t\t\t *            50   90                            50   90\n\t\t\t *           /R\\   /=\\                          /L\\   /=\\\n\t\t\t *          20 65 75  95                       20 65 75  95\n\t\t\t *         /=\\ =  /=  /=\\                     /=\\ =  /L  /=\\\n\t\t\t *        10  40 73  93 97                   10  40 73  93 97\n\t\t\t *        =   =   =   =  =                   =   =  =   =   =\n\t\t\t *          \n\t\t\t */\n            ancestor.balanceFactor = 'L';\n            adjustPath(ancestor.parent.right, inserted);\n        } else {\n\t\t\t/*\n\t\t\t * 第2种，新增的节点在旋转完成后为不为ancestor父节点，且新增节点比旋转后ancestor的父节点要小\n\t\t\t * 的情况\n\t\t\t * \n\t\t\t * 由于插入元素(73)比旋转后ancestor(50)的父节点(70)要大， 所以新增节点会在其右子树中\n\t\t\t * \n\t\t\t * 新增63                          绕90右旋\n\t\t\t *   →       50 ← ancestor       →                 50\n\t\t\t *          /R\\                                    /R\\\n\t\t\t *        20   90                                20   70\n\t\t\t *       /=\\   /=\\                              /=\\   /=\\\n\t\t\t *     10  40 70  95                          10  40 65 90\n\t\t\t *     =   = /=\\  /=\\                         =   =  /= /=\\ \n\t\t\t *          65 75 93 97                             63 75 95\n\t\t\t *          /= =  =  =                              =  =  /=\\\n\t\t\t *         63                                            93 97\n\t\t\t *         =                                             =  =\n\t\t\t *                          \n\t\t\t * 绕50左旋                       调整平衡因子\n\t\t\t *   →          70                →                70\n\t\t\t *              /=\\                                /=\\\n\t\t\t *            50   90                            50   90\n\t\t\t *           /R\\   /=\\                          /=\\   /R\\\n\t\t\t *         20  65 75 95                       20  65 75 95\n\t\t\t *        /=\\  /= =  /=\\                     /=\\  /L    /=\\\n\t\t\t *       10 40 63   93 97                   10 40 63   93 97\n\t\t\t *       =  =  =    =  =                    =  =  =    =  =         \n\t\t\t */\n            ancestor.parent.right.balanceFactor = 'R';\n            ancestor.balanceFactor = '=';\n            adjustPath(ancestor, inserted);\n        }\n    }\n\n    /**\n     * 删除指定节点\n     *\n     * @param elem\n     * @return boolean\n     */\n    public boolean remove(E elem) {\n        Entry<E> e = getEntry(elem);\n        if (e == null)\n            return false;\n        deleteEntry(e);\n        return true;\n    }\n\n    private Entry<E> getEntry(E e) {\n        Entry<E> tmp = root;\n        int c;\n        while (tmp != null) {\n            c = e.compareTo(tmp.elem);\n            if (c == 0) {\n                return tmp;\n            } else if (c < 0) {\n                tmp = tmp.left;\n            } else {\n                tmp = tmp.right;\n            }\n        }\n        return null;\n    }\n\n    private void deleteEntry(Entry<E> p) {\n        if (p.left != null && p.right != null) {\n\n            Entry<E> s = successor(p);\n\n            p.elem = s.elem;\n\n            p = s;\n        }\n\n        if (p.left == null && p.right == null) {\n\n            if (p.parent == null) {\n                root = null;\n            } else if (p == p.parent.left) {\n                p.parent.left = null;\n            } else {\n                p.parent.right = null;\n            }\n\n        } else {\n\n            Entry<E> rep;\n            if (p.left != null) {\n                rep = p.left;\n            } else {\n                rep = p.right;\n            }\n\n            rep.parent = p.parent;\n\n            if (p.parent == null) {\n                root = rep;\n            } else if (p == p.parent.left) {\n                p.parent.left = rep;\n            } else {\n                p.parent.right = rep;\n            }\n\n        }\n        fixAfterDeletion(p.elem, p.parent);\n\n        p.parent = null;\n        p.left = null;\n        p.right = null;\n\n        size--;\n    }\n\n    /**\n     * 查找指定节点的中序遍历序列的直接后继节点，此方法的实现与二叉搜索树类（BinSearchTree.java）的此方法是\n     * 一样的，具体的思路请参考二叉搜索树类中的相应方法\n     *\n     * @param e 需要查找哪个节点的直接后继节点\n     * @return Entry<E> 直接后继节点\n     */\n    private Entry<E> successor(Entry<E> e) {\n        if (e == null) {\n            return null;\n        }//如果待找的节点有右子树，则在右子树上查找\n        else if (e.right != null) {\n            //默认后继节点为右子节点（如果右子节点没有左子树时即为该节点）\n            Entry<E> p = e.right;\n            while (p.left != null) {\n                //注，如果右子节点的左子树不为空，则在左子树中查找，且后面找时要一直向左拐\n                p = p.left;\n            }\n            return p;\n        }//如果待查节点没有右子树，则要在祖宗节点中查找后继节点\n        else {\n\n            //默认后继节点为父节点（如果待查节点为父节点的左子树，则后继为父节点）\n            Entry<E> p = e.parent;\n            Entry<E> c = e;//当前节点，如果其父不为后继，则下次指向父节点\n            //如果待查节点为父节点的右节点时，继续向上找，一直要找到c为左子节点，则p才是后继\n            while (p != null && c == p.right) {\n                c = p;\n                p = p.parent;\n            }\n            return p;\n        }\n    }\n\n\n    /**\n     * 删除节点后平衡调整实现\n     *\n     * @param elem 被删除节点的数据域\n     * @param ancestor 被删除节点的祖先节点，从父节点向上迭代\n     */\n    protected void fixAfterDeletion(E elem, Entry<E> ancestor) {\n\n        boolean heightHasDecreased = true;//树的高度是否还需要减小\n\n\t\t/*\n\t\t * 1、如果删除的是根节点，则ancestor为空，此时不需调整了，直接退出\n\t\t * 2、如果删除的不是根节点，且根节点都已调整，则退出\n\t\t * 3、如果删除的不是根节点，且树的高度不需再减小（heightHasDecreased为false），退出\n\t\t */\n        while (ancestor != null && heightHasDecreased) {\n\n            int comp = elem.compareTo(ancestor.elem);\n\n\t\t\t/*\n\t\t\t * 当要删除的节点有左右子树时，comp就会等于0，比如下面要删除33这个节点，删除方法deleteEntry\n\t\t\t * 会用36替换掉33节点中的数据的elem，删除后会调用fixAfterDeletion(p.elem, p.parent)方\n\t\t\t * 法来调整平衡因子，p又是指向的36，所以p.elem与p.parent.elem是相等的，都是36\n\t\t\t * \n\t\t\t *            82\n\t\t\t *           /L\\\n\t\t\t *         42   95\n\t\t\t *        /=\\   R\\\n\t\t\t *       33 48   96\n\t\t\t *      /=\\  /=\\\n\t\t\t *     29 36 43 75\n\t\t\t */\n\n            //从ancestor的右子树中删除节点\n            if (comp >= 0) {\n                // ancestor 的平衡因子为 '='\n                if (ancestor.balanceFactor == '=') {\n\n\t\t\t\t\t/* 删除15       调整因子\n\t\t\t\t\t *      20       →           20\n\t\t\t\t\t *      /L\\                  /L\\\n\t\t\t\t\t *   → 10 50                10 50\n\t\t\t\t\t *     /=\\                  /L\n\t\t\t\t\t *    5  15                5\n\t\t\t\t\t */\n                    ancestor.balanceFactor = 'L';\n                    heightHasDecreased = false;\n\n                } // ancestor 的平衡因子为 'R'\n                else if (ancestor.balanceFactor == 'R') {\n\t\t\t\t\t/* 删除15       调整因子                    下次循环调整20的因子\n\t\t\t\t\t *      20       →         → 20 ← ancestor   → ...\n\t\t\t\t\t *      /L\\                  /L\\\n\t\t\t\t\t *   → 10 50                10 50\n\t\t\t\t\t *     /R\\ R\\               /=\\ R\\\n\t\t\t\t\t *    5  15 60              5 18 60\n\t\t\t\t\t *        R\\\n\t\t\t\t\t *         18\n\t\t\t\t\t */\n                    ancestor.balanceFactor = '=';\n                    ancestor = ancestor.parent;\n\n                }// ancestor 的平衡因子为 'L'\n                else if (ancestor.balanceFactor == 'L') {\n                    // ancestor 的左子节点平衡因子为 '='\n                    if (ancestor.left.balanceFactor == '=') {\n\n\t\t\t\t\t\t/* 删除60       调整因子              绕50右旋\n\t\t\t\t\t\t *      20       →     → 20         →        20\n\t\t\t\t\t\t *      /R\\              / \\                 /R\\\n\t\t\t\t\t\t *     10 50 ← ancestor 10 50 ←             10 45\n\t\t\t\t\t\t *     /L /L\\           /  /L\\              /L /R\\\n\t\t\t\t\t\t *    5  45 60         5  45 60            5  35 50 ← \n\t\t\t\t\t\t *      /=\\              /R\\                     /L\n\t\t\t\t\t\t *     35 48            35 48                   48\n\t\t\t\t\t\t */\n                        ancestor.left.balanceFactor = 'R';\n                        ancestor.balanceFactor = 'L';\n                        rotateRight(ancestor);\n                        heightHasDecreased = false;\n\n                    }// ancestor 的左子节点平衡因子为 'L'\n                    else if (ancestor.left.balanceFactor == 'L') {\n\n\t\t\t\t\t\t/* 删除60       调整因子           绕50右旋   下次循环调整20的因子\n\t\t\t\t\t\t *      20       →     → 20     →    20 ← p     → ...\n\t\t\t\t\t\t *      /R\\              / \\         /R\\\n\t\t\t\t\t\t *     10 50 ← ancestor 10 50 ←     10 45\n\t\t\t\t\t\t *     /L /L\\           /  /=\\      /L /=\\\n\t\t\t\t\t\t *    5  45 60         5  45 60    5  35 50 ← ancestor\n\t\t\t\t\t\t *      /L               /=              =\n\t\t\t\t\t\t *     35               35                      \n\t\t\t\t\t\t */\n                        Entry<E> p = ancestor.parent;\n                        ancestor.balanceFactor = '=';\n                        ancestor.left.balanceFactor = '=';\n                        rotateRight(ancestor);\n                        ancestor = p;\n\n                    } // ancestor 的左子节点平衡因子为 'R'\n                    else if (ancestor.left.balanceFactor == 'R') {\n\n                        Entry<E> p = ancestor.parent;\n\n                        // ancestor 的左子节点的右子节点的平衡因子为 'L'\n                        if (ancestor.left.right.balanceFactor == 'L') {\n\n\t\t\t\t\t\t\t/* 删除60        调整因子               \n\t\t\t\t\t\t\t *      20        →       20             \n\t\t\t\t\t\t\t *      /R\\               / \\\n\t\t\t\t\t\t\t *    10   50 ← ancestor 10  50 ← ancestor\n\t\t\t\t\t\t\t *    /L\\   /L\\          / \\  /R\\\n\t\t\t\t\t\t\t *   5  12 45 60        5  12 45 70\n\t\t\t\t\t\t\t *  /L    /R\\  R\\      /     /=\\  \n\t\t\t\t\t\t\t * 3     42 48  70    3     42 48  \n\t\t\t\t\t\t\t *          /L                 /= \n\t\t\t\t\t\t\t *         46                 46\n\t\t\t\t\t\t\t *         \n\t\t\t\t\t\t\t *  绕45左旋         绕50右旋           下次循环调整20的因子\n\t\t\t\t\t\t\t *    →     20       →         20 ← p      → ...\n\t\t\t\t\t\t\t *          /R\\                /R\\\n\t\t\t\t\t\t\t *         10  50 ←          10   48\n\t\t\t\t\t\t\t *         /L\\  /R\\          /L\\   /=\\\n\t\t\t\t\t\t\t *        5 12 48 70        5  12 45 50 ← ancestor\n\t\t\t\t\t\t\t *       /L   /=           /L    /=\\  R\\\n\t\t\t\t\t\t\t *      3    45           3     42 46  70\n\t\t\t\t\t\t\t *          /=\\\n\t\t\t\t\t\t\t *         42 46\n\t\t\t\t\t\t\t */\n                            ancestor.balanceFactor = 'R';\n                            ancestor.left.balanceFactor = '=';\n\n                        }// ancestor 的左子节点的右子节点的平衡因子为 'R'\n                        else if (ancestor.left.right.balanceFactor == 'R') {\n\n\t\t\t\t\t\t\t/* 删除60        调整因子               \n\t\t\t\t\t\t\t *      20        →       20             \n\t\t\t\t\t\t\t *      /R\\               / \\\n\t\t\t\t\t\t\t *    10   50 ← ancestor 10  50 ← \n\t\t\t\t\t\t\t *    /L\\   /L\\          / \\  /=\\\n\t\t\t\t\t\t\t *   5  12 45 60        5  12 45 70\n\t\t\t\t\t\t\t *  /L    /R\\  R\\      /     /L\\  \n\t\t\t\t\t\t\t * 3     42 48  70    3     42 48  \n\t\t\t\t\t\t\t *           R\\                 =\\ \n\t\t\t\t\t\t\t *            49                 49\n\t\t\t\t\t\t\t *         \n\t\t\t\t\t\t\t *  绕45左旋         绕50右旋           下次循环调整20的因子\n\t\t\t\t\t\t\t *    →     20       →         20 ← p      → ...\n\t\t\t\t\t\t\t *          /R\\                /R\\\n\t\t\t\t\t\t\t *         10  50 ←          10   48\n\t\t\t\t\t\t\t *         /L\\  /=\\          /L\\   /=\\\n\t\t\t\t\t\t\t *        5 12 48 70        5  12 45 50 ← ancestor\n\t\t\t\t\t\t\t *       /L   /=\\          /L    /L  /=\\\n\t\t\t\t\t\t\t *      3    45 49        3     42  49 70\n\t\t\t\t\t\t\t *          /L\n\t\t\t\t\t\t\t *         42 \n\t\t\t\t\t\t\t */\n                            ancestor.balanceFactor = '=';\n                            ancestor.left.balanceFactor = 'L';\n\n                        }// ancestor 的左子节点的右子节点的平衡因子为 '='\n                        else {\n\t\t\t\t\t\t\t/* 删除60        调整因子               \n\t\t\t\t\t\t\t *      20        →       20             \n\t\t\t\t\t\t\t *      /R\\               / \\\n\t\t\t\t\t\t\t *    10   50 ← ancestor 10  50 ← \n\t\t\t\t\t\t\t *    /L\\   /L\\          / \\  /=\\\n\t\t\t\t\t\t\t *   5  12 45 60        5  12 45 70\n\t\t\t\t\t\t\t *  /L    /R\\  R\\      /     /=\\  \n\t\t\t\t\t\t\t * 3     42 48  70    3     42 48  \n\t\t\t\t\t\t\t *          /=\\                /=\\ \n\t\t\t\t\t\t\t *         46 49              46 49\n\t\t\t\t\t\t\t *         \n\t\t\t\t\t\t\t *  绕45左旋         绕50右旋           下次循环调整20的因子\n\t\t\t\t\t\t\t *    →     20       →         20 ← p      → ...\n\t\t\t\t\t\t\t *          /R\\                /R\\\n\t\t\t\t\t\t\t *         10  50 ←          10   48\n\t\t\t\t\t\t\t *         /L\\  /=\\          /L\\   /=\\\n\t\t\t\t\t\t\t *        5 12 48 70        5  12 45  50 ← ancestor\n\t\t\t\t\t\t\t *       /L   /=\\          /L    /=\\   /=\\\n\t\t\t\t\t\t\t *      3    45 49        3     42 46 49 70\n\t\t\t\t\t\t\t *          /=\\\n\t\t\t\t\t\t\t *         42 46\n\t\t\t\t\t\t\t */\n                            ancestor.balanceFactor = '=';\n                            ancestor.left.balanceFactor = '=';\n\n                        }\n                        ancestor.left.right.balanceFactor = '=';\n                        rotateLeft(ancestor.left);\n                        rotateRight(ancestor);\n                        ancestor = p;\n                    }\n                }\n\n            }\n            //从ancestor的左子树中删除节点,与上面是对称的\n            else if (comp < 0) {\n\n                if (ancestor.balanceFactor == '=') {\n\n                    ancestor.balanceFactor = 'R';\n                    heightHasDecreased = false;\n                } else if (ancestor.balanceFactor == 'L') {\n\n                    ancestor.balanceFactor = '=';\n                    ancestor = ancestor.parent;\n\n                } else if (ancestor.balanceFactor == 'R') {\n\n                    if (ancestor.right.balanceFactor == '=') {\n\n                        ancestor.balanceFactor = 'R';\n                        ancestor.right.balanceFactor = 'L';\n                        rotateLeft(ancestor);\n                        heightHasDecreased = false;\n\n                    } else if (ancestor.right.balanceFactor == 'R') {\n\n                        Entry<E> p = ancestor.parent;\n                        ancestor.balanceFactor = '=';\n                        ancestor.right.balanceFactor = '=';\n                        rotateLeft(ancestor);\n                        ancestor = p;\n\n                    } else if (ancestor.right.balanceFactor == 'L') {\n\n                        Entry<E> p = ancestor.parent;\n                        if (ancestor.right.left.balanceFactor == 'R') {\n\n                            ancestor.balanceFactor = 'L';\n                            ancestor.right.balanceFactor = '=';\n\n                        } else if (ancestor.right.left.balanceFactor == 'L') {\n\n                            ancestor.balanceFactor = '=';\n                            ancestor.right.balanceFactor = 'R';\n\n                        } else {\n\n                            ancestor.balanceFactor = '=';\n                            ancestor.right.balanceFactor = '=';\n\n                        }\n                        ancestor.right.left.balanceFactor = '=';\n                        rotateRight(ancestor.right);\n                        rotateLeft(ancestor);\n                        ancestor = p;\n\n                    }\n                }\n            }\n        }\n    }\n\n    public boolean contains(E o) {\n\n        Entry<E> e = root;\n\n        int comp;\n\n        while (e != null) {\n\n            comp = o.compareTo(e.elem);\n            if (comp == 0)\n                return true;\n            else if (comp < 0)\n                e = e.left;\n            else\n                e = e.right;\n\n        }\n        return false;\n    }\n\n    //验证树是否是平衡二叉树\n    public boolean isAVL() {\n\n        return checkAVL(root);\n\n    }\n\n    /**\n     * 验证指定的树是否是平衡二叉树\n     * @param p\n     * @return\n     */\n    public static <E extends Comparable<E>> boolean checkAVL(Entry<E> p) {\n\n        if (p == null)\n            return true;\n        //左子树与右子树绝对值不能超过 1，并且左右子树也是平衡二叉树\n        return (Math.abs(h(p.left) - h(p.right)) <= 1 && checkAVL(p.left) && checkAVL(p.right));\n\n    }\n\n    /**\n     * 求指定节点的高度\n     * @param <E>\n     * @param p\n     * @return\n     */\n    protected static <E extends Comparable<E>> int h(Entry<E> p) {\n\n        if (p == null)\n            return -1;\n        return 1 + Math.max(h(p.left), h(p.right));\n    }\n\n    /**\n     * 树的高度\n     * @return\n     */\n    public int height() {\n\n        return h(root);\n\n    }\n\n    //树的高度非递归求法\n    public int heightIter() {\n\n        int height = -1;\n        for (Entry<E> temp = root; temp != null; height++)\n            if (temp.balanceFactor == 'L')\n                temp = temp.left;\n            else\n                temp = temp.right;\n        return height;\n    }\n\n    @Override\n    public Iterator<E> iterator() {\n        return new TreeIterator();\n    }\n\n    @Override\n    public int size() {\n        return size;\n    }\n\n    public static void main(String[] args) {\n        BaseAvlTree<Integer> myTree = new BaseAvlTree<Integer>();\n        Random random = new Random();\n        System.out.print(\"随机产生的节点为：\");\n        int num = 0;\n        //直到树的节点数为n止  \n        while (myTree.size() < 10) {\n            num = new Integer(random.nextInt(100));\n            myTree.add(num);\n            System.out.print(num + \" \");\n        }\n        System.out.println(\"\");\n        if (myTree.isAVL()) {\n            System.out.println(\"这棵平衡二叉树的总节点数：\" + myTree.size());\n            System.out.println(\"这棵平衡二叉树的高度是：\" + myTree.height());\n            System.out.println(\"在树中查找 \" + num + \" 节点:\"\n                    + myTree.contains(new Integer(num)));\n            System.out.println(\"在树中查找 100 节点:\" + myTree.contains(new Integer(100)));\n            System.out.print(\"中序遍历：\");\n            Iterator<Integer> itr = myTree.iterator();\n            while (itr.hasNext()) {\n                System.out.print(itr.next() + \" \");\n            }\n            System.out.println(\"\");\n\n            myTree.remove(num);\n            System.out.print(\"删除节点 \" + num + \" 后遍历：\");\n            itr = myTree.iterator();\n            while (itr.hasNext()) {\n                System.out.print(itr.next() + \" \");\n            }\n            System.out.println(\"\");\n\n            System.out.println(\"使用迭代器删除所有节点\");\n            itr = myTree.iterator();\n            while (itr.hasNext()) {\n                itr.next();\n                itr.remove();\n            }\n            System.out.println(\"删除后树的总节点数：\" + myTree.size());\n        } else {\n            System.out.println(\"failure\");\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseDate.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport java.sql.Timestamp;\nimport java.text.SimpleDateFormat;\nimport java.util.Date;\n\npublic class BaseDate {\n\n    public static String FORMAT_YY_MM_DD_HH_MM_SS = \"yyyy-MM-dd HH:mm:ss\";\n    public static String FORMAT_YY_MM_DD = \"yyyy-MM-dd\";\n\n    /**\n     * 转换时间to字符串\n     * @param String format\n     * @param long time\n     * @return String\n     */\n    public static String time2String(String format, long time) {\n        SimpleDateFormat formatter = new SimpleDateFormat(format);\n        Date curDate = new Date(time);\n        return formatter.format(curDate);\n    }\n\n    /**\n     * 转换时间to字符串\n     * @param String format\n     * @return String\n     */\n    public static String time2String(String format) {\n        return time2String(format, System.currentTimeMillis());\n    }\n\n    /**\n     * 字符时间到long\n     * @param date\n     * @return\n     */\n    public static long string2Time(String date) {\n        if (date != null && !date.equals(\"\")) {\n            return Timestamp.valueOf(date).getTime();\n        }\n        return 0l;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseFile.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.*;\nimport java.net.URL;\nimport java.net.URLDecoder;\nimport java.util.*;\nimport java.util.jar.JarEntry;\nimport java.util.jar.JarFile;\n\n@SuppressWarnings(\"resource\")\npublic class BaseFile {\n\n    private static final Logger log = LoggerFactory.getLogger(BaseFile.class);\n\n\n    public static Set<Class<?>> getClasses(String pack, boolean recursive) {\n        return getClasses(pack, \"\", recursive);\n    }\n\n    /**\n     * 从包package中获取所有的Class\n     *\n     * @param pack String\n     * @param suffix String\n     * @param recursive 是迭代\n     * @return String\n     */\n    public static Set<Class<?>> getClasses(String pack, String suffix, boolean recursive) {\n        // 第一个class类的集合\n        Set<Class<?>> classes = new LinkedHashSet<Class<?>>();\n        // 获取包的名字 并进行替换\n        String packageName = pack;\n        String packageDirName = packageName.replace('.', '/');\n        // 定义一个枚举的集合 并进行循环来处理这个目录下的things\n        Enumeration<URL> dirs;\n        try {\n            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);\n            // 循环迭代下去\n            while (dirs.hasMoreElements()) {\n                // 获取下一个元素\n                URL url = dirs.nextElement();\n                // 得到协议的名称\n                String protocol = url.getProtocol();\n                // 如果是以文件的形式保存在服务器上\n                if (\"file\".equals(protocol)) {\n                    // 获取包的物理路径\n                    String filePath = URLDecoder.decode(url.getFile(), \"UTF-8\");\n                    // 以文件的方式扫描整个包下的文件 并添加到集合中\n                    findAndAddClassesInPackageByFile(packageName, filePath, suffix, recursive, classes);\n                } else if (\"jar\".equals(protocol)) {\n                    // 如果是jar包文件\n                    // 定义一个JarFile\n                    JarFile jar;\n                    try {\n                        String jarPath = url.getPath();\n                        if (jarPath.indexOf(\"file:\") == 0) {\n                            jarPath = jarPath.substring(5);\n                        }\n                        int index = jarPath.lastIndexOf(\".jar\");\n                        jarPath = jarPath.substring(0, index) + \".jar\";\n                        // 获取jar\n                        jar = new JarFile(jarPath);\n                        // 从此jar包 得到一个枚举类\n                        Enumeration<JarEntry> entries = jar.entries();\n                        // 同样的进行循环迭代\n                        while (entries.hasMoreElements()) {\n                            // 获取jar里的一个实体 可以是目录 和一些jar包里的其他文件 如META-INF等文件\n                            JarEntry entry = entries.nextElement();\n                            String name = entry.getName();\n                            // 如果是以/开头的\n                            if (name.charAt(0) == '/') {\n                                // 获取后面的字符串\n                                name = name.substring(1);\n                            }\n                            // 如果前半部分和定义的包名相同\n                            if (name.startsWith(packageDirName)) {\n                                int idx = name.lastIndexOf('/');\n                                // 如果以\"/\"结尾 是一个包\n                                if (idx != -1) {\n                                    // 获取包名 把\"/\"替换成\".\"\n                                    packageName = name.substring(0, idx).replace('/', '.');\n                                }\n                                // 如果可以迭代下去 并且是一个包\n                                if ((idx != -1) || recursive) {\n                                    // 如果是一个.class文件 而且不是目录\n                                    if (name.endsWith(\".class\") && !entry.isDirectory()) {\n                                        // 去掉后面的\".class\" 获取真正的类名\n                                        String className = name.substring(packageName.length() + 1, name.length() - 6);\n                                        try {\n                                            // 添加到classes\n                                            classes.add(Class.forName(packageName + '.' + className));\n                                        } catch (ClassNotFoundException e) {\n                                            log.error(\"添加用户自定义视图类错误 找不到此类的.class文件\", e);\n                                        }\n                                    }\n                                }\n                            }\n                        }\n                    } catch (IOException e) {\n                        log.error(\"在扫描用户定义视图时从jar包获取文件出错\", e);\n                    }\n                }\n            }\n        } catch (IOException e) {\n        }\n\n        return classes;\n    }\n\n    /**\n     * 以文件的形式来获取包下的所有Class\n     *\n     * @param packageName\n     * @param packagePath\n     * @param recursive\n     * @param classes\n     */\n    private static void findAndAddClassesInPackageByFile(String packageName, String packagePath, final String suffix, final boolean recursive, Set<Class<?>> classes) {\n        // 获取此包的目录 建立一个File\n        File dir = new File(packagePath);\n        // 如果不存在或者 也不是目录就直接返回\n        if (!dir.exists() || !dir.isDirectory()) {\n            // log.warn(\"用户定义包名 \" + packageName + \" 下没有任何文件\");\n            return;\n        }\n        // 如果存在 就获取包下的所有文件 包括目录\n        File[] dirfiles = dir.listFiles(new FileFilter() {\n            // 自定义过滤规则 如果可以循环(包含子目录) 或则是以.class结尾的文件(编译好的java类文件)\n            public boolean accept(File file) {\n                return (recursive && file.isDirectory()) || (file.getName().endsWith(suffix + \".class\"));\n            }\n        });\n        // 循环所有文件\n        for (File file : dirfiles) {\n            // 如果是目录 则继续扫描\n            if (file.isDirectory()) {\n                findAndAddClassesInPackageByFile(packageName + \".\" + file.getName(), file.getAbsolutePath(), suffix, recursive, classes);\n            } else {\n                // 如果是java类文件 去掉后面的.class 只留下类名\n                String className = file.getName().substring(0, file.getName().length() - 6);\n                try {\n                    // 添加到集合中去\n                    // classes.add(Class.forName(packageName + '.' +\n                    // className));\n                    // 经过回复同学的提醒，这里用forName有一些不好，会触发static方法，没有使用classLoader的load干净\n                    classes.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + '.' + className));\n                } catch (ClassNotFoundException e) {\n                    log.error(\"添加用户自定义视图类错误 找不到此类的.class文件\", e);\n                }\n            }\n        }\n    }\n\n    public static List<String> fileList(String path) {\n        return fileList(path, false);\n    }\n\n    public static List<String> fileList(String path, boolean needDir) {\n        List<String> list = new ArrayList<String>();\n        File file = new File(path);\n        if (file.isDirectory()) {\n            String[] filelist = file.list();\n            for (int i = 0; i < filelist.length; i++) {\n                file = new File(path + \"/\" + filelist[i]);\n                if (!file.isDirectory()) {\n                    list.add(file.getName());\n                } else {\n                    if (needDir) {\n                        list = fileList(list, path, file.getName());\n                    }\n                }\n            }\n        }\n        return list;\n    }\n\n    private static List<String> fileList(List<String> list, String path, String dir) {\n        File file = new File(path + \"/\" + dir);\n        if (file.isDirectory()) {\n            String[] filelist = file.list();\n            for (int i = 0; i < filelist.length; i++) {\n                file = new File(path + \"/\" + dir + \"/\" + filelist[i]);\n                if (!file.isDirectory()) {\n                    list.add(dir + \"/\" + file.getName());\n                } else {\n                    list = fileList(list, path, dir + \"/\" + file.getName());\n                }\n            }\n        }\n        return list;\n    }\n\n    public static String readResourceByLines(String resourcePath) {\n        // 返回读取指定资源的输入流\n        InputStream is = BaseFile.class.getClassLoader().getResourceAsStream(resourcePath);\n        BufferedReader reader = new BufferedReader(new InputStreamReader(is));\n        StringBuffer buffer = new StringBuffer(\"\");\n        try {\n            String tempString = null;\n            while ((tempString = reader.readLine()) != null) {\n                buffer.append(tempString);\n                buffer.append(\"\\n\");\n            }\n        } catch (IOException e) {\n            log.error(\"读取文件失败\", e);\n        } finally {\n            if (reader != null) {\n                try {\n                    reader.close();\n                } catch (IOException e1) {\n                }\n            }\n        }\n        return buffer.toString();\n    }\n\n    /**\n     * 以行为单位读取文件，常用于读面向行的格式化文件\n     */\n    public static String readFileByLines(String fileName) {\n        File file = new File(fileName);\n        return readFileByLines(file);\n    }\n\n    /**\n     * 以行为单位读取文件，常用于读面向行的格式化文件\n     */\n    public static String readFileByLines(File file) {\n        BufferedReader reader = null;\n        StringBuffer buffer = new StringBuffer(\"\");\n        try {\n            reader = new BufferedReader(new FileReader(file));\n            String tempString = null;\n            // 一次读入一行，直到读入null为文件结束\n            while ((tempString = reader.readLine()) != null) {\n                buffer.append(tempString);\n                buffer.append(\"\\n\");\n            }\n            reader.close();\n        } catch (IOException e) {\n            log.error(\"读取文件失败\", e);\n        } finally {\n            if (reader != null) {\n                try {\n                    reader.close();\n                } catch (IOException e1) {\n                }\n            }\n        }\n        return buffer.toString();\n    }\n\n    public static String readFileLastByLine(String filePath, int lastStart, int limit) {\n        File file = new File(filePath);\n        String buffer = \"\";\n        if (!file.exists()) {\n            return buffer;\n        }\n        RandomAccessFile raf;\n        try {\n            raf = new RandomAccessFile(file, \"r\");\n            long len = raf.length();\n            int line = 0;\n            if (len != 0L) {\n                long pos = len - 1;\n                while (pos > 0) {\n                    raf.seek(pos);\n                    if (raf.readByte() == '\\n') {\n                        if (lastStart <= line && line < lastStart + limit) {\n                            String temp = \"\";\n                            // Windows下有乱码问题\n                            String tempLine = raf.readLine();\n                            if (tempLine == null) {\n                                pos--;\n                                continue;\n                            }\n                            temp += tempLine;\n                            temp += \"\\n\";\n                            buffer += temp;\n                            pos--;\n                        }\n                        line++;\n                    } else {\n                        pos--;\n                    }\n                    if (line >= lastStart + limit) {\n                        break;\n                    }\n                }\n            }\n            raf.close();\n        } catch (IOException e) {\n            log.error(\"读取文件失败\", e);\n        }\n        return buffer;\n    }\n\n    /**\n     * 判断文件的编码格式\n     *\n     * @param fileName\n     *            :file\n     * @return 文件编码格式\n     * @throws Exception\n     */\n    public static String codeString(String fileName) throws Exception {\n        BufferedInputStream bin = new BufferedInputStream(new FileInputStream(fileName));\n        int p = (bin.read() << 8) + bin.read();\n        String code = null;\n        // 其中的 0xefbb、0xfffe、0xfeff、0x5c75这些都是这个文件的前面两个字节的16进制数\n        switch (p) {\n            case 0xefbb:\n                code = \"UTF-8\";\n                break;\n            case 0xfffe:\n                code = \"Unicode\";\n                break;\n            case 0xfeff:\n                code = \"UTF-16BE\";\n                break;\n            case 0x5c75:\n                code = \"ANSI|ASCII\";\n                break;\n            default:\n                code = \"GBK\";\n        }\n\n        return code;\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseGeneratePassword.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport java.util.Random;\n\npublic class BaseGeneratePassword {\n\n    private static char arrayString[] = new char[62]; // 候选字符数组\n\n    static {\n        int j = 0;\n        for (int i = 48; i <= 57; i++) { // 0-9\n            arrayString[j] = (char) i;\n            j++;\n        }\n        for (int i = 65; i <= 90; i++) { // A-Z\n            arrayString[j] = (char) i;\n            j++;\n        }\n        for (int i = 97; i <= 122; i++) { // a-z\n            arrayString[j] = (char) i;\n            j++;\n        }\n    }\n\n    /**\n     * 生成密码\n     * @param intPassLength 密码长度\n     * @return String\n     */\n    public static String doGenerate(final int intPassLength) {\n        int intTemp;\n        String strPassword = \"\";\n        Random rand = new Random();\n        for (int i = 0; i < intPassLength; i++) {\n            intTemp = rand.nextInt(62);\n            strPassword += arrayString[intTemp];\n        }\n        return strPassword;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseIp.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class BaseIp {\n\n    private static final Logger log = LoggerFactory.getLogger(BaseIp.class);\n\n    public static Long[] stringToIp(String ips) {\n        Long[] longArr;\n        String[] ipArr = ips.split(\"-\");\n        if (ipArr.length == 2) {\n            longArr = new Long[2];\n            longArr[0] = ipToLong(ipArr[0]);\n            longArr[1] = ipToLong(ipArr[1]);\n        } else {\n            longArr = new Long[1];\n            longArr[0] = ipToLong(ipArr[0]);\n        }\n        return longArr;\n    }\n\n    public static long ipToLong(String ip) {\n        String[] ipArr = ip.split(\"\\\\.\");\n        if (ipArr.length != 4) {\n            log.error(\"ip格式错误：\" + ip);\n            return 0L;\n        }\n        long s = 0;\n        for (int i = 0; i < ipArr.length; i++) {\n            s += (long) (Long.parseLong(ipArr[i]) * Math.pow(1000, 3 - i));\n        }\n        return s;\n    }\n\n    public static boolean checkIp(String ip, Long[] ipArr) {\n        long ipLong = ipToLong(ip);\n        if (ipArr.length == 1) {\n            if (ipLong == ipArr[0]) {\n                return true;\n            }\n        } else {\n            if (ipArr[0] <= ipLong && ipLong <= ipArr[1]) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseJson.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport com.alibaba.fastjson.JSON;\nimport com.alibaba.fastjson.serializer.SerializerFeature;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\npublic class BaseJson {\n\n    private static final Logger log = LoggerFactory.getLogger(BaseJson.class);\n\n    public static <T> T JsonToObject(String jsonStr, Class<T> c) {\n        return JSON.parseObject(jsonStr, c);\n    }\n\n    public static String ObjectToJson(Object obj) {\n        return JSON.toJSONString(obj, SerializerFeature.WriteNonStringKeyAsString, SerializerFeature.BrowserCompatible);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseRunTimer.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport org.apache.commons.logging.Log;\nimport org.apache.commons.logging.LogFactory;\nimport org.springframework.util.Assert;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * Copyright (c) 2013, zhidaosi.com\n *\n * @description: 记录运行时间\n * @author: 俊杰Jerry\n * @date: 2013-7-5\n */\npublic class BaseRunTimer {\n\n    private static ThreadLocal<List<String>> timerHolder = new ThreadLocal<List<String>>();\n\n    private static final Log log = LogFactory.getLog(BaseRunTimer.class);\n\n    private static boolean active = false;\n\n    public static void addTimer(String msg) {\n        if (active) {\n            Assert.notNull(msg, \"msg cannot be null\");\n            List<String> timer = getTimer();\n            timer.add(msg);\n            timerHolder.set(timer);\n        }\n    }\n\n    private static List<String> getTimer() {\n        List<String> timer = (List<String>) timerHolder.get();\n        if (timer == null) {\n            timer = new ArrayList<String>();\n        }\n        return timer;\n    }\n\n    public static void showTimer() {\n        if (active && log.isInfoEnabled()) {\n            List<String> timer = getTimer();\n            if (timer.size() > 0) {\n                String line = \"**********************************************************************\";\n                String message = \"\\n\" + line + \"\\n\";\n                for (String msg : timer) {\n                    message += \"********** \";\n                    message += msg;\n                    message += \"\\n\";\n                }\n                message += line;\n                log.info(message);\n            }\n        }\n        timerHolder.remove();\n    }\n\n    public static boolean isActive() {\n        return active;\n    }\n\n    public static void toActive() {\n        BaseRunTimer.active = true;\n    }\n\n\n}\n\n\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseSocket.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\nimport com.zhaidaosi.game.jgframework.common.excption.MessageException;\nimport com.zhaidaosi.game.jgframework.message.InMessage;\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintWriter;\nimport java.net.Socket;\nimport java.net.UnknownHostException;\nimport java.util.HashMap;\n\npublic class BaseSocket {\n\n    private String host;\n    private int port;\n    private Socket socket;\n\n    private static HashMap<String, BaseSocket> socketMap = new HashMap<String, BaseSocket>();\n\n    private BaseSocket(String host, int port) throws UnknownHostException, IOException {\n        this.socket = new Socket(host, port);\n        this.host = host;\n        this.port = port;\n    }\n\n    public static BaseSocket getNewInstance(String host, int port)\n            throws UnknownHostException, IOException {\n        return new BaseSocket(host, port);\n    }\n\n    public static BaseSocket getInstance(String host, int port)\n            throws UnknownHostException, IOException {\n        BaseSocket mySocket = socketMap.get(host + \":\" + port);\n        if (mySocket == null || mySocket.socket.isClosed()) {\n            mySocket = new BaseSocket(host, port);\n            socketMap.put(host + \":\" + port, mySocket);\n        }\n        return mySocket;\n    }\n\n    public void reconnect() throws IOException {\n        if (!socket.isClosed()) {\n            socket.close();\n        }\n        socket = new Socket(host, port);\n        socketMap.put(host + \":\" + port, this);\n    }\n\n    public OutMessage request(InMessage msg) throws IOException, MessageException {\n        send(msg);\n        OutMessage om = receive();\n        if (om == null) {\n            throw new IOException(\"连接已被强制中断\");\n        }\n        return om;\n    }\n\n    public void heartBeat() throws IOException {\n        send(new InMessage());\n    }\n\n    public void send(InMessage msg) throws IOException {\n        String out = msg.toString();\n        PrintWriter printWriter = new PrintWriter(socket.getOutputStream(), true);\n        printWriter.write(out);\n        printWriter.flush();\n    }\n\n    private OutMessage receive() throws IOException, MessageException {\n        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));\n        return OutMessage.getMessage(bufferedReader.readLine());\n    }\n\n    public void close() throws IOException {\n        socketMap.remove(socket.getLocalAddress() + \":\" + socket.getPort());\n        if (!socket.isClosed()) {\n            socket.close();\n        }\n    }\n\n    public void closeNew() throws IOException {\n        if (!socket.isClosed()) {\n            socket.close();\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/BaseString.java",
    "content": "package com.zhaidaosi.game.jgframework.common;\n\npublic class BaseString {\n\n    public static boolean isEmpty(String str) {\n        if (str == null) {\n            return true;\n        }\n        str = str.trim();\n        return str.equals(\"\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/cache/BaseLocalCached.java",
    "content": "package com.zhaidaosi.game.jgframework.common.cache;\n\nimport java.util.*;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\n/**\n * 用户保持不会垮服务器的数据\n * @author Jerry\n */\npublic class BaseLocalCached {\n\n    public static final String INVALID = \"%IT IS INVALID!!%\";\n\n    private class BaseCacheElement {\n        private Object value;\n        private long failureTime;\n\n        private BaseCacheElement(Object value, long failureTime) {\n            this.value = value;\n            this.failureTime = failureTime;\n        }\n    }\n\n    private ConcurrentMap<String, BaseCacheElement> cache = new ConcurrentHashMap<String, BaseCacheElement>();\n\n    private static Timer timer = null;\n    private static List<BaseLocalCached> list = Collections.synchronizedList(new ArrayList<BaseLocalCached>());\n    private static final long period = 600000;\n\n\n    public BaseLocalCached() {\n        if (!list.contains(this)) {\n            list.add(this);\n            startTimer();\n        }\n    }\n\n    /**\n     * 设置缓存\n     * @param key\n     * @param value\n     * @param time 单位秒\n     */\n    public void set(String key, Object value, int time) {\n        cache.put(key, new BaseCacheElement(value, System.currentTimeMillis() + time * 1000));\n    }\n\n    public void set(String key, Object value) {\n        cache.put(key, new BaseCacheElement(value, 0L));\n    }\n\n    public void delete(String key) {\n        cache.remove(key);\n    }\n\n    /**\n     * 判断是否过期，过期返回true\n     * @param value\n     * @return\n     */\n    public boolean checkInvalid(Object value) {\n        return INVALID.equals(value);\n    }\n\n    public Object get(String key) {\n        BaseCacheElement element = cache.get(key);\n        if (checkTime(element)) {\n            return element.value;\n        } else {\n            if (element != null) {\n                cache.remove(key);\n            }\n            return INVALID;\n        }\n    }\n\n    private boolean checkTime(BaseCacheElement element) {\n        if (element == null) {\n            return false;\n        }\n        if (element.failureTime == 0L || element.failureTime > System.currentTimeMillis()) {\n            return true;\n        }\n        return false;\n    }\n\n    public static void startTimer() {\n        if (timer == null && list.size() > 0) {\n            timer = new Timer(\"BaseLocalCachedTimer\");\n            timer.schedule(new InvalidTask(), period, period);\n        }\n    }\n\n    public static void cancelTimer() {\n        if (timer != null) {\n            timer.cancel();\n            timer = null;\n        }\n    }\n\n    private static void invalid() {\n        for (BaseLocalCached localCached : list) {\n            for (Map.Entry<String, BaseCacheElement> entry : localCached.cache.entrySet()) {\n                String key = entry.getKey();\n                BaseCacheElement element = entry.getValue();\n                if (!localCached.checkTime(element)) {\n                    localCached.delete(key);\n                }\n            }\n        }\n    }\n\n    private static class InvalidTask extends TimerTask {\n        @Override\n        public void run() {\n            BaseLocalCached.invalid();\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/cache/BaseMemCached.java",
    "content": "package com.zhaidaosi.game.jgframework.common.cache;\n\nimport com.whalin.MemCached.MemCachedClient;\nimport com.whalin.MemCached.SockIOPool;\nimport com.zhaidaosi.game.jgframework.Boot;\n\nimport java.util.ArrayList;\n\npublic class BaseMemCached extends MemCachedClient {\n\n    // 创建全局的唯一实例\n    private static BaseMemCached mc = new BaseMemCached();\n    private final static String KEYPREFIX;\n\n    // 设置与缓存服务器的连接池\n    static {\n        String[] servers;\n        Integer[] weights;\n        ArrayList<String> confServers = Boot.getMemcacheServers();\n        KEYPREFIX = Boot.getMemcacheKeyPrefix();\n        int size = confServers.size();\n        if (size > 1) {\n            servers = new String[size];\n            weights = new Integer[size];\n            for (int i = 0; i < size; i++) {\n                String[] temp2 = confServers.get(i).split(\",\");\n                servers[i] = temp2[0];\n                if (temp2.length > 1) {\n                    weights[i] = new Integer(temp2[1]);\n                } else {\n                    weights[i] = 1;\n                }\n            }\n        } else {\n            // 服务器列表和其权重\n            servers = new String[]{\"127.0.0.1:11211\"};\n            weights = new Integer[]{1};\n        }\n        // 获取socke连接池的实例对象\n        SockIOPool pool = SockIOPool.getInstance();\n        // 设置服务器信息\n        pool.setServers(servers);\n        pool.setWeights(weights);\n        // 设置初始连接数、最小和最大连接数以及最大处理时间\n        pool.setInitConn(100);\n        pool.setMinConn(100);\n        pool.setMaxConn(2000);\n        pool.setMaxIdle(1000 * 60 * 60 * 6);\n        // 设置主线程的睡眠时间\n        pool.setMaintSleep(30);\n        // 设置TCP的参数，连接超时等\n        pool.setNagle(false);\n        //连接建立后的超时时间\n        pool.setSocketTO(3000);\n        //连接建立时的超时时间\n        pool.setSocketConnectTO(0);\n        pool.setHashingAlg(SockIOPool.NEW_COMPAT_HASH);\n        // 初始化连接池\n        pool.initialize();\n    }\n\n    /**\n     * 保护型构造方法，不允许实例化！\n     *\n     */\n    private BaseMemCached() {\n\n    }\n\n\n    /**\n     * 获取唯一实例.\n     */\n    public static BaseMemCached getInstance() {\n        return mc;\n    }\n\n    public static String getMcKey(String key) {\n        return KEYPREFIX + key;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/encrpt/BaseDes.java",
    "content": "package com.zhaidaosi.game.jgframework.common.encrpt;\n\nimport com.zhaidaosi.game.jgframework.Boot;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.DESKeySpec;\nimport javax.xml.bind.DatatypeConverter;\nimport java.security.SecureRandom;\n\n\npublic class BaseDes {\n\n\n    private final static String DES = \"DES\";\n    private static byte[] keyBytes = \"1234567890!@#$qweasd\".getBytes();\n\n    public static void setDesKey(String key) {\n        keyBytes = key.getBytes();\n    }\n\n    /**\n     * Description 根据键值进行加密\n     * @param data\n     * @return\n     */\n    public static String encrypt(String data) {\n        byte[] bt;\n        try {\n            bt = encrypt(data.getBytes(Boot.getCharset()), keyBytes);\n        } catch (Exception e) {\n            return null;\n        }\n        return DatatypeConverter.printBase64Binary(bt);\n    }\n\n    /**\n     * Description 根据键值进行解密\n     * @param data\n     * @return\n     */\n    public static String decrypt(String data) {\n        if (data == null)\n            return null;\n        byte[] buf;\n        byte[] bt;\n        try {\n            buf = DatatypeConverter.parseBase64Binary(data);\n            bt = decrypt(buf, keyBytes);\n        } catch (Exception e) {\n//\t\t\te.printStackTrace();\n            return null;\n        }\n        return new String(bt, Boot.getCharset());\n    }\n\n    /**\n     * Description 根据键值进行加密\n     * @param data\n     * @param key 加密键byte数组\n     * @return\n     * @throws Exception\n     */\n    private static byte[] encrypt(byte[] data, byte[] key) throws Exception {\n        // 生成一个可信任的随机数源\n        SecureRandom sr = new SecureRandom();\n\n        // 从原始密钥数据创建DESKeySpec对象\n        DESKeySpec dks = new DESKeySpec(key);\n\n        // 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象\n        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);\n        SecretKey secretKey = keyFactory.generateSecret(dks);\n\n        // Cipher对象实际完成加密操作\n        Cipher cipher = Cipher.getInstance(DES);\n\n        // 用密钥初始化Cipher对象\n        cipher.init(Cipher.ENCRYPT_MODE, secretKey, sr);\n\n        return cipher.doFinal(data);\n    }\n\n    /**\n     * Description 根据键值进行解密\n     * @param data\n     * @param key 加密键byte数组\n     * @return\n     * @throws Exception\n     */\n    private static byte[] decrypt(byte[] data, byte[] key) throws Exception {\n        // 生成一个可信任的随机数源\n        SecureRandom sr = new SecureRandom();\n\n        // 从原始密钥数据创建DESKeySpec对象\n        DESKeySpec dks = new DESKeySpec(key);\n\n        // 创建一个密钥工厂，然后用它把DESKeySpec转换成SecretKey对象\n        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(DES);\n        SecretKey secretKey = keyFactory.generateSecret(dks);\n\n        // Cipher对象实际完成解密操作\n        Cipher cipher = Cipher.getInstance(DES);\n\n        // 用密钥初始化Cipher对象\n        cipher.init(Cipher.DECRYPT_MODE, secretKey, sr);\n\n        return cipher.doFinal(data);\n    }\n}"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/encrpt/BaseMd5.java",
    "content": "package com.zhaidaosi.game.jgframework.common.encrpt;\n\nimport com.zhaidaosi.game.jgframework.Boot;\n\nimport javax.xml.bind.DatatypeConverter;\nimport java.security.MessageDigest;\n\npublic class BaseMd5 {\n\n    /**\n     * 进行MD5加密\n     *\n     * @param text 原始的SPKEY\n     * @return String 指定加密方式为md5后的String\n     */\n    public static String encrypt(String text) {\n        byte[] returnByte;\n        try {\n            MessageDigest md5 = MessageDigest.getInstance(\"MD5\");\n            returnByte = md5.digest(text.getBytes(Boot.getCharset()));\n        } catch (Exception e) {\n            return null;\n        }\n        return DatatypeConverter.printBase64Binary(returnByte);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/encrpt/BaseRsa.java",
    "content": "package com.zhaidaosi.game.jgframework.common.encrpt;\n\nimport com.zhaidaosi.game.jgframework.Boot;\n\nimport javax.crypto.Cipher;\nimport javax.xml.bind.DatatypeConverter;\nimport java.security.*;\nimport java.security.interfaces.RSAPrivateKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.security.spec.X509EncodedKeySpec;\n\npublic class BaseRsa {\n\n    private static PublicKey publicKey;\n    private static PrivateKey privateKey;\n\n    static {\n        if (publicKey == null) {\n            publicKey = getPublicKey(\"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCifAl6RlbG1PVOowZJ2niVlijq9FC19jEIaA2WVm+En64roRsTjlWpAKOfYBHIwEYWvI7rObyobTIPyOkBOCx5Sbopq2ME7FUQEwI2IeEBGHwnIBPzkhTEt9kMT88g8hZRBV6D/p6J8Z1u2WU0q88Xpd4o7VDxFRmGUTSePOGcjQIDAQAB\");\n        }\n        if (privateKey == null) {\n            privateKey = getPrivateKey(\"MIICdQIBADANBgkqhkiG9w0BAQEFAASCAl8wggJbAgEAAoGBAKJ8CXpGVsbU9U6jBknaeJWWKOr0ULX2MQhoDZZWb4SfriuhGxOOVakAo59gEcjARha8jus5vKhtMg/I6QE4LHlJuimrYwTsVRATAjYh4QEYfCcgE/OSFMS32QxPzyDyFlEFXoP+nonxnW7ZZTSrzxel3ijtUPEVGYZRNJ484ZyNAgMBAAECgYA3SHCJE8mOmQJloP4Qvq5sZszBNCMJ5hvEunJ1Bi+nNhUybvwhaTon6DnDjhI+9XxjXABcdCaGP7DawgbVDWHDzjgQG0xQle2ryrZFa0thgQDYM4iraMgxMN/5kTXD9DlZcf871N0DeI8dTpxJhVMcM5d95sml6pJxxqwyzABiAQJBAO1rvTpHS6OgDVRpHV4HksyEcKETEayVknAIbTGP3VH3L4X50CpwOwPsvaHi5sENkSEA2JtKj0qF0CbP3sAdDcECQQCvMxhuq2V+dRyMkFLot3YZbMffr2dJi6o4XwxDtI/nhHzS5bQIzKX7L1m8ZJ0GR6CSjZ6X+LBRW6h3tLTsNdnNAkANsK+5o5DN/5WlL2Z9HIyvdFeWQiY7wGgwQ5wgRn5pkopP/Gave8c7Y7RPmGjb6u9aatUSp0r57hthkYzzoPlBAkBG6sfZBEfxCDamL0VgLeMAJ6hAQx/sBTzB1LeCMHSPonFkbNaTOUN2iZQpThDBmfzFVc38dg3o4NEwo1UYyDOBAkAsfnopb+Msp8pMBw7mcX/CeCXNIVpBNWSLtT0AssDf9ofaQ+bIsFIsy2GaPt/UuZmltXgTP5J3iWqFIKQDRstH\");\n        }\n    }\n\n    public static void init(String publicKeyString, String privateKeyString) {\n        publicKey = getPublicKey(publicKeyString);\n        privateKey = getPrivateKey(privateKeyString);\n    }\n\n    public static String encrypt(String data) {\n        if (data == null) {\n            return null;\n        }\n        try {\n            Cipher cipher = Cipher.getInstance(\"RSA\");\n            cipher.init(Cipher.ENCRYPT_MODE, publicKey);\n            return DatatypeConverter.printBase64Binary(cipher.doFinal(data.getBytes(Boot.getCharset())));\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public static String decrypt(String data) {\n        if (data == null) {\n            return null;\n        }\n        try {\n            Cipher cipher = Cipher.getInstance(\"RSA\");\n            cipher.init(Cipher.DECRYPT_MODE, privateKey);\n            return new String(cipher.doFinal(DatatypeConverter.parseBase64Binary(data)), Boot.getCharset());\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    /**\n     * 得到公钥\n     *\n     * @param key 密钥字符串（经过base64编码）\n     * @throws Exception\n     */\n    private static PublicKey getPublicKey(String key) {\n        byte[] keyBytes;\n        PublicKey publicKey = null;\n        try {\n            keyBytes = DatatypeConverter.parseBase64Binary(key);\n\n            X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);\n            KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n            publicKey = keyFactory.generatePublic(keySpec);\n        } catch (Exception e) {\n            return null;\n        }\n        return publicKey;\n    }\n\n    /**\n     * 得到私钥\n     *\n     * @param key 密钥字符串（经过base64编码）\n     * @throws Exception\n     */\n    private static PrivateKey getPrivateKey(String key) {\n        byte[] keyBytes;\n        PrivateKey privateKey = null;\n        try {\n            keyBytes = DatatypeConverter.parseBase64Binary(key);\n\n            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);\n            KeyFactory keyFactory = KeyFactory.getInstance(\"RSA\");\n            privateKey = keyFactory.generatePrivate(keySpec);\n        } catch (Exception e) {\n            return null;\n        }\n        return privateKey;\n    }\n\n    /**\n     * 得到密钥字符串（经过base64编码）\n     *\n     * @return\n     */\n    private static String getKeyString(Key key) throws Exception {\n        byte[] keyBytes = key.getEncoded();\n        return DatatypeConverter.printBase64Binary(keyBytes);\n    }\n\n    public static void main(String[] args) throws Exception {\n\n        KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance(\"RSA\");\n        // 密钥位数\n        keyPairGen.initialize(1024);\n        // 密钥对\n        KeyPair keyPair = keyPairGen.generateKeyPair();\n        // 公钥\n        PublicKey publicKey = keyPair.getPublic();\n        // 私钥\n        PrivateKey privateKey = keyPair.getPrivate();\n\n        String publicKeyString = getKeyString(publicKey);\n        System.out.println(\"public:\\n\" + publicKeyString);\n\n        String privateKeyString = getKeyString(privateKey);\n        System.out.println(\"private:\\n\" + privateKeyString);\n\n        BaseRsa.init(publicKeyString, privateKeyString);\n        String test = \"1231232123_2013-01-01 00:00:00\";\n\n        String t = BaseRsa.encrypt(test);\n        System.out.println(t);\n\n        String a = BaseRsa.decrypt(t);\n        System.out.println(a);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/excption/BaseException.java",
    "content": "package com.zhaidaosi.game.jgframework.common.excption;\n\n\n@SuppressWarnings(\"serial\")\npublic class BaseException extends Exception implements IBaseException {\n\n    protected int code = 0;\n\n    public BaseException(String msg, int code) {\n        super(msg);\n        this.code = code;\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/excption/HttpException.java",
    "content": "package com.zhaidaosi.game.jgframework.common.excption;\n\n@SuppressWarnings(\"serial\")\npublic class HttpException extends BaseException {\n\n    public HttpException(String message) {\n        super(message, 60000);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/excption/IBaseException.java",
    "content": "package com.zhaidaosi.game.jgframework.common.excption;\n\npublic interface IBaseException {\n\n    public int getCode();\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/excption/MessageException.java",
    "content": "package com.zhaidaosi.game.jgframework.common.excption;\n\n@SuppressWarnings(\"serial\")\npublic class MessageException extends BaseException {\n\n    public MessageException(String msg) {\n        super(msg, 50000);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/http/BaseCookie.java",
    "content": "package com.zhaidaosi.game.jgframework.common.http;\n\npublic class BaseCookie {\n\n    private String key;\n    private String value;\n\n    public BaseCookie(String key, String value) {\n        this.key = key;\n        this.value = value;\n    }\n\n    public String getKey() {\n        return key;\n    }\n\n    public String getValue() {\n        return value;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/http/BaseHttp.java",
    "content": "package com.zhaidaosi.game.jgframework.common.http;\n\nimport com.zhaidaosi.game.jgframework.common.excption.HttpException;\nimport org.apache.commons.httpclient.*;\nimport org.apache.commons.httpclient.cookie.CookiePolicy;\nimport org.apache.commons.httpclient.methods.GetMethod;\nimport org.apache.commons.httpclient.methods.PostMethod;\nimport org.apache.commons.httpclient.params.HttpMethodParams;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.io.*;\nimport java.net.*;\nimport java.net.URI;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n@SuppressWarnings(\"unchecked\")\npublic class BaseHttp {\n\n    public static String GBK = \"GBK\";\n    public static String GB2312 = \"GB2312\";\n    public static String UTF8 = \"UTF-8\";\n    public static String HEADER_HOST = \"Host\";\n    public static String HEADER_REFERER = \"Referer\";\n\n    private static final Logger log = LoggerFactory.getLogger(BaseHttp.class);\n    private static int DEFAULT_TIMEOUT = 3000;\n    private static String DEFAULT_CHARSET = \"UTF-8\";\n    private static int DEFAULT_MAX_REDIRECT = 2;\n    private static String DEFAULT_USER_AGENT = \"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:12.0) Gecko/20100101 Firefox/22.0 zhaidaosi.com\";\n\n    public static int header(String url) throws Exception {\n        return header(url, null, null, null, DEFAULT_TIMEOUT);\n    }\n\n    public static String get(String url) throws Exception {\n        return get(url, null, null, DEFAULT_CHARSET, DEFAULT_MAX_REDIRECT, DEFAULT_TIMEOUT);\n    }\n\n    public static String get(String url, Map<String, String> header) throws Exception {\n        return get(url, header, null, DEFAULT_CHARSET, DEFAULT_MAX_REDIRECT, DEFAULT_TIMEOUT);\n    }\n\n    public static String get(String url, String charset) throws Exception {\n        return get(url, null, null, charset, DEFAULT_MAX_REDIRECT, DEFAULT_TIMEOUT);\n    }\n\n    public static String post(String url, Map<String, Object> params) throws Exception {\n        return post(url, params, null, null, DEFAULT_CHARSET, DEFAULT_TIMEOUT);\n    }\n\n    public static String post(String url, Map<String, Object> params, int timeout) throws Exception {\n        return post(url, params, null, null, DEFAULT_CHARSET, timeout);\n    }\n\n    public static String post(String url, Map<String, Object> params, Map<String, String> header) throws Exception {\n        return post(url, params, header, null, DEFAULT_CHARSET, DEFAULT_TIMEOUT);\n    }\n\n    public static void sendRequest(String url) throws Exception {\n        sendRequest(url, null, null, null, DEFAULT_CHARSET);\n    }\n\n    public static void sendRequest(String url, Map<String, Object> params) throws Exception {\n        sendRequest(url, params, null, null, DEFAULT_CHARSET);\n    }\n\n    /**\n     * 返回状态码\n     *\n     * @param url\n     * @param header\n     * @param cookie\n     * @return\n     * @throws HttpException\n     */\n    public static int header(String url, HashMap<String, String> header, BaseCookie[] cookie, String charset, int timeout) throws Exception {\n        check(url);\n        if (charset == null) {\n            charset = DEFAULT_CHARSET;\n        }\n        HashMap<String, Object> args = new HashMap<String, Object>();\n        args.put(\"url\", url);\n        args.put(\"header\", header);\n        args.put(\"cookie\", cookie);\n        args.put(\"charset\", charset);\n        args.put(\"timeout\", timeout);\n        return doHeader(args);\n    }\n\n    /**\n     * 模拟get\n     *\n     * @param url\n     * @param header\n     * @param cookie\n     * @param charset\n     * @param maxRedirect\n     * @return\n     * @throws HttpException\n     */\n    public static String get(String url, Map<String, String> header, BaseCookie[] cookie, String charset, int maxRedirect, int timeout) throws Exception {\n        check(url);\n        HashMap<String, Object> args = new HashMap<String, Object>();\n        args.put(\"url\", url);\n        args.put(\"header\", header);\n        args.put(\"cookie\", cookie);\n        args.put(\"charset\", charset);\n        args.put(\"maxRedirect\", maxRedirect);\n        args.put(\"timeout\", timeout);\n        return doGet(args, 0);\n    }\n\n    /**\n     * 模拟post\n     *\n     * @param url\n     * @param params\n     *            可以是String和String[]\n     * @param header\n     * @param cookie\n     * @param charset\n     * @return\n     * @throws HttpException\n     */\n    public static String post(String url, Map<String, Object> params, Map<String, String> header, BaseCookie[] cookie, String charset, int timeout) throws Exception {\n        check(url);\n        if (charset == null) {\n            charset = DEFAULT_CHARSET;\n        }\n        HashMap<String, Object> args = new HashMap<String, Object>();\n        args.put(\"url\", url);\n        args.put(\"header\", header);\n        args.put(\"cookie\", cookie);\n        args.put(\"charset\", charset);\n        args.put(\"params\", params);\n        args.put(\"timeout\", timeout);\n        return doPost(args);\n    }\n\n    /**\n     * 模拟http请求，不接受返回信息\n     *\n     * @param url\n     * @param params\n     *            可以是String和String[]\n     * @param header\n     * @param cookie\n     * @param charset\n     * @throws Exception\n     */\n    public static void sendRequest(String url, Map<String, Object> params, Map<String, String> header, BaseCookie[] cookie, String charset) throws Exception {\n        check(url);\n        if (charset == null) {\n            charset = DEFAULT_CHARSET;\n        }\n        HashMap<String, Object> args = new HashMap<String, Object>();\n        args.put(\"url\", url);\n        args.put(\"header\", header);\n        args.put(\"cookie\", cookie);\n        args.put(\"charset\", charset);\n        args.put(\"params\", params);\n        doSendRequest(args);\n    }\n\n    private static void doSendRequest(Map<String, Object> args) throws URISyntaxException, UnknownHostException, IOException {\n        String url = (String) args.get(\"url\");\n        HashMap<String, Object> params = (HashMap<String, Object>) args.get(\"params\");\n        HashMap<String, String> header = (HashMap<String, String>) args.get(\"header\");\n        BaseCookie[] cookie = (BaseCookie[]) args.get(\"cookie\");\n        String charset = (String) args.get(\"charset\");\n        URI uri = new URI(url);\n        int port = uri.getPort();\n        @SuppressWarnings(\"resource\")\n        Socket s = new Socket(uri.getHost(), port == -1 ? 80 : port);\n        OutputStreamWriter osw = new OutputStreamWriter(s.getOutputStream());\n        StringBuffer sb = new StringBuffer();\n        String postStr = null;\n        if (params != null) {\n            postStr = \"\";\n            for (Map.Entry<String, Object> entry : params.entrySet()) {\n                String key = entry.getKey();\n                Object val = entry.getValue();\n                if (val instanceof String) {\n                    postStr += (URLEncoder.encode(key, charset) + \"=\" + URLEncoder.encode((String) val, charset) + \"&\");\n                } else if (entry.getValue() instanceof String[]) {\n                    for (String value : (String[]) val) {\n                        postStr += (URLEncoder.encode(key, charset) + \"=\" + URLEncoder.encode(value, charset) + \"&\");\n                    }\n                }\n            }\n            postStr = postStr.substring(0, postStr.length() - 1);\n            sb.append(\"POST \");\n        } else {\n            sb.append(\"GET \");\n        }\n        String fullPath = uri.getQuery() == null ? uri.getPath() : uri.getPath() + \"?\" + uri.getQuery();\n        sb.append(fullPath + \" HTTP/1.1\\r\\n\");\n        sb.append(\"Host: \" + uri.getHost() + \"\\r\\n\");\n        sb.append(\"User-Agent: \" + DEFAULT_USER_AGENT + \"\\r\\n\");\n        sb.append(\"Connection: keep-alive\\r\\n\");\n        if (header != null) {\n            for (Map.Entry<String, String> h : header.entrySet()) {\n                sb.append(h.getKey() + \": \" + h.getValue() + \"\\r\\n\");\n            }\n        }\n        if (postStr != null) {\n            sb.append(\"Content-type: application/x-www-form-urlencoded\\r\\n\");\n            sb.append(\"Content-Length: \" + postStr.length() + \"\\r\\n\");\n        }\n        if (cookie != null) {\n            int size = cookie.length;\n            for (int i = 0; i < size; i++) {\n                sb.append(\"Cookie: \" + URLEncoder.encode(cookie[i].getKey(), charset) + \"=\" + URLEncoder.encode(cookie[i].getValue(), charset));\n                if (i < size - 1) {\n                    sb.append(\"; \");\n                }\n            }\n        }\n        sb.append(\"\\r\\nConnection: Close\\r\\n\\r\\n\");\n        if (postStr != null) {\n            sb.append(postStr + \"\\r\\n\");\n        }\n        osw.write(sb.toString());\n        osw.flush();\n        osw.close();\n    }\n\n    /**\n     * 模拟get\n     *\n     * @param args\n     * @param retry\n     *            重试第几次了\n     * @return\n     * @throws HttpException\n     */\n    private static String doGet(HashMap<String, Object> args, int retry) throws HttpException {\n        int maxRedirect = (Integer) args.get(\"maxRedirect\");\n        String result = null;\n        if (retry > maxRedirect) {\n            return result;\n        }\n        String url = (String) args.get(\"url\");\n        HashMap<String, String> header = (HashMap<String, String>) args.get(\"header\");\n        BaseCookie[] cookie = (BaseCookie[]) args.get(\"cookie\");\n        String charset = (String) args.get(\"charset\");\n        Integer timeout = (Integer) args.get(\"timeout\");\n        HttpClient client = new HttpClient();\n        GetMethod method = new GetMethod(url);\n        BaseHttp.init(client, method, header, cookie, charset, timeout);\n        try {\n            int statusCode = client.executeMethod(method);\n            if (statusCode == HttpStatus.SC_OK) {\n                result = getResponse(method, charset);\n            } else if (statusCode == HttpStatus.SC_MOVED_PERMANENTLY || statusCode == HttpStatus.SC_MOVED_TEMPORARILY || statusCode == HttpStatus.SC_SEE_OTHER\n                    || statusCode == HttpStatus.SC_TEMPORARY_REDIRECT) {\n                // 301, 302, 303, 307 跳转\n                Header locationHeader = method.getResponseHeader(\"location\");\n                String location = null;\n                if (locationHeader != null) {\n                    location = locationHeader.getValue();\n                    retry++;\n                    args.put(\"url\", location);\n                    result = BaseHttp.doGet(args, retry);\n                }\n            }\n        } catch (IOException e) {\n            throw new HttpException(\"执行HTTP Get请求\" + url + \"时，发生异常！ => \" + e.getMessage());\n        } finally {\n            method.releaseConnection();\n        }\n        return result;\n    }\n\n    /**\n     * 模拟post\n     *\n     * @param args\n     * @return\n     * @throws HttpException\n     */\n    private static String doPost(HashMap<String, Object> args) throws HttpException {\n        String result = null;\n        String url = (String) args.get(\"url\");\n        HashMap<String, String> header = (HashMap<String, String>) args.get(\"header\");\n        BaseCookie[] cookie = (BaseCookie[]) args.get(\"cookie\");\n        String charset = (String) args.get(\"charset\");\n        Integer timeout = (Integer) args.get(\"timeout\");\n        HashMap<String, Object> params = (HashMap<String, Object>) args.get(\"params\");\n        HttpClient client = new HttpClient();\n        PostMethod method = new PostMethod(url);\n        BaseHttp.init(client, method, header, cookie, charset, timeout);\n        if (params != null) {\n            NameValuePair[] data = new NameValuePair[params.size()];\n            int i = 0;\n            for (Map.Entry<String, Object> entry : params.entrySet()) {\n                String key = entry.getKey();\n                Object val = entry.getValue();\n                if (val instanceof String) {\n                    data[i] = new NameValuePair(key, (String) val);\n                } else if (val instanceof String[]) {\n                    for (String value : (String[]) val) {\n                        data[i] = new NameValuePair(key, value);\n                    }\n                } else {\n                    throw new HttpException(\"post 参数类型必须为 String 或 String[]\");\n                }\n                i++;\n            }\n            method.setRequestBody(data);\n        }\n        try {\n            if (client.executeMethod(method) == HttpStatus.SC_OK) {\n                result = getResponse(method, charset);\n            }\n        } catch (IOException e) {\n            throw new HttpException(\"执行HTTP Post请求\" + url + \"时，发生异常！ => \" + e.getMessage());\n        } finally {\n            method.releaseConnection();\n        }\n        return result;\n    }\n\n    /**\n     * 获取状态码\n     *\n     * @param args\n     * @return\n     * @throws HttpException\n     */\n    private static int doHeader(HashMap<String, Object> args) throws HttpException {\n        int statusCode = 0;\n        String url = (String) args.get(\"url\");\n        HashMap<String, String> header = (HashMap<String, String>) args.get(\"header\");\n        String charset = (String) args.get(\"charset\");\n        BaseCookie[] cookie = (BaseCookie[]) args.get(\"cookie\");\n        Integer timeout = (Integer) args.get(\"timeout\");\n        HttpClient client = new HttpClient();\n        HttpMethod method = new GetMethod(url);\n        BaseHttp.init(client, method, header, cookie, charset, timeout);\n        try {\n            statusCode = client.executeMethod(method);\n        } catch (IOException e) {\n            throw new HttpException(\"执行HTTP Header请求\" + url + \"时，发生异常！ => \" + e.getMessage());\n        } finally {\n            method.releaseConnection();\n        }\n        return statusCode;\n    }\n\n    /**\n     * 初始化\n     *\n     * @param client\n     * @param method\n     * @param headers\n     * @param cookie\n     * @throws UnsupportedEncodingException\n     */\n    private static void init(HttpClient client, HttpMethod method, HashMap<String, String> header, BaseCookie[] cookie, String charset, int timeout) {\n        client.getParams().setParameter(HttpMethodParams.HTTP_URI_CHARSET, charset);\n        client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, charset);\n        client.getHttpConnectionManager().getParams().setConnectionTimeout(timeout);\n        client.getHttpConnectionManager().getParams().setSoTimeout(timeout);\n        method.setFollowRedirects(false);\n        method.setRequestHeader(\"User-Agent\", BaseHttp.DEFAULT_USER_AGENT);\n        method.setRequestHeader(\"Cache-Control\", \"no-cache\");\n        method.setRequestHeader(\"Connection\", \"keep-alive\");\n        if (cookie != null) {\n            String cookieString = \"\";\n            for (BaseCookie ci : cookie) {\n                try {\n                    cookieString += URLEncoder.encode(ci.getKey(), charset) + \"=\" + URLEncoder.encode(ci.getValue(), charset) + \"; \";\n                } catch (UnsupportedEncodingException e) {\n                    log.error(e.getMessage(), e);\n                }\n            }\n            method.setRequestHeader(\"Cookie\", cookieString);\n        } else {\n            method.getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES);\n        }\n        if (header != null) {\n            for (Entry<String, String> h : header.entrySet()) {\n                method.setRequestHeader(h.getKey(), h.getValue());\n            }\n        }\n    }\n\n    /**\n     * 获取http请求结果\n     *\n     * @param method\n     * @param charset\n     * @return\n     * @throws IOException\n     */\n    private static String getResponse(HttpMethod method, String charset) {\n        StringBuffer response = new StringBuffer();\n        try {\n            BufferedReader reader = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream(), charset));\n            String line;\n            while ((line = reader.readLine()) != null) {\n                response.append(line);\n            }\n            reader.close();\n        } catch (IOException e) {\n            log.error(e.getMessage(), e);\n        }\n        return response.toString();\n    }\n\n    /**\n     * 检查url是否为空\n     *\n     * @param url\n     * @throws HttpException\n     */\n    private static void check(String url) throws HttpException {\n        if (url == null || url.trim().equals(\"\")) {\n            throw new HttpException(\"url不能为空\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/queue/BaseQueue.java",
    "content": "package com.zhaidaosi.game.jgframework.common.queue;\n\n/**\n * 可快速定位的FIFO队列\n */\npublic class BaseQueue<E> {\n\n    private BaseQueueElement<E> start = null;\n    private BaseQueueElement<E> end = null;\n    private final Object lock = new Object();\n    private long putCount = 0;\n    private long takeCount = 0;\n    private long size = 0;\n\n    /**\n     * 获取队列头\n     */\n    public BaseQueueElement<E> getStart() {\n        return start;\n    }\n\n    /**\n     * 从队列尾插入元素\n     */\n    public BaseQueueElement<E> put(E value) {\n        if (value == null) {\n            return null;\n        }\n        BaseQueueElement<E> element = new BaseQueueElement<E>(value);\n        synchronized (lock) {\n            if (start == null) {\n                start = element;\n                end = element;\n            } else {\n                element.setBefore(end);\n                end.setNext(element);\n                end = element;\n            }\n            putCount++;\n            size++;\n            element.setNo(putCount);\n        }\n        return element;\n    }\n\n    /**\n     * 从队列头弹出元素\n     */\n    public BaseQueueElement<E> take() {\n        if (start == null) {\n            return null;\n        }\n        BaseQueueElement<E> element;\n        synchronized (lock) {\n            element = start;\n            if (start == end) {\n                start = null;\n                end = null;\n                putCount = 0;\n                takeCount = 0;\n            } else {\n                start = start.getNext();\n                start.setBefore(null);\n                takeCount++;\n            }\n            size--;\n            element.reset();\n        }\n        return element;\n    }\n\n    /**\n     * 删除一个元素\n     */\n    public boolean remove(BaseQueueElement<E> element) {\n        BaseQueueElement<E> after = null;\n        synchronized (lock) {\n            if (element == start && element == end) {\n                start = null;\n                end = null;\n                putCount = 0;\n                takeCount = 0;\n            } else if (element == start) {\n                start = start.getNext();\n                start.setBefore(null);\n                takeCount++;\n            } else if (element == end) {\n                end = element.getBefore();\n                end.setNext(null);\n            } else {\n                // 判断是否在队列中\n                if (element.getBefore().getNext() != element || element.getNext().getBefore() != element) {\n                    return false;\n                }\n                after = element.getNext();\n                after.setBefore(element.getBefore());\n                element.getBefore().setNext(after);\n            }\n            size--;\n            element.reset();\n            if (after != null) {\n                do {\n                    after.setNo(after.getNo() - 1);\n                    after = after.getNext();\n                } while (after != null);\n            }\n        }\n        return true;\n    }\n\n    /**\n     * 查找元素所在的位置\n     */\n    public long findIndex(BaseQueueElement<E> element) {\n        if (element == null) {\n            return -1;\n        }\n        synchronized (lock) {\n            return element.getNo() - takeCount;\n        }\n    }\n\n    /**\n     * 返回队列长度\n     */\n    public long size() {\n        synchronized (lock) {\n            return size;\n        }\n    }\n\n    /**\n     * 删除队列所有元素\n     */\n    public void clear() {\n        synchronized (lock) {\n            while (start != null) {\n                BaseQueueElement<E> element = start;\n                start = start.getNext();\n                element.reset();\n                element = null;\n            }\n            start = null;\n            end = null;\n            putCount = 0;\n            takeCount = 0;\n            size = 0;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/queue/BaseQueueElement.java",
    "content": "package com.zhaidaosi.game.jgframework.common.queue;\n\npublic class BaseQueueElement<E> {\n\n    private E value;\n    private BaseQueueElement<E> before;\n    private BaseQueueElement<E> next;\n    private long No;\n\n    public BaseQueueElement(E value) {\n        this.value = value;\n    }\n\n    public void setValue(E value) {\n        this.value = value;\n    }\n\n    public E getValue() {\n        return value;\n    }\n\n    public BaseQueueElement<E> getBefore() {\n        return before;\n    }\n\n    public void setBefore(BaseQueueElement<E> before) {\n        this.before = before;\n    }\n\n    public BaseQueueElement<E> getNext() {\n        return next;\n    }\n\n    public void setNext(BaseQueueElement<E> next) {\n        this.next = next;\n    }\n\n    public void setNo(long No) {\n        this.No = No;\n    }\n\n    public long getNo() {\n        return No;\n    }\n\n    public void reset() {\n        before = null;\n        next = null;\n        No = 0;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/sdm/BaseDao.java",
    "content": "package com.zhaidaosi.game.jgframework.common.sdm;\n\nimport com.zhaidaosi.game.jgframework.Boot;\nimport org.hibernate.LockMode;\nimport org.hibernate.SQLQuery;\nimport org.hibernate.Session;\nimport org.hibernate.SessionFactory;\nimport org.hibernate.transform.Transformers;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.beans.factory.annotation.Autowired;\nimport org.springframework.orm.hibernate3.HibernateTemplate;\nimport org.springframework.orm.hibernate3.support.HibernateDaoSupport;\n\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\n@SuppressWarnings({\"rawtypes\", \"unchecked\"})\npublic abstract class BaseDao extends HibernateDaoSupport implements IBaseDao {\n    private static final Logger log = LoggerFactory\n            .getLogger(BaseDao.class);\n\n    protected String tableName = \"\";\n    protected String modelName = \"\";\n    protected String entityPackage = Boot.SDM_BASE_PACKAGE_NAME + \".model.\";\n\n    @Override\n    public List<?> find(String queryString) {\n        return this.getQuery(queryString, null).list();\n    }\n\n    @Override\n    public List<?> find(String queryString, Map<String, Object> data) {\n        return this.getQuery(queryString, data).list();\n    }\n\n    @Override\n    public List<?> find(String queryString, Map<String, Object> data, int start, int limit) {\n        return this.getQuery(queryString, data, start, limit).list();\n    }\n\n    @Override\n    public int total() {\n        return this.total(null, null);\n    }\n\n    @Override\n    public int total(String queryString) {\n        return this.total(queryString, null);\n    }\n\n    @Override\n    public int total(Map<String, Object> where) {\n        return this.total(null, where);\n    }\n\n\n    @Override\n    public int total(String queryString, Map<String, Object> where) {\n        if (queryString == null) {\n            queryString = \"select count(1) from \" + this.tableName;\n            if (where != null) {\n                queryString += \" where \" + this.formateWhereSql(where, \"and\");\n                ;\n            }\n        }\n\n        return ((Number) getQuery(queryString, where, false).uniqueResult()).intValue();\n    }\n\n    @Override\n    public int update(String queryString) {\n        return this.execute(queryString);\n    }\n\n    @Override\n    public int update(Map<String, Object> where) {\n        String queryString = \"update \" + this.tableName + \" set \" + this.formateWhereSql(where, \",\");\n        return this.execute(queryString, where);\n    }\n\n    @Override\n    public int delete(String queryString) {\n        return this.execute(queryString);\n    }\n\n    @Override\n    public int delete(String queryString, Map<String, Object> where) {\n        return this.execute(queryString, where);\n    }\n\n    @Override\n    public int execute(String queryString) {\n        return this.execute(queryString, null);\n    }\n\n    @Override\n    public int execute(String queryString, Map<String, Object> where) {\n        int result = this.getQuery(queryString, where, false).executeUpdate();\n        return result;\n    }\n\n    @Override\n    public List<IBaseModel> findByProperty(String propertyName, Object value) {\n        log.debug(\"finding Object instance with property: \" + propertyName\n                + \", value: \" + value);\n        try {\n            String queryString = \"from \" + this.modelName + \" as model where model.\"\n                    + propertyName + \"= ?\";\n            return getHibernateTemplate().find(queryString, value);\n        } catch (RuntimeException re) {\n            log.error(\"find by property name failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public IBaseModel findOneByProperty(String propertyName, Object value) {\n        log.debug(\"finding Object instance with property: \" + propertyName\n                + \", value: \" + value);\n        try {\n            String queryString = \"from \" + this.modelName + \" as model where model.\"\n                    + propertyName + \"= ?\";\n            return (IBaseModel) getHibernateTemplate().find(queryString, value).get(0);\n        } catch (RuntimeException re) {\n            log.error(\"find by property name failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public IBaseModel findById(int id) {\n        log.debug(\"getting Object instance with id: \" + id);\n        try {\n            IBaseModel instance = (IBaseModel) getHibernateTemplate().get(\n                    this.entityPackage + this.modelName, id);\n            return instance;\n        } catch (RuntimeException re) {\n            log.error(\"get failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public void update(IBaseModel persistentInstance) {\n        log.debug(\"update Object instance\");\n        try {\n            getHibernateTemplate().update(persistentInstance);\n            log.debug(\"update successful\");\n        } catch (RuntimeException re) {\n            log.error(\"update failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public void save(IBaseModel transientInstance) {\n        log.debug(\"saving CronModel instance\");\n        try {\n            getHibernateTemplate().save(transientInstance);\n            log.debug(\"save successful\");\n        } catch (RuntimeException re) {\n            log.error(\"save failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public void delete(IBaseModel persistentInstance) {\n        log.debug(\"deleting Object instance\");\n        try {\n            getHibernateTemplate().delete(persistentInstance);\n            log.debug(\"delete successful\");\n        } catch (RuntimeException re) {\n            log.error(\"delete failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public List<IBaseModel> findAll() {\n        log.debug(\"finding all Object instances\");\n        try {\n            String queryString = \"from \" + this.modelName;\n            return getHibernateTemplate().find(queryString);\n        } catch (RuntimeException re) {\n            log.error(\"find all failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public List<IBaseModel> findAll(int start, int limit) {\n        log.debug(\"finding all Object instances\");\n        try {\n            HibernateTemplate ht = getHibernateTemplate();\n            int PRE_MAX_RESULT = ht.getMaxResults();\n            int PRE_LIMIT = ht.getFetchSize();\n            ht.setMaxResults(limit);\n            ht.setFetchSize(start);\n            String queryString = \"from \" + this.modelName;\n            List<IBaseModel> list = ht.find(queryString);\n            ht.setMaxResults(PRE_MAX_RESULT);\n            ht.setFetchSize(PRE_LIMIT);\n            return list;\n        } catch (RuntimeException re) {\n            log.error(\"find all failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public IBaseModel merge(IBaseModel detachedInstance) {\n        log.debug(\"merging BaseModel instance\");\n        try {\n            IBaseModel result = (IBaseModel) getSession().merge(detachedInstance);\n            log.debug(\"merge successful\");\n            return result;\n        } catch (RuntimeException re) {\n            log.error(\"merge failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public void saveOrUpdate(IBaseModel instance) {\n        log.debug(\"attaching dirty BaseModel instance\");\n        try {\n            getSession().saveOrUpdate(instance);\n            log.debug(\"attach successful\");\n        } catch (RuntimeException re) {\n            log.error(\"attach failed\", re);\n            throw re;\n        }\n    }\n\n    @Override\n    public void attachClean(IBaseModel instance) {\n        log.debug(\"attaching clean Article instance\");\n        try {\n            getSession().lock(instance, LockMode.NONE);\n            log.debug(\"attach successful\");\n        } catch (RuntimeException re) {\n            log.error(\"attach failed\", re);\n            throw re;\n        }\n    }\n\n    protected SQLQuery getQuery(String queryString, Map<String, Object> where) {\n        return this.getQuery(queryString, where, true);\n    }\n\n    protected SQLQuery getQuery(String queryString, Map<String, Object> where, boolean returnMap) {\n        return this.getQuery(queryString, where, -1, -1, returnMap);\n    }\n\n    protected SQLQuery getQuery(String queryString, Map<String, Object> where, int start, int limit) {\n        return this.getQuery(queryString, where, start, limit, true);\n    }\n\n    protected String formateWhereSql(Map<String, Object> where, String middleString) {\n        String queryString = \"\";\n        Iterator<String> iterator = where.keySet().iterator();\n        boolean hasNext = iterator.hasNext();\n        while (hasNext) {\n            String key = iterator.next();\n            queryString += key + \" = :\" + key;\n            hasNext = iterator.hasNext();\n            if (hasNext) {\n                queryString += \" \" + middleString + \" \";\n            }\n        }\n        return queryString;\n    }\n\n    protected SQLQuery getQuery(String queryString, Map<String, Object> where, int start, int limit, boolean returnMap) {\n        Session session = this.getSession();\n        SQLQuery query = null;\n        if (start > -1 && limit > 0) {\n            query = session.createSQLQuery(queryString);\n            query.setFirstResult(start);\n            query.setMaxResults(limit);\n        } else {\n            query = session.createSQLQuery(queryString);\n        }\n        if (where != null) {\n            for (Entry<String, Object> entry : where.entrySet()) {\n                Object value = entry.getValue();\n                String key = entry.getKey();\n                if (value instanceof Collection) {\n                    query.setParameterList(key, (Collection) value);\n                } else if (value instanceof Object[]) {\n                    query.setParameterList(key, (Object[]) value);\n                } else {\n                    query.setParameter(key, value);\n                }\n            }\n        }\n        if (returnMap) {\n            query.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);\n        }\n        return query;\n    }\n\n    @Autowired\n    public void setSessionFactoryOverride(SessionFactory sessionFactory) {\n        super.setSessionFactory(sessionFactory);\n    }\n\n    public String getTableName() {\n        return tableName;\n    }\n\n    public void setTableName(String tableName) {\n        this.tableName = tableName;\n    }\n\n    public String getModelName() {\n        return modelName;\n    }\n\n    public void setModelName(String modelName) {\n        this.modelName = modelName;\n    }\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/sdm/BaseModel.java",
    "content": "package com.zhaidaosi.game.jgframework.common.sdm;\n\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.reflect.Field;\n\n@SuppressWarnings(\"serial\")\npublic abstract class BaseModel implements IBaseModel, Cloneable, java.io.Serializable {\n\n    protected static final Logger log = LoggerFactory.getLogger(BaseModel.class);\n\n    public String toString() {\n        Field[] fields = this.getClass().getDeclaredFields();\n        StringBuffer strBuf = new StringBuffer();\n        strBuf.append(this.getClass().getName());\n        strBuf.append(\" { \");\n        for (int i = 0; i < fields.length; i++) {\n            Field fd = fields[i];\n            fd.setAccessible(true);\n            strBuf.append(\"[\" + fd.getName() + \": \");\n            try {\n                strBuf.append(fd.get(this) + \"]\");\n            } catch (IllegalArgumentException | IllegalAccessException e) {\n//\t\t\t\t\te.printStackTrace();\n            }\n            if (i != fields.length - 1)\n                strBuf.append(\", \");\n        }\n\n        strBuf.append(\" }\");\n        return strBuf.toString();\n    }\n\n    public IBaseModel clone() {\n        IBaseModel o = null;\n        try {\n            o = (IBaseModel) super.clone();\n        } catch (CloneNotSupportedException e) {\n            log.error(e.getMessage(), e);\n        }\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/sdm/BaseService.java",
    "content": "package com.zhaidaosi.game.jgframework.common.sdm;\n\nimport java.util.List;\n\npublic abstract class BaseService {\n\n    protected IBaseDao dao;\n\n    protected abstract void setDao();\n\n    public IBaseModel findById(int id) {\n        return dao.findById(id);\n    }\n\n    public List<?> findAll(int start, int limit) {\n        return dao.findAll(start, limit);\n    }\n\n    public List<?> findByProperty(String propertyName, Object value) {\n        return dao.findByProperty(propertyName, value);\n    }\n\n    public IBaseModel findOneByProperty(String propertyName, Object value) {\n        return dao.findOneByProperty(propertyName, value);\n    }\n\n    public int total() {\n        return dao.total();\n    }\n\n    public void save(IBaseModel obj) {\n        dao.save(obj);\n    }\n\n    public void update(IBaseModel obj) {\n        dao.update(obj);\n    }\n\n    public List<?> findAll() {\n        return dao.findAll();\n    }\n\n    public void delete(IBaseModel obj) {\n        dao.delete(obj);\n    }\n\n    public String getDatabase() {\n        return null;\n    }\n\n    protected void setDao(IBaseDao dao) {\n        this.dao = dao;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/sdm/IBaseDao.java",
    "content": "package com.zhaidaosi.game.jgframework.common.sdm;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface IBaseDao {\n\n    public List<?> find(String queryString);\n\n    public List<?> find(String queryString, Map<String, Object> data);\n\n    public List<?> find(String queryString, Map<String, Object> data, int start, int limit);\n\n    public int total();\n\n    public int total(String queryString);\n\n    public int total(Map<String, Object> where);\n\n    public int total(String queryString, Map<String, Object> where);\n\n    public int update(String queryString);\n\n    public int update(Map<String, Object> where);\n\n    public int delete(String queryString);\n\n    public int delete(String queryString, Map<String, Object> where);\n\n    public int execute(String queryString);\n\n    public int execute(String queryString, Map<String, Object> where);\n\n    public List<IBaseModel> findByProperty(String propertyName, Object value);\n\n    public IBaseModel findOneByProperty(String propertyName, Object value);\n\n    public IBaseModel findById(int id);\n\n    public void update(IBaseModel persistentInstance);\n\n    public void save(IBaseModel transientInstance);\n\n    public void delete(IBaseModel persistentInstance);\n\n    public List<IBaseModel> findAll();\n\n    public List<IBaseModel> findAll(int start, int limit);\n\n    public IBaseModel merge(IBaseModel detachedInstance);\n\n    public void saveOrUpdate(IBaseModel instance);\n\n    public void attachClean(IBaseModel instance);\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/sdm/IBaseModel.java",
    "content": "package com.zhaidaosi.game.jgframework.common.sdm;\n\npublic interface IBaseModel {\n\n    public String toString();\n\n    public IBaseModel clone();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/spring/AnnotationSessionFactoryBeanEx.java",
    "content": "package com.zhaidaosi.game.jgframework.common.spring;\n\nimport org.hibernate.HibernateException;\nimport org.hibernate.cfg.AnnotationConfiguration;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\nimport org.springframework.core.io.Resource;\nimport org.springframework.core.io.support.PathMatchingResourcePatternResolver;\nimport org.springframework.core.io.support.ResourcePatternResolver;\nimport org.springframework.core.type.classreading.CachingMetadataReaderFactory;\nimport org.springframework.core.type.classreading.MetadataReader;\nimport org.springframework.core.type.classreading.MetadataReaderFactory;\nimport org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean;\nimport org.springframework.util.CollectionUtils;\n\nimport javax.persistence.Entity;\nimport java.io.IOException;\nimport java.util.HashSet;\nimport java.util.Set;\n\n/**\n * 该类扩展了Spring的AnnotationSessionFactoryBean类，增加了对AnnotatedClass的批量导入功能。\n * 通过使用setAnnotatedClassesLocations(String[])方法（其中的参数，是导入文件的路径数组），\n * 添加所有需要导入的AnnotatedClass，支持Spring的ResourceLoader对资源的加载方式。\n * 通过使用setExcludedClasses(String[])方法（其中参数，是待去除的类的全路径名），\n * 来去除在上述包路径中不需要导入的AnnotatedClass。\n */\npublic class AnnotationSessionFactoryBeanEx extends\n        AnnotationSessionFactoryBean {\n    private static final Logger logger = LoggerFactory\n            .getLogger(AnnotationSessionFactoryBeanEx.class);\n\n    /**\n     * The locations of the hibernate enity class files. They are often some of\n     * the string with Sping-style resource. A \".class\" subfix can make the\n     * scaning more precise.\n     * example:\n     * classpath*:com/systop/** /model/*.class\n     */\n    private String[] annotatedClassesLocations;\n\n    /**\n     * Which classes are not included in the session. They are some of the\n     * regular expression.\n     */\n    private Set<String> excludedClasseses = new HashSet<String>(0);\n\n    /**\n     * @param annotatedClassesLocations\n     *            the annotatedClassesLocations to set\n     */\n    public void setAnnotatedClassesLocations(String[] annotatedClassesLocations) {\n        this.annotatedClassesLocations = annotatedClassesLocations;\n    }\n\n    /**\n     * @see AnnotationSessionFactoryBean#postProcessAnnotationConfiguration(org.hibernate.cfg.AnnotationConfiguration)\n     */\n    @Override\n    protected void postProcessAnnotationConfiguration(\n            AnnotationConfiguration config) throws HibernateException {\n        Set<Class<?>> annClasses = scanAnnotatedClasses(); // Scan enity\n        // classes.\n        // Add entity classes to the configuration.\n        if (!CollectionUtils.isEmpty(annClasses)) {\n            for (Class<?> annClass : annClasses) {\n                config.addAnnotatedClass(annClass);\n            }\n        }\n    }\n\n    /**\n     * Scan annotated hibernate classes in the locations.\n     *\n     * @return Set of the annotated classes, if no matched class, return empty\n     *         Set.\n     */\n    private Set<Class<?>> scanAnnotatedClasses() {\n        ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();\n        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(\n                resourcePatternResolver);\n        Set<Class<?>> annotatedClasses = new HashSet<Class<?>>();\n        if (annotatedClassesLocations != null) {\n            try {\n                for (String annClassesLocation : annotatedClassesLocations) {\n                    // Resolve the resources\n                    Resource[] resources = resourcePatternResolver\n                            .getResources(annClassesLocation);\n                    for (Resource resource : resources) {\n                        MetadataReader metadataReader = metadataReaderFactory\n                                .getMetadataReader(resource);\n                        String className = metadataReader.getClassMetadata()\n                                .getClassName();\n                        // If the class is hibernate enity class, and it does\n                        // not match the excluded class patterns.\n                        if (isEntityClass(metadataReader)\n                                && !isExcludedClass(className)) {\n                            Class<?> clazz = Class.forName(className);\n                            annotatedClasses.add(clazz);\n                            logger.debug(\"A entity class has been found. ({})\",\n                                    clazz.getName());\n                        }\n                    }\n\n                }\n            } catch (IOException e) {\n                logger.error(\"I/O failure during classpath scanning, ({})\", e\n                        .getMessage());\n                throw new HibernateException(e);\n            } catch (ClassNotFoundException e) {\n                logger.error(\"Class not found, ({})\", e.getMessage());\n                throw new HibernateException(e);\n            } catch (LinkageError e) {\n                logger.error(\"LinkageError ({})\", e.getMessage());\n                throw new HibernateException(e);\n            }\n        }\n\n        return annotatedClasses;\n    }\n\n    /**\n     * @return True if the given MetadataReader shows that the class is\n     *         annotated by <code>javax.persistence.Enity</code>\n     */\n    private boolean isEntityClass(MetadataReader metadataReader) {\n        Set<String> annTypes = metadataReader.getAnnotationMetadata()\n                .getAnnotationTypes();\n        if (CollectionUtils.isEmpty(annTypes)) {\n            return false;\n        }\n\n        return annTypes.contains(Entity.class.getName());\n    }\n\n    /**\n     *\n     * @return True if the given class name match the excluded class patterns.\n     */\n    private boolean isExcludedClass(String className) {\n        return excludedClasseses.contains(className);\n    }\n\n    /**\n     * @param exculdePatterns\n     *            the exculdePatterns to set\n     */\n    public void setExcludedClasses(String[] excludedClasses) {\n        for (String cls : excludedClasses) {\n            this.excludedClasseses.add(cls);\n        }\n    }\n\n}"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/spring/DataSourceAdvice.java",
    "content": "package com.zhaidaosi.game.jgframework.common.spring;\n\nimport com.zhaidaosi.game.jgframework.common.BaseRunTimer;\nimport com.zhaidaosi.game.jgframework.common.sdm.BaseService;\nimport org.springframework.aop.AfterReturningAdvice;\nimport org.springframework.aop.MethodBeforeAdvice;\nimport org.springframework.aop.ThrowsAdvice;\n\nimport java.lang.reflect.Method;\n\npublic class DataSourceAdvice implements MethodBeforeAdvice,\n        AfterReturningAdvice, ThrowsAdvice {\n\n    private long startTime;\n\n    public void before(Method method, Object[] args, Object target) {\n        if (BaseRunTimer.isActive()) {\n            startTime = System.currentTimeMillis();\n        }\n        String database = null;\n        if (target instanceof BaseService) {\n            database = ((BaseService) target).getDatabase();\n        }\n        if (method.getName().startsWith(\"save\")\n                || method.getName().startsWith(\"add\")\n                || method.getName().startsWith(\"update\")\n                || method.getName().startsWith(\"delete\")) {\n            DataSourceSwitcher.setMaster(database);\n        } else {\n            DataSourceSwitcher.setSlave(database);\n        }\n    }\n\n    public void afterReturning(Object arg0, Method method, Object[] args,\n                               Object target) {\n        DataSourceSwitcher.clearDataSource();\n        this.setRunTime(method, target);\n    }\n\n    public void afterThrowing(Method method, Object[] args, Object target,\n                              Exception ex) {\n        DataSourceSwitcher.clearDataSource();\n        this.setRunTime(method, target);\n    }\n\n    private void setRunTime(Method method, Object target) {\n        if (BaseRunTimer.isActive()) {\n            long runningTime = System.currentTimeMillis() - startTime;\n            BaseRunTimer.addTimer(target.getClass().getName() + \".\"\n                    + method.getName() + \" run \" + runningTime + \" ms\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/spring/DataSourceSwitcher.java",
    "content": "package com.zhaidaosi.game.jgframework.common.spring;\n\nimport org.springframework.util.Assert;\n\npublic class DataSourceSwitcher {\n\n    private static ThreadLocal<String> contextHolder = new ThreadLocal<String>();\n    private static String defaultDatabase;\n\n\n    public static void setDataSource(String dataSource) {\n        Assert.notNull(dataSource, \"dataSource cannot be null\");\n        contextHolder.set(dataSource);\n    }\n\n    public static void setMaster(String database) {\n        if (database == null) {\n            database = defaultDatabase;\n        }\n        setDataSource(database + \"-master\");\n    }\n\n    public static void setSlave(String database) {\n        if (database == null) {\n            database = defaultDatabase;\n        }\n        setDataSource(database + \"-slave\");\n    }\n\n    public static String getDataSource() {\n        return (String) contextHolder.get();\n    }\n\n    public static void clearDataSource() {\n        contextHolder.remove();\n    }\n\n    public static void setDefaultDatabase(String database) {\n        defaultDatabase = database;\n    }\n\n}\n\n\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/spring/DynamicDataSource.java",
    "content": "package com.zhaidaosi.game.jgframework.common.spring;\n\nimport org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;\n\npublic class DynamicDataSource extends AbstractRoutingDataSource {\n\n    private String defaultDatabase;\n\n    @Override\n    protected Object determineCurrentLookupKey() {\n        return DataSourceSwitcher.getDataSource();\n    }\n\n    public void setDefaultDatabase(String defaultDatabase) {\n        this.defaultDatabase = defaultDatabase;\n        DataSourceSwitcher.setDefaultDatabase(this.defaultDatabase);\n    }\n\n}\n\n\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/common/spring/ServiceManager.java",
    "content": "package com.zhaidaosi.game.jgframework.common.spring;\n\nimport org.springframework.context.support.ClassPathXmlApplicationContext;\n\npublic class ServiceManager {\n\n    private static ClassPathXmlApplicationContext context = null;\n\n    public static void init() {\n        context = new ClassPathXmlApplicationContext(\"applicationContext.xml\");\n    }\n\n    public static <T> Object getService(String id) {\n        return context.getBean(id);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/connector/AuthConnector.java",
    "content": "package com.zhaidaosi.game.jgframework.connector;\n\nimport com.zhaidaosi.game.jgframework.Boot;\nimport com.zhaidaosi.game.jgframework.Router;\nimport com.zhaidaosi.game.jgframework.common.BaseRunTimer;\nimport com.zhaidaosi.game.jgframework.message.IBaseMessage;\nimport com.zhaidaosi.game.jgframework.message.InMessage;\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.*;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.*;\nimport io.netty.handler.codec.http.cors.CorsConfig;\nimport io.netty.handler.codec.http.cors.CorsHandler;\nimport io.netty.handler.stream.ChunkedWriteHandler;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.InetSocketAddress;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\n\nimport static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_LENGTH;\nimport static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;\nimport static io.netty.handler.codec.http.HttpMethod.POST;\nimport static io.netty.handler.codec.http.HttpResponseStatus.FORBIDDEN;\nimport static io.netty.handler.codec.http.HttpResponseStatus.OK;\nimport static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;\n\npublic class AuthConnector implements IBaseConnector {\n\n    private static final Logger log = LoggerFactory.getLogger(AuthConnector.class);\n    private final InetSocketAddress localAddress;\n    private ServerBootstrap bootstrap;\n    private NioEventLoopGroup bossGroup;\n    private NioEventLoopGroup workerGroup;\n    private String charset = Boot.getCharset().name();\n    private boolean isPause = false;\n\n    public AuthConnector(int port) {\n        this.localAddress = new InetSocketAddress(port);\n    }\n\n    @Override\n    public void start() {\n        if (bootstrap != null) {\n            return;\n        }\n\n        bootstrap = new ServerBootstrap();\n        bossGroup = new NioEventLoopGroup(1);\n\n        if (Boot.getAuthThreadCount() > 0) {\n            workerGroup = new NioEventLoopGroup(Boot.getAuthThreadCount());\n        } else {\n            workerGroup = new NioEventLoopGroup();\n        }\n\n        try {\n            bootstrap.group(bossGroup, workerGroup)\n                    .option(ChannelOption.SO_BACKLOG, 1024)\n                    .channel(NioServerSocketChannel.class)\n                    .childOption(ChannelOption.TCP_NODELAY, true)\n                    .childOption(ChannelOption.SO_REUSEADDR, true)\n                    .childHandler(new HttpServerInitializer())\n                    .bind(localAddress);\n            log.info(\"Auth Service is running! port : \" + localAddress.getPort());\n        } catch (Exception e) {\n            log.error(e.getMessage());\n        }\n    }\n\n    void pause() {\n        isPause = true;\n    }\n\n    void resume() {\n        isPause = false;\n    }\n\n    @Override\n    public void stop() {\n        if (bootstrap == null) {\n            return;\n        }\n        workerGroup.shutdownGracefully();\n        bossGroup.shutdownGracefully();\n    }\n\n    private class HttpServerInitializer extends ChannelInitializer<SocketChannel> {\n\n        @Override\n        public void initChannel(SocketChannel ch) {\n            CorsConfig corsConfig = CorsConfig.withAnyOrigin().build();\n            ChannelPipeline p = ch.pipeline();\n            p.addLast(new HttpResponseEncoder());\n            p.addLast(new HttpRequestDecoder());\n            p.addLast(new HttpObjectAggregator(65536));\n            p.addLast(new ChunkedWriteHandler());\n            p.addLast(new CorsHandler(corsConfig));\n            p.addLast(new HttpHandler());\n        }\n\n    }\n\n    private class HttpHandler extends ChannelInboundHandlerAdapter {\n\n        private InMessage inMsg;\n\n        @Override\n        public void channelActive(ChannelHandlerContext ctx) throws Exception {\n            if (isPause) {\n                sendHttpResponse(ctx, OutMessage.showError(\"系统已关闭\", 11000).toString(), true);\n            }\n        }\n\n        @Override\n        public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {\n            String error = t.getMessage();\n            log.error(error, t);\n            sendHttpResponse(ctx, OutMessage.showError(\"系统错误:\" + error, 10000).toString(), true);\n            ctx.close();\n        }\n\n        @Override\n        public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n            BaseRunTimer.showTimer();\n        }\n\n        @Override\n        public void channelReadComplete(ChannelHandlerContext ctx) {\n            ctx.flush();\n        }\n\n        @Override\n        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n\n            if (msg instanceof HttpRequest) {\n                HttpRequest request = (HttpRequest) msg;\n                if (request.getMethod() != POST) {\n                    sendErrorHttpResponse(ctx, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));\n                    return;\n                }\n                inMsg = new InMessage(Boot.getAuthHandler() + request.getUri().substring(1).replace(\"/\", \"\\\\.\").toLowerCase());\n            }\n\n            long startTime = 0;\n            if (BaseRunTimer.isActive()) {\n                startTime = System.currentTimeMillis();\n            }\n\n            if (msg instanceof HttpContent) {\n\n                HttpContent httpContent = (HttpContent) msg;\n                ByteBuf content = httpContent.content();\n                String post = content.toString(Boot.getCharset());\n                content.release();\n\n                QueryStringDecoder queryStringDecoder = new QueryStringDecoder(post, Boot.getCharset(), false);\n                Map<String, List<String>> params = queryStringDecoder.parameters();\n                if (!params.isEmpty()) {\n                    for (Entry<String, List<String>> p : params.entrySet()) {\n                        String key = p.getKey();\n                        List<String> vals = p.getValue();\n                        inMsg.putMember(key, vals.get(0));\n                    }\n                }\n                IBaseMessage rs = Router.run(inMsg, ctx.channel());\n\n                if (BaseRunTimer.isActive()) {\n                    long runningTime = System.currentTimeMillis() - startTime;\n                    BaseRunTimer.addTimer(\"AuthConnector messageReceived run \" + runningTime + \" ms\");\n                }\n                if (rs == null) {\n                    sendErrorHttpResponse(ctx, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));\n                } else {\n                    sendHttpResponse(ctx, rs.toString(), true);\n                }\n            }\n        }\n\n        private void sendHttpResponse(ChannelHandlerContext ctx, String res, boolean isJson) {\n            FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, OK, Unpooled.wrappedBuffer(res.getBytes()));\n            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());\n//            response.headers().set(ACCESS_CONTROL_ALLOW_ORIGIN, \"*\");\n            if (isJson) {\n                response.headers().set(CONTENT_TYPE, \"application/json; charset=\" + charset);\n            } else {\n                response.headers().set(CONTENT_TYPE, \"text/html; charset=\" + charset);\n            }\n            ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);\n        }\n\n        private void sendErrorHttpResponse(ChannelHandlerContext ctx, DefaultFullHttpResponse response) {\n            response.headers().set(CONTENT_LENGTH, response.content().readableBytes());\n            ctx.channel().write(response).addListener(ChannelFutureListener.CLOSE);\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/connector/IBaseConnector.java",
    "content": "package com.zhaidaosi.game.jgframework.connector;\n\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter;\nimport io.netty.util.AttributeKey;\n\npublic interface IBaseConnector {\n\n    AttributeKey<IBaseCharacter> PLAYER = AttributeKey.valueOf(\"player\");\n\n    void start();\n\n    void stop();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/connector/ManagerConnector.java",
    "content": "package com.zhaidaosi.game.jgframework.connector;\n\nimport com.zhaidaosi.game.jgframework.Boot;\nimport com.zhaidaosi.game.jgframework.common.BaseDate;\nimport com.zhaidaosi.game.jgframework.common.BaseIp;\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\nimport com.zhaidaosi.game.jgframework.session.SessionManager;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.channel.*;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.DelimiterBasedFrameDecoder;\nimport io.netty.handler.codec.Delimiters;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.lang.management.ManagementFactory;\nimport java.lang.management.RuntimeMXBean;\nimport java.net.InetSocketAddress;\nimport java.util.ArrayList;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\n\n\npublic class ManagerConnector implements IBaseConnector {\n\n    private static final Logger log = LoggerFactory.getLogger(ManagerConnector.class);\n    private final InetSocketAddress localAddress;\n    private ServerBootstrap bootstrap;\n    private NioEventLoopGroup bossGroup;\n    private NioEventLoopGroup workerGroup;\n\n    public ManagerConnector(int port) {\n        this.localAddress = new InetSocketAddress(port);\n    }\n\n    @Override\n    public void start() {\n        if (bootstrap != null) {\n            return;\n        }\n\n        bootstrap = new ServerBootstrap();\n        bossGroup = new NioEventLoopGroup(1);\n        workerGroup = new NioEventLoopGroup(1);\n\n        try{\n            bootstrap.group(bossGroup, workerGroup)\n                    .channel(NioServerSocketChannel.class)\n                    .childHandler(new TelnetServerInitializer())\n                    .bind(localAddress);\n            log.info(\"Manager Service is running! port : \" + localAddress.getPort());\n        } catch (Exception e) {\n            log.error(e.getMessage());\n        }\n    }\n\n    @Override\n    public void stop() {\n        if (bootstrap == null) {\n            return;\n        }\n        workerGroup.shutdownGracefully();\n        bossGroup.shutdownGracefully();\n        bootstrap = null;\n    }\n\n\n\n    class TelnetServerInitializer extends ChannelInitializer<SocketChannel> {\n\n        @Override\n        public void initChannel(SocketChannel ch) throws Exception {\n            ChannelPipeline pipeline = ch.pipeline();\n            pipeline.addLast(new DelimiterBasedFrameDecoder(8192, Delimiters.lineDelimiter()));\n            pipeline.addLast(new StringDecoder());\n            pipeline.addLast(new StringEncoder());\n            pipeline.addLast(new ManagerHandler());\n        }\n\n    }\n\n\n    class ManagerHandler extends ChannelInboundHandlerAdapter {\n\n        private final String nextLine = \"\\r\\n\";\n        private boolean close = false;\n\n        @Override\n        public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {\n            log.error(t.getMessage(), t);\n        }\n\n        @Override\n        public void channelActive(ChannelHandlerContext ctx) throws Exception {\n            Channel ch = ctx.channel();\n            String ip = ch.remoteAddress().toString();\n            String[] ipArr = ip.split(\":\");\n            String realIp = ipArr[0].substring(ipArr[0].indexOf(\"/\") + 1);\n            if (!ManagerService.checkIp(realIp)) {\n                ch.close();\n            } else {\n                ch.write(\"Please input user name:\" + nextLine);\n                ch.flush();\n                ManagerService.goNextSetp(ch.hashCode());\n                log.info(\"ManagerConnector connected \" + ip);\n            }\n        }\n\n        @Override\n        public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n            Channel ch = ctx.channel();\n            ManagerService.clear(ch.hashCode());\n            log.info(\"ManagerConnector closed \" + ch.remoteAddress());\n        }\n\n        @Override\n        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n            Channel ch = ctx.channel();\n            String request = msg.toString().toLowerCase();\n            String response = \"Please i something.\";\n            if (request.length() > 0) {\n                Integer cid = ch.hashCode();\n                Integer step = ManagerService.getStep(cid);\n                if (step == 1 || step == 2) {\n                    response = login(request, step, cid);\n                } else {\n                    response = handler(request);\n                }\n            }\n            ChannelFuture future = ch.write(response + nextLine);\n            if (close) {\n                future.addListener(ChannelFutureListener.CLOSE);\n            }\n        }\n\n        private String handler(String request) {\n            String response;\n            String[] requestArr = request.split(\" \");\n            AuthConnector authConnector = Boot.getAuthConnector();\n            ServiceConnector serviceConnector = Boot.getServiceConnector();\n\n            switch (requestArr[0]) {\n                case \"exit\":\n                case \"quit\":\n                    response = \"Have a good day!\";\n                    close = true;\n                    break;\n                case \"help\":\n                    response = \"#### status : system status\" + nextLine;\n                    response += \"#### start : start all service\" + nextLine;\n                    response += \"#### stop : stop all service\" + nextLine;\n                    response += \"#### start-service : start service\" + nextLine;\n                    response += \"#### stop-service : stop service\" + nextLine;\n                    response += \"#### start-auth : start auth\" + nextLine;\n                    response += \"#### stop-auth : stop auth\" + nextLine;\n                    response += \"#### pause-auth : pause auth\" + nextLine;\n                    response += \"#### resume-auth : resume auth\" + nextLine;\n                    response += \"#### msg : send msg to all users\" + nextLine;\n                    response += \"#### exit/quit : exit\";\n                    break;\n                case \"status\":\n                    ServiceConnector c = Boot.getServiceConnector();\n                    long startTime = c.getStartTime();\n                    response = nextLine + \"#### pid : \" + ManagerService.getPid() + nextLine;\n                    response += \"#### start_time : \" + BaseDate.time2String(BaseDate.FORMAT_YY_MM_DD_HH_MM_SS, startTime) + nextLine;\n                    response += \"#### running time : \" + (System.currentTimeMillis() - startTime) / 1000 + \"s\" + nextLine;\n                    response += \"#### socket_connect : \" + c.getConnectCount() + nextLine;\n                    response += \"#### socket_wait : \" + SessionManager.getWaitCount() + nextLine;\n                    response += \"#### login_user_count : \" + SessionManager.getUserCount() + nextLine;\n                    break;\n                case \"start\":\n                    serviceConnector.start();\n                    if (authConnector != null) {\n                        authConnector.start();\n                    }\n                    response = \"start is ok\";\n                    break;\n                case \"stop\":\n                    serviceConnector.stop();\n                    if (authConnector != null) {\n                        authConnector.stop();\n                    }\n                    response = \"stop is ok\";\n                    break;\n                case \"start-service\":\n                    serviceConnector.start();\n                    response = \"start service is ok\";\n                    break;\n                case \"stop-service\":\n                    serviceConnector.stop();\n                    response = \"stop service is ok\";\n                    break;\n                case \"start-auth\":\n                    if (authConnector != null) {\n                        authConnector.start();\n                    }\n                    response = \"start auth is ok\";\n                    break;\n                case \"stop-auth\":\n                    if (authConnector != null) {\n                        authConnector.stop();\n                    }\n                    response = \"stop auth is ok\";\n                    break;\n                case \"pause-auth\":\n                    if (authConnector != null) {\n                        authConnector.pause();\n                    }\n                    response = \"pause auth is ok\";\n                    break;\n                case \"resume-auth\":\n                    if (authConnector != null) {\n                        authConnector.resume();\n                    }\n                    response = \"resume auth is ok\";\n                    break;\n                case \"msg\":\n                    if (requestArr.length < 2) {\n                        response = \"Please input msg.\";\n                    } else {\n                        String msg = \"\";\n                        for (int i = 1; i < requestArr.length; i++) {\n                            msg += requestArr[i] + \" \";\n                        }\n                        msg = msg.trim();\n                        response = sendMsg(msg);\n                    }\n                    break;\n                default:\n                    response = \"ERROR\";\n                    break;\n            }\n            return response;\n        }\n\n        @Override\n        public void channelReadComplete(ChannelHandlerContext ctx) {\n            ctx.flush();\n        }\n\n        private String sendMsg(String msg) {\n            Map<Integer, Channel> channels = SessionManager.getChannels();\n            for (Map.Entry<Integer, Channel> entry : channels.entrySet()) {\n                Channel ch = entry.getValue();\n                if (ch.isWritable()) {\n                    ch.write(OutMessage.showSucc(msg));\n                }\n            }\n            return \"OK\";\n        }\n\n        private String login(String request, Integer step, Integer cid) {\n            String response;\n            if (step == 1) {\n                String user = Boot.getManagerUser();\n                if (!request.equals(user)) {\n                    response = \"User name is error, please input again!\";\n                } else {\n                    ManagerService.goNextSetp(cid);\n                    response = \"Please input password:\";\n                }\n            } else {\n                String password = Boot.getManagerPassword();\n                if (!request.equals(password)) {\n                    response = \"Password is error, please input again!\";\n                } else {\n                    ManagerService.goNextSetp(cid);\n                    response = \"Login success!\" + nextLine;\n                }\n            }\n            return response;\n        }\n    }\n\n    static class ManagerService {\n\n        private static ConcurrentHashMap<Integer, Integer> authStep = new ConcurrentHashMap<>();\n\n        private static int pId = 0;\n\n        static boolean checkIp(String ip) {\n            ArrayList<Long[]> ipList = Boot.getManagerAllowIps();\n            for (Long[] longs : ipList) {\n                if (BaseIp.checkIp(ip, longs)) {\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        static Integer getStep(Integer cid) {\n            Integer setp = authStep.get(cid);\n            if (setp == null) {\n                setp = 1;\n                authStep.put(cid, 1);\n            }\n            return setp;\n        }\n\n        static void goNextSetp(Integer cid) {\n            Integer step = authStep.get(cid);\n            if (step == null) {\n                authStep.put(cid, 1);\n            } else {\n                authStep.put(cid, ++step);\n            }\n        }\n\n        static void clear(Integer cid) {\n            authStep.remove(cid);\n        }\n\n        static int getPid() {\n            if (pId == 0) {\n                RuntimeMXBean runtime = ManagementFactory.getRuntimeMXBean();\n                String name = runtime.getName();\n                try {\n                    pId = Integer.parseInt(name.substring(0, name.indexOf('@')));\n                } catch (Exception e) {\n                    pId = -1;\n                }\n            }\n            return pId;\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/connector/ServiceConnector.java",
    "content": "package com.zhaidaosi.game.jgframework.connector;\n\nimport com.zhaidaosi.game.jgframework.Boot;\nimport com.zhaidaosi.game.jgframework.Router;\nimport com.zhaidaosi.game.jgframework.common.BaseRunTimer;\nimport com.zhaidaosi.game.jgframework.common.excption.MessageException;\nimport com.zhaidaosi.game.jgframework.message.*;\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter;\nimport com.zhaidaosi.game.jgframework.rsync.RsyncManager;\nimport com.zhaidaosi.game.jgframework.session.SessionManager;\nimport io.netty.bootstrap.ServerBootstrap;\nimport io.netty.buffer.ByteBuf;\nimport io.netty.buffer.PooledByteBufAllocator;\nimport io.netty.buffer.Unpooled;\nimport io.netty.channel.*;\nimport io.netty.channel.nio.NioEventLoopGroup;\nimport io.netty.channel.socket.SocketChannel;\nimport io.netty.channel.socket.nio.NioServerSocketChannel;\nimport io.netty.handler.codec.http.*;\nimport io.netty.handler.codec.http.FullHttpRequest;\nimport io.netty.handler.codec.http.FullHttpResponse;\nimport io.netty.handler.codec.http.HttpHeaders;\nimport io.netty.handler.codec.http.websocketx.*;\nimport io.netty.handler.codec.string.StringDecoder;\nimport io.netty.handler.codec.string.StringEncoder;\nimport io.netty.handler.timeout.IdleState;\nimport io.netty.handler.timeout.IdleStateEvent;\nimport io.netty.handler.timeout.IdleStateHandler;\nimport io.netty.handler.timeout.ReadTimeoutException;\n\nimport static io.netty.handler.codec.http.HttpHeaders.Names.*;\nimport static io.netty.handler.codec.http.HttpMethod.*;\nimport static io.netty.handler.codec.http.HttpResponseStatus.*;\nimport static io.netty.handler.codec.http.HttpVersion.*;\n\nimport io.netty.util.CharsetUtil;\nimport io.netty.util.ReferenceCountUtil;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.net.InetSocketAddress;\nimport java.nio.channels.ClosedChannelException;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.TimeUnit;\n\n\npublic class ServiceConnector implements IBaseConnector {\n\n    private static final Logger log = LoggerFactory.getLogger(ServiceConnector.class);\n    private final InetSocketAddress localAddress;\n    private NioEventLoopGroup bossGroup;\n    private NioEventLoopGroup workerGroup;\n    private ServerBootstrap bootstrap;\n    private Timer timer;\n    private final long period;\n    private final String mode;\n    private final Object lock = new Object();\n    private int connectCount = 0;\n    private long startTime;\n    public static final String MODE_SOCKET = \"socket\";\n    public static final String MODE_WEB_SOCKET = \"websocket\";\n    public static final String WEB_SOCKET_PATH = \"/websocket\";\n\n    private int heartbeatTime = Boot.getServiceHeartbeatTime();\n\n    long getStartTime() {\n        return startTime;\n    }\n\n    public int getConnectCount() {\n        return connectCount;\n    }\n\n    public ServiceConnector(int port, long period, String mode) {\n        this.localAddress = new InetSocketAddress(port);\n        this.period = period;\n        this.mode = mode;\n    }\n\n    public void start() {\n        if (bootstrap != null) {\n            return;\n        }\n        bootstrap = new ServerBootstrap();\n        bossGroup = new NioEventLoopGroup(1);\n\n        if (Boot.getServiceThreadCount() > 0) {\n            workerGroup = new NioEventLoopGroup(Boot.getServiceThreadCount());\n        } else {\n            workerGroup = new NioEventLoopGroup();\n        }\n\n        try {\n            bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class);\n\n            switch (mode) {\n                case MODE_SOCKET:\n                    bootstrap.childHandler(new SocketServerInitializer());\n                    break;\n                case MODE_WEB_SOCKET:\n                    bootstrap.childHandler(new WebSocketServerInitializer());\n                    break;\n                default:\n                    log.error(\"Service 运行模式设置错误,必须为\" + MODE_SOCKET + \"或\" + MODE_WEB_SOCKET);\n                    return;\n            }\n\n            SessionManager.init();\n            RsyncManager.init();\n            timer = new Timer(\"SyncManagerTimer\");\n            timer.schedule(new MyTimerTask(), period, period);\n            startTime = System.currentTimeMillis();\n            bootstrap.option(ChannelOption.TCP_NODELAY, true)\n                    .option(ChannelOption.RCVBUF_ALLOCATOR, AdaptiveRecvByteBufAllocator.DEFAULT)\n                    .option(ChannelOption.SO_RCVBUF, 128 * 1024)\n                    .option(ChannelOption.SO_SNDBUF, 128 * 1024)\n                    .option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT)\n                    .bind(localAddress);\n            log.info(\"Connect Service is running! port : \" + localAddress.getPort());\n        } catch (Exception e) {\n            log.error(e.getMessage());\n        }\n    }\n\n    @Override\n    public void stop() {\n        if (bootstrap == null) {\n            return;\n        }\n        workerGroup.shutdownGracefully();\n        bossGroup.shutdownGracefully();\n        bootstrap = null;\n        timer.cancel();\n        timer = null;\n        SessionManager.destroy();\n        RsyncManager.run();\n    }\n\n    private class SocketServerInitializer extends ChannelInitializer<SocketChannel> {\n\n        @Override\n        public void initChannel(SocketChannel ch) throws Exception {\n            ChannelPipeline pipeline = ch.pipeline();\n            if (!Boot.getDebug()) {\n                pipeline.addLast(new IdleStateHandler(heartbeatTime * 2, 0, heartbeatTime, TimeUnit.SECONDS));\n            }\n            pipeline.addLast(new StringEncoder(Boot.getCharset()));\n            pipeline.addLast(new StringDecoder(Boot.getCharset()));\n            pipeline.addLast(new MessageEncode());\n            pipeline.addLast(new MessageDecode());\n            pipeline.addLast(new ServiceChannelHandler());\n        }\n\n    }\n\n    private class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> {\n\n        @Override\n        public void initChannel(SocketChannel ch) throws Exception {\n            ChannelPipeline pipeline = ch.pipeline();\n            if (!Boot.getDebug()) {\n                pipeline.addLast(new IdleStateHandler(heartbeatTime * 2, 0, heartbeatTime, TimeUnit.SECONDS));\n            }\n            pipeline.addLast(\n                    new HttpResponseEncoder(),\n                    new HttpRequestDecoder(),\n                    new HttpObjectAggregator(65536),\n                    new WebSocketEncode(),\n                    new ServiceChannelHandler()\n            );\n        }\n    }\n\n    private class MyTimerTask extends TimerTask {\n        @Override\n        public void run() {\n            log.info(\"start sync ...\");\n            RsyncManager.run();\n        }\n    }\n\n    private class ServiceChannelHandler extends ChannelInboundHandlerAdapter {\n\n        private WebSocketServerHandshaker handshake;\n        private IBaseCharacter player;\n\n        @Override\n        public void exceptionCaught(ChannelHandlerContext ctx, Throwable t) throws Exception {\n            String errorMsg = t.getMessage();\n            if (!(t instanceof ClosedChannelException)) {\n                Channel ch = ctx.channel();\n                if (t instanceof MessageException) {\n                    log.error(errorMsg);\n                } else if (t instanceof ReadTimeoutException) {\n                    log.error(\"强制关闭超时连接  => \" + ch.remoteAddress());\n                } else {\n                    log.error(errorMsg, t);\n                }\n                ch.close();\n            }\n        }\n\n        @Override\n        public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {\n           /*心跳处理*/\n            if (evt instanceof IdleStateEvent) {\n                IdleStateEvent event = (IdleStateEvent) evt;\n                if (event.state() == IdleState.READER_IDLE) {\n                    log.debug(\"close read time out connect => \" + ctx.channel().remoteAddress());\n                    ctx.disconnect();\n                } else if (event.state() == IdleState.WRITER_IDLE) {\n                    log.debug(\"close write time out connect => \" + ctx.channel().remoteAddress());\n                } else if (event.state() == IdleState.ALL_IDLE) {\n                    ctx.writeAndFlush(new PingWebSocketFrame());\n                }\n            }\n        }\n\n        @Override\n        public void channelActive(ChannelHandlerContext ctx) throws Exception {\n            synchronized (lock) {\n                connectCount++;\n            }\n            player = Boot.getPlayerFactory().getPlayer();\n            player.sChannel(ctx.channel());\n            ctx.channel().attr(IBaseConnector.PLAYER).set(player);\n        }\n\n        @Override\n        public void channelInactive(ChannelHandlerContext ctx) throws Exception {\n            SessionManager.removeSession(ctx.channel());\n            synchronized (lock) {\n                connectCount--;\n            }\n            BaseRunTimer.showTimer();\n        }\n\n        @Override\n        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {\n            long startTime = 0;\n            if (BaseRunTimer.isActive()) {\n                startTime = System.currentTimeMillis();\n            }\n            try {\n                if (msg instanceof FullHttpRequest) {\n                    handleHttpRequest(ctx, (FullHttpRequest) msg);\n                } else {\n                    handleWebSocketRequest(ctx, msg);\n                }\n            } finally {\n                ReferenceCountUtil.release(msg);\n            }\n            if (BaseRunTimer.isActive()) {\n                long runningTime = System.currentTimeMillis() - startTime;\n                BaseRunTimer.addTimer(\"ServiceConnector messageReceived run \" + runningTime + \" ms\");\n                BaseRunTimer.showTimer();\n            }\n        }\n\n        @Override\n        public void channelReadComplete(ChannelHandlerContext ctx) {\n            ctx.flush();\n        }\n\n        private void handleWebSocketRequest(ChannelHandlerContext ctx, Object msg) throws Exception {\n            InMessage inMsg = null;\n            IBaseMessage rs = null;\n            Channel ch = ctx.channel();\n            if (msg instanceof WebSocketFrame) {\n                if (msg instanceof CloseWebSocketFrame) {\n                    handshake.close(ctx.channel(), ((CloseWebSocketFrame) msg).retain());\n                    return;\n                }\n                if (msg instanceof PingWebSocketFrame) {\n                    ctx.write(new PongWebSocketFrame(((PingWebSocketFrame) msg).content().retain()));\n                    return;\n                }\n                if (msg instanceof PongWebSocketFrame) {\n                    return;\n                }\n                if (!(msg instanceof TextWebSocketFrame)) {\n                    throw new UnsupportedOperationException(String.format(\"%s msg types not supported\", msg.getClass().getName()));\n                }\n                inMsg = InMessage.getMessage(((TextWebSocketFrame) msg).text());\n            } else if (msg instanceof IBaseMessage) {\n                inMsg = (InMessage) msg;\n            }\n\n            boolean error = true;\n            if (!SessionManager.isAuthHandler(inMsg)) {\n                int result = SessionManager.checkSession(inMsg, ch);\n                if (result != SessionManager.ADD_SESSION_ERROR) {\n                    error = false;\n                    if (result == SessionManager.ADD_SESSION_SUCC) {\n                        rs = Router.run(inMsg, ch);\n                    } else {\n                        rs = SessionManager.getWaitMessage(player);\n                    }\n                }\n            }\n\n            if (error) {\n                log.error(\"强制关闭没授权的连接  => \" + ch.remoteAddress());\n                ch.close();\n            } else if (rs != null && ch.isWritable()) {\n                ch.write(rs);\n            }\n        }\n\n        private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception {\n            // Handle a bad request.\n            if (!req.getDecoderResult().isSuccess()) {\n                sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST));\n                return;\n            }\n            if (req.getMethod() != GET) {\n                sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));\n                return;\n            }\n            if (!WEB_SOCKET_PATH.equals(req.getUri())) {\n                sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN));\n                return;\n            }\n            // Handshake\n            WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(\n                    getWebSocketLocation(req), null, true);\n            handshake = wsFactory.newHandshaker(req);\n            if (handshake == null) {\n                WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());\n            } else {\n                handshake.handshake(ctx.channel(), req);\n            }\n        }\n\n        private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res) {\n            // Generate an error page if response getStatus code is not OK (200).\n            if (res.getStatus().code() != 200) {\n                ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);\n                res.content().writeBytes(buf);\n                buf.release();\n                HttpHeaders.setContentLength(res, res.content().readableBytes());\n            }\n\n            // Send the response and close the connection if necessary.\n            ChannelFuture f = ctx.channel().writeAndFlush(res);\n            if (!HttpHeaders.isKeepAlive(req) || res.getStatus().code() != 200) {\n                f.addListener(ChannelFutureListener.CLOSE);\n            }\n        }\n\n        private String getWebSocketLocation(HttpRequest req) {\n            return \"ws://\" + req.headers().get(HOST) + WEB_SOCKET_PATH;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/handler/BaseHandler.java",
    "content": "package com.zhaidaosi.game.jgframework.handler;\n\nimport com.zhaidaosi.game.jgframework.message.IBaseMessage;\nimport com.zhaidaosi.game.jgframework.message.InMessage;\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\nimport io.netty.channel.Channel;\n\npublic abstract class BaseHandler implements IBaseHandler {\n\n    protected String handlerName;\n\n    @Override\n    public abstract IBaseMessage run(InMessage im, Channel ch) throws Exception;\n\n    @Override\n    public String getHandlerName() {\n        return handlerName;\n    }\n\n    @Override\n    public void setHandlerName(String handlerName) {\n        this.handlerName = handlerName;\n    }\n\n    public static IBaseMessage doHeart() {\n        return OutMessage.showSucc(\"\");\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/handler/BaseHandlerChannel.java",
    "content": "package com.zhaidaosi.game.jgframework.handler;\n\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\nimport io.netty.channel.Channel;\nimport io.netty.channel.ChannelFuture;\nimport io.netty.channel.group.ChannelGroup;\nimport io.netty.channel.group.ChannelGroupFuture;\n\npublic class BaseHandlerChannel {\n\n    private Channel chanel;\n    private ChannelGroup chanelGroup;\n    private String handlerName;\n\n    public BaseHandlerChannel(String handlerName, Channel chanel) {\n        this.handlerName = handlerName;\n        this.chanel = chanel;\n    }\n\n    public BaseHandlerChannel(String handlerName, ChannelGroup chanelGroup) {\n        this.handlerName = handlerName;\n        this.chanelGroup = chanelGroup;\n    }\n\n    public Channel getChanel() {\n        return chanel;\n    }\n\n    public ChannelGroup getChannelGroup() {\n        return chanelGroup;\n    }\n\n    public String getHandlerName() {\n        return handlerName;\n    }\n\n    public ChannelFuture write(OutMessage message) {\n        message.setH(handlerName);\n        if (chanel != null && chanel.isWritable()) {\n            return chanel.write(message);\n        }\n        return null;\n    }\n\n    public ChannelGroupFuture writeGroup(OutMessage message) {\n        message.setH(handlerName);\n        if (chanelGroup != null) {\n            return chanelGroup.write(message);\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/handler/IBaseHandler.java",
    "content": "package com.zhaidaosi.game.jgframework.handler;\n\nimport com.zhaidaosi.game.jgframework.message.IBaseMessage;\nimport com.zhaidaosi.game.jgframework.message.InMessage;\nimport io.netty.channel.Channel;\n\npublic interface IBaseHandler {\n\n    IBaseMessage run(InMessage im, Channel ch) throws Exception;\n\n    String getHandlerName();\n\n    void setHandlerName(String handlerName);\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/message/IBaseMessage.java",
    "content": "package com.zhaidaosi.game.jgframework.message;\n\npublic interface IBaseMessage {\n\n    String toString();\n\n    String getH();\n\n    void setH(String h);\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/message/InMessage.java",
    "content": "package com.zhaidaosi.game.jgframework.message;\n\nimport com.zhaidaosi.game.jgframework.common.BaseJson;\nimport com.zhaidaosi.game.jgframework.common.excption.MessageException;\n\nimport java.util.HashMap;\n\n\npublic class InMessage implements IBaseMessage {\n    /**\n     * 控制器handler路径\n     */\n    private String h;\n    /**\n     * 参数\n     */\n    private HashMap<String, Object> p = new HashMap<>();\n\n    public InMessage() {\n    }\n\n    public InMessage(String h) {\n        this.h = h;\n    }\n\n    public InMessage(String h, HashMap<String, Object> p) {\n        this.h = h;\n        this.p = p;\n    }\n\n    public static InMessage getMessage(String msg) throws MessageException {\n        if (msg.startsWith(\"{\") && msg.endsWith(\"}\")) {\n            return BaseJson.JsonToObject(msg, InMessage.class);\n        } else {\n            throw new MessageException(\"msg格式错误\");\n        }\n    }\n\n    public String toString() {\n        return BaseJson.ObjectToJson(this);\n    }\n\n    public String getH() {\n        return h;\n    }\n\n    public HashMap<String, Object> getP() {\n        return p;\n    }\n\n    public void setH(String h) {\n        this.h = h;\n    }\n\n\n    public void setP(HashMap<String, Object> p) {\n        this.p = p;\n    }\n\n    public void putMember(String key, Object value) {\n        this.p.put(key, value);\n    }\n\n    public Object getMember(String key) {\n        return p.get(key);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/message/MessageDecode.java",
    "content": "package com.zhaidaosi.game.jgframework.message;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.MessageToMessageDecoder;\n\nimport java.util.List;\n\npublic class MessageDecode extends MessageToMessageDecoder<Object> {\n\n    @Override\n    protected void decode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {\n        if (msg instanceof String) {\n            msg = InMessage.getMessage((String) msg);\n        }\n        out.add(msg);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/message/MessageEncode.java",
    "content": "package com.zhaidaosi.game.jgframework.message;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.MessageToMessageEncoder;\nimport io.netty.util.ReferenceCountUtil;\n\nimport java.util.List;\n\npublic class MessageEncode extends MessageToMessageEncoder<Object> {\n\n    @Override\n    protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) {\n        if(msg == null) {\n            return ;\n        }\n        if (msg instanceof IBaseMessage) {\n            msg = msg.toString() + \"\\n\";\n        } else {\n            ReferenceCountUtil.retain(msg);\n        }\n        out.add(msg);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/message/OutMessage.java",
    "content": "package com.zhaidaosi.game.jgframework.message;\n\nimport com.zhaidaosi.game.jgframework.common.BaseJson;\nimport com.zhaidaosi.game.jgframework.common.excption.MessageException;\nimport org.apache.commons.beanutils.PropertyUtils;\n\nimport java.lang.reflect.InvocationTargetException;\n\npublic class OutMessage implements IBaseMessage {\n\n    private int code = 0;\n\n    private String h;\n\n    private Object result = null;\n\n    public OutMessage() {\n    }\n\n    public OutMessage(Object result, int code) {\n        this.code = code;\n        this.result = result;\n    }\n\n    public OutMessage(Object result, int code, String h) {\n        this.code = code;\n        this.result = result;\n        this.h = h;\n    }\n\n    public String toString() {\n        return BaseJson.ObjectToJson(this);\n    }\n\n    public static OutMessage getMessage(String om) throws MessageException {\n        if (om.startsWith(\"{\") && om.endsWith(\"}\")) {\n            return BaseJson.JsonToObject(om, OutMessage.class);\n        } else {\n            throw new MessageException(\"msg格式错误\");\n        }\n    }\n\n    public static OutMessage showError(String result) {\n        return showMessage(result, 1);\n    }\n\n    public static OutMessage showError(String result, String h) {\n        return showMessage(result, 1, h);\n    }\n\n    public static OutMessage showError(String result, int code) {\n        return showMessage(result, code);\n    }\n\n    public static OutMessage showSucc(Object result, String h) {\n        return showMessage(result, 0, h);\n    }\n\n    public static OutMessage showSucc(Object result) {\n        return showMessage(result, 0);\n    }\n\n    private static OutMessage showMessage(Object result, int code) {\n        return new OutMessage(result, code);\n    }\n\n    private static OutMessage showMessage(Object result, int code, String h) {\n        return new OutMessage(result, code, h);\n    }\n\n    public int getCode() {\n        return code;\n    }\n\n    public void setCode(int code) {\n        this.code = code;\n    }\n\n    public Object getResult() {\n        return result;\n    }\n\n    public void setResult(Object result) {\n        this.result = result;\n    }\n\n    public Object getResultValue(String key) {\n        Object value = null;\n        try {\n            value = PropertyUtils.getProperty(result, key).toString();\n        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {\n            e.printStackTrace();\n        }\n        return value;\n    }\n\n    public String getH() {\n        return h;\n    }\n\n    public void setH(String h) {\n        this.h = h;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/message/WebSocketEncode.java",
    "content": "package com.zhaidaosi.game.jgframework.message;\n\nimport io.netty.channel.ChannelHandlerContext;\nimport io.netty.handler.codec.MessageToMessageEncoder;\nimport io.netty.handler.codec.http.websocketx.TextWebSocketFrame;\nimport io.netty.util.ReferenceCountUtil;\n\nimport java.util.List;\n\npublic class WebSocketEncode extends MessageToMessageEncoder<Object> {\n\n    @Override\n    protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) {\n        if(msg == null) {\n            return ;\n        }\n        if (msg instanceof IBaseMessage) {\n            TextWebSocketFrame tsf = new TextWebSocketFrame(msg.toString());\n            out.add(tsf);\n        } else {\n            ReferenceCountUtil.retain(msg);\n            out.add(msg);\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/BasePosition.java",
    "content": "package com.zhaidaosi.game.jgframework.model;\n\nimport com.zhaidaosi.game.jgframework.model.area.IBaseArea;\n\npublic class BasePosition {\n\n    private int x;\n    private int y;\n    private int z;\n    private IBaseArea area;\n\n    public BasePosition(IBaseArea area) {\n        this.area = area;\n    }\n\n    public BasePosition(int x, int y, int z, IBaseArea area) {\n        this.x = x;\n        this.y = y;\n        this.z = z;\n        this.area = area;\n    }\n\n    public BasePosition(int x, int y, IBaseArea area) {\n        this.x = x;\n        this.y = y;\n        this.area = area;\n    }\n\n    public int getX() {\n        return x;\n    }\n\n    public void setX(int x) {\n        this.x = x;\n    }\n\n    public int getY() {\n        return y;\n    }\n\n    public void setY(int y) {\n        this.y = y;\n    }\n\n    public int getZ() {\n        return z;\n    }\n\n    public void setZ(int z) {\n        this.z = z;\n    }\n\n    public IBaseArea getArea() {\n        return area;\n    }\n\n    public void setArea(IBaseArea area) {\n        this.area = area;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/action/ActionManager.java",
    "content": "package com.zhaidaosi.game.jgframework.model.action;\n\nimport com.zhaidaosi.game.jgframework.common.BaseFile;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class ActionManager {\n\n    private static final Logger log = LoggerFactory.getLogger(ActionManager.class);\n    private static Map<Integer, IBaseAction> actions = new HashMap<Integer, IBaseAction>();\n    private static final String classSuffix = \"Action\";\n\n    public static void initAction(String packagePath) {\n        if (packagePath == null) {\n            return;\n        }\n        Set<Class<?>> classes = BaseFile.getClasses(packagePath, classSuffix, true);\n        for (Class<?> c : classes) {\n            IBaseAction obj;\n            try {\n                obj = (IBaseAction) c.newInstance();\n                actions.put(obj.getId(), obj);\n                log.info(\"Action类 : \" + c.getName() + \" 加载完成\");\n            } catch (InstantiationException | IllegalAccessException e) {\n                log.error(\"Action类 : \" + c.getName() + \"加载失败\", e);\n            }\n        }\n    }\n\n    public static IBaseAction getAction(int id) {\n        return actions.get(id).clone();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/action/BaseAction.java",
    "content": "package com.zhaidaosi.game.jgframework.model.action;\n\nimport com.zhaidaosi.game.jgframework.handler.BaseHandlerChannel;\n\n\npublic abstract class BaseAction implements IBaseAction, Cloneable {\n\n    protected int id;\n    protected String name;\n\n\n    public BaseAction(int id, String name) {\n        this.id = id;\n        this.name = name;\n    }\n\n    @Override\n    public int getId() {\n        return id;\n    }\n\n    @Override\n    public abstract void doAction(Object self, Object target, BaseHandlerChannel ch);\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    public IBaseAction clone() {\n        IBaseAction o = null;\n        try {\n            o = (IBaseAction) super.clone();\n        } catch (CloneNotSupportedException e) {\n//\t\t\te.printStackTrace();\n        }\n        return o;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/action/IBaseAction.java",
    "content": "package com.zhaidaosi.game.jgframework.model.action;\n\nimport com.zhaidaosi.game.jgframework.handler.BaseHandlerChannel;\n\n\npublic interface IBaseAction {\n\n    int getId();\n\n    void doAction(Object self, Object target, BaseHandlerChannel ch);\n\n    String getName();\n\n    void setName(String name);\n\n    IBaseAction clone();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/area/AreaManager.java",
    "content": "package com.zhaidaosi.game.jgframework.model.area;\n\nimport com.zhaidaosi.game.jgframework.common.BaseFile;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\n\npublic class AreaManager {\n\n    private static final Logger log = LoggerFactory.getLogger(AreaManager.class);\n    private static Map<Integer, IBaseArea> areas = new HashMap<Integer, IBaseArea>();\n    private static final String classSuffix = \"Area\";\n\n    public static void initArea(String packagePath) {\n        if (packagePath == null) {\n            return;\n        }\n        Set<Class<?>> classes = BaseFile.getClasses(packagePath, classSuffix, true);\n        for (Class<?> c : classes) {\n            IBaseArea obj;\n            try {\n                obj = (IBaseArea) c.newInstance();\n                areas.put(obj.getId(), obj);\n                log.info(\"Area类 : \" + c.getName() + \" 加载完成\");\n            } catch (InstantiationException | IllegalAccessException e) {\n                log.error(\"Area类 : \" + c.getName() + \"加载失败\", e);\n            }\n        }\n        for (Map.Entry<Integer, IBaseArea> entry : areas.entrySet()) {\n            entry.getValue().init();\n        }\n    }\n\n    public static IBaseArea getArea(int id) {\n        return areas.get(id);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/area/BaseArea.java",
    "content": "package com.zhaidaosi.game.jgframework.model.area;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.entity.BaseNpc;\nimport com.zhaidaosi.game.jgframework.model.entity.BasePlayer;\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter;\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseEntity;\nimport com.zhaidaosi.game.jgframework.model.map.IBaseMap;\nimport io.netty.channel.group.ChannelGroup;\nimport io.netty.channel.group.DefaultChannelGroup;\nimport io.netty.util.concurrent.GlobalEventExecutor;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * 服务器启动时通过AreaManager自动初始化的，不需要重复new的\n *\n * @author Jerry\n */\npublic abstract class BaseArea implements IBaseArea {\n\n    protected int id;\n    protected String name;\n    protected boolean open = true;\n    protected IBaseMap map;\n    protected Map<Integer, IBaseEntity> entitys = new HashMap<>();\n    protected Map<Integer, IBaseEntity> npcs = new HashMap<>();\n    protected Map<Integer, IBaseCharacter> players = new HashMap<>();\n    protected ChannelGroup channelGroup;\n    protected final Object lock = new Object();\n    protected BasePosition entrancePosition = new BasePosition(this);\n\n    public BaseArea(String name) {\n        this.id = hashCode();\n        this.name = name;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(int id, String name) {\n        this.id = id;\n        this.name = name;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(String name, BasePosition entrancePosition) {\n        this.id = hashCode();\n        this.name = name;\n        this.entrancePosition = entrancePosition;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(int id, String name, BasePosition entrancePosition) {\n        this.id = id;\n        this.name = name;\n        this.entrancePosition = entrancePosition;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(String name, IBaseMap map) {\n        this.id = hashCode();\n        this.name = name;\n        this.map = map;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(int id, String name, IBaseMap map) {\n        this.id = id;\n        this.name = name;\n        this.map = map;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(String name, BasePosition entrancePosition, IBaseMap map) {\n        this.id = hashCode();\n        this.name = name;\n        this.map = map;\n        this.entrancePosition = entrancePosition;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    public BaseArea(int id, String name, BasePosition entrancePosition, IBaseMap map) {\n        this.id = id;\n        this.name = name;\n        this.map = map;\n        this.entrancePosition = entrancePosition;\n        this.channelGroup = new DefaultChannelGroup(name, GlobalEventExecutor.INSTANCE);\n    }\n\n    @Override\n    public abstract void init();\n\n    @Override\n    public boolean isOpen() {\n        return open;\n    }\n\n    @Override\n    public void open() {\n        this.open = true;\n        init();\n    }\n\n    @Override\n    public void close() {\n        this.open = false;\n        channelGroup.clear();\n        entitys.clear();\n        players.clear();\n        npcs.clear();\n        map = null;\n    }\n\n    @Override\n    public int getId() {\n        return id;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public IBaseMap getMap() {\n        return map;\n    }\n\n    @Override\n    public IBaseEntity getEntity(int id) {\n        return entitys.get(id);\n    }\n\n    @Override\n    public Map<Integer, IBaseEntity> getEntities() {\n        return entitys;\n    }\n\n    @Override\n    public void addEntity(IBaseEntity entity) {\n        entitys.put(entity.getId(), entity);\n    }\n\n    @Override\n    public void removeEntity(int id) {\n        entitys.remove(id);\n    }\n\n    @Override\n    public IBaseCharacter getPlayer(int id) {\n        return players.get(id);\n    }\n\n    @Override\n    public Collection<IBaseCharacter> getPlayers() {\n        return players.values();\n    }\n\n    @Override\n    public void addPlayer(BasePlayer player) {\n        int id = player.getId();\n        synchronized (lock) {\n            IBaseArea area = player.gArea();\n            if (area != null) {\n                area.removePlayer(id);\n            }\n            players.put(id, player);\n            channelGroup.add(player.gChannel());\n            player.sPosition(entrancePosition);\n        }\n    }\n\n    @Override\n    public void removePlayer(int id) {\n        synchronized (lock) {\n            IBaseCharacter player = players.get(id);\n            if (player != null) {\n                players.remove(id);\n                channelGroup.remove(player.gChannel());\n            }\n        }\n    }\n\n    @Override\n    public IBaseEntity getNpc(int id) {\n        return npcs.get(id);\n    }\n\n    @Override\n    public void addNpc(BaseNpc npc) {\n        npcs.put(npc.getId(), npc);\n    }\n\n    @Override\n    public void removeNpc(int id) {\n        npcs.remove(id);\n    }\n\n    @Override\n    public ChannelGroup getChannelGroup() {\n        return channelGroup;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/area/BaseZone.java",
    "content": "package com.zhaidaosi.game.jgframework.model.area;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.map.IBaseMap;\n\n/**\n * 可以随时new的\n * @author Jerry\n */\npublic abstract class BaseZone extends BaseArea {\n\n    public BaseZone(String name) {\n        super(name);\n    }\n\n    public BaseZone(String name, BasePosition entrancePosition) {\n        super(name, entrancePosition);\n    }\n\n    public BaseZone(String name, IBaseMap map) {\n        super(name, map);\n    }\n\n    public BaseZone(String name, BasePosition entrancePosition, IBaseMap map) {\n        super(name, entrancePosition, map);\n    }\n\n    @Override\n    public abstract void init();\n\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/area/IBaseArea.java",
    "content": "package com.zhaidaosi.game.jgframework.model.area;\n\nimport com.zhaidaosi.game.jgframework.model.entity.BaseNpc;\nimport com.zhaidaosi.game.jgframework.model.entity.BasePlayer;\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter;\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseEntity;\nimport com.zhaidaosi.game.jgframework.model.map.IBaseMap;\nimport io.netty.channel.group.ChannelGroup;\n\nimport java.util.Collection;\nimport java.util.Map;\n\npublic interface IBaseArea {\n\n    void init();\n\n    boolean isOpen();\n\n    void open();\n\n    void close();\n\n    int getId();\n\n    String getName();\n\n    void setName(String name);\n\n    IBaseMap getMap();\n\n    IBaseEntity getEntity(int id);\n\n    Map<Integer, IBaseEntity> getEntities();\n\n    void addEntity(IBaseEntity entity);\n\n    void removeEntity(int id);\n\n    IBaseCharacter getPlayer(int id);\n\n    Collection<IBaseCharacter> getPlayers();\n\n    void addPlayer(BasePlayer player);\n\n    void removePlayer(int id);\n\n    IBaseEntity getNpc(int id);\n\n    void addNpc(BaseNpc npc);\n\n    void removeNpc(int id);\n\n    ChannelGroup getChannelGroup();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/BaseEntity.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.action.IBaseAction;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class BaseEntity implements IBaseEntity {\n\n    protected int id;\n    protected String name;\n    protected BasePosition position;\n    protected String roll;\n    protected Map<Integer, IBaseAction> actions = new HashMap<Integer, IBaseAction>();\n\n    @Override\n    public int getId() {\n        return id;\n    }\n\n    @Override\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public String getRoll() {\n        return roll;\n    }\n\n    @Override\n    public void setRoll(String roll) {\n        this.roll = roll;\n    }\n\n    @Override\n    public BasePosition getPosition() {\n        return position;\n    }\n\n    @Override\n    public void setPosition(BasePosition position) {\n        this.position = position;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public void addAction(IBaseAction action) {\n        actions.put(action.getId(), action);\n    }\n\n    @Override\n    public void removeAction(int id) {\n        actions.remove(id);\n    }\n\n    @Override\n    public IBaseAction getAction(int id) {\n        return actions.get(id);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/BaseNpc.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.action.IBaseAction;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class BaseNpc implements IBaseEntity {\n\n    protected int id;\n    protected String name;\n    protected Map<Integer, IBaseAction> actions = new HashMap<Integer, IBaseAction>();\n    protected String roll;\n    protected BasePosition position;\n\n    @Override\n    public int getId() {\n        return id;\n    }\n\n    @Override\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public String getRoll() {\n        return roll;\n    }\n\n    @Override\n    public void setRoll(String roll) {\n        this.roll = roll;\n    }\n\n    @Override\n    public BasePosition getPosition() {\n        return position;\n    }\n\n    @Override\n    public void setPosition(BasePosition position) {\n        this.position = position;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public IBaseAction getAction(int id) {\n        return actions.get(id);\n    }\n\n    @Override\n    public void addAction(IBaseAction action) {\n        actions.put(action.getId(), action);\n    }\n\n    @Override\n    public void removeAction(int id) {\n        actions.remove(id);\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/BasePlayer.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.action.IBaseAction;\nimport com.zhaidaosi.game.jgframework.model.area.IBaseArea;\nimport io.netty.channel.Channel;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class BasePlayer implements IBaseCharacter {\n\n    protected int id;\n    protected Channel channel;\n    protected String name;\n    protected String roll;\n    protected int level;\n    protected int experience;\n    protected int totalHp;\n    protected int totalMp;\n    protected int hp;\n    protected int mp;\n    protected BasePosition position;\n    protected Map<Integer, IBaseAction> actions = new HashMap<Integer, IBaseAction>();\n    protected boolean isInQueue = false;\n\n    @Override\n    public void loginHook() {\n        if (channel == null || position == null) {\n            return;\n        }\n        IBaseArea area = position.getArea();\n        if (area == null) {\n            return;\n        }\n        area.addPlayer(this);\n    }\n\n    @Override\n    public void logoutHook() {\n        if (channel == null || position == null) {\n            return;\n        }\n        IBaseArea area = position.getArea();\n        if (area == null) {\n            return;\n        }\n        area.removePlayer(id);\n    }\n\n    @Override\n    public int getId() {\n        return id;\n    }\n\n    @Override\n    public void setId(int id) {\n        this.id = id;\n    }\n\n    @Override\n    public String getRoll() {\n        return roll;\n    }\n\n    @Override\n    public void setRoll(String roll) {\n        this.roll = roll;\n    }\n\n    @Override\n    public IBaseArea gArea() {\n        if (position != null) {\n            return position.getArea();\n        }\n        return null;\n    }\n\n    @Override\n    public BasePosition gPosition() {\n        return position;\n    }\n\n    @Override\n    public void sPosition(BasePosition position) {\n        this.position = position;\n    }\n\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    @Override\n    public void setName(String name) {\n        this.name = name;\n    }\n\n    @Override\n    public Map<Integer, IBaseAction> getActions() {\n        return actions;\n    }\n\n    @Override\n    public void setActions(Map<Integer, IBaseAction> actions) {\n        this.actions = actions;\n    }\n\n    @Override\n    public IBaseAction findActionById(int id) {\n        return actions.get(id);\n    }\n\n    @Override\n    public void addAction(IBaseAction action) {\n        actions.put(action.getId(), action);\n    }\n\n    @Override\n    public void removeAction(int id) {\n        actions.remove(id);\n    }\n\n    @Override\n    public Channel gChannel() {\n        return channel;\n    }\n\n    @Override\n    public void sChannel(Channel channel) {\n        this.channel = channel;\n    }\n\n    @Override\n    public int getLevel() {\n        return level;\n    }\n\n    @Override\n    public void setLevel(int level) {\n        this.level = level;\n    }\n\n    @Override\n    public int getExperience() {\n        return experience;\n    }\n\n    @Override\n    public void setExperience(int experience) {\n        this.experience = experience;\n    }\n\n    @Override\n    public int getTotalHp() {\n        return totalHp;\n    }\n\n    @Override\n    public void setTotalHp(int totalHp) {\n        this.totalHp = totalHp;\n    }\n\n    @Override\n    public int getTotalMp() {\n        return totalMp;\n    }\n\n    @Override\n    public void setTotalMp(int totalMp) {\n        this.totalMp = totalMp;\n    }\n\n    @Override\n    public int getHp() {\n        return hp;\n    }\n\n    @Override\n    public void setHp(int hp) {\n        this.hp = hp;\n    }\n\n    @Override\n    public int getMp() {\n        return mp;\n    }\n\n    @Override\n    public void setMp(int mp) {\n        this.mp = mp;\n    }\n\n    @Override\n    public boolean isInQueue() {\n        return isInQueue;\n    }\n\n    @Override\n    public void setIsInQueue(boolean isInQueue) {\n        this.isInQueue = isInQueue;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/BasePlayerFactory.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\n\npublic class BasePlayerFactory implements IBasePlayerFactory {\n\n    public IBaseCharacter getPlayer() {\n        return new BasePlayer();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/IBaseCharacter.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.action.IBaseAction;\nimport com.zhaidaosi.game.jgframework.model.area.IBaseArea;\nimport io.netty.channel.Channel;\n\nimport java.util.Map;\n\npublic interface IBaseCharacter {\n\n    int getId();\n\n    void setId(int id);\n\n    String getRoll();\n\n    void setRoll(String roll);\n\n    BasePosition gPosition();\n\n    void sPosition(BasePosition position);\n\n    IBaseArea gArea();\n\n    String getName();\n\n    void setName(String name);\n\n    IBaseAction findActionById(int id);\n\n    void addAction(IBaseAction action);\n\n    void setActions(Map<Integer, IBaseAction> actions);\n\n    Map<Integer, IBaseAction> getActions();\n\n    void removeAction(int id);\n\n    Channel gChannel();\n\n    void sChannel(Channel channel);\n\n    int getLevel();\n\n    void setLevel(int level);\n\n    int getExperience();\n\n    void setExperience(int experience);\n\n    int getTotalHp();\n\n    void setTotalHp(int totalHp);\n\n    int getTotalMp();\n\n    void setTotalMp(int totalMp);\n\n    int getHp();\n\n    void setHp(int hp);\n\n    int getMp();\n\n    void setMp(int mp);\n\n    void logoutHook();\n\n    void loginHook();\n\n    boolean isInQueue();\n\n    void setIsInQueue(boolean isInQueue);\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/IBaseEntity.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\nimport com.zhaidaosi.game.jgframework.model.BasePosition;\nimport com.zhaidaosi.game.jgframework.model.action.IBaseAction;\n\npublic interface IBaseEntity {\n\n    int getId();\n\n    void setId(int id);\n\n    String getRoll();\n\n    void setRoll(String roll);\n\n    BasePosition getPosition();\n\n    void setPosition(BasePosition position);\n\n    String getName();\n\n    void setName(String name);\n\n    IBaseAction getAction(int id);\n\n    void addAction(IBaseAction action);\n\n    void removeAction(int id);\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/entity/IBasePlayerFactory.java",
    "content": "package com.zhaidaosi.game.jgframework.model.entity;\n\npublic interface IBasePlayerFactory {\n\n    IBaseCharacter getPlayer();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/model/map/IBaseMap.java",
    "content": "package com.zhaidaosi.game.jgframework.model.map;\n\npublic interface IBaseMap {\n\n    public void init();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/rsync/BaseRsync.java",
    "content": "package com.zhaidaosi.game.jgframework.rsync;\n\nimport com.zhaidaosi.game.jgframework.common.sdm.IBaseModel;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic abstract class BaseRsync implements IBaseRsync {\n\n    private boolean isRunning = false;\n    private ConcurrentMap<Integer, IBaseModel> mapOne = new ConcurrentHashMap<>();\n    private ConcurrentMap<Integer, IBaseModel> mapTwo = new ConcurrentHashMap<>();\n    private ConcurrentMap<Integer, IBaseModel> mapThree = new ConcurrentHashMap<>();\n    protected Map<Integer, IBaseModel> rsyncMap = new HashMap<>();\n\n\n    @Override\n    public abstract void runRsync();\n\n    @Override\n    public void addRsync(Integer id, IBaseModel obj) {\n        this.getNowMap().put(id, obj);\n    }\n\n    @Override\n    public void setRsyncMap(Map<Integer, IBaseModel> map) {\n        this.rsyncMap = map;\n    }\n\n    @Override\n    public void clearRsyncMap() {\n        this.rsyncMap.clear();\n    }\n\n    @Override\n    public IBaseModel get(Integer id) {\n        IBaseModel model = this.getNowMap().get(id);\n        if (model == null) {\n            model = this.rsyncMap.get(id);\n        }\n        return model;\n    }\n\n    @Override\n    public Map<Integer, IBaseModel> getNeedRsync() {\n        return new HashMap<>(this.getNeedRsyncMap());\n    }\n\n    @Override\n    public void clearNeedRsync() {\n        this.getNeedRsyncMap().clear();\n    }\n\n    @Override\n    public boolean isRunning() {\n        return isRunning;\n    }\n\n    @Override\n    public void toRunning() {\n        this.isRunning = true;\n    }\n\n    @Override\n    public void toStop() {\n        this.isRunning = false;\n    }\n\n    /**\n     * 选择当前map\n     * @return\n     */\n    private ConcurrentMap<Integer, IBaseModel> getNowMap() {\n        return this.selectMap(this.getSelect(System.currentTimeMillis()));\n\n    }\n\n    private ConcurrentMap<Integer, IBaseModel> getNeedRsyncMap() {\n        return this.selectMap(this.getSelect(System.currentTimeMillis() - RsyncManager.getSyncPeriod()));\n    }\n\n    /**\n     * 判断当前是哪个map\n     * @return\n     */\n    private int getSelect(long now) {\n        return (int) (Math.floor(now / RsyncManager.getSyncPeriod()) % 3);\n    }\n\n    /**\n     * 选择map\n     * @param select\n     * @return\n     */\n    private ConcurrentMap<Integer, IBaseModel> selectMap(int select) {\n        if (select == 0) {\n            return mapOne;\n        } else if (select == 1) {\n            return mapTwo;\n        } else {\n            return mapThree;\n        }\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/rsync/IBaseRsync.java",
    "content": "package com.zhaidaosi.game.jgframework.rsync;\n\nimport com.zhaidaosi.game.jgframework.common.sdm.IBaseModel;\n\nimport java.util.Map;\n\npublic interface IBaseRsync {\n\n    void addRsync(Integer id, IBaseModel obj);\n\n    void runRsync();\n\n    void setRsyncMap(Map<Integer, IBaseModel> map);\n\n    void clearRsyncMap();\n\n    Map<Integer, IBaseModel> getNeedRsync();\n\n    IBaseModel get(Integer id);\n\n    void clearNeedRsync();\n\n    boolean isRunning();\n\n    void toRunning();\n\n    void toStop();\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/rsync/RsyncManager.java",
    "content": "package com.zhaidaosi.game.jgframework.rsync;\n\nimport com.zhaidaosi.game.jgframework.Boot;\nimport com.zhaidaosi.game.jgframework.common.BaseFile;\nimport com.zhaidaosi.game.jgframework.common.BaseRunTimer;\nimport com.zhaidaosi.game.jgframework.common.sdm.IBaseModel;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Set;\n\npublic class RsyncManager {\n\n    private static long serviceSyncPeriod;\n    private static final Logger log = LoggerFactory.getLogger(RsyncManager.class);\n    private static HashMap<Class<?>, IBaseRsync> rsyncMap;\n    private static final String classSuffix = \"Rsync\";\n\n    public static void init() {\n        rsyncMap = new HashMap<Class<?>, IBaseRsync>();\n        serviceSyncPeriod = Boot.getServiceSyncPeriod();\n        Set<Class<?>> classes = BaseFile.getClasses(Boot.SERVER_RSYNC_PACKAGE_PATH, classSuffix, true);\n        for (Class<?> c : classes) {\n            IBaseRsync obj;\n            try {\n                obj = (IBaseRsync) c.newInstance();\n                rsyncMap.put(c, obj);\n                log.info(\"rsync类 : \" + c.getName() + \" 加载完成\");\n            } catch (InstantiationException | IllegalAccessException e) {\n                log.error(\"rsync类 : \" + c.getName() + \"加载失败\", e);\n            }\n        }\n    }\n\n    public static long getSyncPeriod() {\n        return serviceSyncPeriod;\n    }\n\n    /**\n     * 添加异步同步\n     * @param uid\n     * @param class\n     */\n    public static void add(Integer userId, Class<?> c, IBaseModel obj) {\n        IBaseRsync rsync = rsyncMap.get(c);\n        if (rsync != null) {\n            rsync.addRsync(userId, obj);\n        } else {\n            log.error(\"添加异步任务失败: \" + c.getName() + \"异步类不存在\");\n        }\n    }\n\n    public static IBaseModel get(Integer userId, Class<?> c) {\n        IBaseModel model = null;\n        IBaseRsync rsync = rsyncMap.get(c);\n        if (rsync != null) {\n            model = rsync.get(userId);\n        }\n        return model;\n    }\n\n    public static void run() {\n\n        long time = System.currentTimeMillis() % serviceSyncPeriod;\n        if (time < 1500) {\n            try {\n                Thread.sleep(1500 - time);\n            } catch (InterruptedException e) {\n                log.error(\"sleep error\", e);\n            }\n        }\n\n        Map<IBaseRsync, Map<Integer, IBaseModel>> needRsync = new HashMap<IBaseRsync, Map<Integer, IBaseModel>>();\n        for (Map.Entry<Class<?>, IBaseRsync> entry : rsyncMap.entrySet()) {\n            IBaseRsync rsync = entry.getValue();\n            //如果前一个任务还没有完成则不导入任务，任务推至下次运行\n            if (!rsync.isRunning()) {\n                Map<Integer, IBaseModel> map = rsync.getNeedRsync();\n                if (map.size() > 0) {\n                    needRsync.put(rsync, map);\n                    rsync.clearNeedRsync();\n                }\n            } else {\n                log.error(rsync.getClass().getName() + \" 任务被推迟！！！\");\n            }\n        }\n        for (Map.Entry<IBaseRsync, Map<Integer, IBaseModel>> entry : needRsync.entrySet()) {\n            RsyncThread rt = new RsyncThread(entry.getKey(), entry.getValue());\n            rt.start();\n        }\n    }\n\n}\n\nclass RsyncThread extends Thread {\n\n    private IBaseRsync rsync;\n    private Map<Integer, IBaseModel> map;\n\n    public RsyncThread(IBaseRsync rsync, Map<Integer, IBaseModel> map) {\n        this.rsync = rsync;\n        this.map = map;\n    }\n\n    public void run() {\n        rsync.toRunning();\n        rsync.setRsyncMap(map);\n        rsync.runRsync();\n        rsync.clearRsyncMap();\n        rsync.toStop();\n        BaseRunTimer.showTimer();\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/session/BaseSecretFactory.java",
    "content": "package com.zhaidaosi.game.jgframework.session;\n\nimport com.zhaidaosi.game.jgframework.common.encrpt.BaseRsa;\nimport com.zhaidaosi.game.jgframework.common.excption.BaseException;\n\npublic class BaseSecretFactory implements IBaseSecretFactory {\n\n    @Override\n    public String createSecret(int userId) throws BaseException {\n        String input = userId + \"_\" + System.currentTimeMillis();\n        String secret = BaseRsa.encrypt(input);\n        if (secret == null) {\n            throw new BaseException(\"秘钥生成失败\", 100);\n        }\n        return secret;\n    }\n\n    @Override\n    public int checkSecret(String secret) throws Exception {\n        secret = BaseRsa.decrypt(secret);\n        if (secret == null) {\n            throw new BaseException(\"非法秘钥\", 101);\n        }\n        String[] arr = secret.split(\"_\");\n        if (arr.length != 2) {\n            throw new BaseException(\"非法秘钥\", 101);\n        }\n        int userId = Integer.valueOf(arr[0]);\n        if (userId <= 0) {\n            throw new BaseException(\"非法秘钥\", 101);\n        }\n        //有效期1分钟\n        if (Long.parseLong(arr[1]) - System.currentTimeMillis() > 60000) {\n            throw new BaseException(\"秘钥已失效\", 102);\n        }\n        return userId;\n    }\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/session/IBaseSecretFactory.java",
    "content": "package com.zhaidaosi.game.jgframework.session;\n\npublic interface IBaseSecretFactory {\n\n    String createSecret(int userId) throws Exception;\n\n    int checkSecret(String secret) throws Exception;\n\n}\n"
  },
  {
    "path": "src/main/java/com/zhaidaosi/game/jgframework/session/SessionManager.java",
    "content": "package com.zhaidaosi.game.jgframework.session;\n\nimport com.zhaidaosi.game.jgframework.Boot;\nimport com.zhaidaosi.game.jgframework.Router;\nimport com.zhaidaosi.game.jgframework.common.queue.BaseQueue;\nimport com.zhaidaosi.game.jgframework.common.queue.BaseQueueElement;\nimport com.zhaidaosi.game.jgframework.connector.IBaseConnector;\nimport com.zhaidaosi.game.jgframework.message.IBaseMessage;\nimport com.zhaidaosi.game.jgframework.message.InMessage;\nimport com.zhaidaosi.game.jgframework.message.OutMessage;\nimport com.zhaidaosi.game.jgframework.model.entity.IBaseCharacter;\nimport io.netty.channel.Channel;\nimport org.slf4j.Logger;\nimport org.slf4j.LoggerFactory;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Timer;\nimport java.util.TimerTask;\nimport java.util.concurrent.ConcurrentHashMap;\nimport java.util.concurrent.ConcurrentMap;\n\npublic class SessionManager {\n\n    public final static String SECRET = \"secret\";\n    public final static int ADD_SESSION_SUCC = 1;\n    public final static int ADD_SESSION_ERROR = -1;\n    public final static int ADD_SESSION_WAIT = 0;\n\n    private static final Logger log = LoggerFactory.getLogger(SessionManager.class);\n    private static IBaseSecretFactory secretFactory = new BaseSecretFactory();\n    private static ConcurrentMap<Integer, Channel> userIdChannels = new ConcurrentHashMap<>();\n    private static ConcurrentMap<Integer, BaseQueueElement<Channel>> waitUserIdChannels = new ConcurrentHashMap<>();\n    private static BaseQueue<Channel> waitQueue = new BaseQueue<>();\n    private static Timer timer;\n    private static int maxUser = 0;\n\n    public static int checkSession(InMessage msg, Channel ch) {\n        IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get();\n        if (player == null) {\n            return ADD_SESSION_ERROR;\n        }\n        if (player.getId() <= 0) {\n            Object secret = msg.getMember(SECRET);\n            if (secret == null || secret.equals(\"\")) {\n                return ADD_SESSION_ERROR;\n            }\n            try {\n                int userId = checkSecret((String) secret);\n                if (userId == 0) {\n                    return ADD_SESSION_ERROR;\n                }\n                player.setId(userId);\n                return SessionManager.addSession(player, ch);\n            } catch (Exception e) {\n                return ADD_SESSION_ERROR;\n            }\n        }\n        if (maxUser > 0 && player.isInQueue()) {\n            return ADD_SESSION_WAIT;\n        }\n        return ADD_SESSION_SUCC;\n    }\n\n    /**\n     * 加入session\n     * @param player\n     * @param ch\n     * @return\n     */\n    private static int addSession(IBaseCharacter player, Channel ch) {\n        int userId;\n        if (player == null || (userId = player.getId()) <= 0) {\n            return ADD_SESSION_ERROR;\n        }\n\n        Channel _ch = userIdChannels.get(userId);\n        BaseQueueElement<Channel> queueElement = null;\n        if (_ch == null && maxUser > 0) {\n            queueElement = waitUserIdChannels.get(userId);\n            if (queueElement != null) {\n                _ch = queueElement.getValue();\n            }\n        }\n\n        boolean same = _ch != null && _ch.hashCode() == ch.hashCode();\n\n        if (_ch != null && !same) {\n            IBaseCharacter _player = _ch.attr(IBaseConnector.PLAYER).get();\n            if (_player != null) {\n                _player.setId(0);\n                // 保持排队名次\n                if (queueElement != null) {\n                    player.setIsInQueue(true);\n                    queueElement.setValue(ch);\n                }\n            }\n            _ch.close();\n        }\n\n        if (maxUser > 0) {\n            if (queueElement != null) {\n                return ADD_SESSION_WAIT;\n            } else if (userIdChannels.size() >= maxUser) {\n                player.setIsInQueue(true);\n                BaseQueueElement<Channel> element = waitQueue.put(ch);\n                if (_ch == null || !same) {\n                    waitUserIdChannels.put(userId, element);\n                }\n                return ADD_SESSION_WAIT;\n            }\n        }\n\n        if (_ch == null || !same) {\n            userIdChannels.put(userId, ch);\n        }\n\n        player.loginHook();\n        return ADD_SESSION_SUCC;\n    }\n\n    public static void removeSession(Channel ch) {\n        IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get();\n        if (player != null) {\n            int userId = player.getId();\n            if (maxUser > 0 && player.isInQueue()) {\n                if (userId > 0) {\n                    BaseQueueElement<Channel> queueElement = waitUserIdChannels.get(userId);\n                    waitUserIdChannels.remove(userId);\n                    waitQueue.remove(queueElement);\n                }\n            } else {\n                if (userId > 0) {\n                    userIdChannels.remove(userId);\n                }\n                player.logoutHook();\n            }\n        }\n    }\n\n    public static List<IBaseCharacter> getOnlineUser() {\n        List<IBaseCharacter> onlineUser = new ArrayList<IBaseCharacter>();\n        for (Channel ch : userIdChannels.values()) {\n            IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get();\n            if (player != null && player.getId() > 0) {\n                onlineUser.add(player);\n            }\n        }\n        return onlineUser;\n    }\n\n    public static IBaseCharacter getPlayerByUserId(Integer uid) {\n        Channel ch = userIdChannels.get(uid);\n        IBaseCharacter player = ch == null ? null : ch.attr(IBaseConnector.PLAYER).get();\n        return (player != null && player.getId() > 0) ? player : null;\n    }\n\n    public static boolean isAuthHandler(InMessage msg) {\n        return msg.getH().startsWith(Boot.getAuthHandler());\n    }\n\n    public static String getServerIp(int userId) {\n        int AuthCount = Boot.getServiceCount();\n        int index = userId % AuthCount;\n        return Boot.getServiceIps().get(index);\n    }\n\n    public static String createSecret(int userId) throws Exception {\n        return secretFactory.createSecret(userId);\n    }\n\n    private static int checkSecret(String secret) throws Exception {\n        return secretFactory.checkSecret(secret);\n    }\n\n    public static void init() {\n        if (maxUser > 0) {\n            initTimer();\n        }\n    }\n\n    public static void destroy() {\n        userIdChannels.clear();\n        if (timer != null) {\n            timer.cancel();\n            timer = null;\n        }\n        if (maxUser > 0) {\n            waitUserIdChannels.clear();\n            waitQueue.clear();\n        }\n    }\n\n    public static long getWaitCount() {\n        return waitQueue.size();\n    }\n\n    public static int getUserCount() {\n        return userIdChannels.size();\n    }\n\n    public static ConcurrentMap<Integer, Channel> getChannels() {\n        return userIdChannels;\n    }\n\n    public static void setSercretFactory(IBaseSecretFactory secretFactory) {\n        SessionManager.secretFactory = secretFactory;\n    }\n\n    public static void setMaxUser(int max) {\n        if (max > 0) {\n            maxUser = max;\n        }\n    }\n\n    private static void initTimer() {\n        if (timer == null) {\n            timer = new Timer(\"QueueTimerTask\");\n            timer.schedule(new QueueTimerTask(), 10000, 10000);\n        }\n    }\n\n    public static IBaseMessage getWaitMessage(IBaseCharacter player) {\n        long index = 0;\n        if (player != null && player.isInQueue()) {\n            BaseQueueElement<Channel> queueElement = waitUserIdChannels.get(player.getId());\n            index = waitQueue.findIndex(queueElement);\n        }\n        return OutMessage.showSucc(index, Router.WAIT_HANDLERNAME);\n    }\n\n    private static class QueueTimerTask extends TimerTask {\n        @Override\n        public void run() {\n            try {\n                while (userIdChannels.size() < maxUser && waitQueue.size() > 0) {\n                    BaseQueueElement<Channel> element = waitQueue.take();\n                    if (element == null) {\n                        continue;\n                    }\n                    Channel ch = element.getValue();\n                    if (ch == null) {\n                        continue;\n                    }\n                    IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get();\n                    if (player == null) {\n                        continue;\n                    }\n                    int userId = player.getId();\n                    if (userId <= 0) {\n                        continue;\n                    }\n                    waitUserIdChannels.remove(userId);\n                    player.setIsInQueue(false);\n                    userIdChannels.put(userId, ch);\n                    ch.writeAndFlush(getWaitMessage(player));\n                }\n                BaseQueueElement<Channel> start = waitQueue.getStart();\n                while (start != null) {\n                    Channel ch = start.getValue();\n                    IBaseCharacter player = ch.attr(IBaseConnector.PLAYER).get();\n                    ch.writeAndFlush(getWaitMessage(player));\n                    start = start.getNext();\n                }\n            } catch (Exception e) {\n                log.error(e.getMessage(), e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/main/resources/errorCode.properties",
    "content": "10000=\\u7CFB\\u7EDF\\u9519\\u8BEF\n11000=\\u7CFB\\u7EDF\\u7EF4\\u62A4\\u4E2D\\uFF0C\\u6682\\u505C\\u4F7F\\u7528\n20000=handler\\u4E0D\\u80FD\\u4E3A\\u7A7A\n21000=handler\\u4E0D\\u5B58\\u5728\n50000=\\u4F20\\u8F93\\u7684\\u6570\\u636E\\u683C\\u5F0F\\u5316\\u9519\\u8BEF\n60000=http\\u8BF7\\u6C42\\u9519\\u8BEF\n"
  }
]