nacos is coming

This commit is contained in:
xingxuechao 2018-07-21 00:27:23 +08:00
commit 91d20f34fd
432 changed files with 62877 additions and 0 deletions

10
.gitignore vendored Normal file
View File

@ -0,0 +1,10 @@
# Except this file !.gitignore
.classpath
.project
.settings
target
.project
.idea
.DS_Store
/logs
*.iml

31
.travis.yml Normal file
View File

@ -0,0 +1,31 @@
notifications:
email:
recipients:
- nacos_dev@linux.alibaba.com
- dev-nacos@googlegroups.com
on_success: change
on_failure: always
language: java
matrix:
include:
# On OSX, run with default JDK only.
# - os: osx
# On Linux, run with specific JDKs only.
- os: linux
env: CUSTOM_JDK="oraclejdk8"
before_install:
- echo 'MAVEN_OPTS="$MAVEN_OPTS -Xmx1024m -XX:MaxPermSize=512m -XX:+BytecodeVerificationLocal"' >> ~/.mavenrc
- cat ~/.mavenrc
- if [ "$TRAVIS_OS_NAME" == "osx" ]; then export JAVA_HOME=$(/usr/libexec/java_home); fi
- if [ "$TRAVIS_OS_NAME" == "linux" ]; then jdk_switcher use "$CUSTOM_JDK"; fi
script:
- travis_retry mvn -B clean apache-rat:check
- travis_retry mvn -B package jacoco:report coveralls:report
after_success:
- mvn clean install -Pit-test
- mvn sonar:sonar -Psonar-apache

38
BUILDING Normal file
View File

@ -0,0 +1,38 @@
Build Instructions for NACOS
====================================================
(1) Prerequisites
JDK 1.8+ is required in order to compile and run Nacos.
nacos utilizes Maven as a distribution management and packaging tool. Version 3.0.3 or later is required.
Maven installation and configuration instructions can be found here:
http://maven.apache.org/run-maven/index.html
(2) Run test cases
Execute the following command in order to compile and run test cases of each components:
$ mvn test
(3) Import projects to Eclipse IDE
First, generate eclipse project files:
$ mvn -U eclipse:eclipse
Then, import to eclipse by specifying the root directory of the project via:
[File] > [Import] > [Existing Projects into Workspace].
(4) Build distribution packages
Execute the following command in order to build the tar.gz packages and install JAR into local repository:
#build nacos
$ mvn -Prelease-nacos -DskipTests clean install -U

31
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,31 @@
## How To Contribute
We are always very happy to have contributions, whether for trivial cleanups or big new features.
We want to have high quality, well documented codes for each programming language.
Nor is code the only way to contribute to the project. We strongly value documentation, integration with other project, and gladly accept improvements for these aspects.
## Contributing code
To submit a change for inclusion, please do the following:
#### If the change is non-trivial please include some unit tests that cover the new functionality.
#### If you are introducing a completely new feature or API it is a good idea to start a wiki and get consensus on the basic design first.
#### It is our job to follow up on patches in a timely fashion. Nag us if we aren't doing our job (sometimes we drop things).
## Becoming a Committer
We are always interested in adding new contributors. What we look for are series of contributions, good taste and ongoing interest in the project. If you are interested in becoming a committer, please let one of the existing committers know and they can help you walk through the process.
Nowadays,we have several important contribution points:
#### Wiki & JavaDoc
#### Nacos Console
#### Nacos SDK(C++\.Net\Php\Python\Go\Node.js)
##### Prerequisite
If you want to contribute the above listing points, you must abide our some prerequisites:
###### Readability - API must have Javadoc,some very important methods also must have javadoc
###### Testability - 80% above unit test coverage about main process
###### Maintainability - Comply with our [PMD spec](style/codeStyle.xml), and at least 3 month update frequency
###### Deployability - We encourage you to deploy into [maven repository](http://search.maven.org/)

201
LICENSE Normal file
View File

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (properties) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

32
NOTICE Normal file
View File

@ -0,0 +1,32 @@
Nacos
Copyright 2018-2019 The Apache Software Foundation
This product includes software developed at
The Alibaba MiddleWare Group.
------
This product has a bundle Spring Boot:
The Spring Boot Project
=================
Please visit the Spring Boot web site for more information:
* https://spring.io/projects/spring-boot
Copyright 2014 The Spring Boot Project
The Spring Boot Project licenses this file to you under the Apache License,
version 2.0 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
License for the specific language governing permissions and limitations
under the License.
Also, please refer to each LICENSE.<component>.txt file, which is located in
the 'license' directory of the distribution file, for the license terms of the
components that this product depends on.

49
README.md Normal file
View File

@ -0,0 +1,49 @@
## Nacos
[![Gitter](https://badges.gitter.im/alibaba/nacos.svg)](https://gitter.im/alibaba/nacos?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) [![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
[![Gitter](https://travis-ci.org/alibaba/nacos.svg?branch=master)](https://travis-ci.org/alibaba/nacos)
-------
<img src="doc/Nacos_Logo.png" width="50%" height="50%" />
Nacos is an easy-to-use platform desgined for dynamic service discovery and configuration and service management. It helps you to build cloud native applications and microservices platform easily.
Service is a first-class citizen in Nacos. Nacos supports almost all type of servicesfor example[Dubbo/gRPC service](xx)、[Spring Cloud RESTFul service](xx) or [Kubernetes service](xx).
Nacos provides four major funcations.
* **Service Discovery and Service Health Check**
Nacos makes it simple for services to register themselves and to discover other services via a DNS or HTTP interface. Nacos also provides real-time healthchecks of services to prevent sending requests to unhealthy hosts or service instance.
* **Dynamic Configuration Management**
Dynamic Configuration Service allows you to manage configurations of all services in a centralized and dynamic manner across all environments. Nacos eliminates the need to redeploy applications and services when configurations are updatedwhich makes configuration changes more efficient and agile.
* **Dynamic DNS Service**
Nacos supports weighted routing, making it easier for you to implement mid-tier load balancing, flexible routing policies, flow control, and simple DNS resolution services in the production environment within your data center. It helps you to implement DNS-based service discovery easily and prevent applications from coupling to vendor-specific service discovery APIs.
* **Service and MetaData Management**
Nacos provides an easy-to-use service dashboard to help you manage your services metadata, configuration, kubernetes DNS, service health and metrics statistics.
## Quick Start (TODO)
It is super easy to get started with your first project.
https://nacos.io/#/docs/quick-start.md
Quick start for other open-source projects:
[quick start with spring cloud](xx)
[quick start with dubbo](xx)
[quick start with kubernetes](xx)
[more...](xx)
## Documentation
You can view full documentation on the Nacos website:
[https://nacos.io/#/blog](https://nacos.io/#/blog)

107
client/pom.xml Normal file
View File

@ -0,0 +1,107 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-all</artifactId>
<version>0.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>nacos-client</artifactId>
<packaging>jar</packaging>
<name>nacos-client ${project.version}</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.8.2</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-slf4j-impl</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>nacos-common</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<artifactId>commons-codec</artifactId>
<groupId>commons-codec</groupId>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-lgpl</artifactId>
</dependency>
<dependency>
<groupId>net.jcip</groupId>
<artifactId>jcip-annotations</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.github.spotbugs</groupId>
<artifactId>spotbugs-annotations</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,86 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api;
import java.util.Properties;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.NamingFactory;
import com.alibaba.nacos.api.naming.NamingService;
/**
* Nacos Factory
*
* @author Nacos
*
*/
public class NacosFactory {
/**
* Create config
*
* @param properties
* init param
* @return config
* @throws NacosException
* Exception
*/
public static ConfigService createConfigService(Properties properties) throws NacosException {
return ConfigFactory.createConfigService(properties);
}
/**
* Create config
*
* @param serverAddr
* server list
* @return config
* @throws NacosException
* Exception
*/
public static ConfigService createConfigService(String serverAddr) throws NacosException {
return ConfigFactory.createConfigService(serverAddr);
}
/**
* Create Naming
*
* @param serverAddr
* server list
* @return Naming
* @throws NacosException
* Exception
*/
public static NamingService createNamingService(String serverAddr) throws NacosException {
return NamingFactory.createNamingService(serverAddr);
}
/**
* Create Naming
*
* @param properties
* init param
* @return Naming
* @throws NacosException
* Exception
*/
public static NamingService createNamingService(Properties properties) throws NacosException {
return NamingFactory.createNamingService(properties);
}
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api;
/**
* properties key
* @author Nacos
*
*/
public class PropertyKeyConst {
public final static String ENDPOINT = "endpoint";
public final static String NAMESPACE = "namespace";
public final static String ACCESS_KEY = "accessKey";
public final static String SECRET_KEY = "secretKey";
public final static String SERVER_ADDR = "serverAddr";
public final static String CONTEXT_PATH = "contextPath";
public final static String CLUSTER_NAME = "clusterName";
public final static String ENCODE = "encode";
}

View File

@ -0,0 +1,60 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config;
import java.util.Properties;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.NacosConfigService;
/**
* Config Factory
*
* @author Nacos
*
*/
public class ConfigFactory {
/**
* Create Config
*
* @param properties
* init param
* @return Config
* @throws NacosException
* Exception
*/
public static ConfigService createConfigService(Properties properties) throws NacosException {
return new NacosConfigService(properties);
}
/**
* Create Config
*
* @param ServerAddr
* serverlist
* @return Config
* @throws NacosException
* Exception
*/
public static ConfigService createConfigService(String serverAddr) throws NacosException {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
return new NacosConfigService(properties);
}
}

View File

@ -0,0 +1,103 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
/**
* Config Interface
*
* @author Nacos
*
*/
public interface ConfigService {
/**
* Get Configuration
*
* @param dataId
* Config ID
* @param group
* Config Group
* @param timeoutMs
* read timeout
* @return config value
* @throws NacosException
* NacosException
*/
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException;
/**
* Add a listener to the configuration, after the server to modify the
* configuration, the client will use the incoming listener callback.
* Recommended asynchronous processing, the application can implement the
* getExecutor method in the ManagerListener, provide a thread pool of
* execution. If provided, use the main thread callback, May block other
* configurations or be blocked by other configurations.
*
* @param dataId
* Config ID
* @param group
* Config Group
* @param listener
* listener
* @throws NacosException
* NacosException
*/
public void addListener(String dataId, String group, Listener listener) throws NacosException;
/**
* publish config.
*
* @param dataId
* Config ID
* @param group
* Config Group
* @param content
* Config Content
* @return Whether publish
* @throws NacosException
* NacosException
*/
public boolean publishConfig(String dataId, String group, String content) throws NacosException;
/**
* Remove Config
*
* @param dataId
* Config ID
* @param group
* Config Group
* @return whether remove
* @throws NacosException
* NacosException
*/
public boolean removeConfig(String dataId, String group) throws NacosException;
/**
* Remove Listener
*
* @param dataId
* Config ID
* @param group
* Config Group
* @param listener
* listener
*/
public void removeListener(String dataId, String group, Listener listener);
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
/**
* Config Context Interface
*
* @author Nacos
*
*/
public interface IConfigContext {
/**
* get context by key
*
* @param key
* @return context
*/
public Object getParameter(String key);
/**
* set context
*
* @param key
* key
* @param value
* value
*/
public void setParameter(String key, Object value);
}

View File

@ -0,0 +1,69 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
import com.alibaba.nacos.api.exception.NacosException;
/**
* Config Filter Interface
*
* @author Nacos
*
*/
public interface IConfigFilter {
/**
* Init Fuction
*
* @param filterConfig
* Filter Config
*/
void init(IFilterConfig filterConfig);
/**
* do filter
*
* @param request
* request
* @param response
* response
* @param filterChain
* filter Chain
* @throws NacosException
* exception
*/
void doFilter(IConfigRequest request, IConfigResponse response, IConfigFilterChain filterChain)
throws NacosException;
/**
* deploy
*/
void deploy();
/**
* order
*
* @return
*/
int getOrder();
/**
* filterName
*
* @return
*/
String getFilterName();
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
import com.alibaba.nacos.api.exception.NacosException;
/**
* Config Filter Chain Interface
*
* @author Nacos
*
*/
public interface IConfigFilterChain {
/**
* Filter aciton
*
* @param request
* request
* @param response
* response
* @throws NacosException
* NacosException
*/
public void doFilter(IConfigRequest request, IConfigResponse response) throws NacosException;
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
/**
* Config Request Interface
*
* @author Nacos
*
*/
public interface IConfigRequest {
/**
* get param
*
* @param key
* key
* @return value
*/
public Object getParameter(String key);
/**
* get config context
*
* @return
*/
public IConfigContext getConfigContext();
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
/**
* Config Response Interface
*
* @author Nacos
*
*/
public interface IConfigResponse {
/**
* get param
*
* @param key
* key
* @return value
*/
public Object getParameter(String key);
/**
* get context
*
* @return configContext
*/
public IConfigContext getConfigContext();
}

View File

@ -0,0 +1,39 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.filter;
/**
* Filter Config Interface
* @author Nacos
*
*/
public interface IFilterConfig {
/**
* get filter name
*
* @return
*/
public String getFilterName();
/**
* get param
*
* @param name
* @return param
*/
public Object getInitParameter(String name);
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.listener;
import java.util.concurrent.Executor;
/**
* Listner Adapter,use default notify thread
*
* @author water.lyl
*
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class AbstractListener implements Listener {
/**
* use default Executor
*/
public Executor getExecutor() {
return null;
}
}

View File

@ -0,0 +1,57 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.listener;
import java.util.concurrent.Executor;
/**
* shared listener
*
* @author Nacos
*
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class AbstractSharedListener implements Listener {
private volatile String dataId;
private volatile String group;
final public void fillContext(String dataId, String group) {
this.dataId = dataId;
this.group = group;
}
@Override
final public void receiveConfigInfo(String configInfo) {
innerReceive(dataId, group, configInfo);
}
@Override
public Executor getExecutor() {
return null;
}
/**
* receive
*
* @param dataId
* data ID
* @param group
* group
* @param configInfo
* content
*/
public abstract void innerReceive(String dataId, String group, String configInfo);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.config.listener;
import java.util.concurrent.Executor;
/**
* Listener for watch config
*
* @author Nacos
*
*/
public interface Listener {
/**
* Executor to excute this receive
*
* @return Executor
*/
public Executor getExecutor();
/**
* 接收配置信息
*
* @param configInfo 配置值
*/
public void receiveConfigInfo(final String configInfo);
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.exception;
/**
* Nacos Exception
*
* @author Nacos
*
*/
public class NacosException extends Exception{
/**
* serialVersionUID
*/
private static final long serialVersionUID = -3913902031489277776L;
private int errCode;
private String errMsg;
public NacosException() {
};
public NacosException(int errCode, String errMsg) {
this.errCode = errCode;
this.errMsg = errMsg;
}
public int getErrCode() {
return errCode;
}
public String getErrMsg() {
return errMsg;
}
public void setErrCode(int errCode) {
this.errCode = errCode;
}
public void setErrMsg(String errMsg) {
this.errMsg = errMsg;
}
@Override
public String toString() {
return "ErrCode:" + errCode + ",ErrMsg:" + errMsg;
}
/**
* client error code
* -400 -503 throw exception to user
*/
/**
* invalid param参数错误
*/
public static final int CLIENT_INVALID_PARAM = -400;
/**
* over client threshold超过server端的限流阈值
*/
public static final int CLIENT_OVER_THRESHOLD = -503;
/**
* server error code
* 400 403 throw exception to user
* 500 502 503 change ip and retry
*/
/**
* invalid param参数错误
*/
public static final int INVALID_PARAM = 400;
/**
* no right鉴权失败
*/
public static final int NO_RIGHT = 403;
/**
* conflict写并发冲突
*/
public static final int CONFLICT = 409;
/**
* server errorserver异常如超时
*/
public static final int SERVER_ERROR = 500;
/**
* bad gateway路由异常如nginx后面的Server挂掉
*/
public static final int BAD_GATEWAY = 502;
/**
* over threshold超过server端的限流阈值
*/
public static final int OVER_THRESHOLD = 503;
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming;
import java.util.Properties;
import com.alibaba.nacos.client.naming.NacosNamingService;
/**
* @author dungu.zpf
*/
public class NamingFactory {
public static NamingService createNamingService(String serverList) {
return new NacosNamingService(serverList);
}
public static NamingService createNamingService(Properties properties) {
return new NacosNamingService(properties);
}
}

View File

@ -0,0 +1,176 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming;
import java.util.List;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.listener.EventListener;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author dungu.zpf
*/
public interface NamingService {
/**
* Register a instance to service
*
* @param serviceName name of service
* @param ip instance ip
* @param port instance port
* @throws NacosException
*/
void registerInstance(String serviceName, String ip, int port) throws NacosException;
/**
* Register a instance to service with specified cluster name
*
* @param serviceName name of service
* @param ip instance ip
* @param port instance port
* @param clusterName instance cluster name
* @throws NacosException
*/
void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException;
/**
* Register a instance to service with specified instance properties
*
* @param serviceName name of service
* @param instance instance to register
* @throws NacosException
*/
void registerInstance(String serviceName, Instance instance) throws NacosException;
/**
* Deregister instance from a service
*
* @param serviceName name of service
* @param ip instance ip
* @param port instance port
* @throws NacosException
*/
void deregisterInstance(String serviceName, String ip, int port) throws NacosException;
/**
* Deregister instance with specified cluster name from a service
*
* @param serviceName name of service
* @param ip instance ip
* @param port instance port
* @param clusterName instance cluster name
* @throws NacosException
*/
void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException;
/**
* Get all instances of a service
*
* @param serviceName name of service
* @return A list of instance
* @throws NacosException
*/
List<Instance> getAllInstances(String serviceName) throws NacosException;
/**
* Get all instances within specified clusters of a service
*
* @param serviceName name of service
* @param clusters list of cluster
* @return A list of qualified instance
* @throws NacosException
*/
List<Instance> getAllInstances(String serviceName, List<String> clusters) throws NacosException;
/**
* Get qualified instances of service
*
* @param serviceName name of service
* @param healthy a flag to indicate returning healthy or unhealthy instances
* @return A qualified list of instance
* @throws NacosException
*/
List<Instance> selectInstances(String serviceName, boolean healthy) throws NacosException;
/**
* Get qualified instances within specified clusters of service
*
* @param serviceName name of service
* @param clusters list of cluster
* @param healthy a flag to indicate returning healthy or unhealthy instances
* @return A qualified list of instance
* @throws NacosException
*/
List<Instance> selectInstances(String serviceName, List<String> clusters, boolean healthy) throws NacosException;
/**
* Select one healthy instance of service using predefined load balance strategy
*
* @param serviceName name of service
* @return qualified instance
* @throws NacosException
*/
Instance selectOneHealthyInstance(String serviceName) throws NacosException;
/**
* Select one healthy instance of service using predefined load balance strategy
*
* @param serviceName name of service
* @param clusters a list of clusters should the instance belongs to
* @return qualified instance
* @throws NacosException
*/
Instance selectOneHealthyInstance(String serviceName, List<String> clusters) throws NacosException;
/**
* Subscribe service to receive events of instances alteration
*
* @param serviceName name of service
* @param listener event listener
* @throws NacosException
*/
void subscribe(String serviceName, EventListener listener) throws NacosException;
/**
* Subscribe service to receive events of instances alteration
*
* @param serviceName name of service
* @param clusters list of cluster
* @param listener event listener
* @throws NacosException
*/
void subscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException;
/**
* Unsubscribe event listener of service
*
* @param serviceName name of service
* @param listener event listener
* @throws NacosException
*/
void unsubscribe(String serviceName, EventListener listener) throws NacosException;
/**
* Unsubscribe event listener of service
*
* @param serviceName name of service
* @param clusters list of cluster
* @param listener event listener
* @throws NacosException
*/
void unsubscribe(String serviceName, List<String> clusters, EventListener listener) throws NacosException;
}

View File

@ -0,0 +1,23 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.listener;
/**
* event interface
* @author dungu.zpf
*/
public interface Event {
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.listener;
/**
* event listener
* @author Nacos
*
*/
public interface EventListener {
/**
* callback event
* @param event
*/
void onEvent(Event event);
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.listener;
import java.util.List;
import com.alibaba.nacos.api.naming.pojo.Instance;
/**
* @author dungu.zpf
*/
public class NamingEvent implements Event {
private String serviceName;
private List<Instance> instances;
public NamingEvent(String serviceName, List<Instance> instances) {
this.serviceName = serviceName;
this.instances = instances;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public List<Instance> getInstances() {
return instances;
}
public void setInstances(List<Instance> instances) {
this.instances = instances;
}
}

View File

@ -0,0 +1,179 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.pojo;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import java.util.Objects;
/**
* @author dungu.zpf
*/
public abstract class AbstractHealthChecker implements Cloneable {
protected String type = "unknown";
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public static class Http extends AbstractHealthChecker {
public static final String TYPE = "HTTP";
private String path = StringUtils.EMPTY;
private String headers = StringUtils.EMPTY;
private int expectedResponseCode = 200;
public Http() {
this.type = TYPE;
}
public int getExpectedResponseCode() {
return expectedResponseCode;
}
public void setExpectedResponseCode(int expectedResponseCode) {
this.expectedResponseCode = expectedResponseCode;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getHeaders() {
return headers;
}
public void setHeaders(String headers) {
this.headers = headers;
}
@Override
public int hashCode() {
return Objects.hash(path, headers, expectedResponseCode);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Http)) {
return false;
}
Http other = (Http) obj;
if (!StringUtils.equals(type, other.getType())) {
return false;
}
if (!StringUtils.equals(path, other.getPath())) {
return false;
}
if (!StringUtils.equals(headers, other.getHeaders())) {
return false;
}
return expectedResponseCode == other.getExpectedResponseCode();
}
}
public static class Tcp extends AbstractHealthChecker {
public static final String TYPE = "TCP";
public Tcp() {
this.type = TYPE;
}
@Override
public int hashCode() {
return Objects.hash(TYPE);
}
@Override
public boolean equals(Object obj) {
return obj instanceof Tcp;
}
}
public static class Mysql extends AbstractHealthChecker {
public static final String TYPE = "MYSQL";
private String user;
private String pwd;
private String cmd;
public Mysql() {
this.type = TYPE;
}
public String getCmd() {
return cmd;
}
public String getPwd() {
return pwd;
}
public String getUser() {
return user;
}
public void setUser(String user) {
this.user = user;
}
public void setCmd(String cmd) {
this.cmd = cmd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
@Override
public int hashCode() {
return Objects.hash(user, pwd, cmd);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Mysql)) {
return false;
}
Mysql other = (Mysql) obj;
if (!StringUtils.equals(user, other.getUser())) {
return false;
}
if (!StringUtils.equals(pwd, other.getPwd())) {
return false;
}
return StringUtils.equals(cmd, other.getCmd());
}
}
}

View File

@ -0,0 +1,124 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.pojo;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author dungu.zpf
*/
public class Cluster {
/**
* Name of belonging service
*/
private String serviceName;
/**
* Name of cluster
*/
private String name = StringUtils.EMPTY;
/**
* Health check config of this cluster
*/
private AbstractHealthChecker healthChecker = new AbstractHealthChecker.Tcp();
/**
* Default registered port for instances in this cluster.
*/
private int defaultPort = 80;
/**
* Default health check port of instances in this cluster.
*/
private int defaultCheckPort = 80;
/**
* Whether or not use instance port to do health check.
*/
private boolean useIPPort4Check = true;
private Map<String, String> metadata = new HashMap<>();
public Cluster() {
}
public Cluster(String clusterName) {
this.name = clusterName;
}
public String getServiceName() {
return serviceName;
}
public void setServiceName(String serviceName) {
this.serviceName = serviceName;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public AbstractHealthChecker getHealthChecker() {
return healthChecker;
}
public void setHealthChecker(AbstractHealthChecker healthChecker) {
this.healthChecker = healthChecker;
}
public int getDefaultPort() {
return defaultPort;
}
public void setDefaultPort(int defaultPort) {
this.defaultPort = defaultPort;
}
public int getDefaultCheckPort() {
return defaultCheckPort;
}
public void setDefaultCheckPort(int defaultCheckPort) {
this.defaultCheckPort = defaultCheckPort;
}
public boolean isUseIPPort4Check() {
return useIPPort4Check;
}
public void setUseIPPort4Check(boolean useIPPort4Check) {
this.useIPPort4Check = useIPPort4Check;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
}

View File

@ -0,0 +1,166 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.pojo;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import java.util.HashMap;
import java.util.Map;
/**
* @author dungu.zpf
*/
public class Instance {
/**
* Unique ID of this instance.
*/
private String instanceId;
/**
* Instance ip
*/
private String ip;
/**
* Instance port
*/
private int port;
/**
* Instance weight
*/
private double weight = 1.0D;
/**
* Instance health status
*/
@JSONField(name = "valid")
private boolean healthy = true;
/**
* Cluster information of instance
*/
@JSONField(serialize = false)
private Cluster cluster = new Cluster();
/**
* Service information of instance
*/
@JSONField(serialize = false)
private Service service;
/**
* User extended attributes
*/
private Map<String, String> metadata = new HashMap<>();
public String getInstanceId() {
return instanceId;
}
public void setInstanceId(String instanceId) {
this.instanceId = instanceId;
}
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public int getPort() {
return port;
}
public void setPort(int port) {
this.port = port;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public boolean isHealthy() {
return healthy;
}
public void setHealthy(boolean healthy) {
this.healthy = healthy;
}
public Cluster getCluster() {
return cluster;
}
public void setCluster(Cluster cluster) {
this.cluster = cluster;
}
public Service getService() {
return service;
}
public void setService(Service service) {
this.service = service;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public void addMetadata(String key, String value) {
this.metadata.put(key, value);
}
@Override
public String toString() {
return JSON.toJSONString(this);
}
public String toInetAddr() {
return ip + ":" + port;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Instance)) {
return false;
}
Instance host = (Instance) obj;
return StringUtils.equals(toString(), host.toString());
}
@Override
public int hashCode() {
return toString().hashCode();
}
}

View File

@ -0,0 +1,108 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.api.naming.pojo;
import java.util.HashMap;
import java.util.Map;
/**
* @author dungu.zpf
*/
public class Service {
/**
* Service name
*/
private String name;
/**
* Protect threshold
*/
private float protectThreshold = 0.0F;
/**
* Application name of this service
*/
private String app;
/**
* Service group which is meant to classify services into different sets.
*/
private String group;
/**
* Health check mode.
*/
private String healthCheckMode;
public Service(String name) {
this.name = name;
}
private Map<String, String> metadata = new HashMap<>();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHealthCheckMode() {
return healthCheckMode;
}
public void setHealthCheckMode(String healthCheckMode) {
this.healthCheckMode = healthCheckMode;
}
public float getProtectThreshold() {
return protectThreshold;
}
public void setProtectThreshold(float protectThreshold) {
this.protectThreshold = protectThreshold;
}
public String getApp() {
return app;
}
public void setApp(String app) {
this.app = app;
}
public String getGroup() {
return group;
}
public void setGroup(String group) {
this.group = group;
}
public Map<String, String> getMetadata() {
return metadata;
}
public void setMetadata(Map<String, String> metadata) {
this.metadata = metadata;
}
public void addMetadata(String key, String value) {
this.metadata.put(key, value);
}
}

View File

@ -0,0 +1,267 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
import com.alibaba.nacos.client.config.filter.impl.ConfigRequest;
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
import com.alibaba.nacos.client.config.impl.ClientWorker;
import com.alibaba.nacos.client.config.impl.LocalConfigInfoProcessor;
import com.alibaba.nacos.client.config.impl.ServerHttpAgent;
import com.alibaba.nacos.client.config.impl.HttpSimpleClient.HttpResult;
import com.alibaba.nacos.client.config.utils.ContentUtils;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.config.utils.ParamUtils;
import com.alibaba.nacos.client.config.utils.TenantUtil;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Config Impl
* @author Nacos
*
*/
@SuppressWarnings("PMD.ServiceOrDaoClassShouldEndWithImplRule")
public class NacosConfigService implements ConfigService {
final static public Logger log = LogUtils.logger(NacosConfigService.class);
public final long POST_TIMEOUT = 3000L;
/**
* http agent
*/
private ServerHttpAgent agent;
/**
* longpulling
*/
private ClientWorker worker;
private String namespace;
private String encode;
private ConfigFilterChainManager configFilterChainManager = new ConfigFilterChainManager();
public NacosConfigService(Properties properties) throws NacosException {
String encodeTmp = properties.getProperty(PropertyKeyConst.ENCODE);
if (StringUtils.isBlank(encodeTmp)) {
encode = Constants.ENCODE;
} else {
encode = encodeTmp.trim();
}
String namespaceTmp = properties.getProperty(PropertyKeyConst.NAMESPACE);
if (StringUtils.isBlank(namespaceTmp)) {
namespace = TenantUtil.getUserTenant();
properties.put(PropertyKeyConst.NAMESPACE, namespace);
} else {
namespace = namespaceTmp;
properties.put(PropertyKeyConst.NAMESPACE, namespace);
}
agent = new ServerHttpAgent(properties);
agent.start();
worker = new ClientWorker(agent, configFilterChainManager);
}
@Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {
return getConfigInner(namespace, dataId, group, timeoutMs);
}
@Override
public void addListener(String dataId, String group, Listener listener) throws NacosException {
worker.addTenantListeners(dataId, group, Arrays.asList(listener));
}
@Override
public boolean publishConfig(String dataId, String group, String content) throws NacosException {
return publishConfigInner(namespace, dataId, group, null, null, null, content);
}
@Override
public boolean removeConfig(String dataId, String group) throws NacosException {
return removeConfigInner(namespace, dataId, group, null);
}
@Override
public void removeListener(String dataId, String group, Listener listener) {
worker.removeTenantListener(dataId, group, listener);
}
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {
group = null2defaultGroup(group);
ParamUtils.checkKeyParam(dataId, group);
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setTenant(tenant);
cr.setGroup(group);
// 优先使用本地配置
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
if (content != null) {
log.warn(agent.getName(), "[get-config] get failover ok, dataId={}, group={}, tenant={}, config={}", dataId,
group, tenant, ContentUtils.truncateContent(content));
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
}
try {
content = worker.getServerConfig(dataId, group, tenant, timeoutMs);
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
} catch (NacosException ioe) {
if (NacosException.NO_RIGHT == ioe.getErrCode()) {
throw ioe;
}
log.warn("NACOS-0003",
LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0003", "环境问题", "get from server error"));
log.warn(agent.getName(), "[get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",
dataId, group, tenant, ioe.toString());
}
log.warn(agent.getName(), "[get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}", dataId,
group, tenant, ContentUtils.truncateContent(content));
content = LocalConfigInfoProcessor.getSnapshot(agent.getName(), dataId, group, tenant);
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
content = cr.getContent();
return content;
}
private String null2defaultGroup(String group) {
return (null == group) ? Constants.DEFAULT_GROUP : group.trim();
}
private boolean removeConfigInner(String tenant, String dataId, String group, String tag) throws NacosException {
group = null2defaultGroup(group);
ParamUtils.checkKeyParam(dataId, group);
String url = Constants.CONFIG_CONTROLLER_PATH;
List<String> params = new ArrayList<String>();
params.add("dataId");
params.add(dataId);
params.add("group");
params.add(group);
if (StringUtils.isNotEmpty(tenant)) {
params.add("tenant");
params.add(tenant);
}
if (StringUtils.isNotEmpty(tag)) {
params.add("tag");
params.add(tag);
}
HttpResult result = null;
try {
result = agent.httpDelete(url, null, params, encode, POST_TIMEOUT);
} catch (IOException ioe) {
log.warn("[remove] error, " + dataId + ", " + group + ", " + tenant + ", msg: " + ioe.toString());
return false;
}
if (HttpURLConnection.HTTP_OK == result.code) {
log.info(agent.getName(), "[remove] ok, dataId={}, group={}, tenant={}", dataId, group, tenant);
return true;
} else if (HttpURLConnection.HTTP_FORBIDDEN == result.code) {
log.warn(agent.getName(), "[remove] error, dataId={}, group={}, tenant={}, code={}, msg={}", dataId, group,
tenant, result.code, result.content);
throw new NacosException(result.code, result.content);
} else {
log.warn(agent.getName(), "[remove] error, dataId={}, group={}, tenant={}, code={}, msg={}", dataId, group,
tenant, result.code, result.content);
return false;
}
}
private boolean publishConfigInner(String tenant, String dataId, String group, String tag, String appName,
String betaIps, String content) throws NacosException {
group = null2defaultGroup(group);
ParamUtils.checkParam(dataId, group, content);
ConfigRequest cr = new ConfigRequest();
cr.setDataId(dataId);
cr.setTenant(tenant);
cr.setGroup(group);
cr.setContent(content);
configFilterChainManager.doFilter(cr, null);
content = cr.getContent();
String url = Constants.CONFIG_CONTROLLER_PATH;
List<String> params = new ArrayList<String>();
params.add("dataId");
params.add(dataId);
params.add("group");
params.add(group);
params.add("content");
params.add(content);
if (StringUtils.isNotEmpty(tenant)) {
params.add("tenant");
params.add(tenant);
}
if (StringUtils.isNotEmpty(appName)) {
params.add("appName");
params.add(appName);
}
if (StringUtils.isNotEmpty(tag)) {
params.add("tag");
params.add(tag);
}
List<String> headers = new ArrayList<String>();
if (StringUtils.isNotEmpty(betaIps)) {
headers.add("betaIps");
headers.add(betaIps);
}
HttpResult result = null;
try {
result = agent.httpPost(url, headers, params, encode, POST_TIMEOUT);
} catch (IOException ioe) {
log.warn("NACOS-0006",
LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0006", "环境问题", "[publish-single] exception"));
log.warn(agent.getName(), "[publish-single] exception, dataId={}, group={}, msg={}", dataId, group,
ioe.toString());
return false;
}
if (HttpURLConnection.HTTP_OK == result.code) {
log.info(agent.getName(), "[publish-single] ok, dataId={}, group={}, tenant={}, config={}", dataId, group,
tenant, ContentUtils.truncateContent(content));
return true;
} else if (HttpURLConnection.HTTP_FORBIDDEN == result.code) {
log.warn(agent.getName(), "[publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}", dataId,
group, tenant, result.code, result.content);
throw new NacosException(result.code, result.content);
} else {
log.warn(agent.getName(), "[publish-single] error, dataId={}, group={}, tenant={}, code={}, msg={}", dataId,
group, tenant, result.code, result.content);
return false;
}
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.common;
/**
* Constant
*
* @author Nacos
*
*/
public class Constants {
public static final String CLIENT_VERSION_HEADER = "Client-Version";
public static final String CLIENT_VERSION = "3.0.0";
public static int DATA_IN_BODY_VERSION = 204;
public static final String DEFAULT_GROUP = "DEFAULT_GROUP";
public static final String APPNAME = "AppName";
public static final String UNKNOWN_APP = "UnknownApp";
public static final String DEFAULT_DOMAINNAME = "commonconfig.config-host.taobao.com";
public static final String DAILY_DOMAINNAME = "commonconfig.taobao.net";
public static final int DEFAULT_PORT = 8080;
public static final String NULL = "";
public static final String DATAID = "dataId";
public static final String GROUP = "group";
public static final String LAST_MODIFIED = "Last-Modified";
public static final String ACCEPT_ENCODING = "Accept-Encoding";
public static final String CONTENT_ENCODING = "Content-Encoding";
public static final String PROBE_MODIFY_REQUEST = "Listening-Configs";
public static final String PROBE_MODIFY_RESPONSE = "Probe-Modify-Response";
public static final String PROBE_MODIFY_RESPONSE_NEW = "Probe-Modify-Response-New";
public static final String USE_ZIP = "true";
public static final String CONTENT_MD5 = "Content-MD5";
public static final String CONFIG_VERSION = "Config-Version";
public static final String IF_MODIFIED_SINCE = "If-Modified-Since";
public static final String SPACING_INTERVAL = "client-spacing-interval";
public static final String BASE_PATH = "/v1/cs";
public static final String CONFIG_CONTROLLER_PATH = BASE_PATH + "/configs";
/**
* second
*/
public static final int ASYNC_UPDATE_ADDRESS_INTERVAL = 300;
/**
* second
*/
public static final int POLLING_INTERVAL_TIME = 15;
/**
* millisecond
*/
public static final int ONCE_TIMEOUT = 2000;
/**
* millisecond
*/
public static final int CONN_TIMEOUT = 2000;
/**
* millisecond
*/
public static final int SO_TIMEOUT = 60000;
/**
* millisecond
*/
public static final int RECV_WAIT_TIMEOUT = ONCE_TIMEOUT * 5;
public static final String ENCODE = "UTF-8";
public static final String MAP_FILE = "map-file.js";
public static final int FLOW_CONTROL_THRESHOLD = 20;
public static final int FLOW_CONTROL_SLOT = 10;
public static final int FLOW_CONTROL_INTERVAL = 1000;
public static final String LINE_SEPARATOR = Character.toString((char) 1);
public static final String WORD_SEPARATOR = Character.toString((char) 2);
public static final String LONGPULLING_LINE_SEPARATOR = "\r\n";
public static final String CLIENT_APPNAME_HEADER = "Client-AppName";
public static final String CLIENT_REQUEST_TS_HEADER = "Client-RequestTS";
public static final String CLIENT_REQUEST_TOKEN_HEADER = "Client-RequestToken";
public static final int ATOMIC_MAX_SIZE = 1000;
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.common;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Synthesize the form of dataId+groupId. Escapes reserved characters in dataId
* and groupId.
*
* @author Nacos
*/
public class GroupKey {
static public String getKey(String dataId, String group) {
StringBuilder sb = new StringBuilder();
urlEncode(dataId, sb);
sb.append('+');
urlEncode(group, sb);
return sb.toString();
}
static public String getKeyTenant(String dataId, String group, String tenant) {
StringBuilder sb = new StringBuilder();
urlEncode(dataId, sb);
sb.append('+');
urlEncode(group, sb);
if (StringUtils.isNotEmpty(tenant)) {
sb.append('+');
urlEncode(tenant, sb);
}
return sb.toString();
}
static public String getKey(String dataId, String group, String datumStr) {
StringBuilder sb = new StringBuilder();
urlEncode(dataId, sb);
sb.append('+');
urlEncode(group, sb);
sb.append('+');
urlEncode(datumStr, sb);
return sb.toString();
}
static public String[] parseKey(String groupKey) {
StringBuilder sb = new StringBuilder();
String dataId = null;
String group = null;
String tenant = null;
for (int i = 0; i < groupKey.length(); ++i) {
char c = groupKey.charAt(i);
if ('+' == c) {
if (null == dataId) {
dataId = sb.toString();
sb.setLength(0);
} else if (null == group) {
group = sb.toString();
sb.setLength(0);
} else {
throw new IllegalArgumentException("invalid groupkey:" + groupKey);
}
} else if ('%' == c) {
char next = groupKey.charAt(++i);
char nextnext = groupKey.charAt(++i);
if ('2' == next && 'B' == nextnext) {
sb.append('+');
} else if ('2' == next && '5' == nextnext) {
sb.append('%');
} else {
throw new IllegalArgumentException("invalid groupkey:" + groupKey);
}
} else {
sb.append(c);
}
}
if (StringUtils.isBlank(group)) {
group = sb.toString();
if (group.length() == 0) {
throw new IllegalArgumentException("invalid groupkey:" + groupKey);
}
} else {
tenant = sb.toString();
if (group.length() == 0) {
throw new IllegalArgumentException("invalid groupkey:" + groupKey);
}
}
return new String[] { dataId, group, tenant };
}
/**
* + -> %2B
* % -> %25
*/
static void urlEncode(String str, StringBuilder sb) {
for (int idx = 0; idx < str.length(); ++idx) {
char c = str.charAt(idx);
if ('+' == c) {
sb.append("%2B");
} else if ('%' == c) {
sb.append("%25");
} else {
sb.append(c);
}
}
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.nacos.api.config.filter.IConfigContext;
/**
* Config Context
*
* @author Nacos
*
*/
public class ConfigContext implements IConfigContext {
private Map<String, Object> param = new HashMap<String, Object>();
@Override
public Object getParameter(String key) {
return param.get(key);
}
@Override
public void setParameter(String key, Object value) {
param.put(key, value);
}
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import java.util.List;
import com.alibaba.nacos.api.config.filter.IConfigFilter;
import com.alibaba.nacos.api.config.filter.IConfigFilterChain;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
import com.alibaba.nacos.api.exception.NacosException;
import com.google.common.collect.Lists;
/**
* Config Filter Chain Management
*
* @author Nacos
*
*/
public class ConfigFilterChainManager implements IConfigFilterChain {
private List<IConfigFilter> filters = Lists.newArrayList();
public synchronized ConfigFilterChainManager addFilter(IConfigFilter filter) {
// 根据order大小顺序插入
int i = 0;
while (i < this.filters.size()) {
IConfigFilter currentValue = this.filters.get(i);
if (currentValue.getFilterName().equals(filter.getFilterName())) {
break;
}
if (filter.getOrder() >= currentValue.getOrder() && i < this.filters.size()) {
i++;
} else {
this.filters.add(i, filter);
break;
}
}
if (i == this.filters.size()) {
this.filters.add(i, filter);
}
return this;
}
@Override
public void doFilter(IConfigRequest request, IConfigResponse response) throws NacosException {
new VirtualFilterChain(this.filters).doFilter(request, response);
}
private static class VirtualFilterChain implements IConfigFilterChain {
private final List<? extends IConfigFilter> additionalFilters;
private int currentPosition = 0;
public VirtualFilterChain(List<? extends IConfigFilter> additionalFilters) {
this.additionalFilters = additionalFilters;
}
@Override
public void doFilter(final IConfigRequest request, final IConfigResponse response) throws NacosException {
if (this.currentPosition == this.additionalFilters.size()) {
return;
} else {
this.currentPosition++;
IConfigFilter nextFilter = this.additionalFilters.get(this.currentPosition - 1);
nextFilter.doFilter(request, response, this);
}
}
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.nacos.api.config.filter.IConfigContext;
import com.alibaba.nacos.api.config.filter.IConfigRequest;
/**
* Config Request
*
* @author Nacos
*
*/
public class ConfigRequest implements IConfigRequest {
private Map<String, Object> param = new HashMap<String, Object>();
private IConfigContext configContext = new ConfigContext();
public String getTenant() {
return (String) param.get("tenant");
}
public void setTenant(String tenant) {
param.put("tenant", tenant);
}
public String getDataId() {
return (String) param.get("dataId");
}
public void setDataId(String dataId) {
param.put("dataId", dataId);
}
public String getGroup() {
return (String) param.get("group");
}
public void setGroup(String group) {
param.put("group", group);
}
public String getContent() {
return (String) param.get("content");
}
public void setContent(String content) {
param.put("content", content);
}
@Override
public Object getParameter(String key) {
return param.get(key);
}
@Override
public IConfigContext getConfigContext() {
return configContext;
}
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.filter.impl;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.nacos.api.config.filter.IConfigContext;
import com.alibaba.nacos.api.config.filter.IConfigResponse;
/**
* Config Response
*
* @author Nacos
*
*/
public class ConfigResponse implements IConfigResponse {
private Map<String, Object> param = new HashMap<String, Object>();
private IConfigContext configContext = new ConfigContext();
public String getTenant() {
return (String) param.get("tenant");
}
public void setTenant(String tenant) {
param.put("tenant", tenant);
}
public String getDataId() {
return (String) param.get("dataId");
}
public void setDataId(String dataId) {
param.put("dataId", dataId);
}
public String getGroup() {
return (String) param.get("group");
}
public void setGroup(String group) {
param.put("group", group);
}
public String getContent() {
return (String) param.get("content");
}
public void setContent(String content) {
param.put("content", content);
}
@Override
public Object getParameter(String key) {
return param.get(key);
}
@Override
public IConfigContext getConfigContext() {
return configContext;
}
}

View File

@ -0,0 +1,319 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import com.alibaba.nacos.api.config.listener.AbstractSharedListener;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
import com.alibaba.nacos.client.config.filter.impl.ConfigResponse;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.config.utils.MD5;
import com.alibaba.nacos.client.config.utils.TenantUtil;
import com.alibaba.nacos.client.logger.Logger;
/**
* Listner Management
*
* @author Nacos
*
*/
public class CacheData {
final static public Logger log = LogUtils.logger(CacheData.class);
public boolean isInitializing() {
return isInitializing;
}
public void setInitializing(boolean isInitializing) {
this.isInitializing = isInitializing;
}
public String getMd5() {
return md5;
}
public String getTenant() {
return tenant;
}
public String getContent() {
return content;
}
public void setContent(String newContent) {
this.content = newContent;
this.md5 = getMd5String(content);
}
/**
* Add listener
*
* @param listener
* listener
*/
public void addListener(Listener listener) {
if (null == listener) {
throw new IllegalArgumentException("listener is null");
}
ManagerListenerWrap wrap = new ManagerListenerWrap(listener);
if (listeners.addIfAbsent(wrap)) {
log.info(name, "[add-listener] ok, tenant={}, dataId={}, group={}, cnt={}", tenant, dataId, group,
listeners.size());
}
}
public void removeListener(Listener listener) {
if (null == listener) {
throw new IllegalArgumentException("listener is null");
}
ManagerListenerWrap wrap = new ManagerListenerWrap(listener);
if (listeners.remove(wrap)) {
log.info(name, "[remove-listener] ok, dataId={}, group={}, cnt={}", dataId, group, listeners.size());
}
}
/**
* 返回监听器列表上的迭代器只读保证不返回NULL
*/
public List<Listener> getListeners() {
List<Listener> result = new ArrayList<Listener>();
for (ManagerListenerWrap wrap : listeners) {
result.add(wrap.listener);
}
return result;
}
public long getLocalConfigInfoVersion() {
return localConfigLastModified;
}
public void setLocalConfigInfoVersion(long localConfigLastModified) {
this.localConfigLastModified = localConfigLastModified;
}
public boolean isUseLocalConfigInfo() {
return isUseLocalConfig;
}
public void setUseLocalConfigInfo(boolean useLocalConfigInfo) {
this.isUseLocalConfig = useLocalConfigInfo;
if (!useLocalConfigInfo) {
localConfigLastModified = -1;
}
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((dataId == null) ? 0 : dataId.hashCode());
result = prime * result + ((group == null) ? 0 : group.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (null == obj || obj.getClass() != getClass()) {
return false;
}
if (this == obj) {
return true;
}
CacheData other = (CacheData) obj;
return dataId.equals(other.dataId) && group.equals(other.group);
}
@Override
public String toString() {
return "CacheData [" + dataId + ", " + group + "]";
}
void checkListenerMd5() {
for (ManagerListenerWrap wrap : listeners) {
if (!md5.equals(wrap.lastCallMd5)) {
safeNotifyListener(dataId, group, content, md5, wrap);
}
}
}
private void safeNotifyListener(final String dataId, final String group, final String content,
final String md5, final ManagerListenerWrap listenerWrap) {
final Listener listener = listenerWrap.listener;
Runnable job = new Runnable() {
public void run() {
ClassLoader myClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader appClassLoader= listener.getClass().getClassLoader();
try {
if(listener instanceof AbstractSharedListener){
AbstractSharedListener adapter = (AbstractSharedListener) listener;
adapter.fillContext(dataId, group);
log.info(name, "[notify-context] dataId={}, group={}, md5={}", dataId, group, md5);
}
// 执行回调之前先将线程classloader设置为具体webapp的classloader以免回调方法中调用spi接口是出现异常或错用多应用部署才会有该问题
Thread.currentThread().setContextClassLoader(appClassLoader);
ConfigResponse cr = new ConfigResponse();
cr.setDataId(dataId);
cr.setGroup(group);
cr.setContent(content);
configFilterChainManager.doFilter(null, cr);
String contentTmp = cr.getContent();
listener.receiveConfigInfo(contentTmp);
listenerWrap.lastCallMd5 = md5;
log.info(
name,
"[notify-ok] dataId={}, group={}, md5={}, listener={} ",
dataId, group, md5, listener);
} catch (NacosException de) {
log.error(name, "NACOS-XXXX",
"[notify-error] dataId={}, group={}, md5={}, listener={} errCode={} errMsg={}", dataId,
group, md5, listener, de.getErrCode(), de.getErrMsg());
} catch (Throwable t) {
log.error(name, "NACOS-XXXX",
"[notify-error] dataId={}, group={}, md5={}, listener={} tx={}", dataId, group, md5,
listener, t.getCause());
}
finally
{
Thread.currentThread().setContextClassLoader(myClassLoader);
}
}
};
final long startNotify = System.currentTimeMillis();
try {
if (null != listener.getExecutor()) {
listener.getExecutor().execute(job);
} else {
job.run();
}
} catch (Throwable t) {
log.error(
name,
"NACOS-XXXX",
"[notify-error] dataId={}, group={}, md5={}, listener={} throwable={}",
dataId, group, md5, listener, t.getCause());
}
final long finishNotify = System.currentTimeMillis();
log.info(name, "[notify-listener] time cost={}ms in ClientWorker, dataId={}, group={}, md5={}, listener={} ",(finishNotify - startNotify), dataId ,group, md5, listener);
}
static public String getMd5String(String config) {
return (null == config) ? Constants.NULL : MD5.getInstance().getMD5String(config);
}
private String loadCacheContentFromDiskLocal(String name, String dataId, String group, String tenant) {
String content = LocalConfigInfoProcessor.getFailover(name, dataId, group, tenant);
content = (null != content) ? content
: LocalConfigInfoProcessor.getSnapshot(name, dataId, group, tenant);
return content;
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group) {
if (null == dataId || null == group) {
throw new IllegalArgumentException("dataId=" + dataId + ", group=" + group);
}
this.name = name;
this.configFilterChainManager = configFilterChainManager;
this.dataId = dataId;
this.group = group;
this.tenant = TenantUtil.getUserTenant();
listeners = new CopyOnWriteArrayList<ManagerListenerWrap>();
this.isInitializing = true;
this.content = loadCacheContentFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String(content);
}
public CacheData(ConfigFilterChainManager configFilterChainManager, String name, String dataId, String group, String tenant) {
if (null == dataId || null == group) {
throw new IllegalArgumentException("dataId=" + dataId + ", group=" + group);
}
this.name = name;
this.configFilterChainManager = configFilterChainManager;
this.dataId = dataId;
this.group = group;
this.tenant = tenant;
listeners = new CopyOnWriteArrayList<ManagerListenerWrap>();
this.isInitializing = true;
this.content = loadCacheContentFromDiskLocal(name, dataId, group, tenant);
this.md5 = getMd5String(content);
}
// ==================
private final String name;
private final ConfigFilterChainManager configFilterChainManager;
public final String dataId;
public final String group;
public final String tenant;
private final CopyOnWriteArrayList<ManagerListenerWrap> listeners;
private volatile String md5;
/**
* whether use local config
*/
private volatile boolean isUseLocalConfig = false;
/**
* last motify time
*/
private volatile long localConfigLastModified;
private volatile String content;
private int taskId;
private volatile boolean isInitializing = true;
}
class ManagerListenerWrap {
final Listener listener;
String lastCallMd5 = CacheData.getMd5String(null);
ManagerListenerWrap(Listener listener) {
this.listener = listener;
}
@Override
public boolean equals(Object obj) {
if (null == obj || obj.getClass() != getClass()) {
return false;
}
if (obj == this) {
return true;
}
ManagerListenerWrap other = (ManagerListenerWrap) obj;
return listener.equals(other.listener);
}
@Override
public int hashCode() {
return super.hashCode();
}
}

View File

@ -0,0 +1,541 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import static com.alibaba.nacos.client.config.common.Constants.LINE_SEPARATOR;
import static com.alibaba.nacos.client.config.common.Constants.WORD_SEPARATOR;
import java.io.File;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
import com.alibaba.nacos.api.config.listener.Listener;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.config.common.GroupKey;
import com.alibaba.nacos.client.config.filter.impl.ConfigFilterChainManager;
import com.alibaba.nacos.client.config.impl.HttpSimpleClient.HttpResult;
import com.alibaba.nacos.client.config.utils.ContentUtils;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.config.utils.MD5;
import com.alibaba.nacos.client.config.utils.TenantUtil;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.client.utils.StringUtils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Longpulling
*
* @author Nacos
*
*/
public class ClientWorker {
final static public Logger log = LogUtils.logger(ClientWorker.class);
public void addListeners(String dataId, String group, List<? extends Listener> listeners) {
group = null2defaultGroup(group);
CacheData cache = addCacheDataIfAbsent(dataId, group);
for (Listener listener : listeners) {
cache.addListener(listener);
}
}
public void removeListener(String dataId, String group, Listener listener) {
group = null2defaultGroup(group);
CacheData cache = getCache(dataId, group);
if (null != cache) {
cache.removeListener(listener);
if (cache.getListeners().isEmpty()) {
removeCache(dataId, group);
}
}
}
public void addTenantListeners(String dataId, String group, List<? extends Listener> listeners) {
group = null2defaultGroup(group);
String tenant = agent.getTenant();
CacheData cache = addCacheDataIfAbsent(dataId, group, tenant);
for (Listener listener : listeners) {
cache.addListener(listener);
}
}
public void removeTenantListener(String dataId, String group, Listener listener) {
group = null2defaultGroup(group);
String tenant = agent.getTenant();
CacheData cache = getCache(dataId, group, tenant);
if (null != cache) {
cache.removeListener(listener);
if (cache.getListeners().isEmpty()) {
removeCache(dataId, group, tenant);
}
}
}
@SuppressFBWarnings("JLM_JSR166_UTILCONCURRENT_MONITORENTER")
void removeCache(String dataId, String group) {
String groupKey = GroupKey.getKey(dataId, group);
synchronized (cacheMap) {
Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
copy.remove(groupKey);
cacheMap.set(copy);
}
log.info(agent.getName(), "[unsubscribe] {}", groupKey);
}
@SuppressFBWarnings("JLM_JSR166_UTILCONCURRENT_MONITORENTER")
void removeCache(String dataId, String group, String tenant) {
String groupKey = GroupKey.getKeyTenant(dataId, group, tenant);
synchronized (cacheMap) {
Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
copy.remove(groupKey);
cacheMap.set(copy);
}
log.info(agent.getName(), "[unsubscribe] {}", groupKey);
}
@SuppressFBWarnings("JLM_JSR166_UTILCONCURRENT_MONITORENTER")
public CacheData addCacheDataIfAbsent(String dataId, String group) {
CacheData cache = getCache(dataId, group);
if (null != cache) {
return cache;
}
String key = GroupKey.getKey(dataId, group);
cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group);
synchronized (cacheMap) {
CacheData cacheFromMap = getCache(dataId, group);
// multiple listeners on the same dataid+group and race condition,so double check again
//other listener thread beat me to set to cacheMap
if(null != cacheFromMap) {
cache = cacheFromMap;
//reset so that server not hang this check
cache.setInitializing(true);
} else {
int taskId = cacheMap.get().size() / (int) ParamUtil.getPerTaskConfigSize();
cache.setTaskId(taskId);
}
Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
copy.put(key, cache);
cacheMap.set(copy);
}
log.info(agent.getName(), "[subscribe] {}", key);
return cache;
}
@SuppressFBWarnings("JLM_JSR166_UTILCONCURRENT_MONITORENTER")
public CacheData addCacheDataIfAbsent(String dataId, String group, String tenant) {
CacheData cache = getCache(dataId, group, tenant);
if (null != cache) {
return cache;
}
String key = GroupKey.getKeyTenant(dataId, group, tenant);
cache = new CacheData(configFilterChainManager, agent.getName(), dataId, group, tenant);
synchronized (cacheMap) {
CacheData cacheFromMap = getCache(dataId, group, tenant);
// multiple listeners on the same dataid+group and race condition,so
// double check again
// other listener thread beat me to set to cacheMap
if (null != cacheFromMap) {
cache = cacheFromMap;
// reset so that server not hang this check
cache.setInitializing(true);
}
Map<String, CacheData> copy = new HashMap<String, CacheData>(cacheMap.get());
copy.put(key, cache);
cacheMap.set(copy);
}
log.info(agent.getName(), "[subscribe] {}", key);
return cache;
}
public CacheData getCache(String dataId, String group) {
return getCache(dataId, group, TenantUtil.getUserTenant());
}
public CacheData getCache(String dataId, String group, String tenant) {
if (null == dataId || null == group) {
throw new IllegalArgumentException();
}
return cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant));
}
public String getServerConfig(String dataId, String group, String tenant, long readTimeout)
throws NacosException {
if (StringUtils.isBlank(group)) {
group = Constants.DEFAULT_GROUP;
}
HttpResult result = null;
try {
List<String> params = null;
if (StringUtils.isBlank(tenant)) {
params = Arrays.asList("dataId", dataId, "group", group);
} else {
params = Arrays.asList("dataId", dataId, "group", group, "tenant", tenant);
}
result = agent.httpGet(Constants.CONFIG_CONTROLLER_PATH, null, params, agent.getEncode(), readTimeout);
} catch (IOException e) {
log.error(agent.getName(), "NACOS-XXXX",
"[sub-server] get server config exception, dataId={}, group={}, tenant={}, msg={}", dataId, group,
tenant, e.toString());
throw new NacosException(NacosException.SERVER_ERROR, e.getMessage());
}
switch (result.code) {
case HttpURLConnection.HTTP_OK:
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, result.content);
return result.content;
case HttpURLConnection.HTTP_NOT_FOUND:
LocalConfigInfoProcessor.saveSnapshot(agent.getName(), dataId, group, tenant, null);
return null;
case HttpURLConnection.HTTP_CONFLICT: {
log.error(agent.getName(), "NACOS-XXXX",
"[sub-server-error] get server config being modified concurrently, dataId={}, group={}, tenant={}",
dataId, group, tenant);
throw new NacosException(NacosException.CONFLICT,
"data being modified, dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
}
case HttpURLConnection.HTTP_FORBIDDEN: {
log.error(agent.getName(), "NACOS-XXXX", "[sub-server-error] no right, dataId={}, group={}, tenant={}",
dataId, group, tenant);
throw new NacosException(result.code, result.content);
}
default: {
log.error(agent.getName(), "NACOS-XXXX", "[sub-server-error] dataId={}, group={}, tenant={}, code={}",
dataId, group, tenant, result.code);
throw new NacosException(result.code,
"http error, code=" + result.code + ",dataId=" + dataId + ",group=" + group + ",tenant=" + tenant);
}
}
}
private void checkLocalConfig(CacheData cacheData) {
final String dataId = cacheData.dataId;
final String group = cacheData.group;
final String tenant = cacheData.tenant;
File path = LocalConfigInfoProcessor.getFailoverFile(agent.getName(), dataId, group, tenant);
// 没有 ->
if (!cacheData.isUseLocalConfigInfo() && path.exists()) {
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
String md5 = MD5.getInstance().getMD5String(content);
cacheData.setUseLocalConfigInfo(true);
cacheData.setLocalConfigInfoVersion(path.lastModified());
cacheData.setContent(content);
log.warn(agent.getName(),
"[failover-change] failover file created. dataId={}, group={}, tenant={}, md5={}, content={}",
dataId, group, tenant, md5, ContentUtils.truncateContent(content));
return;
}
// -> 没有不通知业务监听器从server拿到配置后通知
if (cacheData.isUseLocalConfigInfo() && !path.exists()) {
cacheData.setUseLocalConfigInfo(false);
log.warn(agent.getName(), "[failover-change] failover file deleted. dataId={}, group={}, tenant={}", dataId,
group, tenant);
return;
}
// 有变更
if (cacheData.isUseLocalConfigInfo() && path.exists()
&& cacheData.getLocalConfigInfoVersion() != path.lastModified()) {
String content = LocalConfigInfoProcessor.getFailover(agent.getName(), dataId, group, tenant);
String md5 = MD5.getInstance().getMD5String(content);
cacheData.setUseLocalConfigInfo(true);
cacheData.setLocalConfigInfoVersion(path.lastModified());
cacheData.setContent(content);
log.warn(agent.getName(),
"[failover-change] failover file changed. dataId={}, group={}, tenant={}, md5={}, content={}",
dataId, group, tenant, md5, ContentUtils.truncateContent(content));
return;
}
}
private String null2defaultGroup(String group) {
return (null == group) ? Constants.DEFAULT_GROUP : group.trim();
}
public void checkConfigInfo() {
// 分任务
int listenerSize = cacheMap.get().size();
// 向上取整为批数
int longingTaskCount = (int) Math.ceil(listenerSize / ParamUtil.getPerTaskConfigSize());
if (longingTaskCount > currentLongingTaskCount) {
for (int i = (int) currentLongingTaskCount; i < longingTaskCount; i++) {
// 要判断任务是否在执行 这块需要好好想想 任务列表现在是无序的变化过程可能有问题
executorService.execute(new LongPullingRunnable(i));
}
currentLongingTaskCount = longingTaskCount;
}
}
/**
* 从Server获取值变化了的DataID列表返回的对象里只有dataId和group是有效的 保证不返回NULL
*/
List<String> checkUpdateDataIds(List<CacheData> cacheDatas, List<String> inInitializingCacheList) {
StringBuilder sb = new StringBuilder();
for (CacheData cacheData : cacheDatas) {
if (!cacheData.isUseLocalConfigInfo()) {
sb.append(cacheData.dataId).append(WORD_SEPARATOR);
sb.append(cacheData.group).append(WORD_SEPARATOR);
if (StringUtils.isBlank(cacheData.tenant)) {
sb.append(cacheData.getMd5()).append(LINE_SEPARATOR);
} else {
sb.append(cacheData.getMd5()).append(WORD_SEPARATOR);
sb.append(cacheData.getTenant()).append(LINE_SEPARATOR);
}
if (cacheData.isInitializing()) {
// cacheData 首次出现在cacheMap中&首次check更新
inInitializingCacheList
.add(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant));
}
}
}
boolean isInitializingCacheList = !inInitializingCacheList.isEmpty();
return checkUpdateConfigStr(sb.toString(), isInitializingCacheList);
}
/**
* 从Server获取值变化了的DataID列表返回的对象里只有dataId和group是有效的 保证不返回NULL
*/
List<String> checkUpdateConfigStr(String probeUpdateString, boolean isInitializingCacheList) {
List<String> params = Arrays.asList(Constants.PROBE_MODIFY_REQUEST, probeUpdateString);
long timeout = TimeUnit.SECONDS.toMillis(30L);
List<String> headers = new ArrayList<String>(2);
headers.add("Long-Pulling-Timeout");
headers.add("" + timeout);
// told server do not hang me up if new initializing cacheData added in
if (isInitializingCacheList) {
headers.add("Long-Pulling-Timeout-No-Hangup");
headers.add("true");
}
if (StringUtils.isBlank(probeUpdateString)) {
return Collections.emptyList();
}
try {
HttpResult result = agent.httpPost(Constants.CONFIG_CONTROLLER_PATH + "/listener", headers, params,
agent.getEncode(), timeout);
if (HttpURLConnection.HTTP_OK == result.code) {
setHealthServer(true);
return parseUpdateDataIdResponse(result.content);
} else {
setHealthServer(false);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR) {
log.error("NACOS-0007", LoggerHelper.getErrorCodeStr("Nacos", "Nacos-0007", "环境问题",
"[check-update] get changed dataId error"));
}
log.error(agent.getName(), "NACOS-XXXX", "[check-update] get changed dataId error, code={}",
result.code);
}
} catch (IOException e) {
setHealthServer(false);
log.error(agent.getName(), "NACOS-XXXX", "[check-update] get changed dataId exception, msg={}",
e.toString());
}
return Collections.emptyList();
}
/**
* 从HTTP响应拿到变化的groupKey保证不返回NULL
*/
private List<String> parseUpdateDataIdResponse(String response) {
if (StringUtils.isBlank(response)) {
return Collections.emptyList();
}
try {
response = URLDecoder.decode(response, "UTF-8");
} catch (Exception e) {
log.error(agent.getName(), "NACOS-XXXX", "[polling-resp] decode modifiedDataIdsString error", e);
}
List<String> updateList = new LinkedList<String>();
for (String dataIdAndGroup : response.split(LINE_SEPARATOR)) {
if (!StringUtils.isBlank(dataIdAndGroup)) {
String[] keyArr = dataIdAndGroup.split(WORD_SEPARATOR);
String dataId = keyArr[0];
String group = keyArr[1];
if (keyArr.length == 2) {
updateList.add(GroupKey.getKey(dataId, group));
log.info(agent.getName(), "[polling-resp] config changed. dataId={}, group={}", dataId, group);
} else if (keyArr.length == 3) {
String tenant = keyArr[2];
updateList.add(GroupKey.getKeyTenant(dataId, group, tenant));
log.info(agent.getName(), "[polling-resp] config changed. dataId={}, group={}, tenant={}", dataId,
group, tenant);
} else {
log.error(agent.getName(), "NACOS-XXXX", "[polling-resp] invalid dataIdAndGroup error",
dataIdAndGroup);
}
}
}
return updateList;
}
@SuppressWarnings("PMD.ThreadPoolCreationRule")
public ClientWorker(final ServerHttpAgent agent, final ConfigFilterChainManager configFilterChainManager) {
this.agent = agent;
this.configFilterChainManager = configFilterChainManager;
executor = Executors.newScheduledThreadPool(1, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker." + agent.getName());
t.setDaemon(true);
return t;
}
});
executorService = Executors.newCachedThreadPool(new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Worker.longPulling" + agent.getName());
t.setDaemon(true);
return t;
}
});
executor.scheduleWithFixedDelay(new Runnable() {
public void run() {
try {
checkConfigInfo();
} catch (Throwable e) {
log.error(agent.getName(), "NACOS-XXXX", "[sub-check] rotate check error", e);
}
}
}, 1L, 10L, TimeUnit.MILLISECONDS);
}
class LongPullingRunnable implements Runnable {
private int taskId;
public LongPullingRunnable(int taskId) {
this.taskId = taskId;
}
public void run() {
try {
List<CacheData> cacheDatas = new ArrayList<CacheData>();
// check failover config
for (CacheData cacheData : cacheMap.get().values()) {
if (cacheData.getTaskId() == taskId) {
cacheDatas.add(cacheData);
try {
checkLocalConfig(cacheData);
if (cacheData.isUseLocalConfigInfo()) {
cacheData.checkListenerMd5();
}
} catch (Exception e) {
log.error("NACOS-CLIENT", "get local config info error", e);
}
}
}
List<String> inInitializingCacheList = new ArrayList<String>();
// check server config
List<String> changedGroupKeys = checkUpdateDataIds(cacheDatas, inInitializingCacheList);
for (String groupKey : changedGroupKeys) {
String[] key = GroupKey.parseKey(groupKey);
String dataId = key[0];
String group = key[1];
String tenant = null;
if (key.length == 3) {
tenant = key[2];
}
try {
String content = getServerConfig(dataId, group, tenant, 3000L);
CacheData cache = cacheMap.get().get(GroupKey.getKeyTenant(dataId, group, tenant));
cache.setContent(content);
log.info(agent.getName(), "[data-received] dataId={}, group={}, tenant={}, md5={}, content={}",
dataId, group, tenant, cache.getMd5(), ContentUtils.truncateContent(content));
} catch (NacosException ioe) {
log.error(agent.getName(), "NACOS-XXXX",
"[get-update] get changed config exception. dataId={}, group={}, tenant={}, msg={}",
dataId, group, tenant, ioe.toString());
}
}
for (CacheData cacheData : cacheDatas) {
if (!cacheData.isInitializing() || inInitializingCacheList
.contains(GroupKey.getKeyTenant(cacheData.dataId, cacheData.group, cacheData.tenant))) {
cacheData.checkListenerMd5();
cacheData.setInitializing(false);
}
}
inInitializingCacheList.clear();
} catch (Throwable e) {
log.error("500", "longPulling error", e);
} finally {
executorService.execute(this);
}
}
}
// =================
public boolean isHealthServer() {
return isHealthServer;
}
private void setHealthServer(boolean isHealthServer) {
this.isHealthServer = isHealthServer;
}
final ScheduledExecutorService executor;
final ExecutorService executorService;
/**
* groupKey -> cacheData
*/
AtomicReference<Map<String, CacheData>> cacheMap = new AtomicReference<Map<String, CacheData>>(new HashMap<String, CacheData>());
ServerHttpAgent agent;
ConfigFilterChainManager configFilterChainManager;
private boolean isHealthServer = true;
private double currentLongingTaskCount = 0;
}

View File

@ -0,0 +1,133 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.logger.Logger;
/**
* Event subscription and publishing tools.
*
* @author Nacos
*
*/
public class EventDispatcher {
final static public Logger log = LogUtils.logger(EventDispatcher.class);
/**
* 添加事件监听器
*/
static public void addEventListener(AbstractEventListener listener) {
for (Class<? extends AbstractEvent> type : listener.interest()) {
getListenerList(type).addIfAbsent(listener);
}
}
/**
* 发布事件首先发布该事件暗示的其他事件最后通知所有对应的监听器
*/
static public void fireEvent(AbstractEvent abstractEvent) {
if (null == abstractEvent) {
return;
}
// 发布该事件暗示的其他事件
for (AbstractEvent implyEvent : abstractEvent.implyEvents()) {
try {
// 避免死循环
if (abstractEvent != implyEvent) {
fireEvent(implyEvent);
}
} catch (Exception e) {
log.warn("", e.toString(), e);
}
}
for (AbstractEventListener listener : getListenerList(abstractEvent.getClass())) {
try {
listener.onEvent(abstractEvent);
} catch (Exception e) {
log.warn(e.toString(), e);
}
}
}
static synchronized CopyOnWriteArrayList<AbstractEventListener> getListenerList(
Class<? extends AbstractEvent> eventType) {
CopyOnWriteArrayList<AbstractEventListener> listeners = LISTENER_MAP.get(eventType);
if (null == listeners) {
listeners = new CopyOnWriteArrayList<AbstractEventListener>();
LISTENER_MAP.put(eventType, listeners);
}
return listeners;
}
// ========================
static final Map<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>> LISTENER_MAP = new HashMap<Class<? extends AbstractEvent>, CopyOnWriteArrayList<AbstractEventListener>>();
// ========================
/**
* Client事件
*/
static public abstract class AbstractEvent {
@SuppressWarnings("unchecked")
protected List<AbstractEvent> implyEvents() {
return Collections.EMPTY_LIST;
}
}
/**
* 事件监听器
*/
static public abstract class AbstractEventListener {
public AbstractEventListener() {
/**
* 自动注册给EventDispatcher
*/
EventDispatcher.addEventListener(this);
}
/**
* 感兴趣的事件列表
*
* @return event list
*/
abstract public List<Class<? extends AbstractEvent>> interest();
/**
* 处理事件
* @param abstractEvent event to do
*/
abstract public void onEvent(AbstractEvent abstractEvent);
}
/**
* serverList has changed
*/
static public class ServerlistChangeEvent extends AbstractEvent {
}
}

View File

@ -0,0 +1,276 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.config.utils.IOUtils;
import com.alibaba.nacos.client.config.utils.MD5;
import com.alibaba.nacos.client.utils.EnvUtil;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.common.util.UuidUtil;
/**
* Http tool
*
* @author Nacos
*
*/
public class HttpSimpleClient {
static public HttpResult httpGet(String url, List<String> headers, List<String> paramValues,
String encoding, long readTimeoutMs, boolean isSSL) throws IOException{
String encodedContent = encodingParams(paramValues, encoding);
url += (null == encodedContent) ? "" : ("?" + encodedContent);
if (Limiter.isLimit(MD5.getInstance().getMD5String(
new StringBuilder(url).append(encodedContent).toString()))) {
return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
"More than client-side current limit threshold");
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(ParamUtil.getConnectTimeout() > 100 ? ParamUtil.getConnectTimeout() : 100);
conn.setReadTimeout((int) readTimeoutMs);
List<String> newHeaders = getHeaders(url, headers, paramValues);
setHeaders(conn, newHeaders, encoding);
conn.connect();
int respCode = conn.getResponseCode();
String resp = null;
if (HttpURLConnection.HTTP_OK == respCode) {
resp = IOUtils.toString(conn.getInputStream(), encoding);
} else {
resp = IOUtils.toString(conn.getErrorStream(), encoding);
}
return new HttpResult(respCode, conn.getHeaderFields(), resp);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
/**
* 发送GET请求
*/
static public HttpResult httpGet(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
return httpGet(url, headers, paramValues, encoding, readTimeoutMs, false);
}
/**
* 发送POST请求
*
* @param url
* @param headers
* 请求Header可以为null
* @param paramValues
* 参数可以为null
* @param encoding
* URL编码使用的字符集
* @param readTimeoutMs
* 响应超时
* @param isSSL
* 是否https
* @return
* @throws IOException
*/
static public HttpResult httpPost(String url, List<String> headers, List<String> paramValues,
String encoding, long readTimeoutMs, boolean isSSL) throws IOException {
String encodedContent = encodingParams(paramValues, encoding);
if (Limiter.isLimit(MD5.getInstance().getMD5String(
new StringBuilder(url).append(encodedContent).toString()))) {
return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
"More than client-side current limit threshold");
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setConnectTimeout(ParamUtil.getConnectTimeout() > 3000 ? ParamUtil.getConnectTimeout() : 3000);
conn.setReadTimeout((int) readTimeoutMs);
conn.setDoOutput(true);
conn.setDoInput(true);
List<String> newHeaders = getHeaders(url, headers, paramValues);
setHeaders(conn, newHeaders, encoding);
conn.getOutputStream().write(encodedContent.getBytes(encoding));
int respCode = conn.getResponseCode();
String resp = null;
if (HttpURLConnection.HTTP_OK == respCode) {
resp = IOUtils.toString(conn.getInputStream(), encoding);
} else {
resp = IOUtils.toString(conn.getErrorStream(), encoding);
}
return new HttpResult(respCode, conn.getHeaderFields(), resp);
} finally {
if (null != conn) {
conn.disconnect();
}
}
}
/**
* 发送POST请求
*
* @param url
* @param headers
* 请求Header可以为null
* @param paramValues
* 参数可以为null
* @param encoding
* URL编码使用的字符集
* @param readTimeoutMs
* 响应超时
* @return
* @throws IOException
*/
static public HttpResult httpPost(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
return httpPost(url, headers, paramValues, encoding, readTimeoutMs, false);
}
static public HttpResult httpDelete(String url, List<String> headers, List<String> paramValues,
String encoding, long readTimeoutMs, boolean isSSL) throws IOException{
String encodedContent = encodingParams(paramValues, encoding);
url += (null == encodedContent) ? "" : ("?" + encodedContent);
if (Limiter.isLimit(MD5.getInstance().getMD5String(
new StringBuilder(url).append(encodedContent).toString()))) {
return new HttpResult(NacosException.CLIENT_OVER_THRESHOLD,
"More than client-side current limit threshold");
}
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("DELETE");
conn.setConnectTimeout(ParamUtil.getConnectTimeout() > 100 ? ParamUtil.getConnectTimeout() : 100);
conn.setReadTimeout((int) readTimeoutMs);
List<String> newHeaders = getHeaders(url, headers, paramValues);
setHeaders(conn, newHeaders, encoding);
conn.connect();
int respCode = conn.getResponseCode();
String resp = null;
if (HttpURLConnection.HTTP_OK == respCode) {
resp = IOUtils.toString(conn.getInputStream(), encoding);
} else {
resp = IOUtils.toString(conn.getErrorStream(), encoding);
}
return new HttpResult(respCode, conn.getHeaderFields(), resp);
} finally {
if (conn != null) {
conn.disconnect();
}
}
}
static public HttpResult httpDelete(String url, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
return httpGet(url, headers, paramValues, encoding, readTimeoutMs, false);
}
static private void setHeaders(HttpURLConnection conn, List<String> headers, String encoding) {
if (null != headers) {
for (Iterator<String> iter = headers.iterator(); iter.hasNext();) {
conn.addRequestProperty(iter.next(), iter.next());
}
}
conn.addRequestProperty("Client-Version", ParamUtil.getClientVersion());
conn.addRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + encoding);
String ts = String.valueOf(System.currentTimeMillis());
String token = MD5.getInstance().getMD5String(ts + ParamUtil.getAppKey());
conn.addRequestProperty(Constants.CLIENT_APPNAME_HEADER, ParamUtil.getAppName());
conn.addRequestProperty(Constants.CLIENT_REQUEST_TS_HEADER, ts);
conn.addRequestProperty(Constants.CLIENT_REQUEST_TOKEN_HEADER, token);
}
private static List<String> getHeaders(String url, List<String> headers, List<String> paramValues)
throws IOException {
List<String> newHeaders = new ArrayList<String>();
newHeaders.add("exConfigInfo");
newHeaders.add("true");
newHeaders.add("RequestId");
newHeaders.add(UuidUtil.generateUuid());
if (headers!=null) {
newHeaders.addAll(headers);
}
return newHeaders;
}
static private String encodingParams(List<String> paramValues, String encoding)
throws UnsupportedEncodingException {
StringBuilder sb = new StringBuilder();
if (null == paramValues) {
return null;
}
for (Iterator<String> iter = paramValues.iterator(); iter.hasNext();) {
sb.append(iter.next()).append("=");
sb.append(URLEncoder.encode(iter.next(), encoding));
if (iter.hasNext()) {
sb.append("&");
}
}
return sb.toString();
}
static public class HttpResult {
final public int code;
final public Map<String,List<String>> headers;
final public String content;
public HttpResult(int code, String content) {
this.code = code;
this.headers = null;
this.content = content;
}
public HttpResult(int code, Map<String, List<String>> headers, String content) {
this.code = code;
this.headers = headers;
this.content = content;
}
}
}

View File

@ -0,0 +1,79 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.logger.Logger;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.util.concurrent.RateLimiter;
/**
* Limiter
*
* @author Nacos
*
*/
public class Limiter {
static final public Logger log = LogUtils.logger(Limiter.class);
private static int CAPACITY_SIZE = 1000;
private static int LIMIT_TIME = 1000;
private static Cache<String, RateLimiter> cache = CacheBuilder.newBuilder()
.initialCapacity(CAPACITY_SIZE).expireAfterAccess(1, TimeUnit.MINUTES)
.build();
/**
* qps 5
*/
private static final String DEFAULT_LIMIT = "5";
private static double limit = 5;
static {
try {
String limitTimeStr = System
.getProperty("limitTime", DEFAULT_LIMIT);
limit = Double.parseDouble(limitTimeStr);
log.info("limitTime:{}", limit);
} catch (Exception e) {
log.error("Nacos-xxx", "init limitTime fail", e);
}
}
public static boolean isLimit(String accessKeyID) {
RateLimiter rateLimiter = null;
try {
rateLimiter = cache.get(accessKeyID, new Callable<RateLimiter>() {
@Override
public RateLimiter call() throws Exception {
return RateLimiter.create(limit);
}
});
} catch (ExecutionException e) {
log.error("Nacos-XXX", "create limit fail", e);
}
if (rateLimiter != null && !rateLimiter.tryAcquire(LIMIT_TIME, TimeUnit.MILLISECONDS)) {
log.error("Nacos-XXX", "access_key_id:{} limited", accessKeyID);
return true;
}
return false;
}
}

View File

@ -0,0 +1,197 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.config.utils.ConcurrentDiskUtil;
import com.alibaba.nacos.client.config.utils.IOUtils;
import com.alibaba.nacos.client.config.utils.JVMUtil;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.config.utils.SnapShotSwitch;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Local Disaster Recovery Directory Tool
*
* @author Nacos
*/
public class LocalConfigInfoProcessor {
final static public Logger log = LogUtils.logger(LocalConfigInfoProcessor.class);
static public String getFailover(String serverName, String dataId, String group, String tenant) {
File localPath = getFailoverFile(serverName, dataId, group, tenant);
if (!localPath.exists() || !localPath.isFile()) {
return null;
}
try {
return readFile(localPath);
} catch (IOException ioe) {
log.error(serverName, "NACOS-XXXX","get failover error, " + localPath + ioe.toString());
return null;
}
}
/**
* 获取本地缓存文件内容NULL表示没有本地文件或抛出异常
*/
static public String getSnapshot(String name, String dataId, String group, String tenant) {
if (!SnapShotSwitch.getIsSnapShot()) {
return null;
}
File file = getSnapshotFile(name, dataId, group, tenant);
if (!file.exists() || !file.isFile()) {
return null;
}
try {
return readFile(file);
} catch (IOException ioe) {
log.error(name, "NACOS-XXXX","get snapshot error, " + file + ", " + ioe.toString());
return null;
}
}
static private String readFile(File file) throws IOException {
if (!file.exists() || !file.isFile()) {
return null;
}
if (JVMUtil.isMultiInstance()) {
return ConcurrentDiskUtil.getFileContent(file, Constants.ENCODE);
} else {
InputStream is = null;
try {
is = new FileInputStream(file);
return IOUtils.toString(is, Constants.ENCODE);
} finally {
try {
if (null != is) {
is.close();
}
} catch (IOException ioe) {
}
}
}
}
static public void saveSnapshot(String envName, String dataId, String group, String tenant, String config) {
if (!SnapShotSwitch.getIsSnapShot()) {
return;
}
File file = getSnapshotFile(envName, dataId, group, tenant);
if (null == config) {
try {
IOUtils.delete(file);
} catch (IOException ioe) {
log.error(envName, "NACOS-XXXX","delete snapshot error, " + file + ", " + ioe.toString());
}
} else {
try {
boolean isMdOk = file.getParentFile().mkdirs();
if (!isMdOk) {
log.error(envName, "NACOS-XXXX", "save snapshot error");
}
if (JVMUtil.isMultiInstance()) {
ConcurrentDiskUtil.writeFileContent(file, config,
Constants.ENCODE);
} else {
IOUtils.writeStringToFile(file, config, Constants.ENCODE);
}
} catch (IOException ioe) {
log.error(envName, "NACOS-XXXX","save snapshot error, " + file + ", " + ioe.toString());
}
}
}
/**
* 清除snapshot目录下所有缓存文件
*/
static public void cleanAllSnapshot() {
try {
File rootFile = new File(LOCAL_SNAPSHOT_PATH);
File[] files = rootFile.listFiles();
if (files == null || files.length == 0) {
return;
}
for(File file : files){
if(file.getName().endsWith("_nacos")){
IOUtils.cleanDirectory(file);
}
}
} catch (IOException ioe) {
log.error("NACOS-XXXX","clean all snapshot error, " + ioe.toString(), ioe);
}
}
static public void cleanEnvSnapshot(String envName){
File tmp = new File(LOCAL_SNAPSHOT_PATH, envName + "_nacos");
tmp = new File(tmp, "snapshot");
try {
IOUtils.cleanDirectory(tmp);
log.info("success dlelet " + envName + "-snapshot");
} catch (IOException e) {
log.info("fail dlelet " + envName + "-snapshot, " + e.toString());
e.printStackTrace();
}
}
static File getFailoverFile(String serverName, String dataId, String group, String tenant) {
File tmp = new File(LOCAL_SNAPSHOT_PATH, serverName + "_nacos");
tmp = new File(tmp, "data");
if (StringUtils.isBlank(tenant)) {
tmp = new File(tmp, "config-data");
} else
{
tmp = new File(tmp, "config-data-tenant");
tmp = new File(tmp, tenant);
}
return new File(new File(tmp, group), dataId);
}
static File getSnapshotFile(String envName, String dataId, String group, String tenant) {
File tmp = new File(LOCAL_SNAPSHOT_PATH, envName + "_nacos");
if (StringUtils.isBlank(tenant)) {
tmp = new File(tmp, "snapshot");
} else {
tmp = new File(tmp, "snapshot-tenant");
tmp = new File(tmp, tenant);
}
return new File(new File(tmp, group), dataId);
}
public static final String LOCAL_FILEROOT_PATH;
public static final String LOCAL_SNAPSHOT_PATH;
static {
LOCAL_FILEROOT_PATH = System.getProperty("JM.LOG.PATH", System.getProperty("user.home")) + File.separator
+ "nacos" + File.separator + "config";
LOCAL_SNAPSHOT_PATH = System.getProperty("JM.SNAPSHOT.PATH", System.getProperty("user.home")) + File.separator
+ "nacos" + File.separator + "config";
log.warn("LOCAL_SNAPSHOT_PATH:{}", LOCAL_SNAPSHOT_PATH);
}
}

View File

@ -0,0 +1,392 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.io.IOException;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.SocketTimeoutException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import org.codehaus.jackson.annotate.JsonProperty;
import org.codehaus.jackson.type.TypeReference;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.config.impl.HttpSimpleClient.HttpResult;
import com.alibaba.nacos.client.config.utils.IOUtils;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.identify.STSConfig;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.utils.JSONUtils;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Server Agent
*
* @author water.lyl
*
*/
public class ServerHttpAgent {
final static public Logger log = LogUtils.logger(ServerHttpAgent.class);
/**
* @param path
* 相对于web应用根/开头
* @param headers
* @param paramValues
* @param encoding
* @param readTimeoutMs
* @return
* @throws IOException
*/
public HttpResult httpGet(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
final long endTime = System.currentTimeMillis() + readTimeoutMs;
boolean isSSL = false;
do {
try {
List<String> newHeaders = getSpasHeaders(paramValues);
if (headers != null) {
newHeaders.addAll(headers);
}
HttpResult result = HttpSimpleClient.httpGet(
getUrl(serverListMgr.getCurrentServerAddr(), path, isSSL), newHeaders, paramValues, encoding,
readTimeoutMs, isSSL);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
log.error("NACOS ConnectException", "currentServerAddr:{}. httpCode:",
new Object[] { serverListMgr.getCurrentServerAddr(), result.code });
} else {
return result;
}
} catch (ConnectException ce) {
log.error("NACOS ConnectException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr() });
serverListMgr.refreshCurrentServerAddr();
} catch (SocketTimeoutException stoe) {
log.error("NACOS SocketTimeoutException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
serverListMgr.refreshCurrentServerAddr();
} catch (IOException ioe) {
log.error("NACOS IOException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
throw ioe;
}
} while (System.currentTimeMillis() > endTime);
log.error("NACOS-0002",
LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0002", "环境问题", "no available server"));
throw new ConnectException("no available server");
}
public HttpResult httpPost(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
final long endTime = System.currentTimeMillis() + readTimeoutMs;
boolean isSSL = false;
do {
try {
List<String> newHeaders = getSpasHeaders(paramValues);
if (headers != null) {
newHeaders.addAll(headers);
}
HttpResult result = HttpSimpleClient.httpPost(
getUrl(serverListMgr.getCurrentServerAddr(), path, isSSL), newHeaders, paramValues, encoding,
readTimeoutMs, isSSL);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
log.error("NACOS ConnectException", "currentServerAddr:{}. httpCode:",
new Object[] { serverListMgr.getCurrentServerAddr(), result.code });
} else {
return result;
}
} catch (ConnectException ce) {
log.error("NACOS ConnectException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
serverListMgr.refreshCurrentServerAddr();
} catch (SocketTimeoutException stoe) {
log.error("NACOS SocketTimeoutException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
serverListMgr.refreshCurrentServerAddr();
} catch (IOException ioe) {
log.error("NACOS IOException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
throw ioe;
}
} while (System.currentTimeMillis() > endTime);
log.error("NACOS-0002",
LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0002", "环境问题", "no available server"));
throw new ConnectException("no available server");
}
public HttpResult httpDelete(String path, List<String> headers, List<String> paramValues, String encoding,
long readTimeoutMs) throws IOException {
final long endTime = System.currentTimeMillis() + readTimeoutMs;
boolean isSSL = false;
do {
try {
List<String> newHeaders = getSpasHeaders(paramValues);
if (headers != null) {
newHeaders.addAll(headers);
}
HttpResult result = HttpSimpleClient.httpDelete(
getUrl(serverListMgr.getCurrentServerAddr(), path, isSSL), newHeaders, paramValues, encoding,
readTimeoutMs, isSSL);
if (result.code == HttpURLConnection.HTTP_INTERNAL_ERROR
|| result.code == HttpURLConnection.HTTP_BAD_GATEWAY
|| result.code == HttpURLConnection.HTTP_UNAVAILABLE) {
log.error("NACOS ConnectException", "currentServerAddr:{}. httpCode:",
new Object[] { serverListMgr.getCurrentServerAddr(), result.code });
} else {
return result;
}
} catch (ConnectException ce) {
log.error("NACOS ConnectException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
serverListMgr.refreshCurrentServerAddr();
} catch (SocketTimeoutException stoe) {
log.error("NACOS SocketTimeoutException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
serverListMgr.refreshCurrentServerAddr();
} catch (IOException ioe) {
log.error("NACOS IOException", "currentServerAddr:{}",
new Object[] { serverListMgr.getCurrentServerAddr()});
throw ioe;
}
} while (System.currentTimeMillis() > endTime);
log.error("NACOS-0002",
LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0002", "环境问题", "no available server"));
throw new ConnectException("no available server");
}
private String getUrl(String serverAddr, String relativePath, boolean isSSL) {
String httpPrefix = "http://";
if (isSSL) {
httpPrefix = "https://";
}
return httpPrefix + serverAddr + "/" + serverListMgr.getContentPath() + relativePath;
}
public static String getAppname() {
return ParamUtil.getAppName();
}
public ServerHttpAgent(ServerListManager mgr) {
serverListMgr = mgr;
}
public ServerHttpAgent(ServerListManager mgr, Properties properties) {
serverListMgr = mgr;
String ak = properties.getProperty(PropertyKeyConst.ACCESS_KEY);
if (StringUtils.isBlank(ak)) {
accessKey = SpasAdapter.getAk();
} else {
accessKey = ak;
}
String sk = properties.getProperty(PropertyKeyConst.SECRET_KEY);
if (StringUtils.isBlank(sk)) {
secretKey = SpasAdapter.getSk();
} else {
secretKey = sk;
}
}
public ServerHttpAgent(Properties properties) throws NacosException {
String encodeTmp = properties.getProperty(PropertyKeyConst.ENCODE);
if (StringUtils.isBlank(encodeTmp)) {
encode = Constants.ENCODE;
} else {
encode = encodeTmp.trim();
}
serverListMgr = new ServerListManager(properties);
String ak = properties.getProperty(PropertyKeyConst.ACCESS_KEY);
if (StringUtils.isBlank(ak)) {
accessKey = SpasAdapter.getAk();
} else {
accessKey = ak;
}
String sk = properties.getProperty(PropertyKeyConst.SECRET_KEY);
if (StringUtils.isBlank(sk)) {
secretKey = SpasAdapter.getSk();
} else {
secretKey = sk;
}
}
public synchronized void start() throws NacosException {
serverListMgr.start();
}
private List<String> getSpasHeaders(List<String> paramValues) throws IOException {
List<String> newHeaders = new ArrayList<String>();
// STS 临时凭证鉴权的优先级高于 AK/SK 鉴权
if (STSConfig.getInstance().isSTSOn()) {
STSCredential sTSCredential = getSTSCredential();
accessKey = sTSCredential.accessKeyId;
secretKey = sTSCredential.accessKeySecret;
newHeaders.add("Spas-SecurityToken");
newHeaders.add(sTSCredential.securityToken);
}
if (StringUtils.isNotEmpty(accessKey) && StringUtils.isNotEmpty(secretKey)) {
newHeaders.add("Spas-AccessKey");
newHeaders.add(accessKey);
List<String> signHeaders = SpasAdapter.getSignHeaders(paramValues, secretKey);
if (signHeaders != null) {
newHeaders.addAll(signHeaders);
}
}
return newHeaders;
}
private STSCredential getSTSCredential() throws IOException {
boolean cacheSecurityCredentials = STSConfig.getInstance().isCacheSecurityCredentials();
if (cacheSecurityCredentials && sTSCredential != null) {
long currentTime = System.currentTimeMillis();
long expirationTime = sTSCredential.expiration.getTime();
int timeToRefreshInMillisecond = STSConfig.getInstance().getTimeToRefreshInMillisecond();
if (expirationTime - currentTime > timeToRefreshInMillisecond) {
return sTSCredential;
}
}
String stsResponse = getSTSResponse();
STSCredential stsCredentialTmp = (STSCredential)JSONUtils.deserializeObject(stsResponse,
new TypeReference<STSCredential>() {});
sTSCredential = stsCredentialTmp;
log.info("getSTSCredential", "code:{}, accessKeyId:{}, lastUpdated:{}, expiration:{}", sTSCredential.getCode(),
sTSCredential.getAccessKeyId(), sTSCredential.getLastUpdated(), sTSCredential.getExpiration());
return sTSCredential;
}
private static String getSTSResponse() throws IOException {
String securityCredentials = STSConfig.getInstance().getSecurityCredentials();
if (securityCredentials != null) {
return securityCredentials;
}
String securityCredentialsUrl = STSConfig.getInstance().getSecurityCredentialsUrl();
HttpURLConnection conn = null;
int respCode;
String response;
try {
conn = (HttpURLConnection)new URL(securityCredentialsUrl).openConnection();
conn.setRequestMethod("GET");
conn.setConnectTimeout(ParamUtil.getConnectTimeout() > 100 ? ParamUtil.getConnectTimeout() : 100);
conn.setReadTimeout(1000);
conn.connect();
respCode = conn.getResponseCode();
if (HttpURLConnection.HTTP_OK == respCode) {
response = IOUtils.toString(conn.getInputStream(), Constants.ENCODE);
} else {
response = IOUtils.toString(conn.getErrorStream(), Constants.ENCODE);
}
} catch (IOException e) {
log.error("500", "can not get security credentials", e);
throw e;
} finally {
if (null != conn) {
conn.disconnect();
}
}
if (HttpURLConnection.HTTP_OK == respCode) {
return response;
}
log.error(respCode + "", "can not get security credentials, securityCredentialsUrl:{}, response:{}",
new Object[] {securityCredentialsUrl, response});
throw new IOException("can not get security credentials, responseCode: " + respCode + ", response: " + response);
}
public String getName() {
return serverListMgr.getName();
}
public String getNamespace() {
return serverListMgr.getNamespace();
}
public String getTenant() {
return serverListMgr.getTenant();
}
public String getEncode() {
return encode;
}
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
private static class STSCredential {
@JsonProperty(value = "AccessKeyId")
private String accessKeyId;
@JsonProperty(value = "AccessKeySecret")
private String accessKeySecret;
@JsonProperty(value = "Expiration")
private Date expiration;
@JsonProperty(value = "SecurityToken")
private String securityToken;
@JsonProperty(value = "LastUpdated")
private Date lastUpdated;
@JsonProperty(value = "Code")
private String code;
public String getAccessKeyId() {
return accessKeyId;
}
public Date getExpiration() {
return expiration;
}
public Date getLastUpdated() {
return lastUpdated;
}
public String getCode() {
return code;
}
public String toString() {
return "STSCredential{" +
"accessKeyId='" + accessKeyId + '\'' +
", accessKeySecret='" + accessKeySecret + '\'' +
", expiration=" + expiration +
", securityToken='" + securityToken + '\'' +
", lastUpdated=" + lastUpdated +
", code='" + code + '\'' +
'}';
}
}
private String accessKey;
private String secretKey;
private String encode;
private volatile STSCredential sTSCredential;
final ServerListManager serverListMgr;
}

View File

@ -0,0 +1,432 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.io.IOException;
import java.io.StringReader;
import java.net.HttpURLConnection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import com.alibaba.nacos.api.PropertyKeyConst;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.config.impl.EventDispatcher.ServerlistChangeEvent;
import com.alibaba.nacos.client.config.impl.HttpSimpleClient.HttpResult;
import com.alibaba.nacos.client.config.utils.IOUtils;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.utils.EnvUtil;
import com.alibaba.nacos.client.utils.ParamUtil;
import com.alibaba.nacos.client.utils.StringUtils;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Serverlist Manager
*
* @author Nacos
*/
public class ServerListManager {
final static public Logger log = LogUtils.logger(ServerListManager.class);
public ServerListManager() {
isFixed = false;
isStarted = false;
name = DEFAULT_NAME;
}
public ServerListManager(List<String> fixed) {
this(fixed, null);
}
public ServerListManager(List<String> fixed, String namespace) {
isFixed = true;
isStarted = true;
List<String> serverAddrs = new ArrayList<String>();
for (String serverAddr : fixed) {
String[] serverAddrArr = serverAddr.split(":");
if (serverAddrArr.length == 1) {
serverAddrs.add(serverAddrArr[0] + ":" + ParamUtil.getDefaultServerPort());
} else {
serverAddrs.add(serverAddr);
}
}
serverUrls = new ArrayList<String>(serverAddrs);
if (StringUtils.isBlank(namespace)) {
name = FIXED_NAME + "-" + getFixedNameSuffix(serverAddrs.toArray(new String[serverAddrs.size()]));
} else {
this.namespace = namespace;
name = FIXED_NAME + "-" + getFixedNameSuffix(serverAddrs.toArray(new String[serverAddrs.size()])) + "-"
+ namespace;
}
}
public ServerListManager(String host, int port) {
isFixed = false;
isStarted = false;
name = CUSTOM_NAME + "-" + host + "-" + port;
addressServerUrl = String.format("http://%s:%d/%s/%s", host, port, contentPath, serverListName);
}
public ServerListManager(String endpoint) throws NacosException {
this(endpoint, null);
}
public ServerListManager(String endpoint, String namespace) throws NacosException {
isFixed = false;
isStarted = false;
if (StringUtils.isBlank(endpoint)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "endpoint is blank");
}
if (StringUtils.isBlank(namespace)) {
name = endpoint;
addressServerUrl = String.format("http://%s:%d/%s/%s", endpoint, endpointPort, contentPath,
serverListName);
} else {
if (StringUtils.isBlank(endpoint)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "endpoint is blank");
}
name = endpoint + "-" + namespace;
this.namespace = namespace;
this.tenant = namespace;
addressServerUrl = String.format("http://%s:%d/%s/%s?namespace=%s", endpoint, endpointPort, contentPath,
serverListName, namespace);
}
}
public ServerListManager(Properties properties) throws NacosException {
isStarted = false;
String serverAddrsStr = properties.getProperty(PropertyKeyConst.SERVER_ADDR);
String namespace = properties.getProperty(PropertyKeyConst.NAMESPACE);
initParam(properties);
if (StringUtils.isNotEmpty(serverAddrsStr)) {
isFixed = true;
List<String> serverAddrs = new ArrayList<String>();
String[] serverAddrsArr = serverAddrsStr.split(",");
for (String serverAddr : serverAddrsArr) {
String[] serverAddrArr = serverAddr.split(":");
if (serverAddrArr.length == 1) {
serverAddrs.add(serverAddrArr[0] + ":" + ParamUtil.getDefaultServerPort());
} else {
serverAddrs.add(serverAddr);
}
}
serverUrls = serverAddrs;
if (StringUtils.isBlank(namespace)) {
name = FIXED_NAME + "-" + getFixedNameSuffix(serverUrls.toArray(new String[serverUrls.size()]));
} else {
this.namespace = namespace;
this.tenant = namespace;
name = FIXED_NAME + "-" + getFixedNameSuffix(serverUrls.toArray(new String[serverUrls.size()])) + "-"
+ namespace;
}
} else {
if (StringUtils.isBlank(endpoint)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "endpoint is blank");
}
isFixed = false;
if (StringUtils.isBlank(namespace)) {
name = endpoint;
addressServerUrl = String.format("http://%s:%d/%s/%s", endpoint, endpointPort, contentPath,
serverListName);
} else {
this.namespace = namespace;
this.tenant = namespace;
name = endpoint + "-" + namespace;
addressServerUrl = String.format("http://%s:%d/%s/%s?namespace=%s", endpoint, endpointPort,
contentPath, serverListName, namespace);
}
}
}
private void initParam(Properties properties) {
String endpointTmp = properties.getProperty(PropertyKeyConst.ENDPOINT);
if (!StringUtils.isBlank(endpointTmp)) {
endpoint = endpointTmp;
}
String contentPathTmp = properties.getProperty(PropertyKeyConst.CONTEXT_PATH);
if (!StringUtils.isBlank(contentPathTmp)) {
contentPath = contentPathTmp;
}
String serverListNameTmp = properties.getProperty(PropertyKeyConst.CLUSTER_NAME);
if (!StringUtils.isBlank(serverListNameTmp)) {
serverListName = serverListNameTmp;
}
}
public synchronized void start() throws NacosException {
if (isStarted || isFixed) {
return;
}
GetServerListTask getServersTask = new GetServerListTask(addressServerUrl);
for (int i = 0; i < initServerlistRetryTimes && serverUrls.isEmpty(); ++i) {
getServersTask.run();
try {
this.wait((i + 1) * 100L);
} catch (Exception e) {
log.warn("get serverlist fail,url: " + addressServerUrl);
}
}
if (serverUrls.isEmpty()) {
log.error("NACOS-0008", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0008", "环境问题",
"fail to get NACOS-server serverlist! env:" + name + ", not connnect url:" + addressServerUrl));
log.error(name, "NACOS-XXXX", "[init-serverlist] fail to get NACOS-server serverlist!");
throw new NacosException(NacosException.SERVER_ERROR,
"fail to get NACOS-server serverlist! env:" + name + ", not connnect url:" + addressServerUrl);
}
TimerService.scheduleWithFixedDelay(getServersTask, 0L, 30L, TimeUnit.SECONDS);
isStarted = true;
}
Iterator<String> iterator() {
if (serverUrls.isEmpty()) {
log.error(name, "NACOS-XXXX", "[iterator-serverlist] No server address defined!");
}
return new ServerAddressIterator(serverUrls);
}
class GetServerListTask implements Runnable {
final String url;
GetServerListTask(String url) {
this.url = url;
}
@Override
public void run() {
/**
* get serverlist from nameserver
*/
try {
updateIfChanged(getApacheServerList(url, name));
} catch (Exception e) {
log.error(name, "NACOS-XXXX", "[update-serverlist] failed to update serverlist from address server!", e);
}
}
}
private void updateIfChanged(List<String> newList) {
if (null == newList || newList.isEmpty()) {
log.warn("NACOS-0001", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0001", "环境问题","[update-serverlist] current serverlist from address server is empty!!!"));
log.warn(name, "[update-serverlist] current serverlist from address server is empty!!!");
return;
}
/**
* no change
*/
if (newList.equals(serverUrls)) {
return;
}
serverUrls = new ArrayList<String>(newList);
currentServerAddr = iterator().next();
EventDispatcher.fireEvent(new ServerlistChangeEvent());
log.info(name, "[update-serverlist] serverlist updated to {}", serverUrls);
}
private List<String> getApacheServerList(String url, String name) {
try {
HttpResult httpResult = HttpSimpleClient.httpGet(url, null, null, null, 3000);
if (HttpURLConnection.HTTP_OK == httpResult.code) {
if (DEFAULT_NAME.equals(name) ) {
EnvUtil.setSelfEnv(httpResult.headers);
}
List<String> lines = IOUtils.readLines(new StringReader(httpResult.content));
List<String> result = new ArrayList<String>(lines.size());
for (String serverAddr : lines) {
if (null == serverAddr || serverAddr.trim().isEmpty()) {
continue;
} else {
String[] ipPort = serverAddr.trim().split(":");
String ip = ipPort[0].trim();
if (ipPort.length == 1) {
result.add(ip + ":" + ParamUtil.getDefaultServerPort());
} else {
result.add(serverAddr);
}
}
}
return result;
} else {
log.error(addressServerUrl, "NACOS-XXXX", "[check-serverlist] error. code={}", httpResult.code);
return null;
}
} catch (IOException e) {
log.error("NACOS-0001", LoggerHelper.getErrorCodeStr("NACOS", "NACOS-0001", "环境问题",e.toString()));
log.error(addressServerUrl, "NACOS-XXXX", "[check-serverlist] exception. msg={}", e.toString(), e);
return null;
}
}
String getUrlString() {
return serverUrls.toString();
}
String getFixedNameSuffix(String... serverIps) {
StringBuilder sb = new StringBuilder();
String split = "";
for (String serverIp : serverIps) {
sb.append(split);
sb.append(serverIp);
split = "-";
}
return sb.toString();
}
@Override
public String toString() {
return "ServerManager-" + name + "-" +getUrlString();
}
public boolean contain(String ip){
return serverUrls.contains(ip);
}
public void refreshCurrentServerAddr() {
currentServerAddr = iterator().next();
}
public String getCurrentServerAddr() {
if (StringUtils.isBlank(currentServerAddr)) {
currentServerAddr = iterator().next();
}
return currentServerAddr;
}
public String getContentPath() {
return contentPath;
}
public String getName() {
return name;
}
public String getNamespace() {
return namespace;
}
public String getTenant() {
return tenant;
}
/**
* 不同环境的名称
*/
private String name;
private String namespace = "";
private String tenant = "";
static public final String DEFAULT_NAME = "default";
static public final String CUSTOM_NAME = "custom";
static public final String FIXED_NAME = "fixed";
private int initServerlistRetryTimes = 5;
/**
* 和其他server的连接超时和socket超时
*/
static final int TIMEOUT = 5000;
final boolean isFixed;
boolean isStarted = false;
private String endpoint;
private int endpointPort = 8080;
private String contentPath = ParamUtil.getDefaultContextPath();
private String serverListName = ParamUtil.getDefaultNodesPath();
volatile List<String> serverUrls = new ArrayList<String>();
private volatile String currentServerAddr;
public String serverPort = ParamUtil.getDefaultServerPort();
public String addressServerUrl;
}
/**
* 对地址列表排序同机房优先
*/
class ServerAddressIterator implements Iterator<String> {
static class RandomizedServerAddress implements Comparable<RandomizedServerAddress> {
static Random random = new Random();
String serverIp;
int priority = 0;
int seed;
public RandomizedServerAddress(String ip) {
try {
this.serverIp = ip;
/**
* change random scope from 32 to Integer.MAX_VALUE to fix load balance issue
*/
this.seed = random.nextInt(Integer.MAX_VALUE);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
@SuppressFBWarnings("EQ_COMPARETO_USE_OBJECT_EQUALS")
public int compareTo(RandomizedServerAddress other) {
if (this.priority != other.priority) {
return other.priority - this.priority;
} else {
return other.seed - this.seed;
}
}
}
public ServerAddressIterator(List<String> source) {
sorted = new ArrayList<RandomizedServerAddress>();
for (String address : source) {
sorted.add(new RandomizedServerAddress(address));
}
Collections.sort(sorted);
iter = sorted.iterator();
}
public boolean hasNext() {
return iter.hasNext();
}
public String next() {
return iter.next().serverIp;
}
public void remove() {
throw new UnsupportedOperationException();
}
final List<RandomizedServerAddress> sorted;
final Iterator<RandomizedServerAddress> iter;
}

View File

@ -0,0 +1,111 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.identify.Base64;
import com.alibaba.nacos.client.identify.CredentialService;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* 适配spas接口
*
* @author Nacos
*
*/
public class SpasAdapter {
public static List<String> getSignHeaders(String resource, String secretKey) {
List<String> header = new ArrayList<String>();
String timeStamp = String.valueOf(System.currentTimeMillis());
header.add("Timestamp");
header.add(timeStamp);
if (secretKey != null) {
header.add("Spas-Signature");
String signature = "";
if (StringUtils.isBlank(resource)) {
signature = signWithhmacSHA1Encrypt(timeStamp, secretKey);
} else {
signature = signWithhmacSHA1Encrypt(resource + "+" + timeStamp, secretKey);
}
header.add(signature);
}
return header;
}
public static List<String> getSignHeaders(List<String> paramValues, String secretKey) {
if (null == paramValues) {
return null;
}
Map<String, String> signMap = new HashMap<String, String>(5);
for (Iterator<String> iter = paramValues.iterator(); iter.hasNext();) {
String key = iter.next();
if (TENANT_KEY.equals(key) || GROUP_KEY.equals(key)) {
signMap.put(key, iter.next());
} else {
iter.next();
}
}
String resource = "";
if (signMap.size() > 1) {
resource = signMap.get(TENANT_KEY) + "+" + signMap.get(GROUP_KEY);
} else {
if (!StringUtils.isBlank(signMap.get(GROUP_KEY))) {
resource = signMap.get(GROUP_KEY);
}
}
return getSignHeaders(resource, secretKey);
}
public static String getSk() {
return CredentialService.getInstance().getCredential().getSecretKey();
}
public static String getAk() {
return CredentialService.getInstance().getCredential().getAccessKey();
}
public static String signWithhmacSHA1Encrypt(String encryptText, String encryptKey) {
try {
byte[] data = encryptKey.getBytes("UTF-8");
// 根据给定的字节数组构造一个密钥,第二参数指定一个密钥算法的名称
SecretKey secretKey = new SecretKeySpec(data, "HmacSHA1");
// 生成一个指定 Mac 算法 Mac 对象
Mac mac = Mac.getInstance("HmacSHA1");
// 用给定密钥初始化 Mac 对象
mac.init(secretKey);
byte[] text = encryptText.getBytes("UTF-8");
byte[] textFinal = mac.doFinal(text);
// 完成 Mac 操作, base64编码将byte数组转换为字符串
return new String(Base64.encodeBase64(textFinal), Constants.ENCODE);
} catch (Exception e) {
throw new RuntimeException("signWithhmacSHA1Encrypt fail", e);
}
}
private static String GROUP_KEY = "group";
private static String TENANT_KEY = "tenant";
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.impl;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
/**
* Time Service
* @author Nacos
*
*/
public class TimerService {
static public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay,
long delay, TimeUnit unit) {
return scheduledExecutor.scheduleWithFixedDelay(command, initialDelay, delay, unit);
}
@SuppressWarnings("PMD.ThreadPoolCreationRule")
static ScheduledExecutorService scheduledExecutor = Executors
.newSingleThreadScheduledExecutor(new ThreadFactory() {
public Thread newThread(Runnable r) {
Thread t = new Thread(r);
t.setName("com.alibaba.nacos.client.Timer");
t.setDaemon(true);
return t;
}
});
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.listener.impl;
import com.alibaba.nacos.api.config.listener.AbstractListener;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.utils.StringUtils;
import java.io.IOException;
import java.io.StringReader;
import java.util.Properties;
/**
* Properties Listener
*
* @author Nacos
*
*/
@SuppressWarnings("PMD.AbstractClassShouldStartWithAbstractNamingRule")
public abstract class PropertiesListener extends AbstractListener {
final static public Logger log = LogUtils.logger(PropertiesListener.class);
public void receiveConfigInfo(String configInfo) {
if (StringUtils.isEmpty(configInfo)) {
return;
}
Properties properties = new Properties();
try {
properties.load(new StringReader(configInfo));
innerReceive(properties);
}
catch (IOException e) {
log.error("NACOS-XXXX","load properties error" + configInfo, e);
}
}
/**
* properties type for receiver
*
* @param properties
* properties
*/
public abstract void innerReceive(Properties properties);
}

View File

@ -0,0 +1,247 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.logger.Logger;
/**
* concurrent disk util;op file with file lock
*
* @author configCenter
*
*/
public class ConcurrentDiskUtil {
/**
* get file content
*
* @param path
* file path
* @param charsetName
* charsetName
* @return content
* @throws IOException
* IOException
*/
public static String getFileContent(String path, String charsetName)
throws IOException {
File file = new File(path);
return getFileContent(file, charsetName);
}
/**
* get file content
*
* @param file
* file
* @param charsetName
* charsetName
* @return content
* @throws IOException
* IOException
*/
public static String getFileContent(File file, String charsetName)
throws IOException {
RandomAccessFile fis = null;
FileLock rlock = null;
try {
fis = new RandomAccessFile(file, "r");
FileChannel fcin = fis.getChannel();
int i = 0;
do {
try {
rlock = fcin.tryLock(0L, Long.MAX_VALUE, true);
} catch (Exception e) {
++i;
if (i > RETRY_COUNT) {
log.error("read {} fail;retryed time:{}",
file.getName(), i);
throw new IOException("read " + file.getAbsolutePath()
+ " conflict");
}
sleep(SLEEP_BASETIME * i);
log.warn("read {} conflict;retry time:{}", file.getName(),
i);
}
} while (null == rlock);
int fileSize = (int) fcin.size();
ByteBuffer byteBuffer = ByteBuffer.allocate(fileSize);
fcin.read(byteBuffer);
byteBuffer.flip();
return byteBufferToString(byteBuffer, charsetName);
} finally {
if (rlock != null) {
rlock.release();
rlock = null;
}
if (fis != null) {
fis.close();
fis = null;
}
}
}
/**
* write file content
*
* @param path
* file path
* @param content
* content
* @param charsetName
* charsetName
* @return whether write ok
* @throws IOException
* IOException
*/
public static Boolean writeFileContent(String path, String content,
String charsetName) throws IOException {
File file = new File(path);
return writeFileContent(file, content, charsetName);
}
/**
* write file content
*
* @param file
* file
* @param content
* content
* @param charsetName
* charsetName
* @return whether write ok
* @throws IOException
* IOException
*/
public static Boolean writeFileContent(File file, String content,
String charsetName) throws IOException {
if (!file.exists()) {
boolean isCreateOk = file.createNewFile();
if (!isCreateOk) {
return false;
}
}
FileChannel channel = null;
FileLock lock = null;
RandomAccessFile raf = null;
try {
raf = new RandomAccessFile(file, "rw");
channel = raf.getChannel();
int i = 0;
do {
try {
lock = channel.tryLock();
} catch (Exception e) {
++i;
if (i > RETRY_COUNT) {
log.error("write {} fail;retryed time:{}",
file.getName(), i);
throw new IOException("write " + file.getAbsolutePath()
+ " conflict");
}
sleep(SLEEP_BASETIME * i);
log.warn("write {} conflict;retry time:{}", file.getName(),
i);
}
} while (null == lock);
ByteBuffer sendBuffer = ByteBuffer.wrap(content
.getBytes(charsetName));
while (sendBuffer.hasRemaining()) {
channel.write(sendBuffer);
}
channel.truncate(content.length());
} catch (FileNotFoundException e) {
throw new IOException("file not exist");
} finally {
if (lock != null) {
try {
lock.release();
lock = null;
} catch (IOException e) {
log.warn("close wrong", e);
}
}
if (channel != null) {
try {
channel.close();
channel = null;
} catch (IOException e) {
log.warn("close wrong", e);
}
}
if (raf != null) {
try {
raf.close();
raf = null;
} catch (IOException e) {
log.warn("close wrong", e);
}
}
}
return true;
}
/**
* transfer ByteBuffer to String
*
* @param buffer
* buffer
* @param charsetName
* charsetName
* @return String
* @throws IOException
* IOException
*/
public static String byteBufferToString(ByteBuffer buffer,
String charsetName) throws IOException {
Charset charset = null;
CharsetDecoder decoder = null;
CharBuffer charBuffer = null;
charset = Charset.forName(charsetName);
decoder = charset.newDecoder();
charBuffer = decoder.decode(buffer.asReadOnlyBuffer());
return charBuffer.toString();
}
private static void sleep(int time) {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
log.warn("sleep wrong", e);
}
}
static final public Logger log = LogUtils.logger(ConcurrentDiskUtil.class);
static final int RETRY_COUNT = 10;
/**
* ms
*/
static final int SLEEP_BASETIME = 10;
}

View File

@ -0,0 +1,78 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import static com.alibaba.nacos.client.config.common.Constants.WORD_SEPARATOR;
import com.alibaba.nacos.client.config.common.Constants;
/**
* Content Util
*
* @author Nacos
*
*/
public class ContentUtils {
public static void verifyIncrementPubContent(String content) {
if (content == null || content.length() == 0) {
throw new IllegalArgumentException("发布/删除内容不能为空");
}
for (int i = 0; i < content.length(); i++) {
char c = content.charAt(i);
if (c == '\r' || c == '\n') {
throw new IllegalArgumentException("发布/删除内容不能包含回车和换行");
}
if (c == Constants.WORD_SEPARATOR.charAt(0)) {
throw new IllegalArgumentException("发布/删除内容不能包含(char)2");
}
}
}
public static String getContentIdentity(String content) {
int index = content.indexOf(WORD_SEPARATOR);
if (index == -1) {
throw new IllegalArgumentException("内容没有包含分隔符");
}
return content.substring(0, index);
}
public static String getContent(String content) {
int index = content.indexOf(WORD_SEPARATOR);
if (index == -1) {
throw new IllegalArgumentException("内容没有包含分隔符");
}
return content.substring(index + 1);
}
public static String truncateContent(String content) {
if (content == null) {
return "";
}
else if (content.length() <= SHOW_CONTENT_SIZE) {
return content;
}
else {
return content.substring(0, SHOW_CONTENT_SIZE) + "...";
}
}
private static int SHOW_CONTENT_SIZE = 100;
}

View File

@ -0,0 +1,151 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import java.io.BufferedReader;
import java.io.CharArrayWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.nacos.client.config.common.Constants;
/**
* IO Util
*
* @author Nacos
*
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class IOUtils {
static public String toString(InputStream input, String encoding) throws IOException {
return (null == encoding) ? toString(new InputStreamReader(input, Constants.ENCODE))
: toString(new InputStreamReader(input, encoding));
}
static public String toString(Reader reader) throws IOException {
CharArrayWriter sw = new CharArrayWriter();
copy(reader, sw);
return sw.toString();
}
static public long copy(Reader input, Writer output) throws IOException {
char[] buffer = new char[1 << 12];
long count = 0;
for (int n = 0; (n = input.read(buffer)) >= 0;) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
/**
* 从输入流读行列表保证不返回NULL
*/
static public List<String> readLines(Reader input) throws IOException {
BufferedReader reader = toBufferedReader(input);
List<String> list = new ArrayList<String>();
String line = null;
for (;;) {
line = reader.readLine();
if (null != line) {
list.add(line);
} else {
break;
}
}
return list;
}
static private BufferedReader toBufferedReader(Reader reader) {
return reader instanceof BufferedReader ? (BufferedReader) reader : new BufferedReader(
reader);
}
public static void delete(File fileOrDir) throws IOException {
if (fileOrDir == null) {
return;
}
if (fileOrDir.isDirectory()) {
cleanDirectory(fileOrDir);
}
boolean isDeleteOk = fileOrDir.delete();
if (!isDeleteOk) {
throw new IOException("delete fail");
}
}
/**
* 清理目录下的内容
*/
public static void cleanDirectory(File directory) throws IOException {
if (!directory.exists()) {
String message = directory + " does not exist";
throw new IllegalArgumentException(message);
}
if (!directory.isDirectory()) {
String message = directory + " is not a directory";
throw new IllegalArgumentException(message);
}
File[] files = directory.listFiles();
/**
* null if security restricted
*/
if (files == null) {
throw new IOException("Failed to list contents of " + directory);
}
IOException exception = null;
for (File file : files) {
try {
delete(file);
} catch (IOException ioe) {
exception = ioe;
}
}
if (null != exception) {
throw exception;
}
}
public static void writeStringToFile(File file, String data, String encoding)
throws IOException {
OutputStream os = null;
try {
os = new FileOutputStream(file);
os.write(data.getBytes(encoding));
} finally {
if (null != os) {
os.close();
}
}
}
}

View File

@ -0,0 +1,49 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.client.logger.Logger;
/**
* Get jvm config
*
* @author Nacos
*
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class JVMUtil {
/**
* whether is multi instance
*
* @return whether multi
*/
public static Boolean isMultiInstance() {
return isMultiInstance;
}
private static Boolean isMultiInstance = false;
private static String TRUE = "true";
static final public Logger log = LogUtils.logger(JVMUtil.class);
static {
String multiDeploy = System.getProperty("isMultiInstance", "false");
if (TRUE.equals(multiDeploy)) {
isMultiInstance = true;
}
log.info("isMultiInstance:{}", isMultiInstance);
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.client.config.common.Constants;
import com.alibaba.nacos.client.logger.Level;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.LoggerFactory;
/**
* Log Util
*
* @author Nacos
*
*/
public class LogUtils {
static int JM_LOG_RETAIN_COUNT = 7;
static String JM_LOG_FILE_SIZE = "10MB";
static {
String tmp = "7";
try {
/**
* change timeout from 100 to 200
*/
tmp = System.getProperty("JM.LOG.RETAIN.COUNT","7");
JM_LOG_RETAIN_COUNT = Integer.parseInt(tmp);
} catch (NumberFormatException e) {
e.printStackTrace();
throw e;
}
JM_LOG_FILE_SIZE = System.getProperty("JM.LOG.FILE.SIZE","10MB");
// logger init
Logger logger = LoggerFactory.getLogger("com.alibaba.nacos.client.config");
logger.setLevel(Level.INFO);
logger.setAdditivity(false);
logger.activateAppenderWithSizeRolling("nacos", "config.log", Constants.ENCODE, JM_LOG_FILE_SIZE, JM_LOG_RETAIN_COUNT);
}
public static Logger logger(Class<?> clazz) {
return LoggerFactory.getLogger(clazz);
}
}

View File

@ -0,0 +1,145 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantLock;
import com.alibaba.nacos.client.config.common.Constants;
/**
* MD5 util
*
* @author Nacos
*
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class MD5 {
private static int DIGITS_SIZE = 16;
private static char[] digits = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
private static Map<Character, Integer> rDigits = new HashMap<Character, Integer>(16);
static {
for (int i = 0; i < digits.length; ++i) {
rDigits.put(digits[i], i);
}
}
private static MD5 me = new MD5();
private MessageDigest mHasher;
private ReentrantLock opLock = new ReentrantLock();
private MD5() {
try {
mHasher = MessageDigest.getInstance("md5");
}
catch (Exception e) {
throw new RuntimeException(e);
}
}
public static MD5 getInstance() {
return me;
}
public String getMD5String(String content) {
return bytes2string(hash(content));
}
public String getMD5String(byte[] content) {
return bytes2string(hash(content));
}
public byte[] getMD5Bytes(byte[] content) {
return hash(content);
}
/**
* 对字符串进行md5
*
* @param str
* @return md5 byte[16]
*/
public byte[] hash(String str) {
opLock.lock();
try {
byte[] bt = mHasher.digest(str.getBytes(Constants.ENCODE));
if (null == bt || bt.length != DIGITS_SIZE) {
throw new IllegalArgumentException("md5 need");
}
return bt;
}
catch (UnsupportedEncodingException e) {
throw new RuntimeException("unsupported utf-8 encoding", e);
}
finally {
opLock.unlock();
}
}
/**
* 对二进制数据进行md5
*
* @param str
* @return md5 byte[16]
*/
public byte[] hash(byte[] data) {
opLock.lock();
try {
byte[] bt = mHasher.digest(data);
if (null == bt || bt.length != DIGITS_SIZE) {
throw new IllegalArgumentException("md5 need");
}
return bt;
}
finally {
opLock.unlock();
}
}
/**
* 将一个字节数组转化为可见的字符串
*
* @param bt
* @return
*/
public String bytes2string(byte[] bt) {
int l = bt.length;
char[] out = new char[l << 1];
for (int i = 0, j = 0; i < l; i++) {
out[j++] = digits[(0xF0 & bt[i]) >>> 4];
out[j++] = digits[0x0F & bt[i]];
}
return new String(out);
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import java.util.List;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.client.utils.IPUtil;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Param check util
*
* @author Nacos
*
*/
public class ParamUtils {
private static char[] validChars = new char[] { '_', '-', '.', ':' };
/**
* 白名单的方式检查, 合法的参数只能包含字母数字以及validChars中的字符, 并且不能为空
*
* @param param
* @return
*/
public static boolean isValid(String param) {
if (param == null) {
return false;
}
int length = param.length();
for (int i = 0; i < length; i++) {
char ch = param.charAt(i);
if (Character.isLetterOrDigit(ch)) {
continue;
}
else if (isValidChar(ch)) {
continue;
}
else {
return false;
}
}
return true;
}
private static boolean isValidChar(char ch) {
for (char c : validChars) {
if (c == ch) {
return true;
}
}
return false;
}
public static void checkKeyParam(String dataId, String group) throws NacosException {
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
if (StringUtils.isBlank(group) || !ParamUtils.isValid(group)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
public static void checkTDG(String tenant, String dataId, String group) throws NacosException {
checkTenant(tenant);
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
if (StringUtils.isBlank(group) || !ParamUtils.isValid(group)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
public static void checkKeyParam(String dataId, String group, String datumId)
throws NacosException {
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
if (StringUtils.isBlank(group) || !ParamUtils.isValid(group)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
if (StringUtils.isBlank(datumId) || !ParamUtils.isValid(datumId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "datumId invalid");
}
}
public static void checkKeyParam(List<String> dataIds, String group) throws NacosException {
if (dataIds == null || dataIds.size() == 0) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataIds invalid");
}
for (String dataId : dataIds) {
if (StringUtils.isBlank(dataId) || !ParamUtils.isValid(dataId)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "dataId invalid");
}
}
if (StringUtils.isBlank(group) || !ParamUtils.isValid(group)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "group invalid");
}
}
public static void checkParam(String dataId, String group, String content) throws NacosException {
checkKeyParam(dataId, group);
if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "content invalid");
}
}
public static void checkParam(String dataId, String group, String datumId, String content) throws NacosException {
checkKeyParam(dataId, group, datumId);
if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "content invalid");
}
}
public static void checkTenant(String tenant) throws NacosException {
if (StringUtils.isBlank(tenant) || !ParamUtils.isValid(tenant)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "tenant invalid");
}
}
public static void checkBetaIps(String betaIps) throws NacosException {
if (StringUtils.isBlank(betaIps)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "betaIps invalid");
}
String[] ipsArr = betaIps.split(",");
for (String ip : ipsArr) {
if (!IPUtil.isIPV4(ip)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "betaIps invalid");
}
}
}
public static void checkContent(String content) throws NacosException {
if (StringUtils.isBlank(content)) {
throw new NacosException(NacosException.CLIENT_INVALID_PARAM, "content invalid");
}
}
}

View File

@ -0,0 +1,42 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.client.config.impl.LocalConfigInfoProcessor;
/**
* Snapshot switch
*
* @author Nacos
*
*/
public class SnapShotSwitch {
/**
* whether use local cache
*/
private static Boolean isSnapShot = true;
public static Boolean getIsSnapShot() {
return isSnapShot;
}
public static void setIsSnapShot(Boolean isSnapShot) {
SnapShotSwitch.isSnapShot = isSnapShot;
LocalConfigInfoProcessor.cleanAllSnapshot();
}
}

View File

@ -0,0 +1,44 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.config.utils;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Tenant Util
*
* @author Nacos
*
*/
public class TenantUtil {
static String userTenant = "";
static {
userTenant = System.getProperty("tenant.id", "");
if (StringUtils.isBlank(userTenant)) {
userTenant = System.getProperty("acm.namespace", "");
}
}
public static String getUserTenant() {
return userTenant;
}
public static void setUserTenant(String userTenant) {
TenantUtil.userTenant = userTenant;
}
}

View File

@ -0,0 +1,707 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.io.UnsupportedEncodingException;
/**
* Provides Base64 encoding and decoding as defined by <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>.
*
* <p>
* This class implements section <cite>6.8. Base64 Content-Transfer-Encoding</cite> from RFC 2045 <cite>Multipurpose
* Internet Mail Extensions (MIME) Part One: Format of Internet Message Bodies</cite> by Freed and Borenstein.
* </p>
* <p>
* The class can be parameterized in the following manner with various constructors:
* <ul>
* <li>URL-safe mode: Default off.</li>
* <li>Line length: Default 76. Line length that aren't multiples of 4 will still essentially end up being multiples of
* 4 in the encoded data.
* <li>Line separator: Default is CRLF ("\r\n")</li>
* </ul>
* </p>
* <p>
* Since this class operates directly on byte streams, and not character streams, it is hard-coded to only encode/decode
* character encodings which are compatible with the lower 127 ASCII chart (ISO-8859-1, Windows-1252, UTF-8, etc).
* </p>
* <p>
* This class is not thread-safe. Each thread should use its own instance.
* </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045</a>
* @author Apache Software Foundation
* @since 1.0
* @version $Revision: 1080712 $
*/
public class Base64 {
/**
* BASE32 characters are 6 bits in length.
* They are formed by taking a block of 3 octets to form a 24-bit string,
* which is converted into 4 BASE64 characters.
*/
private static final int BITS_PER_ENCODED_BYTE = 6;
private static final int BYTES_PER_UNENCODED_BLOCK = 3;
private static final int BYTES_PER_ENCODED_BLOCK = 4;
/**
* Chunk separator per RFC 2045 section 2.1.
*
* <p>
* N.B. The next major release may break compatibility and make this field private.
* </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 2.1</a>
*/
static final byte[] CHUNK_SEPARATOR = {'\r', '\n'};
/**
* This array is a lookup table that translates 6-bit positive integer index values into their "Base64 Alphabet"
* equivalents as specified in Table 1 of RFC 2045.
*
* Thanks to "commons" project in ws.apache.org for this code.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/
private static final byte[] STANDARD_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
};
/**
* This is a copy of the STANDARD_ENCODE_TABLE above, but with + and /
* changed to - and _ to make the encoded Base64 results more URL-SAFE.
* This table is only used when the Base64's mode is set to URL-SAFE.
*/
private static final byte[] URL_SAFE_ENCODE_TABLE = {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_'
};
/**
* This array is a lookup table that translates Unicode characters drawn from the "Base64 Alphabet" (as specified in
* Table 1 of RFC 2045) into their 6-bit positive integer equivalents. Characters that are not in the Base64
* alphabet but fall within the bounds of the array are translated to -1.
*
* Note: '+' and '-' both decode to 62. '/' and '_' both decode to 63. This means decoder seamlessly handles both
* URL_SAFE and STANDARD base64. (The encoder, on the other hand, needs to know ahead of time what to emit).
*
* Thanks to "commons" project in ws.apache.org for this code.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
*/
private static final byte[] DECODE_TABLE = {
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, 62, -1, 63, 52, 53, 54,
55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4,
5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
24, 25, -1, -1, -1, -1, 63, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
};
/**
* Base64 uses 6-bit fields.
*/
/** Mask used to extract 6 bits, used when encoding */
private static final int MASK_6BITS = 0x3f;
// The static final fields above are used for the original static byte[] methods on Base64.
// The private member fields below are used with the new streaming approach, which requires
// some state be preserved between calls of encode() and decode().
/**
* Encode table to use: either STANDARD or URL_SAFE. Note: the DECODE_TABLE above remains static because it is able
* to decode both STANDARD and URL_SAFE streams, but the encodeTable must be a member variable so we can switch
* between the two modes.
*/
private final byte[] encodeTable;
/**
* Only one decode table currently; keep for consistency with Base32 code
*/
private final byte[] decodeTable = DECODE_TABLE;
/**
* Line separator for encoding. Not used when decoding. Only used if lineLength > 0.
*/
private final byte[] lineSeparator;
/**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
* <code>decodeSize = 3 + lineSeparator.length;</code>
*/
private final int decodeSize;
/**
* Convenience variable to help us determine when our buffer is going to run out of room and needs resizing.
* <code>encodeSize = 4 + lineSeparator.length;</code>
*/
private final int encodeSize;
/**
* Place holder for the bytes we're dealing with for our based logic.
* Bitwise operations store and extract the encoding or decoding from this variable.
*/
private int bitWorkArea;
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p>
* When encoding the line length is 0 (no chunking), and the encoding table is STANDARD_ENCODE_TABLE.
* </p>
*
* <p>
* When decoding all variants are supported.
* </p>
*/
public Base64() {
this(0, CHUNK_SEPARATOR, false);
}
/**
* Creates a Base64 codec used for decoding (all modes) and encoding in URL-unsafe mode.
* <p>
* When encoding the line length and line separator are given in the constructor, and the encoding table is
* STANDARD_ENCODE_TABLE.
* </p>
* <p>
* Line lengths that aren't multiples of 4 will still essentially end up being multiples of 4 in the encoded data.
* </p>
* <p>
* When decoding all variants are supported.
* </p>
*
* @param lineLength
* Each line of encoded data will be at most of the given length (rounded down to nearest multiple of 4).
* If lineLength <= 0, then the output will not be divided into lines (chunks). Ignored when decoding.
* @param lineSeparator
* Each line of encoded data will end with this sequence of bytes.
* @param urlSafe
* Instead of emitting '+' and '/' we emit '-' and '_' respectively. urlSafe is only applied to encode
* operations. Decoding seamlessly handles both modes.
* @throws IllegalArgumentException
* The provided lineSeparator included some base64 characters. That's not going to work!
* @since 1.4
*/
public Base64(int lineLength, byte[] lineSeparator, boolean urlSafe) {
chunkSeparatorLength = lineSeparator == null ? 0 : lineSeparator.length;
unencodedBlockSize = BYTES_PER_UNENCODED_BLOCK;
encodedBlockSize = BYTES_PER_ENCODED_BLOCK;
this.lineLength = (lineLength > 0 && chunkSeparatorLength > 0) ? (lineLength / encodedBlockSize) * encodedBlockSize : 0;
// TODO could be simplified if there is no requirement to reject invalid line sep when length <=0
// @see test case Base64Test.testConstructors()
if (lineSeparator != null) {
if (containsAlphabetOrPad(lineSeparator)) {
String sep = null;
try {
sep = new String(lineSeparator, "UTF-8");
} catch (UnsupportedEncodingException e) {
}
throw new IllegalArgumentException("lineSeparator must not contain base64 characters: [" + sep + "]");
}
if (lineLength > 0){
this.encodeSize = BYTES_PER_ENCODED_BLOCK + lineSeparator.length;
this.lineSeparator = new byte[lineSeparator.length];
System.arraycopy(lineSeparator, 0, this.lineSeparator, 0, lineSeparator.length);
} else {
this.encodeSize = BYTES_PER_ENCODED_BLOCK;
this.lineSeparator = null;
}
} else {
this.encodeSize = BYTES_PER_ENCODED_BLOCK;
this.lineSeparator = null;
}
this.decodeSize = this.encodeSize - 1;
this.encodeTable = urlSafe ? URL_SAFE_ENCODE_TABLE : STANDARD_ENCODE_TABLE;
}
/**
* <p>
* Encodes all of the provided data, starting at inPos, for inAvail bytes. Must be called at least twice: once with
* the data to encode, and once with inAvail set to "-1" to alert encoder that EOF has been reached, so flush last
* remaining bytes (if not multiple of 3).
* </p>
* <p>
* Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
* </p>
*
* @param in
* byte[] array of binary data to base64 encode.
* @param inPos
* Position to start reading data from.
* @param inAvail
* Amount of bytes available from input for encoding.
*/
void encode(byte[] in, int inPos, int inAvail) {
if (eof) {
return;
}
if (inAvail < 0) {
eof = true;
if (0 == modulus && lineLength == 0) {
return;
}
ensureBufferSize(encodeSize);
int savedPos = pos;
switch (modulus) {
case 1 :
buffer[pos++] = encodeTable[(bitWorkArea >> 2) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea << 4) & MASK_6BITS];
if (encodeTable == STANDARD_ENCODE_TABLE) {
buffer[pos++] = PAD;
buffer[pos++] = PAD;
}
break;
case 2 :
buffer[pos++] = encodeTable[(bitWorkArea >> 10) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea >> 4) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea << 2) & MASK_6BITS];
if (encodeTable == STANDARD_ENCODE_TABLE) {
buffer[pos++] = PAD;
}
break;
default:
break;
}
currentLinePos += pos - savedPos;
/**
* if currentPos == 0 we are at the start of a line, so don't add CRLF
*/
if (lineLength > 0 && currentLinePos > 0) {
System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
pos += lineSeparator.length;
}
} else {
for (int i = 0; i < inAvail; i++) {
ensureBufferSize(encodeSize);
modulus = (modulus+1) % BYTES_PER_UNENCODED_BLOCK;
int b = in[inPos++];
if (b < 0) {
b += 256;
}
bitWorkArea = (bitWorkArea << 8) + b;
if (0 == modulus) {
buffer[pos++] = encodeTable[(bitWorkArea >> 18) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea >> 12) & MASK_6BITS];
buffer[pos++] = encodeTable[(bitWorkArea >> 6) & MASK_6BITS];
buffer[pos++] = encodeTable[bitWorkArea & MASK_6BITS];
currentLinePos += BYTES_PER_ENCODED_BLOCK;
if (lineLength > 0 && lineLength <= currentLinePos) {
System.arraycopy(lineSeparator, 0, buffer, pos, lineSeparator.length);
pos += lineSeparator.length;
currentLinePos = 0;
}
}
}
}
}
/**
* <p>
* Decodes all of the provided data, starting at inPos, for inAvail bytes. Should be called at least twice: once
* with the data to decode, and once with inAvail set to "-1" to alert decoder that EOF has been reached. The "-1"
* call is not necessary when decoding, but it doesn't hurt, either.
* </p>
* <p>
* Ignores all non-base64 characters. This is how chunked (e.g. 76 character) data is handled, since CR and LF are
* silently ignored, but has implications for other bytes, too. This method subscribes to the garbage-in,
* garbage-out philosophy: it will not check the provided data for validity.
* </p>
* <p>
* Thanks to "commons" project in ws.apache.org for the bitwise operations, and general approach.
* http://svn.apache.org/repos/asf/webservices/commons/trunk/modules/util/
* </p>
*
* @param in
* byte[] array of ascii data to base64 decode.
* @param inPos
* Position to start reading data from.
* @param inAvail
* Amount of bytes available from input for encoding.
*/
void decode(byte[] in, int inPos, int inAvail) {
if (eof) {
return;
}
if (inAvail < 0) {
eof = true;
}
for (int i = 0; i < inAvail; i++) {
ensureBufferSize(decodeSize);
byte b = in[inPos++];
if (b == PAD) {
// We're done.
eof = true;
break;
} else {
if (b >= 0 && b < DECODE_TABLE.length) {
int result = DECODE_TABLE[b];
if (result >= 0) {
modulus = (modulus+1) % BYTES_PER_ENCODED_BLOCK;
bitWorkArea = (bitWorkArea << BITS_PER_ENCODED_BYTE) + result;
if (modulus == 0) {
buffer[pos++] = (byte) ((bitWorkArea >> 16) & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea >> 8) & MASK_8BITS);
buffer[pos++] = (byte) (bitWorkArea & MASK_8BITS);
}
}
}
}
}
// Two forms of EOF as far as base64 decoder is concerned: actual
// EOF (-1) and first time '=' character is encountered in stream.
// This approach makes the '=' padding characters completely optional.
if (eof && modulus != 0) {
ensureBufferSize(decodeSize);
// We have some spare bits remaining
// Output all whole multiples of 8 bits and ignore the rest
switch (modulus) {
// case 1: // 6 bits - ignore entirely
// break;
case 2 :
bitWorkArea = bitWorkArea >> 4;
buffer[pos++] = (byte) ((bitWorkArea) & MASK_8BITS);
break;
case 3 :
bitWorkArea = bitWorkArea >> 2;
buffer[pos++] = (byte) ((bitWorkArea >> 8) & MASK_8BITS);
buffer[pos++] = (byte) ((bitWorkArea) & MASK_8BITS);
break;
default:
break;
}
}
}
/**
* Encodes binary data using the base64 algorithm but does not chunk the output.
*
* @param binaryData
* binary data to encode
* @return byte[] containing Base64 characters in their UTF-8 representation.
*/
public static byte[] encodeBase64(byte[] binaryData) {
return encodeBase64(binaryData, false, false, Integer.MAX_VALUE);
}
/**
* Encodes binary data using the base64 algorithm, optionally chunking the output into 76 character blocks.
*
* @param binaryData
* Array containing binary data to encode.
* @param isChunked
* if <code>true</code> this encoder will chunk the base64 output into 76 character blocks
* @param urlSafe
* if <code>true</code> this encoder will emit - and _ instead of the usual + and / characters.
* @param maxResultSize
* The maximum result size to accept.
* @return Base64-encoded data.
* @throws IllegalArgumentException
* Thrown when the input array needs an output array bigger than maxResultSize
* @since 1.4
*/
public static byte[] encodeBase64(byte[] binaryData, boolean isChunked, boolean urlSafe, int maxResultSize) {
if (binaryData == null || binaryData.length == 0) {
return binaryData;
}
// Create this so can use the super-class method
// Also ensures that the same roundings are performed by the ctor and the code
Base64 b64 = isChunked ? new Base64(MIME_CHUNK_SIZE, CHUNK_SEPARATOR, urlSafe) : new Base64(0, CHUNK_SEPARATOR, urlSafe);
long len = b64.getEncodedLength(binaryData);
if (len > maxResultSize) {
throw new IllegalArgumentException("Input array too big, the output array would be bigger (" +
len +
") than the specified maximum size of " +
maxResultSize);
}
return b64.encode(binaryData);
}
/**
* Decodes Base64 data into octets
*
* @param base64Data
* Byte array containing Base64 data
* @return Array containing decoded data.
*/
public static byte[] decodeBase64(byte[] base64Data) {
return new Base64().decode(base64Data);
}
/**
* Returns whether or not the <code>octet</code> is in the Base32 alphabet.
*
* @param octet
* The value to test
* @return <code>true</code> if the value is defined in the the Base32 alphabet <code>false</code> otherwise.
*/
protected boolean isInAlphabet(byte octet) {
return octet >= 0 && octet < decodeTable.length && decodeTable[octet] != -1;
}
/**
* Below from base class
*/
/**
* MIME chunk size per RFC 2045 section 6.8.
*
* <p>
* The {@value} character limit does not count the trailing CRLF, but counts all other characters, including any
* equal signs.
* </p>
*
* @see <a href="http://www.ietf.org/rfc/rfc2045.txt">RFC 2045 section 6.8</a>
*/
private static final int MIME_CHUNK_SIZE = 76;
private static final int DEFAULT_BUFFER_RESIZE_FACTOR = 2;
/**
* Defines the default buffer size - currently {@value}
* - must be large enough for at least one encoded block+separator
*/
private static final int DEFAULT_BUFFER_SIZE = 8192;
/** Mask used to extract 8 bits, used in decoding bytes */
private static final int MASK_8BITS = 0xff;
/**
* Byte used to pad output.
*/
private static final byte PAD_DEFAULT = '=';
private static final byte PAD = PAD_DEFAULT;
/** Number of bytes in each full block of unencoded data, e.g. 4 for Base64 and 5 for Base32 */
private final int unencodedBlockSize;
/** Number of bytes in each full block of encoded data, e.g. 3 for Base64 and 8 for Base32 */
private final int encodedBlockSize;
/**
* Chunksize for encoding. Not used when decoding.
* A value of zero or less implies no chunking of the encoded data.
* Rounded down to nearest multiple of encodedBlockSize.
*/
private final int lineLength;
/**
* Size of chunk separator. Not used unless {@link #lineLength} > 0.
*/
private final int chunkSeparatorLength;
/**
* Buffer for streaming.
*/
private byte[] buffer;
/**
* Position where next character should be written in the buffer.
*/
private int pos;
/**
* Position where next character should be read from the buffer.
*/
private int readPos;
/**
* Boolean flag to indicate the EOF has been reached. Once EOF has been reached, this object becomes useless,
* and must be thrown away.
*/
private boolean eof;
/**
* Variable tracks how many characters have been written to the current line. Only used when encoding. We use it to
* make sure each encoded line never goes beyond lineLength (if lineLength > 0).
*/
private int currentLinePos;
/**
* Writes to the buffer only occur after every 3/5 reads when encoding, and every 4/8 reads when decoding.
* This variable helps track that.
*/
private int modulus;
/**
* Ensure that the buffer has room for <code>size</code> bytes
*
* @param size minimum spare space required
*/
private void ensureBufferSize(int size){
if ((buffer == null) || (buffer.length < pos + size)){
if (buffer == null) {
buffer = new byte[DEFAULT_BUFFER_SIZE];
pos = 0;
readPos = 0;
} else {
byte[] b = new byte[buffer.length * DEFAULT_BUFFER_RESIZE_FACTOR];
System.arraycopy(buffer, 0, b, 0, buffer.length);
buffer = b;
}
}
}
/**
* Extracts buffered data into the provided byte[] array, starting at position bPos,
* up to a maximum of bAvail bytes. Returns how many bytes were actually extracted.
*
* @param b
* byte[] array to extract the buffered data into.
* @param bPos
* position in byte[] array to start extraction at.
* @param bAvail
* amount of bytes we're allowed to extract. We may extract fewer (if fewer are available).
* @return The number of bytes successfully extracted into the provided byte[] array.
*/
private int readResults(byte[] b, int bPos, int bAvail) {
if (buffer != null) {
int len = Math.min(pos - readPos, bAvail);
System.arraycopy(buffer, readPos, b, bPos, len);
readPos += len;
if (readPos >= pos) {
buffer = null;
}
return len;
}
return eof ? -1 : 0;
}
/**
* Resets this object to its initial newly constructed state.
*/
private void reset() {
buffer = null;
pos = 0;
readPos = 0;
currentLinePos = 0;
modulus = 0;
eof = false;
}
/**
* Decodes a byte[] containing characters in the Base-N alphabet.
*
* @param pArray
* A byte array containing Base-N character data
* @return a byte array containing binary data
*/
private byte[] decode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
decode(pArray, 0, pArray.length);
decode(pArray, 0, -1);
byte[] result = new byte[pos];
readResults(result, 0, result.length);
return result;
}
/**
* Encodes a byte[] containing binary data, into a byte[] containing characters in the alphabet.
*
* @param pArray
* a byte array containing binary data
* @return A byte array containing only the basen alphabetic character data
*/
private byte[] encode(byte[] pArray) {
reset();
if (pArray == null || pArray.length == 0) {
return pArray;
}
encode(pArray, 0, pArray.length);
encode(pArray, 0, -1);
byte[] buf = new byte[pos - readPos];
readResults(buf, 0, buf.length);
return buf;
}
/**
* Tests a given byte array to see if it contains any characters within the alphabet or PAD.
*
* Intended for use in checking line-ending arrays
*
* @param arrayOctet
* byte array to test
* @return <code>true</code> if any byte is a valid character in the alphabet or PAD; <code>false</code> otherwise
*/
private boolean containsAlphabetOrPad(byte[] arrayOctet) {
if (arrayOctet == null) {
return false;
}
for (int i = 0; i < arrayOctet.length; i++) {
if (PAD == arrayOctet[i] || isInAlphabet(arrayOctet[i])) {
return true;
}
}
return false;
}
/**
* Calculates the amount of space needed to encode the supplied array.
*
* @param pArray byte[] array which will later be encoded
*
* @return amount of space needed to encoded the supplied array.
* Returns a long since a max-len array will require > Integer.MAX_VALUE
*/
private long getEncodedLength(byte[] pArray) {
// Calculate non-chunked size - rounded up to allow for padding
// cast to long is needed to avoid possibility of overflow
long len = ((pArray.length + unencodedBlockSize-1) / unencodedBlockSize) * (long) encodedBlockSize;
if (lineLength > 0) {
/**
* Round up to nearest multiple
*/
len += ((len + lineLength-1) / lineLength) * chunkSeparatorLength;
}
return len;
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Identify Constants
*
* @author Nacos
*
*/
public class Constants {
public static final String ACCESS_KEY = "accessKey";
public static final String SECRET_KEY = "secretKey";
public static final String PROPERTIES_FILENAME = "spas.properties";
public static final String CREDENTIAL_PATH = "/home/admin/.spas_key/";
public static final String CREDENTIAL_DEFAULT = "default";
public static final String DOCKER_CREDENTIAL_PATH = "/etc/instanceInfo";
public static final String DOCKER_ACCESS_KEY = "env_spas_accessKey";
public static final String DOCKER_SECRET_KEY = "env_spas_secretKey";
public static final String ENV_ACCESS_KEY = "spas_accessKey";
public static final String ENV_SECRET_KEY = "spas_secretKey";
public static final String NO_APP_NAME = "";
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Credential Listener
*
* @author Nacos
*
*/
public interface CredentialListener {
/**
* update Credential
*/
public void onUpdateCredential();
}

View File

@ -0,0 +1,135 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.utils.StringUtils;
import java.util.concurrent.ConcurrentHashMap;
/**
* Credential Service
*
* @author Nacos
*
*/
public final class CredentialService implements SpasCredentialLoader {
static final public Logger log = LogUtils.logger(CredentialService.class);
private static ConcurrentHashMap<String, CredentialService> instances = new ConcurrentHashMap<String, CredentialService>();
private String appName;
private Credentials credentials = new Credentials();
private CredentialWatcher watcher;
private CredentialListener listener;
private CredentialService(String appName) {
if (appName == null) {
String value = System.getProperty("project.name");
if (StringUtils.isNotEmpty(value)) {
appName = value;
}
}
this.appName = appName;
watcher = new CredentialWatcher(appName, this);
}
public static CredentialService getInstance() {
return getInstance(null);
}
public static CredentialService getInstance(String appName) {
String key = appName != null ? appName : Constants.NO_APP_NAME;
CredentialService instance = instances.get(key);
if (instance == null) {
instance = new CredentialService(appName);
CredentialService previous = instances.putIfAbsent(key, instance);
if (previous != null) {
instance = previous;
}
}
return instance;
}
public static CredentialService freeInstance() {
return freeInstance(null);
}
public static CredentialService freeInstance(String appName) {
String key = appName != null ? appName : Constants.NO_APP_NAME;
CredentialService instance = instances.remove(key);
if (instance != null) {
instance.free();
}
return instance;
}
public void free() {
if (watcher != null) {
watcher.stop();
}
log.info(appName, this.getClass().getSimpleName() + " is freed");
}
public Credentials getCredential() {
Credentials localCredential = credentials;
if (localCredential.valid()) {
return localCredential;
}
return credentials;
}
public void setCredential(Credentials credential) {
boolean changed = !(credentials == credential || (credentials != null && credentials.identical(credential)));
credentials = credential;
if (changed && listener != null) {
listener.onUpdateCredential();
}
}
public void setStaticCredential(Credentials credential) {
if (watcher != null) {
watcher.stop();
}
setCredential(credential);
}
public void registerCredentialListener(CredentialListener listener) {
this.listener = listener;
}
@Deprecated
public void setAccessKey(String accessKey) {
credentials.setAccessKey(accessKey);
}
@Deprecated
public void setSecretKey(String secretKey) {
credentials.setSecretKey(secretKey);
}
@Deprecated
public String getAccessKey() {
return credentials.getAccessKey();
}
@Deprecated
public String getSecretKey() {
return credentials.getSecretKey();
}
}

View File

@ -0,0 +1,214 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.Properties;
import java.util.Timer;
import java.util.TimerTask;
import com.alibaba.nacos.client.config.utils.LogUtils;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Credential Watcher
*
* @author Nacos
*
*/
public class CredentialWatcher {
static final public Logger SpasLogger = LogUtils.logger(CredentialWatcher.class);
private static final long REFRESH_INTERVAL = 10 * 1000;
private CredentialService serviceInstance;
private String appName;
private String propertyPath;
private TimerTask watcher;
private boolean stopped;
@SuppressWarnings("PMD.AvoidUseTimerRule")
public CredentialWatcher(String appName, CredentialService serviceInstance) {
this.appName = appName;
this.serviceInstance = serviceInstance;
loadCredential(true);
watcher = new TimerTask() {
private Timer timer = new Timer(true);
private long modified = 0;
{
timer.schedule(this, REFRESH_INTERVAL, REFRESH_INTERVAL);
}
@Override
public void run() {
synchronized (this) {
if (stopped) {
return;
}
boolean reload = false;
if (propertyPath == null) {
reload = true;
} else {
File file = new File(propertyPath);
long lastModified = file.lastModified();
if (modified != lastModified) {
reload = true;
modified = lastModified;
}
}
if (reload) {
loadCredential(false);
}
}
}
};
}
public void stop() {
if (stopped) {
return;
}
if (watcher != null) {
synchronized (watcher) {
watcher.cancel();
stopped = true;
}
}
SpasLogger.info(appName, this.getClass().getSimpleName() + " is stopped");
}
private void loadCredential(boolean init) {
boolean logWarn = init;
if (propertyPath == null) {
URL url = ClassLoader.getSystemResource(Constants.PROPERTIES_FILENAME);
if (url != null) {
propertyPath = url.getPath();
}
if (propertyPath == null || propertyPath.isEmpty()) {
String value = System.getProperty("spas.identity");
if (StringUtils.isNotEmpty(value)) {
propertyPath = value;
}
if (propertyPath == null || propertyPath.isEmpty()) {
propertyPath = Constants.CREDENTIAL_PATH + (appName == null ? Constants.CREDENTIAL_DEFAULT : appName);
}
else {
if (logWarn) {
SpasLogger.info(appName, "Defined credential file: -D" + "spas.identity" + "=" + propertyPath);
}
}
}
else {
if (logWarn) {
SpasLogger.info(appName, "Load credential file from classpath: " + Constants.PROPERTIES_FILENAME);
}
}
}
InputStream propertiesIS = null;
do {
try {
propertiesIS = new FileInputStream(propertyPath);
} catch (FileNotFoundException e) {
if (appName != null && !appName.equals(Constants.CREDENTIAL_DEFAULT) && propertyPath.equals(Constants.CREDENTIAL_PATH + appName)) {
propertyPath = Constants.CREDENTIAL_PATH + Constants.CREDENTIAL_DEFAULT;
continue;
}
if (!Constants.DOCKER_CREDENTIAL_PATH.equals(propertyPath)) {
propertyPath = Constants.DOCKER_CREDENTIAL_PATH;
continue;
}
}
break;
} while (true);
String accessKey = null;
String secretKey = null;
if (propertiesIS == null) {
propertyPath = null;
accessKey = System.getenv(Constants.ENV_ACCESS_KEY);
secretKey = System.getenv(Constants.ENV_SECRET_KEY);
if (accessKey == null && secretKey == null) {
if (logWarn) {
SpasLogger.info(appName, "No credential found");
}
return;
}
}
else {
Properties properties = new Properties();
try {
properties.load(propertiesIS);
} catch (IOException e) {
SpasLogger.error("26", "Unable to load credential file, appName:" + appName
+ "Unable to load credential file " + propertyPath, e);
propertyPath = null;
return;
} finally {
try {
propertiesIS.close();
} catch (IOException e) {
SpasLogger.error("27", "Unable to close credential file, appName:" + appName
+ "Unable to close credential file " + propertyPath, e);
}
}
if (logWarn) {
SpasLogger.info(appName, "Load credential file " + propertyPath);
}
if (!Constants.DOCKER_CREDENTIAL_PATH.equals(propertyPath)) {
if (properties.containsKey(Constants.ACCESS_KEY)) {
accessKey = properties.getProperty(Constants.ACCESS_KEY);
}
if (properties.containsKey(Constants.SECRET_KEY)) {
secretKey = properties.getProperty(Constants.SECRET_KEY);
}
} else {
if (properties.containsKey(Constants.DOCKER_ACCESS_KEY)) {
accessKey = properties.getProperty(Constants.DOCKER_ACCESS_KEY);
}
if (properties.containsKey(Constants.DOCKER_SECRET_KEY)) {
secretKey = properties.getProperty(Constants.DOCKER_SECRET_KEY);
}
}
}
if (accessKey != null) {
accessKey = accessKey.trim();
}
if (secretKey != null) {
secretKey = secretKey.trim();
}
Credentials credential = new Credentials(accessKey, secretKey);
if (!credential.valid()) {
SpasLogger.warn("1", "Credential file missing required property" + appName + "Credential file missing "
+ Constants.ACCESS_KEY + " or " + Constants.SECRET_KEY);
propertyPath = null;
// return;
}
serviceInstance.setCredential(credential);
}
}

View File

@ -0,0 +1,65 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Credentials
*
* @author Nacos
*
*/
public class Credentials implements SpasCredential {
private volatile String accessKey;
private volatile String secretKey;
public Credentials(String accessKey, String secretKey) {
this.accessKey = accessKey;
this.secretKey = secretKey;
}
public Credentials() {
this(null, null);
}
public String getAccessKey() {
return accessKey;
}
public void setAccessKey(String accessKey) {
this.accessKey = accessKey;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public boolean valid() {
return accessKey != null && !accessKey.isEmpty() && secretKey != null && !secretKey.isEmpty();
}
public boolean identical(Credentials other) {
return this == other ||
(other != null &&
(accessKey == null && other.accessKey == null || accessKey != null && accessKey.equals(other.accessKey)) &&
(secretKey == null && other.secretKey == null || secretKey != null && secretKey.equals(other.secretKey)));
}
}

View File

@ -0,0 +1,128 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
import com.alibaba.nacos.client.utils.StringUtils;
/**
* Sts config
*
* @author Nacos
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class STSConfig {
private static final String RAM_SECURITY_CREDENTIALS_URL
= "";
private String ramRoleName;
/**
* STS 临时凭证有效期剩余多少时开始刷新允许本地时间比 STS 服务时间最多慢多久
*/
private int timeToRefreshInMillisecond = 3 * 60 * 1000;
/**
* 获取 STS 临时凭证的元数据接口包含角色名称
*/
private String securityCredentialsUrl;
/**
* 设定 STS 临时凭证不再通过元数据接口获取
*/
private String securityCredentials;
/**
* 是否缓存
*/
private boolean cacheSecurityCredentials = true;
private static class Singleton {
private static final STSConfig INSTANCE = new STSConfig();
}
private STSConfig() {
String ramRoleName = System.getProperty("ram.role.name");
if (!StringUtils.isBlank(ramRoleName)) {
setRamRoleName(ramRoleName);
}
String timeToRefreshInMillisecond = System.getProperty("time.to.refresh.in.millisecond");
if (!StringUtils.isBlank(timeToRefreshInMillisecond)) {
setTimeToRefreshInMillisecond(Integer.parseInt(timeToRefreshInMillisecond));
}
String securityCredentials = System.getProperty("security.credentials");
if (!StringUtils.isBlank(securityCredentials)) {
setSecurityCredentials(securityCredentials);
}
String securityCredentialsUrl = System.getProperty("security.credentials.url");
if (!StringUtils.isBlank(securityCredentialsUrl)) {
setSecurityCredentialsUrl(securityCredentialsUrl);
}
String cacheSecurityCredentials = System.getProperty("cache.security.credentials");
if (!StringUtils.isBlank(cacheSecurityCredentials)) {
setCacheSecurityCredentials(Boolean.valueOf(cacheSecurityCredentials));
}
}
public static STSConfig getInstance() {
return Singleton.INSTANCE;
}
public String getRamRoleName() {
return ramRoleName;
}
public void setRamRoleName(String ramRoleName) {
this.ramRoleName = ramRoleName;
}
public int getTimeToRefreshInMillisecond() {
return timeToRefreshInMillisecond;
}
public void setTimeToRefreshInMillisecond(int timeToRefreshInMillisecond) {
this.timeToRefreshInMillisecond = timeToRefreshInMillisecond;
}
public String getSecurityCredentialsUrl() {
if (securityCredentialsUrl == null && ramRoleName != null) {
return RAM_SECURITY_CREDENTIALS_URL + ramRoleName;
}
return securityCredentialsUrl;
}
public void setSecurityCredentialsUrl(String securityCredentialsUrl) {
this.securityCredentialsUrl = securityCredentialsUrl;
}
public String getSecurityCredentials() {
return securityCredentials;
}
public void setSecurityCredentials(String securityCredentials) {
this.securityCredentials = securityCredentials;
}
public boolean isSTSOn() {
return StringUtils.isNotEmpty(getSecurityCredentials()) || StringUtils.isNotEmpty(getSecurityCredentialsUrl());
}
public boolean isCacheSecurityCredentials() {
return cacheSecurityCredentials;
}
public void setCacheSecurityCredentials(boolean cacheSecurityCredentials) {
this.cacheSecurityCredentials = cacheSecurityCredentials;
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Spas Credential Interface
*
* @author Nacos
*
*/
public interface SpasCredential {
/**
* get AccessKey
*
* @return AccessKey
*/
public String getAccessKey();
/**
* get SecretKey
*
* @return SecretKey
*/
public String getSecretKey();
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.identify;
/**
* Spas Credential Loader
*
* @author Nacos
*
*/
public interface SpasCredentialLoader {
/**
* get Credential
*
* @return Credential
*/
SpasCredential getCredential();
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger;
/**
* 阿里中间件日志级别
*
* @author zhuyong 2014年3月20日 上午9:57:27
*/
public enum Level {
/**
* log level
*/
DEBUG("DEBUG"), INFO("INFO"), WARN("WARN"), ERROR("ERROR"), OFF("OFF");
private String name;
Level(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public static Level codeOf(String level) {
for (Level l : Level.values()) {
if (l.name.equals(level)) {
return l;
}
}
return OFF;
}
}

View File

@ -0,0 +1,238 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger;
import com.alibaba.nacos.client.logger.option.ActivateOption;
/**
* <pre>
* 阿里中间件日志API用于输出定制化的日志
*
* 定制格式如下01 %d{yyyy-MM-dd HH:mm:ss.SSS} %p [%-5t:%c{2}] %m%n
* 其中
* 01 日志API版本后续如果格式有变化会修改此版本号方便机器解析
* d{yyyy-MM-dd HH:mm:ss.SSS} 时间2014-03-19 20:55:08.501最后面的表示毫秒
* %p 日志级别如INFO,ERROR
* [%-5t:%c{2}] 线程名:日志名
* %m 日志信息
* %n 换行
*
* 关于%m也有其中的格式要求[Context] [STAT-INFO] [ERROR-CODE]
* 其中
* Context 打印时间时的上下文信息如果没有则内容为空'[]'这个占位符仍要输出
* STAT-INFO 待定
* ERROR-CODE 常见的错误码帮助用户解决问题
*
* 在异常中也需要输出ErrorCode及对应的TraceUrl可以使用
* com.alibaba.nacos.client.logger.support.LoggerHelper.getErrorCodeStr(String errorCode)来获取格式化后的串
* </pre>
*
* @author zhuyong 2014年3月20日 上午9:58:27
*/
public interface Logger extends ActivateOption {
/**
* 输出Debug日志
*
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void debug(String message);
/**
* 输出Debug日志
*
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数数组
*/
void debug(String format, Object... args);
/**
* 输出Debug日志
*
* @param context 日志上下文信息
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void debug(String context, String message);
/**
* 输出Debug日志
*
* @param context 日志上下文信息
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数数组
*/
void debug(String context, String format, Object... args);
/**
* 输出Info日志
*
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void info(String message);
/**
* 输出Info日志
*
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数数组
*/
void info(String format, Object... args);
/**
* 输出Info日志
*
* @param context 日志上下文信息
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void info(String context, String message);
/**
* 输出Info日志
*
* @param context 日志上下文信息
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数数组
*/
void info(String context, String format, Object... args);
/**
* 输出Warn日志
*
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void warn(String message);
/**
* 输出Warn日志
*
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param t 异常信息
* @since 0.1.5
*/
void warn(String message, Throwable t);
/**
* 输出Warn日志
*
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数数组
*/
void warn(String format, Object... args);
/**
* 输出Warn日志
*
* @param context 日志上下文信息
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void warn(String context, String message);
/**
* 输出Warn日志
*
* @param context 日志上下文信息
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数数组
*/
void warn(String context, String format, Object... args);
/**
* 输出Error日志
*
* @param errorCode 错误码如HSF-0001
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void error(String errorCode, String message);
/**
* 输出Error日志
*
* @param errorCode 错误码如HSF-0001
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param t 异常信息
*/
void error(String errorCode, String message, Throwable t);
/**
* 输出Error日志
*
* @param errorCode 错误码如HSF-0001
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param objs 格式化串参数数组
*/
void error(String errorCode, String format, Object... objs);
/**
* 输出Error日志
*
* @param context 日志上下文信息
* @param errorCode 错误码
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
*/
void error(String context, String errorCode, String message);
/**
* 输出Error日志
*
* @param context 日志上下文信息
* @param errorCode 错误码
* @param message 日志信息当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param t 异常信息
*/
void error(String context, String errorCode, String message, Throwable t);
/**
* 输出Error日志
*
* @param context 日志上下文信息
* @param errorCode 错误码
* @param format 日志信息格式化字符串比如 'Hi,{} {} {}'当使用ResourceBundle用于国际化日志输出时message为对应的key, since 0.1.5
* @param args 格式化串参数
*/
void error(String context, String errorCode, String format, Object... args);
/**
* 判断Debug级别是否开启
*
* @return Debug级别是否开启
*/
boolean isDebugEnabled();
/**
* 判断Info级别是否开启
* @return Info级别是否开启
*/
boolean isInfoEnabled();
/**
* 判断Warn级别是否开启
* @return Warn级别是否开启
*/
boolean isWarnEnabled();
/**
* 判断Error级别是否开启
*
* @return Error级别是否开启
*/
boolean isErrorEnabled();
/**
* * 获取内部日志实现对象
* @return 内部日志实现对象
*/
Object getDelegate();
}

View File

@ -0,0 +1,100 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import com.alibaba.nacos.client.logger.log4j.Log4jLoggerFactory;
import com.alibaba.nacos.client.logger.log4j2.Log4j2LoggerFactory;
import com.alibaba.nacos.client.logger.nop.NopLoggerFactory;
import com.alibaba.nacos.client.logger.slf4j.Slf4jLoggerFactory;
import com.alibaba.nacos.client.logger.support.ILoggerFactory;
import com.alibaba.nacos.client.logger.support.LogLog;
/**
* <pre>
* 阿里中间件LoggerFactory获取具体日志实现
* 目前支持log4j/log4j2/slf4j/jcl日志门面和log4j/log4j2/logback日志实现
* log4j
* log4j2
* slf4j + logback
* slf4j + slf4j-log4j12 + log4j
* slf4j + slf4j-log4j-impl + log4j2
* jcl + log4j
* jcl + jcl-over-slf4j + slf4j + logback
* jcl + jcl-over-slf4j + slf4j + slf4j-log4j-impl + log4j
* 查找实现的优先顺序依次为slf4j > log4j > log4j2
* </pre>
*
* @author zhuyong 2014年3月20日 上午10:17:33
*/
public class LoggerFactory {
private LoggerFactory() {
}
private static volatile ILoggerFactory LOGGER_FACTORY;
private static Map<String, Logger> loggerCache;
// 查找常用的日志框架
static {
try {
setLoggerFactory(new Slf4jLoggerFactory());
LogLog.info("Init JM logger with Slf4jLoggerFactory success, " + LoggerFactory.class.getClassLoader());
} catch (Throwable e1) {
try {
setLoggerFactory(new Log4jLoggerFactory());
LogLog.info("Init JM logger with Log4jLoggerFactory, " + LoggerFactory.class.getClassLoader());
} catch (Throwable e2) {
try {
setLoggerFactory(new Log4j2LoggerFactory());
LogLog.info("Init JM logger with Log4j2LoggerFactory, " + LoggerFactory.class.getClassLoader());
} catch (Throwable e3) {
setLoggerFactory(new NopLoggerFactory());
LogLog.warn("Init JM logger with NopLoggerFactory, pay attention. "
+ LoggerFactory.class.getClassLoader(), e2);
}
}
}
loggerCache = new ConcurrentHashMap<String, Logger>();
}
public static Logger getLogger(String name) {
Logger logger = loggerCache.get(name);
if (logger == null) {
synchronized (LOGGER_FACTORY) {
logger = loggerCache.get(name);
if (logger == null) {
logger = LOGGER_FACTORY.getLogger(name);
loggerCache.put(name, logger);
}
}
}
return logger;
}
public static Logger getLogger(Class<?> clazz) {
return getLogger(clazz.getName());
}
private static void setLoggerFactory(ILoggerFactory loggerFactory) {
if (loggerFactory != null) {
LoggerFactory.LOGGER_FACTORY = loggerFactory;
}
}
}

View File

@ -0,0 +1,398 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: JSONArray.java,v 1.1 2006/04/15 14:10:48 platform Exp $
* Created on 2006-4-10
*/
package com.alibaba.nacos.client.logger.json;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
/**
* A JSON array. JSONObject supports java.util.List interface.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class JSONArray extends ArrayList implements JSONAware, JSONStreamAware {
private static final long serialVersionUID = 3957988303675231981L;
/**
* Constructs an empty JSONArray.
*/
public JSONArray(){
super();
}
/**
* Constructs a JSONArray containing the elements of the specified
* collection, in the order they are returned by the collection's iterator.
*
* @param c the collection whose elements are to be placed into this JSONArray
*/
public JSONArray(Collection c){
super(c);
}
/**
* Encode a list into JSON text and write it to out.
* If this list is also a JSONStreamAware or a JSONAware, JSONStreamAware and JSONAware specific behaviours will be ignored at this top level.
*
* @see com.alibaba.nacos.client.logger.json.JSONValue#writeJSONString(Object, Writer)
*
* @param collection
* @param out
*/
public static void writeJSONString(Collection collection, Writer out) throws IOException{
if(collection == null){
out.write("null");
return;
}
boolean first = true;
Iterator iter=collection.iterator();
out.write('[');
while(iter.hasNext()){
if(first) {
first = false;
}
else {
out.write(',');
}
Object value=iter.next();
if(value == null){
out.write("null");
continue;
}
JSONValue.writeJSONString(value, out);
}
out.write(']');
}
public void writeJSONString(Writer out) throws IOException{
writeJSONString(this, out);
}
/**
* Convert a list to JSON text. The result is a JSON array.
* If this list is also a JSONAware, JSONAware specific behaviours will be omitted at this top level.
*
* @see com.alibaba.nacos.client.logger.json.JSONValue#toJSONString(Object)
*
* @param collection
* @return JSON text, or "null" if list is null.
*/
public static String toJSONString(Collection collection){
final StringWriter writer = new StringWriter();
try {
writeJSONString(collection, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(byte[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(byte[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(short[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(short[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(int[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(int[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(long[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(long[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(float[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(float[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(double[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(double[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(boolean[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write(",");
out.write(String.valueOf(array[i]));
}
out.write("]");
}
}
public static String toJSONString(boolean[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(char[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[\"");
out.write(String.valueOf(array[0]));
for(int i = 1; i < array.length; i++){
out.write("\",\"");
out.write(String.valueOf(array[i]));
}
out.write("\"]");
}
}
public static String toJSONString(char[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public static void writeJSONString(Object[] array, Writer out) throws IOException{
if(array == null){
out.write("null");
} else if(array.length == 0) {
out.write("[]");
} else {
out.write("[");
JSONValue.writeJSONString(array[0], out);
for(int i = 1; i < array.length; i++){
out.write(",");
JSONValue.writeJSONString(array[i], out);
}
out.write("]");
}
}
public static String toJSONString(Object[] array){
final StringWriter writer = new StringWriter();
try {
writeJSONString(array, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
public String toJSONString(){
return toJSONString(this);
}
/**
* Returns a string representation of this array. This is equivalent to
* calling {@link JSONArray#toJSONString()}.
*/
public String toString() {
return toJSONString();
}
}

View File

@ -0,0 +1,30 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.json;
/**
* Beans that support customized output of JSON text shall implement this interface.
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public interface JSONAware {
/**
* format change
*
* @return JSON text
*/
String toJSONString();
}

View File

@ -0,0 +1,152 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: JSONObject.java,v 1.1 2006/04/15 14:10:48 platform Exp $
* Created on 2006-4-10
*/
package com.alibaba.nacos.client.logger.json;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* A JSON object. Key value pairs are unordered. JSONObject supports java.util.Map interface.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class JSONObject extends HashMap implements Map, JSONAware, JSONStreamAware{
private static final long serialVersionUID = -503443796854799292L;
public JSONObject() {
super();
}
/**
* Allows creation of a JSONObject from a Map. After that, both the
* generated JSONObject and the Map can be modified independently.
*
* @param map
*/
public JSONObject(Map map) {
super(map);
}
/**
* Encode a map into JSON text and write it to out.
* If this map is also a JSONAware or JSONStreamAware, JSONAware or JSONStreamAware specific behaviours will be ignored at this top level.
*
* @see com.alibaba.nacos.client.logger.json.JSONValue#writeJSONString(Object, Writer)
*
* @param map
* @param out
*/
public static void writeJSONString(Map map, Writer out) throws IOException {
if(map == null){
out.write("null");
return;
}
boolean first = true;
Iterator iter=map.entrySet().iterator();
out.write('{');
while(iter.hasNext()){
if (first) {
first = false;
}
else {
out.write(',');
}
Map.Entry entry = (Map.Entry) iter.next();
out.write('\"');
out.write(escape(String.valueOf(entry.getKey())));
out.write('\"');
out.write(':');
JSONValue.writeJSONString(entry.getValue(), out);
}
out.write('}');
}
public void writeJSONString(Writer out) throws IOException{
writeJSONString(this, out);
}
/**
* Convert a map to JSON text. The result is a JSON object.
* If this map is also a JSONAware, JSONAware specific behaviours will be omitted at this top level.
*
* @see com.alibaba.nacos.client.logger.json.JSONValue#toJSONString(Object)
*
* @param map
* @return JSON text, or "null" if map is null.
*/
public static String toJSONString(Map map){
final StringWriter writer = new StringWriter();
try {
writeJSONString(map, writer);
return writer.toString();
} catch (IOException e) {
// This should never happen with a StringWriter
throw new RuntimeException(e);
}
}
public String toJSONString(){
return toJSONString(this);
}
public String toString(){
return toJSONString();
}
public static String toString(String key,Object value){
StringBuffer sb = new StringBuffer();
sb.append('\"');
if(key == null) {
sb.append("null");
}
else {
JSONValue.escape(key, sb);
}
sb.append('\"').append(':');
sb.append(JSONValue.toJSONString(value));
return sb.toString();
}
/**
* Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).
* It's the same as JSONValue.escape() only for compatibility here.
*
* @see com.alibaba.nacos.client.logger.json.JSONValue#escape(String)
*
* @param s
* @return
*/
public static String escape(String s){
return JSONValue.escape(s);
}
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.json;
import java.io.IOException;
import java.io.Writer;
/**
* Beans that support customized output of JSON text to a writer shall implement
* this interface.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public interface JSONStreamAware {
/**
* write JSON string to out.
*
* @param out
* out writer
* @throws IOException
* Exception
*/
void writeJSONString(Writer out) throws IOException;
}

View File

@ -0,0 +1,343 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: JSONValue.java,v 1.1 2006/04/15 14:37:04 platform Exp $
* Created on 2006-4-15
*/
package com.alibaba.nacos.client.logger.json;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.util.Collection;
import java.util.Map;
import com.alibaba.nacos.client.logger.json.parser.JSONParser;
import com.alibaba.nacos.client.logger.json.parser.ParseException;
/**
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class JSONValue {
/**
* Parse JSON text into java object from the input source.
* Please use parseWithException() if you don't want to ignore the exception.
*
* @see com.alibaba.nacos.client.logger.jsonparser.JSONParser#parse(Reader)
* @see #parseWithException(Reader)
*
* @param in
* @return Instance of the following:
* com.alibaba.nacos.client.logger.jsonJSONObject,
* com.alibaba.nacos.client.logger.jsonJSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
* @deprecated this method may throw an {@code Error} instead of returning
* {@code null}; please use {@link JSONValue#parseWithException(Reader)}
* instead
*/
public static Object parse(Reader in){
try{
JSONParser parser=new JSONParser();
return parser.parse(in);
}
catch(Exception e){
return null;
}
}
/**
* Parse JSON text into java object from the given string.
* Please use parseWithException() if you don't want to ignore the exception.
*
* @see com.alibaba.nacos.client.logger.jsonparser.JSONParser#parse(Reader)
* @see #parseWithException(Reader)
*
* @param s
* @return Instance of the following:
* com.alibaba.nacos.client.logger.jsonJSONObject,
* com.alibaba.nacos.client.logger.jsonJSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
* @deprecated this method may throw an {@code Error} instead of returning
* {@code null}; please use {@link JSONValue#parseWithException(String)}
* instead
*/
public static Object parse(String s){
StringReader in=new StringReader(s);
return parse(in);
}
/**
* Parse JSON text into java object from the input source.
*
* @see com.alibaba.nacos.client.logger.jsonparser.JSONParser
*
* @param in
* @return Instance of the following:
* com.alibaba.nacos.client.logger.jsonJSONObject,
* com.alibaba.nacos.client.logger.jsonJSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
* @throws IOException
* @throws ParseException
*/
public static Object parseWithException(Reader in) throws IOException, ParseException {
JSONParser parser=new JSONParser();
return parser.parse(in);
}
public static Object parseWithException(String s) throws ParseException{
JSONParser parser=new JSONParser();
return parser.parse(s);
}
/**
* Encode an object into JSON text and write it to out.
* <p>
* If this object is a Map or a List, and it's also a JSONStreamAware or a JSONAware, JSONStreamAware or JSONAware will be considered firstly.
* <p>
* DO NOT call this method from writeJSONString(Writer) of a class that implements both JSONStreamAware and (Map or List) with
* "this" as the first parameter, use JSONObject.writeJSONString(Map, Writer) or JSONArray.writeJSONString(List, Writer) instead.
*
* @see com.alibaba.nacos.client.logger.jsonJSONObject#writeJSONString(Map, Writer)
* @see com.alibaba.nacos.client.logger.jsonJSONArray#writeJSONString(List, Writer)
*
* @param value
* @param writer
*/
public static void writeJSONString(Object value, Writer out) throws IOException {
if(value == null){
out.write("null");
return;
}
if(value instanceof String){
out.write('\"');
out.write(escape((String)value));
out.write('\"');
return;
}
if(value instanceof Double){
if(((Double)value).isInfinite() || ((Double)value).isNaN()) {
out.write("null");
}
else {
out.write(value.toString());
}
return;
}
if(value instanceof Float){
if(((Float)value).isInfinite() || ((Float)value).isNaN()) {
out.write("null");
}
else {
out.write(value.toString());
}
return;
}
if(value instanceof Number){
out.write(value.toString());
return;
}
if(value instanceof Boolean){
out.write(value.toString());
return;
}
if((value instanceof JSONStreamAware)){
((JSONStreamAware)value).writeJSONString(out);
return;
}
if((value instanceof JSONAware)){
out.write(((JSONAware)value).toJSONString());
return;
}
if(value instanceof Map){
JSONObject.writeJSONString((Map)value, out);
return;
}
if(value instanceof Collection){
JSONArray.writeJSONString((Collection)value, out);
return;
}
if(value instanceof byte[]){
JSONArray.writeJSONString((byte[])value, out);
return;
}
if(value instanceof short[]){
JSONArray.writeJSONString((short[])value, out);
return;
}
if(value instanceof int[]){
JSONArray.writeJSONString((int[])value, out);
return;
}
if(value instanceof long[]){
JSONArray.writeJSONString((long[])value, out);
return;
}
if(value instanceof float[]){
JSONArray.writeJSONString((float[])value, out);
return;
}
if(value instanceof double[]){
JSONArray.writeJSONString((double[])value, out);
return;
}
if(value instanceof boolean[]){
JSONArray.writeJSONString((boolean[])value, out);
return;
}
if(value instanceof char[]){
JSONArray.writeJSONString((char[])value, out);
return;
}
if(value instanceof Object[]){
JSONArray.writeJSONString((Object[])value, out);
return;
}
out.write(value.toString());
}
/**
* Convert an object to JSON text.
* <p>
* If this object is a Map or a List, and it's also a JSONAware, JSONAware will be considered firstly.
* <p>
* DO NOT call this method from toJSONString() of a class that implements both JSONAware and Map or List with
* "this" as the parameter, use JSONObject.toJSONString(Map) or JSONArray.toJSONString(List) instead.
*
* @see com.alibaba.nacos.client.logger.json.JSONObject#toJSONString(Map)
*
* @param value
* @return JSON text, or "null" if value is null or it's an NaN or an INF number.
*/
public static String toJSONString(Object value){
final StringWriter writer = new StringWriter();
try{
writeJSONString(value, writer);
return writer.toString();
} catch(IOException e){
// This should never happen for a StringWriter
throw new RuntimeException(e);
}
}
/**
* Escape quotes, \, /, \r, \n, \b, \f, \t and other control characters (U+0000 through U+001F).
* @param s
* @return
*/
public static String escape(String s){
if(s==null) {
return null;
}
StringBuffer sb = new StringBuffer();
escape(s, sb);
return sb.toString();
}
/**
* @param s - Must not be null.
* @param sb
*/
static void escape(String s, StringBuffer sb) {
final int len = s.length();
for(int i=0;i<len;i++){
char ch=s.charAt(i);
switch(ch){
case '"':
sb.append("\\\"");
break;
case '\\':
sb.append("\\\\");
break;
case '\b':
sb.append("\\b");
break;
case '\f':
sb.append("\\f");
break;
case '\n':
sb.append("\\n");
break;
case '\r':
sb.append("\\r");
break;
case '\t':
sb.append("\\t");
break;
case '/':
sb.append("\\/");
break;
default:
//Reference: http://www.unicode.org/versions/Unicode5.1.0/
if(isUnicodeChar(ch)){
String ss=Integer.toHexString(ch);
sb.append("\\u");
for(int k=0;k<FOUR-ss.length();k++){
sb.append('0');
}
sb.append(ss.toUpperCase());
}
else{
sb.append(ch);
}
}
}//for
}
private static boolean isUnicodeChar(char ch) {
return (ch >= '\u0000' && ch <= '\u001F') || (ch >= '\u007F' && ch <= '\u009F')
|| (ch >= '\u2000' && ch <= '\u20FF');
}
private static int FOUR = 4;
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.json.parser;
import java.util.List;
import java.util.Map;
/**
* Container factory for creating containers for JSON object and JSON array.
*
* @see com.alibaba.nacos.client.logger.json.parser.JSONParser#parse(java.io.Reader, ContainerFactory)
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public interface ContainerFactory {
/**
* create json container
* @return A Map instance to store JSON object, or null if you want to use com.alibaba.nacos.client.logger.jsonJSONObject.
*/
Map createObjectContainer();
/**
* create array json container
* @return A List instance to store JSON array, or null if you want to use com.alibaba.nacos.client.logger.jsonJSONArray.
*/
List creatArrayContainer();
}

View File

@ -0,0 +1,129 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.json.parser;
import java.io.IOException;
/**
* A simplified and stoppable SAX-like content handler for stream processing of JSON text.
*
* @see org.xml.sax.ContentHandler
* @see com.alibaba.nacos.client.logger.json.parser.JSONParser#parse(java.io.Reader, ContentHandler, boolean)
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public interface ContentHandler {
/**
* Receive notification of the beginning of JSON processing.
* The parser will invoke this method only once.
*
* @throws ParseException
* - JSONParser will stop and throw the same exception to the caller when receiving this exception.
* @throws IOException
*/
void startJSON() throws ParseException, IOException;
/**
* Receive notification of the end of JSON processing.
*
* @throws ParseException
* @throws IOException
*/
void endJSON() throws ParseException, IOException;
/**
* Receive notification of the beginning of a JSON object.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* - JSONParser will stop and throw the same exception to the caller when receiving this exception.
* @throws IOException
* @see #endJSON
*/
boolean startObject() throws ParseException, IOException;
/**
* Receive notification of the end of a JSON object.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* @throws IOException
* @see #startObject
*/
boolean endObject() throws ParseException, IOException;
/**
* Receive notification of the beginning of a JSON object entry.
*
* @param key - Key of a JSON object entry.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* @throws IOException
* @see #endObjectEntry
*/
boolean startObjectEntry(String key) throws ParseException, IOException;
/**
* Receive notification of the end of the value of previous object entry.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* @throws IOException
* @see #startObjectEntry
*/
boolean endObjectEntry() throws ParseException, IOException;
/**
* Receive notification of the beginning of a JSON array.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* @throws IOException
* @see #endArray
*/
boolean startArray() throws ParseException, IOException;
/**
* Receive notification of the end of a JSON array.
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* @throws IOException
* @see #startArray
*/
boolean endArray() throws ParseException, IOException;
/**
* Receive notification of the JSON primitive values:
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean
* null
*
* @param value - Instance of the following:
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean
* null
*
* @return false if the handler wants to stop parsing after return.
* @throws ParseException
* @throws IOException
*/
boolean primitive(Object value) throws ParseException, IOException;
}

View File

@ -0,0 +1,574 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: JSONParser.java,v 1.1 2006/04/15 14:10:48 platform Exp $
* Created on 2006-4-15
*/
package com.alibaba.nacos.client.logger.json.parser;
import java.io.IOException;
import java.io.Reader;
import java.io.StringReader;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.client.logger.json.JSONArray;
import com.alibaba.nacos.client.logger.json.JSONObject;
/**
* Parser for JSON text. Please note that JSONParser is NOT thread-safe.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
@SuppressWarnings("PMD.ClassNamingShouldBeCamelRule")
public class JSONParser {
public static final int S_INIT=0;
public static final int S_IN_FINISHED_VALUE=1;
public static final int S_IN_OBJECT=2;
public static final int S_IN_ARRAY=3;
public static final int S_PASSED_PAIR_KEY=4;
public static final int S_IN_PAIR_VALUE=5;
public static final int S_END=6;
public static final int S_IN_ERROR=-1;
private LinkedList handlerStatusStack;
private Yylex lexer = new Yylex((Reader)null);
private Yytoken token = null;
private int status = S_INIT;
private int peekStatus(LinkedList statusStack){
if(statusStack.size()==0) {
return -1;
}
Integer status=(Integer)statusStack.getFirst();
return status.intValue();
}
/**
* Reset the parser to the initial state without resetting the underlying reader.
*
*/
public void reset(){
token = null;
status = S_INIT;
handlerStatusStack = null;
}
/**
* Reset the parser to the initial state with a new character reader.
*
* @param in - The new character reader.
* @throws IOException
* @throws ParseException
*/
public void reset(Reader in){
lexer.yyreset(in);
reset();
}
/**
* @return The position of the beginning of the current token.
*/
public int getPosition(){
return lexer.getPosition();
}
public Object parse(String s) throws ParseException{
return parse(s, (ContainerFactory)null);
}
public Object parse(String s, ContainerFactory containerFactory) throws ParseException{
StringReader in=new StringReader(s);
try{
return parse(in, containerFactory);
}
catch(IOException ie){
/*
* Actually it will never happen.
*/
throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
}
}
public Object parse(Reader in) throws IOException, ParseException{
return parse(in, (ContainerFactory)null);
}
/**
* Parse JSON text into java object from the input source.
*
* @param in
* @param containerFactory - Use this factory to createyour own JSON object and JSON array containers.
* @return Instance of the following:
* com.alibaba.nacos.client.logger.jsonJSONObject,
* com.alibaba.nacos.client.logger.jsonJSONArray,
* java.lang.String,
* java.lang.Number,
* java.lang.Boolean,
* null
*
* @throws IOException
* @throws ParseException
*/
public Object parse(Reader in, ContainerFactory containerFactory) throws IOException, ParseException{
reset(in);
LinkedList statusStack = new LinkedList();
LinkedList valueStack = new LinkedList();
try{
do{
nextToken();
switch(status){
case S_INIT:
switch(token.type){
case Yytoken.TYPE_VALUE:
status=S_IN_FINISHED_VALUE;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(token.value);
break;
case Yytoken.TYPE_LEFT_BRACE:
status=S_IN_OBJECT;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(createObjectContainer(containerFactory));
break;
case Yytoken.TYPE_LEFT_SQUARE:
status=S_IN_ARRAY;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(createArrayContainer(containerFactory));
break;
default:
status=S_IN_ERROR;
}//inner switch
break;
case S_IN_FINISHED_VALUE:
if(token.type==Yytoken.TYPE_EOF) {
return valueStack.removeFirst();
}
else {
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
case S_IN_OBJECT:
switch(token.type){
case Yytoken.TYPE_COMMA:
break;
case Yytoken.TYPE_VALUE:
if(token.value instanceof String){
String key=(String)token.value;
valueStack.addFirst(key);
status=S_PASSED_PAIR_KEY;
statusStack.addFirst(Integer.valueOf(status));
}
else{
status=S_IN_ERROR;
}
break;
case Yytoken.TYPE_RIGHT_BRACE:
if(valueStack.size()>1){
statusStack.removeFirst();
valueStack.removeFirst();
status=peekStatus(statusStack);
}
else{
status=S_IN_FINISHED_VALUE;
}
break;
default:
status=S_IN_ERROR;
break;
}//inner switch
break;
case S_PASSED_PAIR_KEY:
switch(token.type){
case Yytoken.TYPE_COLON:
break;
case Yytoken.TYPE_VALUE:
statusStack.removeFirst();
String key=(String)valueStack.removeFirst();
Map parent=(Map)valueStack.getFirst();
parent.put(key,token.value);
status=peekStatus(statusStack);
break;
case Yytoken.TYPE_LEFT_SQUARE:
statusStack.removeFirst();
key=(String)valueStack.removeFirst();
parent=(Map)valueStack.getFirst();
List newArray=createArrayContainer(containerFactory);
parent.put(key,newArray);
status=S_IN_ARRAY;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(newArray);
break;
case Yytoken.TYPE_LEFT_BRACE:
statusStack.removeFirst();
key=(String)valueStack.removeFirst();
parent=(Map)valueStack.getFirst();
Map newObject=createObjectContainer(containerFactory);
parent.put(key,newObject);
status=S_IN_OBJECT;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(newObject);
break;
default:
status=S_IN_ERROR;
}
break;
case S_IN_ARRAY:
switch(token.type){
case Yytoken.TYPE_COMMA:
break;
case Yytoken.TYPE_VALUE:
List val=(List)valueStack.getFirst();
val.add(token.value);
break;
case Yytoken.TYPE_RIGHT_SQUARE:
if(valueStack.size()>1){
statusStack.removeFirst();
valueStack.removeFirst();
status=peekStatus(statusStack);
}
else{
status=S_IN_FINISHED_VALUE;
}
break;
case Yytoken.TYPE_LEFT_BRACE:
val=(List)valueStack.getFirst();
Map newObject=createObjectContainer(containerFactory);
val.add(newObject);
status=S_IN_OBJECT;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(newObject);
break;
case Yytoken.TYPE_LEFT_SQUARE:
val=(List)valueStack.getFirst();
List newArray=createArrayContainer(containerFactory);
val.add(newArray);
status=S_IN_ARRAY;
statusStack.addFirst(Integer.valueOf(status));
valueStack.addFirst(newArray);
break;
default:
status=S_IN_ERROR;
}//inner switch
break;
case S_IN_ERROR:
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
default:
break;
}//switch
if(status==S_IN_ERROR){
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
}while(token.type!=Yytoken.TYPE_EOF);
}
catch(IOException ie){
throw ie;
}
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
private void nextToken() throws ParseException, IOException{
token = lexer.yylex();
if(token == null) {
token = new Yytoken(Yytoken.TYPE_EOF, null);
}
}
private Map createObjectContainer(ContainerFactory containerFactory){
if(containerFactory == null) {
return new JSONObject();
}
Map m = containerFactory.createObjectContainer();
if(m == null) {
return new JSONObject();
}
return m;
}
private List createArrayContainer(ContainerFactory containerFactory){
if(containerFactory == null) {
return new JSONArray();
}
List l = containerFactory.creatArrayContainer();
if(l == null) {
return new JSONArray();
}
return l;
}
public void parse(String s, ContentHandler contentHandler) throws ParseException{
parse(s, contentHandler, false);
}
public void parse(String s, ContentHandler contentHandler, boolean isResume) throws ParseException{
StringReader in=new StringReader(s);
try{
parse(in, contentHandler, isResume);
}
catch(IOException ie){
/*
* Actually it will never happen.
*/
throw new ParseException(-1, ParseException.ERROR_UNEXPECTED_EXCEPTION, ie);
}
}
public void parse(Reader in, ContentHandler contentHandler) throws IOException, ParseException{
parse(in, contentHandler, false);
}
/**
* Stream processing of JSON text.
*
* @see ContentHandler
*
* @param in
* @param contentHandler
* @param isResume - Indicates if it continues previous parsing operation.
* If set to true, resume parsing the old stream, and parameter 'in' will be ignored.
* If this method is called for the first time in this instance, isResume will be ignored.
*
* @throws IOException
* @throws ParseException
*/
public void parse(Reader in, ContentHandler contentHandler, boolean isResume) throws IOException, ParseException{
if(!isResume){
reset(in);
handlerStatusStack = new LinkedList();
}
else{
if(handlerStatusStack == null){
isResume = false;
reset(in);
handlerStatusStack = new LinkedList();
}
}
LinkedList statusStack = handlerStatusStack;
try{
do{
switch(status){
case S_INIT:
contentHandler.startJSON();
nextToken();
switch(token.type){
case Yytoken.TYPE_VALUE:
status=S_IN_FINISHED_VALUE;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.primitive(token.value)) {
return;
}
break;
case Yytoken.TYPE_LEFT_BRACE:
status=S_IN_OBJECT;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startObject()) {
return;
}
break;
case Yytoken.TYPE_LEFT_SQUARE:
status=S_IN_ARRAY;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startArray()) {
return;
}
break;
default:
status=S_IN_ERROR;
}//inner switch
break;
case S_IN_FINISHED_VALUE:
nextToken();
if(token.type==Yytoken.TYPE_EOF){
contentHandler.endJSON();
status = S_END;
return;
}
else{
status = S_IN_ERROR;
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
case S_IN_OBJECT:
nextToken();
switch(token.type){
case Yytoken.TYPE_COMMA:
break;
case Yytoken.TYPE_VALUE:
if(token.value instanceof String){
String key=(String)token.value;
status=S_PASSED_PAIR_KEY;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startObjectEntry(key)) {
return;
}
}
else{
status=S_IN_ERROR;
}
break;
case Yytoken.TYPE_RIGHT_BRACE:
if(statusStack.size()>1){
statusStack.removeFirst();
status=peekStatus(statusStack);
}
else{
status=S_IN_FINISHED_VALUE;
}
if(!contentHandler.endObject()) {
return;
}
break;
default:
status=S_IN_ERROR;
break;
}//inner switch
break;
case S_PASSED_PAIR_KEY:
nextToken();
switch(token.type){
case Yytoken.TYPE_COLON:
break;
case Yytoken.TYPE_VALUE:
statusStack.removeFirst();
status=peekStatus(statusStack);
if(!contentHandler.primitive(token.value)) {
return;
}
if(!contentHandler.endObjectEntry()) {
return;
}
break;
case Yytoken.TYPE_LEFT_SQUARE:
statusStack.removeFirst();
statusStack.addFirst(Integer.valueOf(S_IN_PAIR_VALUE));
status=S_IN_ARRAY;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startArray()) {
return;
}
break;
case Yytoken.TYPE_LEFT_BRACE:
statusStack.removeFirst();
statusStack.addFirst(Integer.valueOf(S_IN_PAIR_VALUE));
status=S_IN_OBJECT;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startObject()) {
return;
}
break;
default:
status=S_IN_ERROR;
}
break;
case S_IN_PAIR_VALUE:
/*
* S_IN_PAIR_VALUE is just a marker to indicate the end of an object entry, it doesn't proccess any token,
* therefore delay consuming token until next round.
*/
statusStack.removeFirst();
status = peekStatus(statusStack);
if(!contentHandler.endObjectEntry()) {
return;
}
break;
case S_IN_ARRAY:
nextToken();
switch(token.type){
case Yytoken.TYPE_COMMA:
break;
case Yytoken.TYPE_VALUE:
if(!contentHandler.primitive(token.value)) {
return;
}
break;
case Yytoken.TYPE_RIGHT_SQUARE:
if(statusStack.size()>1){
statusStack.removeFirst();
status=peekStatus(statusStack);
}
else{
status=S_IN_FINISHED_VALUE;
}
if(!contentHandler.endArray()) {
return;
}
break;
case Yytoken.TYPE_LEFT_BRACE:
status=S_IN_OBJECT;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startObject()) {
return;
}
break;
case Yytoken.TYPE_LEFT_SQUARE:
status=S_IN_ARRAY;
statusStack.addFirst(Integer.valueOf(status));
if(!contentHandler.startArray()) {
return;
}
break;
default:
status=S_IN_ERROR;
}//inner switch
break;
case S_END:
return;
case S_IN_ERROR:
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
default:
break;
}//switch
if(status==S_IN_ERROR){
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
}while(token.type!=Yytoken.TYPE_EOF);
}
catch(IOException ie){
status = S_IN_ERROR;
throw ie;
}
catch(ParseException pe){
status = S_IN_ERROR;
throw pe;
}
catch(RuntimeException re){
status = S_IN_ERROR;
throw re;
}
catch(Error e){
status = S_IN_ERROR;
throw e;
}
status = S_IN_ERROR;
throw new ParseException(getPosition(), ParseException.ERROR_UNEXPECTED_TOKEN, token);
}
}

View File

@ -0,0 +1,105 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.json.parser;
/**
* ParseException explains why and where the error occurs in source JSON text.
*
* @author FangYidong<fangyidong@yahoo.com.cn>
*
*/
public class ParseException extends Exception {
private static final long serialVersionUID = -7880698968187728547L;
public static final int ERROR_UNEXPECTED_CHAR = 0;
public static final int ERROR_UNEXPECTED_TOKEN = 1;
public static final int ERROR_UNEXPECTED_EXCEPTION = 2;
private int errorType;
private Object unexpectedObject;
private int position;
public ParseException(int errorType){
this(-1, errorType, null);
}
public ParseException(int errorType, Object unexpectedObject){
this(-1, errorType, unexpectedObject);
}
public ParseException(int position, int errorType, Object unexpectedObject){
this.position = position;
this.errorType = errorType;
this.unexpectedObject = unexpectedObject;
}
public int getErrorType() {
return errorType;
}
public void setErrorType(int errorType) {
this.errorType = errorType;
}
/**
* @see com.alibaba.nacos.client.logger.json.parser.JSONParser#getPosition()
*
* @return The character position (starting with 0) of the input where the error occurs.
*/
public int getPosition() {
return position;
}
public void setPosition(int position) {
this.position = position;
}
/**
* @see com.alibaba.nacos.client.logger.json.parser.Yytoken
*
* @return One of the following base on the value of errorType:
* ERROR_UNEXPECTED_CHAR java.lang.Character
* ERROR_UNEXPECTED_TOKEN com.alibaba.nacos.client.logger.jsonparser.Yytoken
* ERROR_UNEXPECTED_EXCEPTION java.lang.Exception
*/
public Object getUnexpectedObject() {
return unexpectedObject;
}
public void setUnexpectedObject(Object unexpectedObject) {
this.unexpectedObject = unexpectedObject;
}
public String getMessage() {
StringBuffer sb = new StringBuffer();
switch(errorType){
case ERROR_UNEXPECTED_CHAR:
sb.append("Unexpected character (").append(unexpectedObject).append(") at position ").append(position).append(".");
break;
case ERROR_UNEXPECTED_TOKEN:
sb.append("Unexpected token ").append(unexpectedObject).append(" at position ").append(position).append(".");
break;
case ERROR_UNEXPECTED_EXCEPTION:
sb.append("Unexpected exception at position ").append(position).append(": ").append(unexpectedObject);
break;
default:
sb.append("Unkown error at position ").append(position).append(".");
break;
}
return sb.toString();
}
}

View File

@ -0,0 +1,665 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* The following code was generated by JFlex 1.4.2 */
package com.alibaba.nacos.client.logger.json.parser;
import java.io.UnsupportedEncodingException;
import com.alibaba.nacos.client.config.common.Constants;
/**
* Yylex
* @author Nacos
*
*/
class Yylex {
/** This character denotes the end of file */
public static final int YYEOF = -1;
/** initial size of the lookahead buffer */
private static final int ZZ_BUFFERSIZE = 16384;
/** lexical states */
public static final int YYINITIAL = 0;
public static final int STRING_BEGIN = 2;
/**
* ZZ_LEXSTATE[l] is the state in the DFA for the lexical state l
* ZZ_LEXSTATE[l+1] is the state in the DFA for the lexical state l
* at the beginning of a line
* l is of the form l = 2*k, k a non negative integer
*/
private static final int ZZ_LEXSTATE[] = { 0, 0, 1, 1 };
/**
* Translates characters to character classes
*/
private static final String ZZ_CMAP_PACKED =
"\11\0\1\7\1\7\2\0\1\7\22\0\1\7\1\0\1\11\10\0" + "\1\6\1\31\1\2\1\4\1\12\12\3\1\32\6\0\4\1\1\5"
+ "\1\1\24\0\1\27\1\10\1\30\3\0\1\22\1\13\2\1\1\21" + "\1\14\5\0\1\23\1\0\1\15\3\0\1\16\1\24\1\17\1\20"
+ "\5\0\1\25\1\0\1\26\uff82\0";
/**
* Translates characters to character classes
*/
private static final char[] ZZ_CMAP = zzUnpackCMap(ZZ_CMAP_PACKED);
/**
* Translates DFA states to action switch labels.
*/
private static final int[] ZZ_ACTION = zzUnpackAction();
private static final String ZZ_ACTION_PACKED_0 =
"\2\0\2\1\1\2\1\3\1\4\3\1\1\5\1\6" + "\1\7\1\10\1\11\1\12\1\13\1\14\1\15\5\0"
+ "\1\14\1\16\1\17\1\20\1\21\1\22\1\23\1\24" + "\1\0\1\25\1\0\1\25\4\0\1\26\1\27\2\0" + "\1\30";
private static int[] zzUnpackAction() {
int[] result = new int[45];
int offset = 0;
zzUnpackAction(ZZ_ACTION_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAction(String packed, int offset, int[] result) {
int i = 0;
int j = offset;
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/**
* Translates a state to a row index in the transition table
*/
private static final int[] ZZ_ROWMAP = zzUnpackRowMap();
private static final String ZZ_ROWMAP_PACKED_0 =
"\0\0\0\33\0\66\0\121\0\154\0\207\0\66\0\242" + "\0\275\0\330\0\66\0\66\0\66\0\66\0\66\0\66"
+ "\0\363\0\u010e\0\66\0\u0129\0\u0144\0\u015f\0\u017a\0\u0195" + "\0\66\0\66\0\66\0\66\0\66\0\66\0\66\0\66"
+ "\0\u01b0\0\u01cb\0\u01e6\0\u01e6\0\u0201\0\u021c\0\u0237\0\u0252" + "\0\66\0\66\0\u026d\0\u0288\0\66";
private static int[] zzUnpackRowMap() {
int[] result = new int[45];
int offset = 0;
zzUnpackRowMap(ZZ_ROWMAP_PACKED_0, offset, result);
return result;
}
private static int zzUnpackRowMap(String packed, int offset, int[] result) {
int i = 0;
int j = offset;
int l = packed.length();
while (i < l) {
int high = packed.charAt(i++) << 16;
result[j++] = high | packed.charAt(i++);
}
return j;
}
/**
* The transition table of the DFA
*/
private static final int ZZ_TRANS[] = { 2, 2, 3, 4, 2, 2, 2, 5, 2, 6, 2, 2, 7, 8, 2, 9, 2, 2, 2, 2, 2, 10, 11, 12,
13, 14, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 18, 16, 16, 16, 16, 16, 16,
16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 4, 19, 20, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 21, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 22, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 23, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 16, 16, 16, 16, 16, 16, 16, 16, -1,
-1, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, -1,
-1, -1, -1, -1, -1, -1, -1, 24, 25, 26, 27, 28, 29, 30, 31, 32, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 33, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 34, 35,
-1, -1, 34, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, 36, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 37, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 39, -1, 39, -1, 39, -1, -1, -1, -1,
-1, 39, 39, -1, -1, -1, -1, 39, 39, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 33, -1, 20, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 20, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 35, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 38, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, 40, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 41, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, 42, -1, 42, -1, 42, -1, -1, -1, -1, -1, 42, 42, -1, -1, -1, -1, 42, 42,
-1, -1, -1, -1, -1, -1, -1, -1, -1, 43, -1, 43, -1, 43, -1, -1, -1, -1, -1,
43, 43, -1, -1, -1, -1, 43, 43, -1, -1, -1, -1, -1, -1, -1, -1, -1, 44, -1,
44, -1, 44, -1, -1, -1, -1, -1, 44, 44, -1, -1, -1, -1, 44, 44, -1, -1, -1,
-1, -1, -1, -1, -1, };
/**
* error codes
*/
private static final int ZZ_UNKNOWN_ERROR = 0;
private static final int ZZ_NO_MATCH = 1;
private static final int ZZ_PUSHBACK_2BIG = 2;
private static final int NIGTY = 90;
/**
* error messages for the codes above
*/
private static final String[] ZZ_ERROR_MSG = { "Unkown internal scanner error", "Error: could not match input",
"Error: pushback value was too large" };
/**
* ZZ_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>
*/
private static final int[] ZZ_ATTRIBUTE = zzUnpackAttribute();
private static final String ZZ_ATTRIBUTE_PACKED_0 =
"\2\0\1\11\3\1\1\11\3\1\6\11\2\1\1\11" + "\5\0\10\11\1\0\1\1\1\0\1\1\4\0\2\11" + "\2\0\1\11";
private static int[] zzUnpackAttribute() {
int[] result = new int[45];
int offset = 0;
zzUnpackAttribute(ZZ_ATTRIBUTE_PACKED_0, offset, result);
return result;
}
private static int zzUnpackAttribute(String packed, int offset, int[] result) {
int i = 0;
int j = offset;
int l = packed.length();
while (i < l) {
int count = packed.charAt(i++);
int value = packed.charAt(i++);
do result[j++] = value; while (--count > 0);
}
return j;
}
/** the input device */
private java.io.Reader zzReader;
/** the current state of the DFA */
private int zzState;
/** the current lexical state */
private int zzLexicalState = YYINITIAL;
/**
* this buffer contains the current text to be matched and is
* the source of the yytext() string
*/
private char zzBuffer[] = new char[ZZ_BUFFERSIZE];
/** the textposition at the last accepting state */
private int zzMarkedPos;
/** the current text position in the buffer */
private int zzCurrentPos;
/** startRead marks the beginning of the yytext() string in the buffer */
private int zzStartRead;
/**
* endRead marks the last character in the buffer, that has been read
* from input
*/
private int zzEndRead;
/** the number of characters up to the start of the matched text */
private int yychar;
/** zzAtEOF == true <=> the scanner is at the EOF */
private boolean zzAtEOF;
/**
* user code
*/
private StringBuffer sb = new StringBuffer();
int getPosition() {
return yychar;
}
/**
* Creates a new scanner
* There is also a java.io.InputStream version of this constructor.
*
* @param in the java.io.Reader to read input from.
*/
Yylex(java.io.Reader in) {
this.zzReader = in;
}
/**
* Creates a new scanner.
* There is also java.io.Reader version of this constructor.
*
* @param in the java.io.Inputstream to read input from.
* @throws UnsupportedEncodingException
*/
Yylex(java.io.InputStream in) throws UnsupportedEncodingException {
this(new java.io.InputStreamReader(in, Constants.ENCODE));
}
/**
* Unpacks the compressed character translation table.
*
* @param packed the packed character translation table
* @return the unpacked character translation table
*/
private static char[] zzUnpackCMap(String packed) {
char[] map = new char[0x10000];
int i = 0;
int j = 0;
while (i < NIGTY) {
int count = packed.charAt(i++);
char value = packed.charAt(i++);
do map[j++] = value; while (--count > 0);
}
return map;
}
/**
* Refills the input buffer.
*
* @return <code>false</code>, iff there was new input.
* @throws java.io.IOException if any I/O-Error occurs
*/
private boolean zzRefill() throws java.io.IOException {
/* first: make room (if you can) */
if (zzStartRead > 0) {
System.arraycopy(zzBuffer, zzStartRead, zzBuffer, 0, zzEndRead - zzStartRead);
/* translate stored positions */
zzEndRead -= zzStartRead;
zzCurrentPos -= zzStartRead;
zzMarkedPos -= zzStartRead;
zzStartRead = 0;
}
/* is the buffer big enough? */
if (zzCurrentPos >= zzBuffer.length) {
/* if not: blow it up */
char newBuffer[] = new char[zzCurrentPos * 2];
System.arraycopy(zzBuffer, 0, newBuffer, 0, zzBuffer.length);
zzBuffer = newBuffer;
}
/* finally: fill the buffer with new input */
int numRead = zzReader.read(zzBuffer, zzEndRead, zzBuffer.length - zzEndRead);
if (numRead > 0) {
zzEndRead += numRead;
return false;
}
// unlikely but not impossible: read 0 characters, but not at end of stream
if (numRead == 0) {
int c = zzReader.read();
if (c == -1) {
return true;
} else {
zzBuffer[zzEndRead++] = (char) c;
return false;
}
}
// numRead < 0
return true;
}
/**
* Closes the input stream.
*/
public final void yyclose() throws java.io.IOException {
zzAtEOF = true;
zzEndRead = zzStartRead;
if (zzReader != null) {
zzReader.close();
}
}
/**
* Resets the scanner to read from a new input stream.
* Does not close the old reader.
* All internal variables are reset, the old input stream
* <b>cannot</b> be reused (internal buffer is discarded and lost).
* Lexical state is set to <tt>ZZ_INITIAL</tt>.
*
* @param reader the new input stream
*/
public final void yyreset(java.io.Reader reader) {
zzReader = reader;
zzAtEOF = false;
zzEndRead = zzStartRead = 0;
zzCurrentPos = zzMarkedPos = 0;
zzLexicalState = YYINITIAL;
}
/**
* Returns the current lexical state.
*/
public final int yystate() {
return zzLexicalState;
}
/**
* Enters a new lexical state
*
* @param newState the new lexical state
*/
public final void yybegin(int newState) {
zzLexicalState = newState;
}
/**
* Returns the text matched by the current regular expression.
*/
public final String yytext() {
return new String(zzBuffer, zzStartRead, zzMarkedPos - zzStartRead);
}
/**
* Returns the character at position <tt>pos</tt> from the
* matched text.
* It is equivalent to yytext().charAt(pos), but faster
*
* @param pos the position of the character to fetch.
* A value from 0 to yylength()-1.
* @return the character at position pos
*/
public final char yycharat(int pos) {
return zzBuffer[zzStartRead + pos];
}
/**
* Returns the length of the matched text region.
*/
public final int yylength() {
return zzMarkedPos - zzStartRead;
}
/**
* Reports an error that occured while scanning.
* In a wellformed scanner (no or only correct usage of
* yypushback(int) and a match-all fallback rule) this method
* will only be called with things that "Can't Possibly Happen".
* If this method is called, something is seriously wrong
* (e.g. a JFlex bug producing a faulty scanner etc.).
* Usual syntax/scanner level error handling should be done
* in error fallback rules.
*
* @param errorCode the code of the errormessage to display
*/
private void zzScanError(int errorCode) {
String message;
try {
message = ZZ_ERROR_MSG[errorCode];
} catch (ArrayIndexOutOfBoundsException e) {
message = ZZ_ERROR_MSG[ZZ_UNKNOWN_ERROR];
}
throw new Error(message);
}
/**
* Pushes the specified amount of characters back into the input stream.
* They will be read again by then next call of the scanning method
*
* @param number the number of characters to be read again.
* This number must not be greater than yylength()!
*/
public void yypushback(int number) {
if (number > yylength()) {
zzScanError(ZZ_PUSHBACK_2BIG);
}
zzMarkedPos -= number;
}
/**
* Resumes scanning until the next regular expression is matched,
* the end of input is encountered or an I/O-Error occurs.
*
* @return the next token
* @throws java.io.IOException if any I/O-Error occurs
*/
@SuppressWarnings("PMD.SwitchStatementRule")
public Yytoken yylex() throws java.io.IOException, ParseException {
int zzInput;
int zzAction;
// cached fields:
int zzCurrentPosL;
int zzMarkedPosL;
int zzEndReadL = zzEndRead;
char[] zzBufferL = zzBuffer;
char[] zzCMapL = ZZ_CMAP;
int[] zzTransL = ZZ_TRANS;
int[] zzRowMapL = ZZ_ROWMAP;
int[] zzAttrL = ZZ_ATTRIBUTE;
while (true) {
zzMarkedPosL = zzMarkedPos;
yychar += zzMarkedPosL - zzStartRead;
zzAction = -1;
zzCurrentPosL = zzCurrentPos = zzStartRead = zzMarkedPosL;
zzState = ZZ_LEXSTATE[zzLexicalState];
zzForAction:
{
while (true) {
if (zzCurrentPosL < zzEndReadL) {
zzInput = zzBufferL[zzCurrentPosL++];
}
else if (zzAtEOF) {
zzInput = YYEOF;
break zzForAction;
} else {
// store back cached positions
zzCurrentPos = zzCurrentPosL;
zzMarkedPos = zzMarkedPosL;
boolean eof = zzRefill();
// get translated positions and possibly new buffer
zzCurrentPosL = zzCurrentPos;
zzMarkedPosL = zzMarkedPos;
zzBufferL = zzBuffer;
zzEndReadL = zzEndRead;
if (eof) {
zzInput = YYEOF;
break zzForAction;
} else {
zzInput = zzBufferL[zzCurrentPosL++];
}
}
int zzNext = zzTransL[zzRowMapL[zzState] + zzCMapL[zzInput]];
if (zzNext == -1) {
break zzForAction;
}
zzState = zzNext;
int zzAttributes = zzAttrL[zzState];
if ((zzAttributes & 1) == 1) {
zzAction = zzState;
zzMarkedPosL = zzCurrentPosL;
if ((zzAttributes & 8) == 8) {
break zzForAction;
}
}
}
}
// store back cached position
zzMarkedPos = zzMarkedPosL;
switch (zzAction < 0 ? zzAction : ZZ_ACTION[zzAction]) {
case 11: {
sb.append(yytext());
}
case 25:
break;
case 4: {
sb = null;
sb = new StringBuffer();
yybegin(STRING_BEGIN);
}
case 26:
break;
case 16: {
sb.append('\b');
}
case 27:
break;
case 6: {
return new Yytoken(Yytoken.TYPE_RIGHT_BRACE, null);
}
case 28:
break;
case 23: {
Boolean val = Boolean.valueOf(yytext());
return new Yytoken(Yytoken.TYPE_VALUE, val);
}
case 29:
break;
case 22: {
return new Yytoken(Yytoken.TYPE_VALUE, null);
}
case 30:
break;
case 13: {
yybegin(YYINITIAL);
return new Yytoken(Yytoken.TYPE_VALUE, sb.toString());
}
case 31:
break;
case 12: {
sb.append('\\');
}
case 32:
break;
case 21: {
Double val = Double.valueOf(yytext());
return new Yytoken(Yytoken.TYPE_VALUE, val);
}
case 33:
break;
case 1: {
throw new ParseException(yychar, ParseException.ERROR_UNEXPECTED_CHAR, Character.valueOf(yycharat(0)));
}
case 34:
break;
case 8: {
return new Yytoken(Yytoken.TYPE_RIGHT_SQUARE, null);
}
case 35:
break;
case 19: {
sb.append('\r');
}
case 36:
break;
case 15: {
sb.append('/');
}
case 37:
break;
case 10: {
return new Yytoken(Yytoken.TYPE_COLON, null);
}
case 38:
break;
case 14: {
sb.append('"');
}
case 39:
break;
case 5: {
return new Yytoken(Yytoken.TYPE_LEFT_BRACE, null);
}
case 40:
break;
case 17: {
sb.append('\f');
}
case 41:
break;
case 24: {
try {
int ch = Integer.parseInt(yytext().substring(2), 16);
sb.append((char) ch);
} catch (Exception e) {
throw new ParseException(yychar, ParseException.ERROR_UNEXPECTED_EXCEPTION, e);
}
}
case 42:
break;
case 20: {
sb.append('\t');
}
case 43:
break;
case 7: {
return new Yytoken(Yytoken.TYPE_LEFT_SQUARE, null);
}
case 44:
break;
case 2: {
Long val = Long.valueOf(yytext());
return new Yytoken(Yytoken.TYPE_VALUE, val);
}
case 45:
break;
case 18: {
sb.append('\n');
}
case 46:
break;
case 9: {
return new Yytoken(Yytoken.TYPE_COMMA, null);
}
case 47:
break;
case 3: {
}
case 48:
break;
default:
if (zzInput == YYEOF && zzStartRead == zzCurrentPos) {
zzAtEOF = true;
return null;
} else {
zzScanError(ZZ_NO_MATCH);
}
}
}
}
}

View File

@ -0,0 +1,81 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* $Id: Yytoken.java,v 1.1 2006/04/15 14:10:48 platform Exp $
* Created on 2006-4-15
*/
package com.alibaba.nacos.client.logger.json.parser;
/**
* @author FangYidong<fangyidong@yahoo.com.cn>
*/
public class Yytoken {
/**
* JSON primitive value: string,number,boolean,null
*/
public static final int TYPE_VALUE=0;
public static final int TYPE_LEFT_BRACE=1;
public static final int TYPE_RIGHT_BRACE=2;
public static final int TYPE_LEFT_SQUARE=3;
public static final int TYPE_RIGHT_SQUARE=4;
public static final int TYPE_COMMA=5;
public static final int TYPE_COLON=6;
/**
* end of file
*/
public static final int TYPE_EOF=-1;
public int type=0;
public Object value=null;
public Yytoken(int type,Object value){
this.type=type;
this.value=value;
}
public String toString(){
StringBuffer sb = new StringBuffer();
switch(type){
case TYPE_VALUE:
sb.append("VALUE(").append(value).append(")");
break;
case TYPE_LEFT_BRACE:
sb.append("LEFT BRACE({)");
break;
case TYPE_RIGHT_BRACE:
sb.append("RIGHT BRACE(})");
break;
case TYPE_LEFT_SQUARE:
sb.append("LEFT SQUARE([)");
break;
case TYPE_RIGHT_SQUARE:
sb.append("RIGHT SQUARE(])");
break;
case TYPE_COMMA:
sb.append("COMMA(,)");
break;
case TYPE_COLON:
sb.append("COLON(:)");
break;
case TYPE_EOF:
sb.append("END OF FILE");
break;
default:
break;
}
return sb.toString();
}
}

View File

@ -0,0 +1,146 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.log4j;
import org.apache.log4j.Level;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.option.Log4jActivateOption;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.logger.support.LoggerSupport;
import com.alibaba.nacos.client.logger.util.MessageUtil;
/**
* Log4jLogger
* @author Nacos
*
*/
public class Log4jLogger extends LoggerSupport implements Logger {
private org.apache.log4j.Logger delegate;
public Log4jLogger(org.apache.log4j.Logger delegate) {
super(delegate);
if (delegate == null) {
throw new IllegalArgumentException("delegate Logger is null");
}
this.delegate = delegate;
this.activateOption = new Log4jActivateOption(delegate);
}
@Override
public void debug(String context, String message) {
if (isDebugEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.debug(MessageUtil.getMessage(context, message));
}
}
@Override
public void debug(String context, String format, Object... args) {
if (isDebugEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.debug(MessageUtil.getMessage(context, MessageUtil.formatMessage(format, args)));
}
}
@Override
public void info(String context, String message) {
if (isInfoEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.info(MessageUtil.getMessage(context, message));
}
}
@Override
public void info(String context, String format, Object... args) {
if (isInfoEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.info(MessageUtil.getMessage(context, MessageUtil.formatMessage(format, args)));
}
}
@Override
public void warn(String message, Throwable t) {
if (isWarnEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.warn(MessageUtil.getMessage(null, message), t);
}
}
@Override
public void warn(String context, String message) {
if (isWarnEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.warn(MessageUtil.getMessage(context, message));
}
}
@Override
public void warn(String context, String format, Object... args) {
if (isWarnEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.warn(MessageUtil.getMessage(context, MessageUtil.formatMessage(format, args)));
}
}
@Override
public void error(String context, String errorCode, String message) {
if (isErrorEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.error(MessageUtil.getMessage(context, errorCode, message));
}
}
@Override
public void error(String context, String errorCode, String message, Throwable t) {
if (isErrorEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.error(MessageUtil.getMessage(context, errorCode, message), t);
}
}
@Override
public void error(String context, String errorCode, String format, Object... args) {
if (isErrorEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.error(MessageUtil.getMessage(context, errorCode, MessageUtil.formatMessage(format, args)));
}
}
@Override
public boolean isDebugEnabled() {
return delegate.isDebugEnabled();
}
@Override
public boolean isInfoEnabled() {
return delegate.isInfoEnabled();
}
@Override
public boolean isWarnEnabled() {
return delegate.isEnabledFor(Level.WARN);
}
@Override
public boolean isErrorEnabled() {
return delegate.isEnabledFor(Level.ERROR);
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.log4j;
import org.apache.log4j.LogManager;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.nop.NopLogger;
import com.alibaba.nacos.client.logger.support.ILoggerFactory;
import com.alibaba.nacos.client.logger.support.LogLog;
/**
* Log4jLogger Factory
* @author Nacos
*
*/
public class Log4jLoggerFactory implements ILoggerFactory {
public Log4jLoggerFactory() throws ClassNotFoundException {
Class.forName("org.apache.log4j.Level");
}
public Logger getLogger(Class<?> clazz) {
try {
return new Log4jLogger(LogManager.getLogger(clazz));
} catch (Throwable t) {
LogLog.error("Failed to get Log4jLogger", t);
return new NopLogger();
}
}
public Logger getLogger(String name) {
try {
return new Log4jLogger(LogManager.getLogger(name));
} catch (Throwable t) {
LogLog.error("Failed to get Log4jLogger", t);
return new NopLogger();
}
}
}

View File

@ -0,0 +1,144 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.log4j2;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.option.Log4j2ActivateOption;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.logger.support.LoggerSupport;
import com.alibaba.nacos.client.logger.util.MessageUtil;
/**
* Log4j2Logger
* @author Nacos
*
*/
public class Log4j2Logger extends LoggerSupport implements Logger {
private org.apache.logging.log4j.Logger delegate;
public Log4j2Logger(org.apache.logging.log4j.Logger delegate) {
super(delegate);
if (delegate == null) {
throw new IllegalArgumentException("delegate Logger is null");
}
this.delegate = delegate;
this.activateOption = new Log4j2ActivateOption(delegate);
}
@Override
public void debug(String context, String message) {
if (isDebugEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.debug(MessageUtil.getMessage(context, message));
}
}
@Override
public void debug(String context, String format, Object... args) {
if (isDebugEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.debug(MessageUtil.getMessage(context, MessageUtil.formatMessage(format, args)));
}
}
@Override
public void info(String context, String message) {
if (isInfoEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.info(MessageUtil.getMessage(context, message));
}
}
@Override
public void info(String context, String format, Object... args) {
if (isInfoEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.info(MessageUtil.getMessage(context, MessageUtil.formatMessage(format, args)));
}
}
@Override
public void warn(String message, Throwable t) {
if (isWarnEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.warn(MessageUtil.getMessage(null, message), t);
}
}
@Override
public void warn(String context, String message) {
if (isWarnEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.warn(MessageUtil.getMessage(context, message));
}
}
@Override
public void warn(String context, String format, Object... args) {
if (isWarnEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.warn(MessageUtil.getMessage(context, MessageUtil.formatMessage(format, args)));
}
}
@Override
public void error(String context, String errorCode, String message) {
if (isErrorEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.error(MessageUtil.getMessage(context, errorCode, message));
}
}
@Override
public void error(String context, String errorCode, String message, Throwable t) {
if (isErrorEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.error(MessageUtil.getMessage(context, errorCode, message), t);
}
}
@Override
public void error(String context, String errorCode, String format, Object... args) {
if (isErrorEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.error(MessageUtil.getMessage(context, errorCode, MessageUtil.formatMessage(format, args)));
}
}
@Override
public boolean isDebugEnabled() {
return delegate.isDebugEnabled();
}
@Override
public boolean isInfoEnabled() {
return delegate.isInfoEnabled();
}
@Override
public boolean isWarnEnabled() {
return delegate.isWarnEnabled();
}
@Override
public boolean isErrorEnabled() {
return delegate.isErrorEnabled();
}
}

View File

@ -0,0 +1,55 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.log4j2;
import org.apache.logging.log4j.LogManager;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.nop.NopLogger;
import com.alibaba.nacos.client.logger.support.ILoggerFactory;
import com.alibaba.nacos.client.logger.support.LogLog;
/**
* Log4j2Logger Factory
* @author Nacos
*
*/
public class Log4j2LoggerFactory implements ILoggerFactory {
public Log4j2LoggerFactory() throws ClassNotFoundException {
Class.forName("org.apache.logging.log4j.core.Logger");
}
@Override
public Logger getLogger(Class<?> clazz) {
try {
return new Log4j2Logger(LogManager.getLogger(clazz));
} catch (Throwable t) {
LogLog.error("Failed to get Log4j2Logger", t);
return new NopLogger();
}
}
@Override
public Logger getLogger(String name) {
try {
return new Log4j2Logger(LogManager.getLogger(name));
} catch (Throwable t) {
LogLog.error("Failed to get Log4j2Logger", t);
return new NopLogger();
}
}
}

View File

@ -0,0 +1,99 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.nop;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerSupport;
/**
* NopLogger
* @author Nacos
*
*/
public class NopLogger extends LoggerSupport implements Logger {
public NopLogger(){
super(null);
}
@Override
public void debug(String context, String message) {
}
@Override
public void debug(String context, String format, Object... args) {
}
@Override
public void info(String context, String message) {
}
@Override
public void info(String context, String format, Object... args) {
}
public void warn(String message, Throwable t) {
}
@Override
public void warn(String context, String message) {
}
@Override
public void warn(String context, String format, Object... args) {
}
@Override
public void error(String context, String errorCode, String message) {
}
@Override
public void error(String context, String errorCode, String message, Throwable t) {
}
@Override
public void error(String context, String errorCode, String format, Object... args) {
}
@Override
public boolean isDebugEnabled() {
return false;
}
@Override
public boolean isInfoEnabled() {
return false;
}
@Override
public boolean isWarnEnabled() {
return false;
}
@Override
public boolean isErrorEnabled() {
return false;
}
}

View File

@ -0,0 +1,36 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.nop;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.ILoggerFactory;
/**
* NopLogger Factory
* @author Nacos
*
*/
public class NopLoggerFactory implements ILoggerFactory {
@Override
public Logger getLogger(Class<?> clazz) {
return new NopLogger();
}
@Override
public Logger getLogger(String name) {
return new NopLogger();
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import org.apache.log4j.AsyncAppender;
import com.alibaba.nacos.client.logger.Level;
import com.alibaba.nacos.client.logger.support.LogLog;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
/**
* AbstractActiveOption
* @author Nacos
*
*/
public abstract class AbstractActiveOption implements ActivateOption {
protected String productName;
protected Level level;
@Override
public String getProductName() {
return productName;
}
@Override
public Level getLevel() {
return level;
}
protected void setProductName(String productName) {
if (this.productName == null && productName != null) {
this.productName = productName;
}
}
public static void invokeMethod(Object object, List<Object[]> args) {
if (args != null && object != null) {
for (Object[] arg : args) {
if (arg != null && arg.length == 3) {
try {
Method m = object.getClass().getMethod((String) arg[0], (Class<?>[]) arg[1]);
m.invoke(object, arg[2]);
} catch (NoSuchMethodException e) {
LogLog.info("Can't find method for " + object.getClass() + " " + arg[0] + " " + arg[2]);
} catch (IllegalAccessException e) {
LogLog.info("Can't invoke method for " + object.getClass() + " " + arg[0] + " " + arg[2]);
} catch (InvocationTargetException e) {
LogLog.info("Can't invoke method for " + object.getClass() + " " + arg[0] + " " + arg[2]);
} catch (Throwable t) {
LogLog.info("Can't invoke method for " + object.getClass() + " " + arg[0] + " " + arg[2]);
}
}
}
}
}
}

View File

@ -0,0 +1,195 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import java.util.List;
import java.util.Map;
import com.alibaba.nacos.client.logger.Level;
import com.alibaba.nacos.client.logger.Logger;
/**
* <pre>
* 激活Logger的选项包括
* Appender/Layout
* Level
* Additivity
* Aysnc
* 请参考具体的实现逻辑
* </pre>
*
* @author zhuyong 2014年3月20日 上午10:20:51
*/
public interface ActivateOption {
/**
* 设置ConsoleAppender生产环境慎用
*
* @param target System.out or System.err
* @param encoding 编码
*/
void activateConsoleAppender(String target, String encoding);
/**
* 设置FileAppender日志按天回滚
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
*/
void activateAppender(String productName, String file, String encoding);
/**
* 设置AsyncAppender内嵌DailyRollingFileAppender日志按天回滚参考 {@link ActivateOption#activateAsync(int, int)}
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
*/
@Deprecated
void activateAsyncAppender(String productName, String file, String encoding);
/**
* 设置AsyncAppender内嵌DailyRollingFileAppender日志按天回滚参考 {@link ActivateOption#activateAsync(int, int)}
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
* @param queueSize 等待队列大小
* @param discardingThreshold discardingThreshold该参数仅对logback实现有效log4j和log4j2无效
*/
@Deprecated
void activateAsyncAppender(String productName, String file, String encoding, int queueSize,
int discardingThreshold);
/**
* 设置按天和文件大小回滚
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
* @param size 文件大小如300MB支持KBMBGB该参数对log4j实现不生效log4j2和logback有效
*/
void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size);
/**
* <pre>
* 设置按日期格式和文件大小回滚
* 说明Log4j 对日期格式不生效只有按大小回滚同时不支持备份文件即达到文件大小直接截断如果需要备份文件请参考带 maxBackupIndex 参数的方法
* </pre>
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
* @param size 文件大小如300MB支持KBMBGB
* @param datePattern 日期格式如yyyy-MM-dd yyyy-MM请自行保证格式正确该参数对log4j实现不生效log4j2和logback有效
*/
void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size,
String datePattern);
/**
* <pre>
* 设置按日期格式文件大小最大备份文件数回滚
* 说明
* 1Log4j 对日期格式不生效只有按大小备份文件数回滚备份文件数 maxBackupIndex 参数必须是 >= 0 的整数为0时表示直接截断不备份
* 2备份日志格式说明
* Log4jnotify.log.1, notify.log.2即备份文件以 .1 .2结尾序号从1开始
* Logback: notify.log.2014-09-19.0 notify.log.2014-09-19.1即中间会带日期格式同时序号从0开始
* </pre>
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
* @param size 文件大小如300MB支持KBMBGB
* @param datePattern 日期格式如yyyy-MM-dd yyyy-MM请自行保证格式正确该参数对log4j实现不生效log4j2和logback有效
* @param maxBackupIndex 最大备份文件数如10对于 Logback则是保留10天的文件但是这10天内的文件则会按大小回滚
*/
void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size,
String datePattern, int maxBackupIndex);
/**
* <pre>
* 设置按文件大小最大备份文件数回滚
* 说明
* 1Log4j 备份文件数 maxBackupIndex 参数必须是 >= 0 的整数为0时表示直接截断不备份
* 2备份日志格式说明
* Log4jnotify.log.1, notify.log.2即备份文件以 .1 .2结尾序号从1开始
* Logback: notify.log.1 notify.log.1
* </pre>
*
* @param productName 中间件产品名如hsf, tddl
* @param file 日志文件名如hsf.log支持子目录如client/hsf.log
* @param encoding 编码
* @param size 文件大小如300MB支持KBMBGB
* @param maxBackupIndex 最大备份文件数如10
*/
void activateAppenderWithSizeRolling(String productName, String file, String encoding, String size,
int maxBackupIndex);
/**
* 将当前logger对象的appender设置为异步Appender
* 注意此logger需要提前进行Appender的初始化
*
* @param queueSize 等待队列大小
* @param discardingThreshold discardingThreshold该参数仅对logback实现有效log4j和log4j2无效
* @since 0.2.2
*/
void activateAsync(int queueSize, int discardingThreshold);
/**
* 将当前logger对象的appender设置为异步Appender
* 注意此logger需要提前进行Appender的初始化
*
* @param args AsyncAppender配置参数请自行保证参数的正确性要求每个Object[]有3个元素第一个为set方法名第二个为方法类型数组第三个为对应的参数值
* args.add(new Object[] { "setBufferSize", new Class<?>[] { int.class }, queueSize });
* @since 0.2.3
*/
void activateAsync(List<Object[]> args);
/**
* 使用logger对象的appender来初始化当前logger
*
* @param logger
*/
void activateAppender(Logger logger);
/**
* 设置日志级别
*
* @param level 日志级别
* @see Level
*/
void setLevel(Level level);
/**
* 获取日志级别
* @return level
*/
Level getLevel();
/**
* 设置日志是否Attach到Parent
*
* @param additivity true or false
*/
void setAdditivity(boolean additivity);
/**
* 获取所属的产品名
* @return 所属的产品名
*/
String getProductName();
}

View File

@ -0,0 +1,274 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import org.apache.logging.log4j.core.Appender;
import org.apache.logging.log4j.core.LogEvent;
import org.apache.logging.log4j.core.appender.AsyncAppender;
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.appender.RollingFileAppender;
import org.apache.logging.log4j.core.appender.rolling.*;
import org.apache.logging.log4j.core.async.ArrayBlockingQueueFactory;
import org.apache.logging.log4j.core.config.AppenderRef;
import org.apache.logging.log4j.core.config.Configuration;
import com.alibaba.nacos.client.logger.Level;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
/**
* @author zhuyong on 2017/4/13.
*/
public class Log4j2ActivateOption extends AbstractActiveOption {
protected org.apache.logging.log4j.core.Logger logger;
protected Configuration configuration;
public Log4j2ActivateOption(org.apache.logging.log4j.Logger logger) {
if (logger != null) {
if (logger instanceof org.apache.logging.log4j.core.Logger) {
this.logger = (org.apache.logging.log4j.core.Logger) logger;
configuration = this.logger.getContext().getConfiguration();
} else {
throw new RuntimeException("logger must instanceof org.apache.logging.log4j.core.Logger, " + logger.getClass().getName());
}
}
}
@Override
public void activateConsoleAppender(String target, String encoding) {
org.apache.logging.log4j.core.Layout layout = org.apache.logging.log4j.core.layout.PatternLayout.newBuilder().
withConfiguration(configuration)
.withPattern(LoggerHelper.getPattern())
.withCharset(Charset.forName(encoding))
.build();
org.apache.logging.log4j.core.appender.ConsoleAppender appender = ConsoleAppender.createAppender(layout, null,
ConsoleAppender.Target.valueOf(target.toUpperCase().replace(".", "_")), "LoggerApiConsoleAppender", false, false, true);
appender.start();
removeAllAppenders(logger);
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAppender(String productName, String file, String encoding) {
org.apache.logging.log4j.core.appender.RollingFileAppender appender = RollingFileAppender.newBuilder()
.withName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender")
.withFileName(LoggerHelper.getLogFileP(productName, file))
.withAppend(true)
.withBufferedIo(true)
.setConfiguration(configuration)
.withFilePattern(LoggerHelper.getLogFile(productName, file) + ".%d{yyyy-MM-dd}")
.withLayout(buildLayout(encoding))
.withCreateOnDemand(false)
.withPolicy(TimeBasedTriggeringPolicy.createPolicy("1", "true"))
.withStrategy(DefaultRolloverStrategy.createStrategy(null, null, "nomax", null, null, false, configuration))
.build();
appender.start();
removeAllAppenders(logger);
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAsyncAppender(String productName, String file, String encoding) {
activateAsyncAppender(productName, file, encoding, Integer.MIN_VALUE, Integer.MIN_VALUE);
}
@Override
public void activateAsyncAppender(String productName, String file, String encoding, int queueSize, int discardingThreshold) {
activateAppender(productName, file, encoding);
activateAsync(queueSize, discardingThreshold);
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size) {
activateAppenderWithTimeAndSizeRolling(productName, file, encoding, size, "yyyy-MM-dd");
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size, String datePattern) {
org.apache.logging.log4j.core.appender.RollingFileAppender appender = RollingFileAppender.newBuilder()
.withName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender")
.withFileName(LoggerHelper.getLogFileP(productName, file))
.withAppend(true)
.withBufferedIo(true)
.setConfiguration(configuration)
.withFilePattern(LoggerHelper.getLogFile(productName, file) + ".%d{" + datePattern + "}")
.withLayout(buildLayout(encoding))
.withCreateOnDemand(false)
.withPolicy(CompositeTriggeringPolicy.createPolicy(TimeBasedTriggeringPolicy.createPolicy("1", "true"), SizeBasedTriggeringPolicy.createPolicy(size)))
.withStrategy(DefaultRolloverStrategy.createStrategy(null, null, "nomax", null, null, false, configuration))
.build();
appender.start();
removeAllAppenders(logger);
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size, String datePattern, int maxBackupIndex) {
org.apache.logging.log4j.core.appender.RollingFileAppender appender = RollingFileAppender.newBuilder()
.withName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender")
.withFileName(LoggerHelper.getLogFileP(productName, file))
.withAppend(true)
.withBufferedIo(true)
.setConfiguration(configuration)
.withFilePattern(LoggerHelper.getLogFile(productName, file) + ".%d{" + datePattern + "}.%i")
.withLayout(buildLayout(encoding))
.withCreateOnDemand(false)
.withPolicy(CompositeTriggeringPolicy.createPolicy(TimeBasedTriggeringPolicy.createPolicy("1", "true"), SizeBasedTriggeringPolicy.createPolicy(size)))
.withStrategy(DefaultRolloverStrategy.createStrategy(String.valueOf(maxBackupIndex), "1", "max", null, null, false, configuration))
.build();
appender.start();
removeAllAppenders(logger);
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAppenderWithSizeRolling(String productName, String file, String encoding, String size, int maxBackupIndex) {
org.apache.logging.log4j.core.appender.RollingFileAppender appender = RollingFileAppender.newBuilder()
.withName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender")
.withFileName(LoggerHelper.getLogFileP(productName, file))
.withAppend(true)
.withBufferedIo(true)
.setConfiguration(configuration)
.withFilePattern(LoggerHelper.getLogFile(productName, file) + ".%i")
.withLayout(buildLayout(encoding))
.withCreateOnDemand(false)
.withPolicy(SizeBasedTriggeringPolicy.createPolicy(size))
.withStrategy(DefaultRolloverStrategy.createStrategy(String.valueOf(maxBackupIndex), "1", "max", null, null, false, configuration))
.build();
appender.start();
removeAllAppenders(logger);
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAsync(int queueSize, int discardingThreshold) {
List<Object[]> args = new ArrayList<Object[]>();
if (queueSize != Integer.MIN_VALUE) {
args.add(new Object[] { "setBufferSize", new Class<?>[] { int.class }, queueSize });
}
activateAsync(args);
}
@Override
public void activateAsync(List<Object[]> args) {
Map<String, Appender> appenders = logger.getAppenders();
if (appenders == null) {
throw new IllegalStateException("Activate async appender failed, no appender exist.");
}
AppenderRef[] refs = new AppenderRef[appenders.size()];
int i = 0;
for (Appender appender : appenders.values()) {
configuration.addAppender(appender);
refs[i++] = AppenderRef.createAppenderRef(appender.getName(), null, null);
}
AsyncAppender.Builder builder = AsyncAppender.newBuilder()
.setName(productName + "." + logger.getName() + ".AsyncAppender")
.setConfiguration(configuration)
.setAppenderRefs(refs)
.setBlockingQueueFactory(ArrayBlockingQueueFactory.<LogEvent>createFactory());
invokeMethod(builder, args);
AsyncAppender asyncAppender = builder.build();
asyncAppender.start();
removeAllAppenders(logger);
logger.addAppender(asyncAppender);
setProductName(productName);
}
@Override
public void activateAppender(Logger logger) {
if (!(logger.getDelegate() instanceof org.apache.logging.log4j.core.Logger)) {
throw new IllegalArgumentException("logger must be org.apache.logging.log4j.core.Logger, but it's "
+ logger.getDelegate().getClass());
}
activateAppender(((org.apache.logging.log4j.core.Logger) logger.getDelegate()));
setProductName(logger.getProductName());
}
protected void activateAppender(org.apache.logging.log4j.core.Logger logger) {
removeAllAppenders(this.logger);
Map<String, Appender> appenders = null;
if ((appenders = logger.getAppenders()) != null) {
for (Appender appender : appenders.values()) {
this.logger.addAppender(appender);
}
}
}
@Override
public void setLevel(Level level) {
this.level = level;
org.apache.logging.log4j.Level l = org.apache.logging.log4j.Level.toLevel(level.getName(), org.apache.logging.log4j.Level.ERROR);
logger.setLevel(l);
logger.getContext().getConfiguration().getLoggerConfig(this.logger.getName()).setLevel(l);
}
@Override
public void setAdditivity(boolean additivity) {
logger.setAdditive(additivity);
}
protected org.apache.logging.log4j.core.Layout buildLayout(String encoding) {
org.apache.logging.log4j.core.Layout layout = org.apache.logging.log4j.core.layout.PatternLayout.newBuilder().
withConfiguration(configuration)
.withPattern(LoggerHelper.getPattern())
.withCharset(Charset.forName(encoding))
.build();
return layout;
}
protected void removeAllAppenders(org.apache.logging.log4j.core.Logger logger) {
Map<String, Appender> appenders = logger.getAppenders();
if (appenders != null) {
for (Appender appender : appenders.values()) {
logger.removeAppender(appender);
}
}
}
}

View File

@ -0,0 +1,212 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import org.apache.log4j.*;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import java.io.File;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* ActivateOption的Log4j实现
*
* @author zhuyong 2014年3月20日 上午10:24:36
*/
public class Log4jActivateOption extends AbstractActiveOption {
protected org.apache.log4j.Logger logger;
public Log4jActivateOption(org.apache.log4j.Logger logger) {
this.logger = logger;
}
@Override
public void activateConsoleAppender(String target, String encoding) {
org.apache.log4j.ConsoleAppender appender = new org.apache.log4j.ConsoleAppender();
appender.setLayout(new PatternLayout(LoggerHelper.getPattern()));
appender.setTarget(target);
appender.setEncoding(encoding);
appender.activateOptions();
logger.removeAllAppenders();
logger.addAppender(appender);
}
@Override
public void activateAppender(String productName, String file, String encoding) {
org.apache.log4j.Appender appender = getLog4jDailyRollingFileAppender(productName, file, encoding);
logger.removeAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAsyncAppender(String productName, String file, String encoding) {
activateAsyncAppender(productName, file, encoding, Integer.MIN_VALUE, Integer.MIN_VALUE);
}
@Override
public void activateAsyncAppender(String productName, String file, String encoding, int queueSize,
int discardingThreshold) {
activateAppender(productName, file, encoding);
activateAsync(queueSize, discardingThreshold);
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size) {
activateAppender(productName, file, encoding);
}
@Override
public void setLevel(com.alibaba.nacos.client.logger.Level level) {
this.level = level;
logger.setLevel(org.apache.log4j.Level.toLevel(level.getName()));
}
@Override
public void setAdditivity(boolean additivity) {
logger.setAdditivity(additivity);
}
protected org.apache.log4j.Appender getLog4jDailyRollingFileAppender(String productName, String file,
String encoding) {
DailyRollingFileAppender appender = new DailyRollingFileAppender();
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setLayout(new PatternLayout(LoggerHelper.getPattern(productName)));
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFileP(productName, file));
appender.setEncoding(encoding);
appender.activateOptions();
return appender;
}
@Override
public void activateAppender(Logger logger) {
if (!(logger.getDelegate() instanceof org.apache.log4j.Logger)) {
throw new IllegalArgumentException(
"logger must be org.apache.log4j.Logger, but it's " + logger.getDelegate().getClass());
}
activateAppender((org.apache.log4j.Logger) logger.getDelegate());
setProductName(logger.getProductName());
}
protected void activateAppender(org.apache.log4j.Logger logger) {
this.logger.removeAllAppenders();
Enumeration<?> enums = logger.getAllAppenders();
while (enums != null && enums.hasMoreElements()) {
this.logger.addAppender((Appender) enums.nextElement());
}
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size,
String datePattern) {
Appender appender = getLog4jRollingFileAppender(productName, file, encoding, size, datePattern, -1);
logger.removeAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size,
String datePattern, int maxBackupIndex) {
Appender appender = getLog4jRollingFileAppender(productName, file, encoding, size, datePattern, maxBackupIndex);
logger.removeAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
protected org.apache.log4j.Appender getLog4jRollingFileAppender(String productName, String file, String encoding,
String size, String datePattern,
int maxBackupIndex) {
RollingFileAppender appender = new RollingFileAppender();
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setLayout(new PatternLayout(LoggerHelper.getPattern(productName)));
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFileP(productName, file));
appender.setEncoding(encoding);
appender.setMaxFileSize(size);
if (maxBackupIndex >= 0) {
// 等于0表示直接truck
appender.setMaxBackupIndex(maxBackupIndex);
}
appender.activateOptions();
return appender;
}
@Override
public void activateAppenderWithSizeRolling(String productName, String file, String encoding, String size,
int maxBackupIndex) {
Appender appender = getLog4jRollingFileAppender(productName, file, encoding, size, null, maxBackupIndex);
logger.removeAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAsync(int queueSize, int discardingThreshold) {
// discardingThreshold is unused for log4j
List<Object[]> args = new ArrayList<Object[]>();
if (queueSize != Integer.MIN_VALUE) {
args.add(new Object[] { "setBufferSize", new Class<?>[] { int.class }, queueSize });
}
activateAsync(args);
}
@Override
public void activateAsync(List<Object[]> args) {
AsyncAppender asyncAppender = new AsyncAppender();
invokeMethod(asyncAppender, args);
asyncAppender.setName(productName + "." + logger.getName() + ".AsyncAppender");
Enumeration<Appender> appenders = logger.getAllAppenders();
if (appenders == null) {
throw new IllegalStateException("Activate async appender failed, no appender exist.");
}
while (appenders.hasMoreElements()) {
asyncAppender.addAppender(appenders.nextElement());
}
appenders = logger.getAllAppenders();
while (appenders.hasMoreElements()) {
logger.removeAppender(appenders.nextElement());
}
logger.addAppender(asyncAppender);
setProductName(productName);
}
}

View File

@ -0,0 +1,334 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import ch.qos.logback.classic.AsyncAppender;
import ch.qos.logback.classic.PatternLayout;
import ch.qos.logback.classic.spi.ILoggingEvent;
import ch.qos.logback.core.Appender;
import ch.qos.logback.core.rolling.*;
import ch.qos.logback.core.util.FileSize;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import com.alibaba.nacos.client.logger.Level;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.support.LogLog;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
/**
* logback 0.9.18版本及以前适用
*
* @author zhuyong 2014年3月20日 上午11:16:26
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class Logback918ActivateOption extends AbstractActiveOption {
private ch.qos.logback.classic.Logger logger;
public Logback918ActivateOption(Object logger) {
if (logger instanceof ch.qos.logback.classic.Logger) {
this.logger = (ch.qos.logback.classic.Logger) logger;
} else {
throw new IllegalArgumentException("logger must be instanceof ch.qos.logback.classic.Logger");
}
}
@Override
public void activateConsoleAppender(String target, String encoding) {
ch.qos.logback.core.ConsoleAppender appender = new ch.qos.logback.core.ConsoleAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setTarget(target);
PatternLayout layout = new PatternLayout();
layout.setPattern(LoggerHelper.getPattern());
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
appender.setLayout(layout);
appender.start();
logger.detachAndStopAllAppenders();
logger.addAppender(appender);
}
@Override
public void activateAppender(String productName, String file, String encoding) {
ch.qos.logback.core.Appender appender = getLogbackDailyRollingFileAppender(productName, file, encoding);
logger.detachAndStopAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAsyncAppender(String productName, String file, String encoding) {
activateAsyncAppender(productName, file, encoding, Integer.MIN_VALUE, Integer.MIN_VALUE);
}
public void activateAsyncAppender(String productName, String file, String encoding, int queueSize,
int discardingThreshold) {
activateAppender(productName, file, encoding);
activateAsync(queueSize, discardingThreshold);
}
@Override
public void setLevel(Level level) {
this.level = level;
logger.setLevel(ch.qos.logback.classic.Level.valueOf(level.getName()));
}
@Override
public void setAdditivity(boolean additivity) {
logger.setAdditive(additivity);
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size) {
ch.qos.logback.core.Appender appender = getLogbackDailyAndSizeRollingFileAppender(productName, file, encoding,
size);
logger.detachAndStopAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
protected ch.qos.logback.core.Appender getLogbackDailyRollingFileAppender(String productName, String file,
String encoding) {
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFile(productName, file));
TimeBasedRollingPolicy rolling = new TimeBasedRollingPolicy();
rolling.setParent(appender);
rolling.setFileNamePattern(LoggerHelper.getLogFile(productName, file) + ".%d{yyyy-MM-dd}");
rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
rolling.start();
appender.setRollingPolicy(rolling);
PatternLayout layout = new PatternLayout();
layout.setPattern(LoggerHelper.getPattern(productName));
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
appender.setLayout(layout);
// 启动
appender.start();
return appender;
}
protected ch.qos.logback.core.Appender getLogbackDailyAndSizeRollingFileAppender(String productName, String file,
String encoding, String size) {
return getLogbackDailyAndSizeRollingFileAppender(productName, file, encoding, size, "yyyy-MM-dd", -1);
}
@Override
public void activateAppender(Logger logger) {
if (!(logger.getDelegate() instanceof ch.qos.logback.classic.Logger)) {
throw new IllegalArgumentException(
"logger must be ch.qos.logback.classic.Logger, but it's " + logger.getDelegate().getClass());
}
this.logger.detachAndStopAllAppenders();
Iterator<ch.qos.logback.core.Appender<ILoggingEvent>> iter = ((ch.qos.logback.classic.Logger) logger.getDelegate()).iteratorForAppenders();
while (iter.hasNext()) {
ch.qos.logback.core.Appender<ILoggingEvent> appender = iter.next();
this.logger.addAppender(appender);
}
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size,
String datePattern) {
ch.qos.logback.core.Appender appender = getLogbackDailyAndSizeRollingFileAppender(productName, file, encoding,
size, datePattern, -1);
logger.detachAndStopAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
protected ch.qos.logback.core.Appender getLogbackDailyAndSizeRollingFileAppender(String productName, String file,
String encoding, String size,
String datePattern,
int maxBackupIndex) {
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFile(productName, file));
TimeBasedRollingPolicy rolling = new TimeBasedRollingPolicy();
rolling.setParent(appender);
if (maxBackupIndex >= 0) {
rolling.setMaxHistory(maxBackupIndex);
}
rolling.setFileNamePattern(LoggerHelper.getLogFile(productName, file) + ".%d{" + datePattern + "}.%i");
rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
SizeAndTimeBasedFNATP fnatp = new SizeAndTimeBasedFNATP();
setMaxFileSize(fnatp, size);
fnatp.setTimeBasedRollingPolicy(rolling);
rolling.setTimeBasedFileNamingAndTriggeringPolicy(fnatp);
rolling.start();
appender.setRollingPolicy(rolling);
PatternLayout layout = new PatternLayout();
layout.setPattern(LoggerHelper.getPattern(productName));
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
appender.setLayout(layout);
// 启动
appender.start();
return appender;
}
@Override
public void activateAppenderWithTimeAndSizeRolling(String productName, String file, String encoding, String size,
String datePattern, int maxBackupIndex) {
ch.qos.logback.core.Appender appender = getLogbackDailyAndSizeRollingFileAppender(productName, file, encoding,
size, datePattern,
maxBackupIndex);
logger.detachAndStopAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAppenderWithSizeRolling(String productName, String file, String encoding, String size,
int maxBackupIndex) {
ch.qos.logback.core.Appender appender = getSizeRollingAppender(productName, file, encoding, size,
maxBackupIndex);
logger.detachAndStopAllAppenders();
logger.addAppender(appender);
setProductName(productName);
}
@Override
public void activateAsync(int queueSize, int discardingThreshold) {
List<Object[]> args = new ArrayList<Object[]>();
if (queueSize != Integer.MIN_VALUE) {
args.add(new Object[] { "setQueueSize", new Class<?>[] { int.class }, queueSize });
}
if (discardingThreshold != Integer.MIN_VALUE) {
args.add(new Object[] { "setDiscardingThreshold", new Class<?>[] { int.class }, discardingThreshold });
}
activateAsync(args);
}
@Override
public void activateAsync(List<Object[]> args) {
AsyncAppender asynAppender = new AsyncAppender();
invokeMethod(asynAppender, args);
asynAppender.setName(productName + "." + logger.getName() + ".AsyncAppender");
asynAppender.setContext(LogbackLoggerContextUtil.getLoggerContext());
Iterator<Appender<ILoggingEvent>> iterator = logger.iteratorForAppenders();
boolean hasAppender = false;
while (iterator.hasNext()) {
hasAppender = true;
asynAppender.addAppender(iterator.next());
}
if (!hasAppender) {
throw new IllegalStateException("Activate async appender failed, no appender exist.");
}
asynAppender.start();
iterator = logger.iteratorForAppenders();
while (iterator.hasNext()) {
logger.detachAppender(iterator.next());
}
logger.addAppender(asynAppender);
setProductName(productName);
}
protected ch.qos.logback.core.Appender getSizeRollingAppender(String productName, String file, String encoding,
String size, int maxBackupIndex) {
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFile(productName, file));
SizeBasedTriggeringPolicy triggerPolicy = new SizeBasedTriggeringPolicy();
setMaxFileSize(triggerPolicy, size);
triggerPolicy.setContext(LogbackLoggerContextUtil.getLoggerContext());
triggerPolicy.start();
FixedWindowRollingPolicy rolling = new FixedWindowRollingPolicy();
rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
rolling.setParent(appender);
rolling.setFileNamePattern(LoggerHelper.getLogFile(productName, file) + ".%i");
rolling.setParent(appender);
if (maxBackupIndex >= 0) {
rolling.setMaxIndex(maxBackupIndex);
}
rolling.start();
appender.setRollingPolicy(rolling);
appender.setTriggeringPolicy(triggerPolicy);
PatternLayout layout = new PatternLayout();
layout.setPattern(LoggerHelper.getPattern(productName));
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
appender.setLayout(layout);
// 启动
appender.start();
return appender;
}
/**
* logback 1.1.8开始不再支持setMaxFileSize(String)方法
*/
protected void setMaxFileSize(Object policy, String size) {
try {
try {
Method setMaxFileSizeMethod = policy.getClass().getDeclaredMethod("setMaxFileSize", String.class);
setMaxFileSizeMethod.invoke(policy, size);
} catch (NoSuchMethodException e) {
Method setMaxFileSizeMethod = policy.getClass().getDeclaredMethod("setMaxFileSize", FileSize.class);
setMaxFileSizeMethod.invoke(policy, FileSize.valueOf(size));
}
} catch (Throwable t) {
throw new RuntimeException("Failed to setMaxFileSize", t);
}
}
}

View File

@ -0,0 +1,154 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import java.io.File;
import java.nio.charset.Charset;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import ch.qos.logback.classic.encoder.PatternLayoutEncoder;
import ch.qos.logback.core.rolling.FixedWindowRollingPolicy;
import ch.qos.logback.core.rolling.RollingFileAppender;
import ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP;
import ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy;
import ch.qos.logback.core.rolling.TimeBasedRollingPolicy;
/**
* ActivateOption的Logback 0.9.19及后续版本的实现
*
* @author zhuyong 2014年3月20日 上午10:24:58
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
public class LogbackActivateOption extends Logback918ActivateOption {
public LogbackActivateOption(Object logger) {
super(logger);
}
protected ch.qos.logback.core.Appender getLogbackDailyRollingFileAppender(String productName, String file,
String encoding) {
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFile(productName, file));
TimeBasedRollingPolicy rolling = new TimeBasedRollingPolicy();
rolling.setParent(appender);
rolling.setFileNamePattern(LoggerHelper.getLogFile(productName, file) + ".%d{yyyy-MM-dd}");
rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
rolling.start();
appender.setRollingPolicy(rolling);
PatternLayoutEncoder layout = new PatternLayoutEncoder();
layout.setPattern(LoggerHelper.getPattern(productName));
layout.setCharset(Charset.forName(encoding));
appender.setEncoder(layout);
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
// 启动
appender.start();
return appender;
}
protected ch.qos.logback.core.Appender getLogbackDailyAndSizeRollingFileAppender(String productName, String file,
String encoding, String size) {
return getLogbackDailyAndSizeRollingFileAppender(productName, file, encoding, size, "yyyy-MM-dd", -1);
}
protected ch.qos.logback.core.Appender getLogbackDailyAndSizeRollingFileAppender(String productName, String file,
String encoding, String size,
String datePattern,
int maxBackupIndex) {
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFile(productName, file));
TimeBasedRollingPolicy rolling = new TimeBasedRollingPolicy();
rolling.setParent(appender);
if (maxBackupIndex >= 0) {
rolling.setMaxHistory(maxBackupIndex);
}
rolling.setFileNamePattern(LoggerHelper.getLogFile(productName, file) + ".%d{" + datePattern + "}.%i");
rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
SizeAndTimeBasedFNATP fnatp = new SizeAndTimeBasedFNATP();
setMaxFileSize(fnatp, size);
fnatp.setTimeBasedRollingPolicy(rolling);
rolling.setTimeBasedFileNamingAndTriggeringPolicy(fnatp);
rolling.start();
appender.setRollingPolicy(rolling);
PatternLayoutEncoder layout = new PatternLayoutEncoder();
layout.setPattern(LoggerHelper.getPattern(productName));
layout.setCharset(Charset.forName(encoding));
appender.setEncoder(layout);
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
// 启动
appender.start();
return appender;
}
protected ch.qos.logback.core.Appender getSizeRollingAppender(String productName, String file, String encoding,
String size, int maxBackupIndex) {
RollingFileAppender appender = new RollingFileAppender();
appender.setContext(LogbackLoggerContextUtil.getLoggerContext());
appender.setName(productName + "." + file.replace(File.separatorChar, '.') + ".Appender");
appender.setAppend(true);
appender.setFile(LoggerHelper.getLogFile(productName, file));
SizeBasedTriggeringPolicy triggerPolicy = new SizeBasedTriggeringPolicy();
setMaxFileSize(triggerPolicy, size);
triggerPolicy.setContext(LogbackLoggerContextUtil.getLoggerContext());
triggerPolicy.start();
FixedWindowRollingPolicy rolling = new FixedWindowRollingPolicy();
rolling.setContext(LogbackLoggerContextUtil.getLoggerContext());
rolling.setParent(appender);
rolling.setFileNamePattern(LoggerHelper.getLogFile(productName, file) + ".%i");
rolling.setParent(appender);
if (maxBackupIndex >= 0) {
rolling.setMaxIndex(maxBackupIndex);
}
rolling.start();
appender.setRollingPolicy(rolling);
appender.setTriggeringPolicy(triggerPolicy);
PatternLayoutEncoder layout = new PatternLayoutEncoder();
layout.setPattern(LoggerHelper.getPattern(productName));
layout.setCharset(Charset.forName(encoding));
appender.setEncoder(layout);
layout.setContext(LogbackLoggerContextUtil.getLoggerContext());
layout.start();
// 启动
appender.start();
return appender;
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import org.slf4j.ILoggerFactory;
import org.slf4j.LoggerFactory;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.core.LogbackException;
/**
* Logback Context Util
* @author Nacos
*
*/
public class LogbackLoggerContextUtil {
private static LoggerContext loggerContext = null;
public static LoggerContext getLoggerContext() {
if (loggerContext == null) {
ILoggerFactory lcObject = LoggerFactory.getILoggerFactory();
if (!(lcObject instanceof LoggerContext)) {
throw new LogbackException(
"Expected LOGBACK binding with SLF4J, but another log system has taken the place: "
+ lcObject.getClass().getSimpleName());
}
loggerContext = (LoggerContext) lcObject;
}
return loggerContext;
}
}

View File

@ -0,0 +1,68 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import java.lang.reflect.Field;
import com.alibaba.nacos.client.logger.Logger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* @author zhuyong on 2017/4/18.
*/
public class Slf4jLog4j2AdapterActivateOption extends Log4j2ActivateOption {
private static Field loggerField = null;
static {
try {
loggerField = org.apache.logging.slf4j.Log4jLogger.class.getDeclaredField("logger");
loggerField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException("logger must be instanceof org.apache.logging.slf4j.Log4jLogger", e);
}
}
public Slf4jLog4j2AdapterActivateOption(Object logger) {
super(null);
try {
org.apache.logging.log4j.core.Logger log4j2Logger = (org.apache.logging.log4j.core.Logger) loggerField.get(logger);
super.logger = log4j2Logger;
super.configuration = super.logger.getContext().getConfiguration();
} catch (Exception e) {
throw new RuntimeException("logger must be instanceof org.apache.logging.slf4j.Log4jLogger", e);
}
}
@Override
@SuppressFBWarnings("NM_WRONG_PACKAGE")
public void activateAppender(Logger logger) {
if (!(logger.getDelegate() instanceof org.apache.logging.slf4j.Log4jLogger)) {
throw new IllegalArgumentException(
"logger must be org.apache.logging.slf4j.Log4jLogger, but it's "
+ logger.getDelegate().getClass());
}
try {
org.apache.logging.log4j.core.Logger log4j2Logger = (org.apache.logging.log4j.core.Logger) loggerField.get(logger.getDelegate());
super.activateAppender(log4j2Logger);
} catch (Exception e) {
throw new RuntimeException("activateAppender error, ", e);
}
}
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.option;
import java.lang.reflect.Field;
import com.alibaba.nacos.client.logger.Logger;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
/**
* Slf4j-log4j12架构下的ActivateOption实现
*
* @author zhuyong 2014年3月20日 上午10:26:04
*/
public class Slf4jLog4jAdapterActivateOption extends Log4jActivateOption {
private static Field loggerField = null;
static {
try {
loggerField = org.slf4j.impl.Log4jLoggerAdapter.class.getDeclaredField("logger");
loggerField.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException("logger must be instanceof org.slf4j.impl.Log4jLoggerAdapter", e);
}
}
public Slf4jLog4jAdapterActivateOption(Object logger) {
super(null);
try {
org.apache.log4j.Logger log4jLogger = (org.apache.log4j.Logger) loggerField.get(logger);
super.logger = log4jLogger;
} catch (Exception e) {
throw new RuntimeException("logger must be instanceof org.slf4j.impl.Log4jLoggerAdapter", e);
}
}
@Override
@SuppressFBWarnings("NM_WRONG_PACKAGE")
public void activateAppender(Logger logger) {
if (!(logger.getDelegate() instanceof org.slf4j.impl.Log4jLoggerAdapter)) {
throw new IllegalArgumentException(
"logger must be org.slf4j.impl.Log4jLoggerAdapter, but it's "
+ logger.getDelegate().getClass());
}
try {
org.apache.log4j.Logger log4jLogger =
(org.apache.log4j.Logger) loggerField.get(logger.getDelegate());
super.activateAppender(log4jLogger);
setProductName(logger.getProductName());
} catch (Exception e) {
throw new RuntimeException("activateAppender error, ", e);
}
}
}

View File

@ -0,0 +1,178 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.slf4j;
import java.lang.reflect.Constructor;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.option.ActivateOption;
import com.alibaba.nacos.client.logger.support.LoggerHelper;
import com.alibaba.nacos.client.logger.support.LoggerSupport;
import com.alibaba.nacos.client.logger.util.MessageUtil;
/**
* slf4j logger
* @author Nacos
*
*/
public class Slf4jLogger extends LoggerSupport implements Logger {
private static boolean CanUseEncoder = false;
private static final String LOGBACK_CLASSNAME = "ch.qos.logback.classic.Logger";
private static final String SLF4J_CLASSNAME = "org.slf4j.impl.Log4jLoggerAdapter";
private static final String SLF4JLOG4J_CLASSNAME = "org.apache.logging.slf4j.Log4jLogger";
static {
try {
// logback从0.9.19开始采用encoder@see http://logback.qos.ch/manual/encoders.html
Class.forName("ch.qos.logback.classic.encoder.PatternLayoutEncoder");
CanUseEncoder = true;
} catch (ClassNotFoundException e) {
CanUseEncoder = false;
}
}
private org.slf4j.Logger delegate;
@SuppressWarnings("unchecked")
public
Slf4jLogger(org.slf4j.Logger delegate){
super(delegate);
if (delegate == null) {
throw new IllegalArgumentException("delegate Logger is null");
}
this.delegate = delegate;
String activateOptionClass = null;
if (LOGBACK_CLASSNAME.equals(delegate.getClass().getName())) {
if (CanUseEncoder) {
activateOptionClass = "com.alibaba.nacos.client.logger.option.LogbackActivateOption";
} else {
activateOptionClass = "com.alibaba.nacos.client.logger.option.Logback918ActivateOption";
}
} else if (SLF4J_CLASSNAME.equals(delegate.getClass().getName())) {
activateOptionClass = "com.alibaba.nacos.client.logger.option.Slf4jLog4jAdapterActivateOption";
} else if (SLF4JLOG4J_CLASSNAME.equals(delegate.getClass().getName())) {
activateOptionClass = "com.alibaba.nacos.client.logger.option.Slf4jLog4j2AdapterActivateOption";
}
try {
Class<ActivateOption> clazz = (Class<ActivateOption>) Class.forName(activateOptionClass);
Constructor<ActivateOption> c = clazz.getConstructor(Object.class);
this.activateOption = c.newInstance(delegate);
} catch (Exception e) {
throw new IllegalArgumentException("delegate must be logback impl or slf4j-log4j impl", e);
}
}
@Override
public void debug(String context, String message) {
if (isDebugEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.debug(MessageUtil.getMessage(context, message));
}
}
@Override
public void debug(String context, String format, Object... args) {
if (isDebugEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.debug(MessageUtil.getMessage(context, format), args);
}
}
@Override
public void info(String context, String message) {
if (isInfoEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.info(MessageUtil.getMessage(context, message));
}
}
@Override
public void info(String context, String format, Object... args) {
if (isInfoEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.info(MessageUtil.getMessage(context, format), args);
}
}
@Override
public void warn(String message, Throwable t) {
if (isWarnEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.warn(MessageUtil.getMessage(null, message), t);
}
}
@Override
public void warn(String context, String message) {
if (isWarnEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.warn(MessageUtil.getMessage(context, message));
}
}
@Override
public void warn(String context, String format, Object... args) {
if (isWarnEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.warn(MessageUtil.getMessage(context, format), args);
}
}
@Override
public void error(String context, String errorCode, String message) {
if (isErrorEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.error(MessageUtil.getMessage(context, errorCode, message));
}
}
@Override
public void error(String context, String errorCode, String message, Throwable t) {
if (isErrorEnabled()) {
message = LoggerHelper.getResourceBundleString(getProductName(), message);
delegate.error(MessageUtil.getMessage(context, errorCode, message), t);
}
}
@Override
public void error(String context, String errorCode, String format, Object... args) {
if (isErrorEnabled()) {
format = LoggerHelper.getResourceBundleString(getProductName(), format);
delegate.error(MessageUtil.getMessage(context, errorCode, format), args);
}
}
@Override
public boolean isDebugEnabled() {
return delegate.isDebugEnabled();
}
@Override
public boolean isInfoEnabled() {
return delegate.isInfoEnabled();
}
@Override
public boolean isWarnEnabled() {
return delegate.isWarnEnabled();
}
@Override
public boolean isErrorEnabled() {
return delegate.isErrorEnabled();
}
}

View File

@ -0,0 +1,51 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.slf4j;
import com.alibaba.nacos.client.logger.Logger;
import com.alibaba.nacos.client.logger.nop.NopLogger;
import com.alibaba.nacos.client.logger.support.ILoggerFactory;
import com.alibaba.nacos.client.logger.support.LogLog;
/**
* Slf4jLogger Factory
* @author Nacos
*
*/
public class Slf4jLoggerFactory implements ILoggerFactory {
public Slf4jLoggerFactory() throws ClassNotFoundException {
Class.forName("org.slf4j.impl.StaticLoggerBinder");
}
public Logger getLogger(String name) {
try {
return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(name));
} catch (Throwable t) {
LogLog.error("Failed to get Slf4jLogger", t);
return new NopLogger();
}
}
public Logger getLogger(Class<?> clazz) {
try {
return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(clazz));
} catch (Throwable t) {
LogLog.error("Failed to get Slf4jLogger", t);
return new NopLogger();
}
}
}

View File

@ -0,0 +1,48 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.nacos.client.logger.support;
import java.util.HashMap;
/**
* @author zhuyong on 2017/6/30.
*/
public class AppenderInfo extends HashMap {
private static String name = "name";
private static String type = "type";
private static String file = "file";
public String getName() {
return (String) get(AppenderInfo.name);
}
public void setName(String name) {
put(AppenderInfo.name, name);
}
public void setType(String type) {
put(AppenderInfo.type, type);
}
public void setFile(String file) {
put(AppenderInfo.file, file);
}
public void withDetail(String name, Object value) {
put(name, value);
}
}

View File

@ -0,0 +1,90 @@
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Copyright 2014 Alibaba.com All right reserved. This software is the
* confidential and proprietary information of Alibaba.com ("Confidential
* Information"). You shall not disclose such Confidential Information and shall
* use it only in accordance with the terms of the license agreement you entered
* into with Alibaba.com.
*/
package com.alibaba.nacos.client.logger.support;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.io.LineNumberReader;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import org.apache.log4j.spi.ThrowableRenderer;
/**
* 针对 Log4j 1.2.16 及以上版本提供对异常栈的深度控制
*
* @author zhuyong 2014年9月19日 上午10:31:48
*/
public final class DepthThrowableRenderer implements ThrowableRenderer {
private int depth = -1;
public DepthThrowableRenderer(int depth) {
this.depth = depth;
}
public void setDepth(int depth) {
this.depth = depth;
}
public String[] doRender(final Throwable throwable) {
return render(throwable, depth);
}
/**
* Render throwable using Throwable.printStackTrace.
*
* @param throwable throwable, may not be null.
* @param depth stack depth
* @return string representation.
*/
public static String[] render(final Throwable throwable, final int depth) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
try {
throwable.printStackTrace(pw);
} catch (RuntimeException ex) {
}
pw.flush();
LineNumberReader reader = new LineNumberReader(new StringReader(sw.toString()));
ArrayList<String> lines = new ArrayList<String>();
try {
String line = reader.readLine();
int count = 0;
while (line != null && (depth == -1 || count++ <= depth)) {
lines.add(line);
line = reader.readLine();
}
} catch (IOException ex) {
if (ex instanceof InterruptedIOException) {
Thread.currentThread().interrupt();
}
lines.add(ex.toString());
}
String[] tempRep = new String[lines.size()];
lines.toArray(tempRep);
return tempRep;
}
}

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