├── .gitignore
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── avos
│ └── avoscloud
│ ├── AVOSCloud.java
│ ├── AVPush.java
│ └── internal
│ ├── MasterKeyConfiguration.java
│ └── impl
│ ├── JavaAppConfiguration.java
│ ├── JavaRequestSignImplementation.java
│ ├── Log4j2Implementation.java
│ └── SimplePersistence.java
└── test
├── java
└── com
│ └── avos
│ └── avoscloud
│ ├── DisableHookTest.java
│ └── TestApp.java
└── resources
└── log4j2.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | java-sdk/target/
2 | java-sdk/.project
3 | java-sdk/.classpath
4 | java-sdk/.settings
5 | .project
6 | .settings
7 | .classpath
8 | leancloud-utils/target
9 | leancloud-utils/.project
10 | leancloud-utils/.settings
11 | leancloud-utils/.classpath
12 | /target/
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## SDK 维护期说明
2 |
3 | 我们于 2018 年 9 月推出了新的 Java Unified SDK,兼容纯 Java、云引擎和 Android 等多个平台,此 java-sdk 目前进入维护状态,直到 2019 年 9 月底停止维护。 欢迎大家切换到新的 Unified SDK,具体使用方法详见 [Unified SDK Wiki](https://github.com/leancloud/java-unified-sdk/wiki)。
4 |
5 | ## LeanCloud Java SDK
6 |
7 | [](https://opensource.org/licenses/Apache-2.0)
8 | 
9 |
10 | java-sdk is the souce code for Java SDK
11 |
12 | leancloud-utils is the mock interface for android platform features which doesn't exist on Java platform
13 |
14 | ## Features
15 | * [x] Data Storage
16 | * [x] Object Query
17 | * [x] Cloud Engine
18 | * [x] File Storage
19 | * [x] Short Message Service
20 |
21 | ## Communication
22 | * If you **have some advice**, open an issue.
23 | * If you **found a bug**, open an issue, or open a ticket in [LeanTicket][LeanTicket].
24 | * If you **want to contribute**, submit a pull request.
25 |
26 |
27 | ## Installation
28 |
29 | ### maven
30 |
31 | add dependency:
32 |
33 | ``` xml
34 |
35 | cn.leancloud
36 | java-sdk
37 | 0.1.6
38 |
39 | ```
40 |
41 | ### gradle
42 |
43 | add dependency:
44 |
45 | ``` gradle
46 | compile 'cn.leancloud:java-sdk:0.1.+'
47 |
48 | ```
49 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 | 4.0.0
3 |
4 | cn.leancloud
5 | java-sdk
6 | 0.2.2-SNAPSHOT
7 | jar
8 |
9 | java-sdk
10 | LeanCloud Storage, Engine, SMS SDK
11 | https://github.com/leancloud/java-sdk
12 |
13 |
14 |
15 | The Apache License, Version 2.0
16 | http://www.apache.org/licenses/LICENSE-2.0.txt
17 |
18 |
19 |
20 |
21 |
22 | LeanCloud Engineer
23 | eng@leancloud.rocks
24 | LeanCloud
25 | https://leancloud.cn
26 |
27 |
28 |
29 |
30 | scm:git:https://github.com/leancloud/java-sdk.git
31 | scm:git:git@github.com:leancloud/java-sdk.git
32 | http://github.com/leancloud/java-sdk/tree/master
33 | HEAD
34 |
35 |
36 |
37 | ossrh
38 | https://oss.sonatype.org/content/repositories/snapshots
39 |
40 |
41 | ossrh
42 | https://oss.sonatype.org/service/local/staging/deploy/maven2/
43 |
44 |
45 |
46 |
47 | UTF-8
48 | 1.6
49 |
50 |
51 |
52 |
53 | junit
54 | junit
55 | 3.8.1
56 | test
57 |
58 |
59 | cn.leancloud
60 | fastjson-leancloud
61 | 1.1.39
62 |
63 |
64 | org.apache.logging.log4j
65 | log4j-api
66 | 2.5
67 |
68 |
69 | org.json
70 | json
71 | 20160212
72 |
73 |
74 | org.apache.logging.log4j
75 | log4j-core
76 | 2.5
77 |
78 |
79 | cn.leancloud
80 | okhttp-leancloud
81 | 2.6.0
82 |
83 |
84 | cn.leancloud
85 | leancloud-common
86 | [0.2.0,0.3.0)
87 |
88 |
89 | cn.leancloud
90 | android-stub
91 | 0.1.1
92 |
93 |
94 |
95 | org.apache.httpcomponents
96 | httpcore
97 | 4.4.4
98 |
99 |
100 |
101 | org.apache.httpcomponents
102 | httpclient
103 | 4.5.2
104 |
105 |
106 |
107 |
108 |
109 | org.apache.maven.plugins
110 | maven-javadoc-plugin
111 | 2.10.4
112 |
113 | false
114 |
115 |
116 |
117 | attach-javadocs
118 |
119 | jar
120 |
121 |
122 |
123 |
124 |
125 | org.apache.maven.plugins
126 | maven-source-plugin
127 | 2.2.1
128 |
129 |
130 | attach-sources
131 |
132 | jar-no-fork
133 |
134 |
135 |
136 |
137 |
138 | org.apache.maven.plugins
139 | maven-gpg-plugin
140 | 1.5
141 |
142 |
143 | sign-artifacts
144 | verify
145 |
146 | sign
147 |
148 |
149 |
150 |
151 |
152 | org.sonatype.plugins
153 | nexus-staging-maven-plugin
154 | 1.6.7
155 | true
156 |
157 | ossrh
158 | https://oss.sonatype.org/
159 | true
160 |
161 |
162 |
163 | org.apache.maven.plugins
164 | maven-release-plugin
165 | 2.5.3
166 |
167 |
168 | org.apache.maven.plugins
169 | maven-compiler-plugin
170 | 3.6.1
171 |
172 | ${jdk.version}
173 | ${jdk.version}
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 | org.apache.maven.plugins
183 | maven-project-info-reports-plugin
184 | 2.7
185 |
186 | false
187 |
188 |
189 |
190 | org.codehaus.mojo
191 | cobertura-maven-plugin
192 | 2.6
193 |
194 |
195 | html
196 | xml
197 |
198 |
199 |
200 |
201 | org.apache.maven.plugins
202 | maven-surefire-plugin
203 | 2.15
204 |
205 |
206 | ${surefireArgLine}
207 |
208 | ${skip.unit.tests}
209 |
210 |
211 | **/NotTest*.java
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/AVOSCloud.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud;
2 |
3 | import java.util.Date;
4 | import java.util.Map;
5 |
6 | import com.alibaba.fastjson.JSON;
7 | import com.avos.avoscloud.callback.AVServerDateCallback;
8 | import com.avos.avoscloud.internal.InternalConfigurationController;
9 | import com.avos.avoscloud.internal.InternalDate;
10 | import com.avos.avoscloud.internal.InternalSMS;
11 | import com.avos.avoscloud.internal.impl.DefaultAppRouter;
12 | import com.avos.avoscloud.internal.impl.JavaAppConfiguration;
13 | import com.avos.avoscloud.internal.impl.JavaRequestSignImplementation;
14 | import com.avos.avoscloud.internal.impl.Log4j2Implementation;
15 | import com.avos.avoscloud.internal.impl.SimplePersistence;
16 |
17 | /**
18 | * The AVOSCloud class contains static functions that handle global configuration for the AVOSCloud
19 | * library.
20 | */
21 | public class AVOSCloud {
22 |
23 | static final String AV_CLOUD_CACHE_EXPIRE_AUTO_CLEAN_KEY = "AV_CLOUD_CACHE_EXPIRE_AUTO_CLEAN_KEY";
24 | static final String AV_CLOUD_CACHE_EXPIRE_DATE_KEY = "AV_CLOUD_CACHE_EXPIRE_DATE_KEY";
25 | static final Integer AV_CLOUD_CACHE_DEFAULT_EXPIRE_DATE = 30;
26 | static final String AV_CLOUD_CACHE_EXPIRE_KEY_ZONE = "AV_CLOUD_CACHE_EXPIRE_KEY_ZONE";
27 | static final String AV_CLOUD_API_VERSION_KEY_ZONE = "AV_CLOUD_API_VERSION_KEY_ZONE";
28 | static final String AV_CLOUD_API_VERSION_KEY = "AV_CLOUD_API_VERSION";
29 |
30 | private static boolean isCN = true;
31 |
32 | /**
33 | * Set network timeout in milliseconds.default is 10 seconds.
34 | *
35 | * @param timeoutInMills 超时时间
36 | */
37 | public static void setNetworkTimeout(int timeoutInMills) {
38 | InternalConfigurationController.globalInstance().getClientConfiguration()
39 | .setNetworkTimeoutInMills(timeoutInMills);
40 | }
41 |
42 | /**
43 | * Returns the network timeout in milliseconds.It's 15 seconds by default.
44 | *
45 | * @return 超时时间
46 | */
47 | public static int getNetworkTimeout() {
48 | return InternalConfigurationController.globalInstance().getClientConfiguration()
49 | .getNetworkTimeoutInMills();
50 | }
51 |
52 | static {
53 | JSON.DEFFAULT_DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
54 | }
55 |
56 | private AVOSCloud() {}
57 |
58 | /**
59 | *
60 | * Authenticates this client as belonging to your application. This must be called before your
61 | * application can use the AVOSCloud library. The recommended way is to put a call to
62 | * AVOSCloud.initialize in each of your onCreate methods. An example:
63 | *
64 | *
65 | * @param applicationId The application id provided in the AVOSCloud dashboard.
66 | * @param clientKey The client key provided in the AVOSCloud dashboard.
67 | * @param masterKey The master key provided in the AVOSCloud dashboard.
68 | */
69 |
70 | public static void initialize(String applicationId, String clientKey, String masterKey) {
71 | JavaAppConfiguration configuration = JavaAppConfiguration.instance();
72 | configuration.setIsCN(isCN);
73 | configuration.setApplicationId(applicationId);
74 | configuration.setClientKey(clientKey);
75 | configuration.setMasterKey(masterKey);
76 |
77 | InternalConfigurationController.Builder builder = new InternalConfigurationController.Builder();
78 | builder.setAppConfiguration(configuration)
79 | .setInternalRequestSign(JavaRequestSignImplementation.instance())
80 | .setInternalPersistence(SimplePersistence.instance())
81 | .setInternalLogger(Log4j2Implementation.instance())
82 | .setAppRouter(DefaultAppRouter.instance());
83 |
84 | builder.build();
85 | InternalConfigurationController.globalInstance().getAppRouter().updateServerHosts();
86 | }
87 |
88 | public static void useAVCloudUS() {
89 | isCN = false;
90 | }
91 |
92 | public static void useAVCloudCN() {
93 | isCN = true;
94 | }
95 |
96 | public static boolean showInternalDebugLog() {
97 | return Log4j2Implementation.instance().showInternalDebugLog();
98 | }
99 |
100 | public static void setDebugLogEnabled(boolean enable) {
101 | Log4j2Implementation.instance().setDebugEnabled(enable);
102 | }
103 |
104 | public static boolean isDebugLogEnabled() {
105 | return Log4j2Implementation.instance().isDebugEnabled()
106 | || Log4j2Implementation.instance().showInternalDebugLog();
107 | }
108 |
109 | /**
110 | * 请求发送短信验证码
111 | *
112 | *
113 | * 短信示范为: 您正在{name}中进行{op},您的验证码是:{Code},请输入完整验证,有效期为:{ttl}
114 | *
115 | *
116 | * @param phone 目标手机号码(必选)
117 | * @param name 应用名,值为null 则默认是您的应用名
118 | * @param op 验证码的目标操作,值为null,则默认为“短信验证”
119 | * @param ttl 验证码过期时间,单位分钟。如果是0,则默认为10分钟
120 | * @throws AVException 发送短信异常
121 | */
122 | public static void requestSMSCode(String phone, String name, String op, int ttl)
123 | throws AVException {
124 | InternalSMS.requestSMSCode(phone, name, op, ttl);
125 | }
126 |
127 | /**
128 | * 通过短信模板来发送短信验证码
129 | *
130 | *
131 | * @param phone 目标手机号码(必选)
132 | * @param templateName 短信模板名称
133 | * @param env 需要注入的变量env
134 | * @throws AVException 发送短信异常
135 | */
136 | public static void requestSMSCode(String phone, String templateName, Map env)
137 | throws AVException {
138 | InternalSMS.requestSMSCode(phone, templateName, env);
139 | }
140 |
141 | /**
142 | * 请求发送短信验证码
143 | *
144 | *
145 | * 短信示范为: 您正在{应用名称}中进行短信验证,您的验证码是:{Code},请输入完整验证,有效期为:10分钟
146 | *
147 | *
148 | * @param phone 目标手机号码
149 | * @throws AVException 发送短信异常
150 | */
151 | public static void requestSMSCode(String phone) throws AVException {
152 | InternalSMS.requestSMSCode(phone, null, null, 0);
153 | }
154 |
155 | /**
156 | * 请求发送语音验证码,验证码会以电话形式打给目标手机
157 | *
158 | * @param phoneNumber 目标手机号
159 | * @throws AVException 发送短信异常
160 | */
161 | public static void requestVoiceCode(String phoneNumber) throws AVException {
162 | InternalSMS.requestVoiceCode(phoneNumber, null);
163 | }
164 |
165 |
166 | /**
167 | * 验证验证码
168 | *
169 | * @param code 验证码
170 | * @param mobilePhoneNumber 手机号码
171 | * @throws AVException 发送短信异常
172 | */
173 | public static void verifySMSCode(String code, String mobilePhoneNumber) throws AVException {
174 | InternalSMS.verifySMSCode(code, mobilePhoneNumber);
175 | }
176 |
177 | /**
178 | * 验证验证码
179 | *
180 | * @param code 验证码
181 | * @param mobilePhoneNumber 手机号码
182 | * @throws AVException 发送短信异常
183 | */
184 | public static void verifyCode(String code, String mobilePhoneNumber) throws AVException {
185 | InternalSMS.verifySMSCode(code, mobilePhoneNumber);
186 | }
187 |
188 | /**
189 | * 获取服务器端当前时间
190 | *
191 | * @return 服务器端当前时间
192 | * @throws AVException 发送短信异常
193 | */
194 | public static Date getServerDate() throws AVException {
195 | return InternalDate.getServerDate();
196 | }
197 |
198 | /**
199 | * 获取服务器端当前时间
200 | *
201 | * @param callback 获取时间回调
202 | */
203 | public static void getServerDateInBackground(AVServerDateCallback callback) {
204 | InternalDate.getServerDateInBackground(callback);
205 | }
206 |
207 | public static void setShouldUseMasterKey(boolean should) {
208 | JavaRequestSignImplementation.instance().setUseMasterKey(should);
209 | }
210 | }
211 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/AVPush.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud;
2 |
3 | import java.util.Collection;
4 | import java.util.Date;
5 | import java.util.HashMap;
6 | import java.util.HashSet;
7 | import java.util.Iterator;
8 | import java.util.Map;
9 | import java.util.Set;
10 |
11 | import org.json.JSONObject;
12 |
13 | import com.alibaba.fastjson.JSON;
14 | import com.avos.avoscloud.internal.InternalConfigurationController;
15 |
16 | /**
17 | *
18 | * The AVPush is a local representation of data that can be sent as a push notification.
19 | *
20 | *
21 | * The typical workflow for sending a push notification from the client is to construct a new
22 | * AVPush, use the setter functions to fill it with data, and then use AVPush.sendInBackground() to
23 | * send it.
24 | *
25 | */
26 | public class AVPush {
27 | private static final String INSTALLATIONTAG = "_Installation";
28 | private static final String deviceTypeTag = "deviceType";
29 | private static final Set DEVICE_TYPES = new HashSet();
30 | static {
31 | DEVICE_TYPES.add("android");
32 | DEVICE_TYPES.add("ios");
33 | }
34 | private final Set channelSet;
35 | private com.avos.avoscloud.AVQuery extends AVObject> pushQuery;
36 | private String cql;
37 | private long expirationTime;
38 | private long expirationTimeInterval;
39 | private final Set pushTarget;
40 | private final Map pushData;
41 | private volatile AVObject notification;
42 | private Date pushDate = null;
43 | private boolean production = true;
44 |
45 | static {
46 | AVPowerfulUtils.createSettings(AVPush.class.getSimpleName(), "push", "");
47 | }
48 |
49 | /**
50 | * Creates a new push notification. The default channel is the empty string, also known as the
51 | * global broadcast channel, but this value can be overridden using AVPush.setChannel(String),
52 | * AVPush.setChannels(Collection) or AVPush.setQuery(AVQuery). Before sending the push
53 | * notification you must call either AVPush.setMessage(String) or AVPush.setData(JSONObject).
54 | */
55 | public AVPush() {
56 | channelSet = new HashSet();
57 | pushData = new HashMap();
58 | pushTarget = new HashSet(DEVICE_TYPES);
59 | pushQuery = new AVQuery(INSTALLATIONTAG);
60 | }
61 |
62 | public Set getChannelSet() {
63 | return channelSet;
64 | }
65 |
66 |
67 | /**
68 | * 返回推送后创建的_Notification对象。
69 | *
70 | * @return _Notification对象
71 | */
72 | public AVObject getNotification() {
73 | return notification;
74 | }
75 |
76 | public AVQuery getPushQuery() {
77 | return pushQuery;
78 | }
79 |
80 | public Date getPushDate() {
81 | return pushDate;
82 | }
83 |
84 | public long getExpirationTime() {
85 | return expirationTime;
86 | }
87 |
88 | public long getExpirationTimeInterval() {
89 | return expirationTimeInterval;
90 | }
91 |
92 | public Set getPushTarget() {
93 | return pushTarget;
94 | }
95 |
96 | public Map getPushData() {
97 | return pushData;
98 | }
99 |
100 | /**
101 | * Clears both expiration values, indicating that the notification should never expire.
102 | */
103 | public void clearExpiration() {
104 | expirationTime = 0L;
105 | expirationTimeInterval = 0L;
106 | }
107 |
108 | /**
109 | * Sends this push notification while blocking this thread until the push notification has
110 | * successfully reached the AVOSCloud servers. Typically, you should use AVPush.sendInBackground()
111 | * instead of this, unless you are managing your own threading.
112 | */
113 | public void send() {
114 | sendInBackground(true, null);
115 | }
116 |
117 | /**
118 | * A helper method to concisely send a push to a query. This method is equivalent to
119 | *
120 | *
121 | * AVPush push = new AVPush();
122 | * push.setData(data);
123 | * push.setQuery(query);
124 | * push.sendInBackground();
125 | *
126 | *
127 | * @param data The entire data of the push message. See the push guide for more details on the
128 | * data format.
129 | * @param query A AVInstallation query which specifies the recipients of a push.
130 | * @throws AVException if query is not valid
131 | */
132 | static void sendDataInBackground(JSONObject data, AVQuery extends AVObject> query)
133 | throws AVException {
134 | if (!query.getClassName().equals(INSTALLATIONTAG)) {
135 | throw new AVException(AVException.OTHER_CAUSE, "only installation query is valid");
136 | }
137 | AVPush push = new AVPush();
138 | push.setData(data);
139 | push.setQuery(query);
140 | push.sendInBackground();
141 | }
142 |
143 | /**
144 | * A helper method to concisely send a push to a query. This method is equivalent to
145 | *
146 | *
147 | * AVPush push = new AVPush();
148 | * push.setData(data);
149 | * push.setQuery(query);
150 | * push.sendInBackground(callback);
151 | *
152 | *
153 | * @param data The entire data of the push message. See the push guide for more details on the
154 | * data format.
155 | * @param query A AVInstallation query which specifies the recipients of a push.
156 | * @param callback callback.done(e) is called when the send completes.
157 | */
158 | public static void sendDataInBackground(JSONObject data, AVQuery extends AVObject> query,
159 | SendCallback callback) {
160 | if (!query.getClassName().equals(INSTALLATIONTAG)) {
161 | if (callback != null) {
162 | callback.done(new AVException(AVException.OTHER_CAUSE, "only installation query is valid"));
163 | }
164 | }
165 | AVPush push = new AVPush();
166 | push.setData(data);
167 | push.setQuery(query);
168 | push.sendInBackground(false, callback);
169 | }
170 |
171 | /**
172 | * Sends this push notification in a background thread. This is preferable to using send(), unless
173 | * your code is already running from a background thread.
174 | */
175 | public void sendInBackground() {
176 | sendInBackground(false, null);
177 | }
178 |
179 | /**
180 | * Sends this push notification in a background thread. This is preferable to using send(), unless
181 | * your code is already running from a background thread.
182 | *
183 | * @param callback callback.done(e) is called when the send completes.
184 | */
185 | public void sendInBackground(SendCallback callback) {
186 | sendInBackground(false, callback);
187 | }
188 |
189 | private Map pushChannelsData() {
190 | return AVUtils.createStringObjectMap("channels", channelSet);
191 | }
192 |
193 | private Map postDataMap() throws AVException {
194 | Map map = new HashMap();
195 |
196 | if (pushQuery != null) {
197 | if (pushTarget.size() == 0) {
198 | pushQuery.whereNotContainedIn(deviceTypeTag, DEVICE_TYPES);
199 | } else if (pushTarget.size() == 1) {
200 | pushQuery.whereEqualTo(deviceTypeTag, pushTarget.toArray()[0]);
201 | }
202 | Map pushParameters = pushQuery.assembleParameters();
203 | if (pushParameters.keySet().size() > 0 && !AVUtils.isBlankString(cql)) {
204 | throw new IllegalStateException("You can't use AVQuery and Cloud query at the same time.");
205 | }
206 | for (String k : pushParameters.keySet()) {
207 | map.put(k, JSON.parse(pushParameters.get(k)));
208 | }
209 | }
210 | if (!AVUtils.isBlankString(cql)) {
211 | map.put("cql", cql);
212 | }
213 | if (channelSet.size() > 0) {
214 | map.putAll(pushChannelsData());
215 | }
216 |
217 | if (this.expirationTime > 0) {
218 | map.put("expiration_time", this.expirationDateTime());
219 | }
220 | if (this.expirationTimeInterval > 0) {
221 | map.put("push_time", AVUtils.stringFromDate(new Date()));
222 | map.put("expiration_interval", new Long(this.expirationTimeInterval));
223 | }
224 | if (this.pushDate != null) {
225 | map.put("push_time", AVUtils.stringFromDate(pushDate));
226 | }
227 |
228 | if (!production) {
229 | map.put("prod", "dev");
230 | }
231 |
232 | map.putAll(pushData);
233 | return map;
234 | }
235 |
236 | /**
237 | * Sends this push notification in a background thread. This is preferable to using send(), unless
238 | * your code is already running from a background thread.
239 | *
240 | * @param callback callback.done(e) is called when the send completes.
241 | */
242 | private void sendInBackground(boolean sync, SendCallback callback) {
243 | final SendCallback internalCallback = callback;
244 | String path = "push";
245 | try {
246 | Map map = postDataMap();
247 | String jsonString = AVUtils.jsonStringFromMapWithNull(map);
248 | PaasClient.storageInstance().postObject(path, jsonString, sync, new GenericObjectCallback() {
249 | @Override
250 | public void onSuccess(String content, AVException e) {
251 | notification = new AVObject("_Notification");
252 | AVUtils.copyPropertiesFromJsonStringToAVObject(content, notification);
253 | if (internalCallback != null) {
254 | internalCallback.internalDone(null);
255 | }
256 | }
257 |
258 | @Override
259 | public void onFailure(Throwable error, String content) {
260 | if (internalCallback != null) {
261 | internalCallback.internalDone(AVErrorUtils.createException(error, content));
262 | }
263 | }
264 | });
265 | } catch (AVException e) {
266 | if (callback != null) {
267 | callback.internalDone(e);
268 | } else {
269 | LogUtil.log.e("AVPush sent exception", e);
270 | }
271 | }
272 | }
273 |
274 | /**
275 | * A helper method to concisely send a push message to a query. This method is equivalent to
276 | *
277 | *
278 | * AVPush push = new AVPush();
279 | * push.setMessage(message);
280 | * push.setQuery(query);
281 | * push.sendInBackground();
282 | *
283 | *
284 | * @param message The message that will be shown in the notification.
285 | * @param query A AVInstallation query which specifies the recipients of a push.
286 | */
287 | public static void sendMessageInBackground(String message, AVQuery extends AVObject> query) {
288 | if (!query.getClassName().equals(INSTALLATIONTAG)) {
289 | InternalConfigurationController.globalInstance().getInternalLogger()
290 | .e(AVPush.class.getSimpleName(), "only installation query is valid");
291 | return;
292 | }
293 | AVPush push = new AVPush();
294 | push.setMessage(message);
295 | push.setQuery(query);
296 | push.sendInBackground(false, null);
297 | }
298 |
299 | /**
300 | * A helper method to concisely send a push message to a query. This method is equivalent to
301 | *
302 | *
303 | * AVPush push = new AVPush();
304 | * push.setMessage(message);
305 | * push.setQuery(query);
306 | * push.sendInBackground(callback);
307 | *
308 | *
309 | * @param message The message that will be shown in the notification.
310 | * @param query A AVInstallation query which specifies the recipients of a push.
311 | * @param callback callback.done(e) is called when the send completes.
312 | */
313 | public static void sendMessageInBackground(String message, AVQuery extends AVObject> query,
314 | SendCallback callback) {
315 | if (!query.getClassName().equals(INSTALLATIONTAG)) {
316 | if (callback != null) {
317 | callback.done(new AVException(AVException.OTHER_CAUSE, "only installation query is valid"));
318 | }
319 | }
320 | AVPush push = new AVPush();
321 | push.setMessage(message);
322 | push.setQuery(query);
323 | push.sendInBackground(false, callback);
324 | }
325 |
326 | /**
327 | * Sets the channel on which this push notification will be sent. The channel name must start with
328 | * a letter and contain only letters, numbers, dashes, and underscores. A push can either have
329 | * channels or a query. Setting this will unset the query.
330 | *
331 | * @param channel set push channel
332 | */
333 | public void setChannel(String channel) {
334 | channelSet.clear();
335 | channelSet.add(channel);
336 | }
337 |
338 | /**
339 | * Sets the collection of channels on which this push notification will be sent. Each channel name
340 | * must start with a letter and contain only letters, numbers, dashes, and underscores. A push can
341 | * either have channels or a query. Setting this will unset the query.
342 | *
343 | * @param channels set push channels
344 | */
345 | public void setChannels(Collection channels) {
346 | channelSet.clear();
347 | channelSet.addAll(channels);
348 | }
349 |
350 | /**
351 | * Sets the entire data of the push message. See the push guide for more details on the data
352 | * format. This will overwrite any data specified in AVPush.setMessage(String).
353 | *
354 | * @param data push data
355 | */
356 | public void setData(Map data) {
357 | this.pushData.put("data", data);
358 | }
359 |
360 | /**
361 | * Sets the entire data of the push message. See the push guide for more details on the data
362 | * format. This will overwrite any data specified in AVPush.setMessage(String).
363 | *
364 | * @param data push data
365 | */
366 | public void setData(JSONObject data) {
367 | try {
368 | Map map = new HashMap();
369 | Iterator iter = data.keys();
370 | while (iter.hasNext()) {
371 | String key = (String) iter.next();
372 | Object value = data.get(key);
373 | map.put(key, value);
374 | }
375 | this.pushData.put("data", map);
376 | } catch (Exception exception) {
377 | throw new AVRuntimeException(exception);
378 | }
379 | }
380 |
381 | private Date expirationDateTime() {
382 | return new Date(expirationTime);
383 | }
384 |
385 | /**
386 | * Set the push date at which the push will be sent.
387 | *
388 | * @param date The push date.
389 | */
390 | public void setPushDate(Date date) {
391 | this.pushDate = date;
392 | }
393 |
394 | /**
395 | * Sets a UNIX epoch timestamp at which this notification should expire, in seconds (UTC). This
396 | * notification will be sent to devices which are either online at the time the notification is
397 | * sent, or which come online before the expiration time is reached. Because device clocks are not
398 | * guaranteed to be accurate, most applications should instead use
399 | * AVPush.setExpirationTimeInterval(long).
400 | *
401 | * @param time expire date
402 | */
403 | public void setExpirationTime(long time) {
404 | this.expirationTime = time;
405 | }
406 |
407 | /**
408 | * Sets the time interval after which this notification should expire, in seconds. This
409 | * notification will be sent to devices which are either online at the time the notification is
410 | * sent, or which come online within the given number of seconds of the notification being
411 | * received by AVOSCloud's server. An interval which is less than or equal to zero indicates that
412 | * the message should only be sent to devices which are currently online.
413 | *
414 | * @param timeInterval expirationTimeInterval
415 | */
416 | public void setExpirationTimeInterval(long timeInterval) {
417 | this.expirationTimeInterval = timeInterval;
418 | }
419 |
420 | /**
421 | * Sets the message that will be shown in the notification. This will overwrite any data specified
422 | * in AVPush.setData(JSONObject).
423 | *
424 | * @param message set push message
425 | */
426 | public void setMessage(String message) {
427 | pushData.clear();
428 | Map map = AVUtils.createStringObjectMap("alert", message);
429 | pushData.put("data", map);
430 | }
431 |
432 | public void setPushToAndroid(boolean pushToAndroid) {
433 | if (pushToAndroid) {
434 | this.pushTarget.add("android");
435 | } else {
436 | this.pushTarget.remove("android");
437 | }
438 | }
439 |
440 | public void setPushToIOS(boolean pushToIOS) {
441 | if (pushToIOS) {
442 | this.pushTarget.add("ios");
443 | } else {
444 | this.pushTarget.remove("ios");
445 | }
446 | }
447 |
448 | public void setPushToWindowsPhone(boolean pushToWP) {
449 | if (pushToWP) {
450 | this.pushTarget.add("wp");
451 | } else {
452 | this.pushTarget.remove("wp");
453 | }
454 | }
455 |
456 | /**
457 | * Sets the query for this push for which this push notification will be sent. This query will be
458 | * executed in the AVOSCloud cloud; this push notification will be sent to Installations which
459 | * this query yields. A push can either have channels or a query. Setting this will unset the
460 | * channels.
461 | *
462 | * @param query A query to which this push should target. This must be a AVInstallation query.
463 | */
464 | public void setQuery(AVQuery extends AVObject> query) {
465 | this.pushQuery = query;
466 | }
467 |
468 | /**
469 | * 可以通过 cql来针对push进行筛选
470 | *
471 | * 请注意cql 的主体应该是_Installation表
472 | *
473 | * 请在设置cql的同时,不要设置pushTarget(ios,android,wp)
474 | *
475 | * @param cql cql for push
476 | * @since 2.6.7
477 | */
478 | public void setCloudQuery(String cql) {
479 | this.cql = cql;
480 | }
481 |
482 | public boolean getProductionMode() {
483 | return this.production;
484 | }
485 |
486 | /**
487 | * 设定iOS推送是否是生产环境
488 | *
489 | *
490 | * @since 2.6.9
491 | * @param production,true为生产环境,默认是true
492 | */
493 | public void setProductionMode(boolean production) {
494 | this.production = production;
495 | }
496 | }
497 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/internal/MasterKeyConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud.internal;
2 |
3 | public interface MasterKeyConfiguration {
4 |
5 | public String getMasterKey();
6 |
7 | public void setMasterKey(String masterKey);
8 | }
9 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/internal/impl/JavaAppConfiguration.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud.internal.impl;
2 |
3 | import java.util.Map;
4 | import java.util.concurrent.ThreadPoolExecutor;
5 |
6 | import com.avos.avoscloud.AVUtils;
7 | import com.avos.avoscloud.internal.AppConfiguration;
8 | import com.avos.avoscloud.internal.MasterKeyConfiguration;
9 |
10 | public class JavaAppConfiguration extends AppConfiguration implements MasterKeyConfiguration {
11 |
12 | String masterKey;
13 |
14 | private final String apiHookKeyField = "X-LC-Hook-Key";
15 |
16 | private final String hookKey;
17 |
18 | public static JavaAppConfiguration instance() {
19 | synchronized (JavaAppConfiguration.class) {
20 | if (instance == null) {
21 | instance = new JavaAppConfiguration();
22 | }
23 | }
24 | return instance;
25 | }
26 |
27 | protected JavaAppConfiguration() {
28 | hookKey = getEnvOrProperty("LEANCLOUD_APP_HOOK_KEY");
29 | }
30 |
31 | private static JavaAppConfiguration instance;
32 |
33 |
34 | @Override
35 | public boolean isConfigured() {
36 | return !(AVUtils.isBlankString(this.getApplicationId())
37 | || AVUtils.isBlankString(this.getClientKey()) || (JavaRequestSignImplementation.instance()
38 | .isUseMasterKey() && AVUtils.isBlankString(this.getMasterKey())));
39 | }
40 |
41 | @Override
42 | public void setupThreadPoolExecutor(ThreadPoolExecutor excutor) {
43 | // do nothing
44 | }
45 |
46 | @Override
47 | public boolean isConnected() {
48 | return true;
49 | }
50 |
51 | @Override
52 | public String getMasterKey() {
53 | return this.masterKey;
54 | }
55 |
56 | @Override
57 | public void setMasterKey(String masterKey) {
58 | this.masterKey = masterKey;
59 | }
60 |
61 | protected String getEnvOrProperty(String key) {
62 | String value = System.getenv(key);
63 | if (value == null) {
64 | value = System.getProperty(key);
65 | }
66 | return value;
67 | }
68 |
69 | @Override
70 | public Map getRequestHeaders() {
71 | Map result = super.getRequestHeaders();
72 | if (hookKey != null) {
73 | result.put(apiHookKeyField, hookKey);
74 | }
75 | return result;
76 | }
77 |
78 | @Override
79 | public String dumpRequestHeaders() {
80 | if (hookKey != null) {
81 | return String.format("%s -H \"%s: %s\"", super.dumpRequestHeaders(), apiHookKeyField,
82 | dumpKey(hookKey, "YourHookKey"));
83 | }
84 | return super.dumpRequestHeaders();
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/internal/impl/JavaRequestSignImplementation.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud.internal.impl;
2 |
3 | import com.avos.avoscloud.AVUtils;
4 | import com.avos.avoscloud.internal.AppConfiguration;
5 | import com.avos.avoscloud.internal.InternalConfigurationController;
6 | import com.avos.avoscloud.internal.InternalRequestSign;
7 | import com.avos.avoscloud.internal.MasterKeyConfiguration;
8 |
9 | public class JavaRequestSignImplementation implements InternalRequestSign {
10 |
11 | boolean useMasterKey = false;
12 |
13 | public static JavaRequestSignImplementation instance() {
14 | synchronized (JavaRequestSignImplementation.class) {
15 | if (instance == null) {
16 | instance = new JavaRequestSignImplementation();
17 | }
18 | }
19 | return instance;
20 | }
21 |
22 | private JavaRequestSignImplementation() {}
23 |
24 | private static JavaRequestSignImplementation instance;
25 |
26 | @Override
27 | public String requestSign() {
28 | return requestSign(AVUtils.getCurrentTimestamp(), this.isUseMasterKey());
29 | }
30 |
31 | public static String requestSign(long ts, boolean useMasterKey) {
32 | StringBuilder builder = new StringBuilder();
33 |
34 | StringBuilder result = new StringBuilder();
35 |
36 | AppConfiguration appConfiguration =
37 | InternalConfigurationController.globalInstance().getAppConfiguration();
38 | String masterKey = null;
39 | if (appConfiguration instanceof MasterKeyConfiguration) {
40 | masterKey = ((MasterKeyConfiguration) appConfiguration).getMasterKey();
41 | }
42 |
43 | result.append(AVUtils.md5(
44 | builder.append(ts).append(useMasterKey ? masterKey : appConfiguration.getClientKey())
45 | .toString()).toLowerCase());
46 | result.append(',').append(ts);
47 | if (!useMasterKey) {
48 | return result.toString();
49 | } else {
50 | return result.append(",master").toString();
51 | }
52 | }
53 |
54 | public void setUseMasterKey(boolean shouldUseMasterKey) {
55 | this.useMasterKey = shouldUseMasterKey;
56 | }
57 |
58 | protected boolean isUseMasterKey() {
59 | return this.useMasterKey;
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/internal/impl/Log4j2Implementation.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud.internal.impl;
2 |
3 | import com.avos.avoscloud.AVOSCloud;
4 | import com.avos.avoscloud.internal.InternalLogger;
5 |
6 | import org.apache.logging.log4j.Logger;
7 | import org.apache.logging.log4j.LogManager;
8 |
9 | public class Log4j2Implementation extends InternalLogger {
10 |
11 | private static final Logger logger = LogManager.getLogger(AVOSCloud.class);
12 |
13 |
14 | public static Log4j2Implementation instance() {
15 | synchronized (Log4j2Implementation.class) {
16 | if (instance == null) {
17 | instance = new Log4j2Implementation();
18 | }
19 | }
20 | return instance;
21 | }
22 |
23 | private Log4j2Implementation() {}
24 |
25 | private static Log4j2Implementation instance;
26 |
27 | @Override
28 | public int v(String tag, String msg) {
29 | logger.info(msg);
30 | return 0;
31 | }
32 |
33 | @Override
34 | public int v(String tag, String msg, Throwable tr) {
35 | logger.info(msg, tr);
36 | return 0;
37 | }
38 |
39 | @Override
40 | public int d(String tag, String msg) {
41 | logger.debug(msg);
42 | return 0;
43 | }
44 |
45 | @Override
46 | public int d(String tag, String msg, Throwable tr) {
47 | logger.debug(msg, tr);
48 | return 0;
49 | }
50 |
51 | @Override
52 | public int i(String tag, String msg) {
53 | logger.info(msg);
54 | return 0;
55 | }
56 |
57 | @Override
58 | public int i(String tag, String msg, Throwable tr) {
59 | logger.info(msg, tr);
60 | return 0;
61 | }
62 |
63 | @Override
64 | public int w(String tag, String msg) {
65 | logger.warn(msg);
66 | return 0;
67 | }
68 |
69 | @Override
70 | public int w(String tag, String msg, Throwable tr) {
71 | logger.warn(msg, tr);
72 | return 0;
73 | }
74 |
75 | @Override
76 | public int w(String tag, Throwable tr) {
77 | logger.warn(tr);
78 | return 0;
79 | }
80 |
81 | @Override
82 | public int e(String tag, String msg) {
83 | logger.error(msg);
84 | return 0;
85 | }
86 |
87 | @Override
88 | public int e(String tag, String msg, Throwable tr) {
89 | logger.error(msg, tr);
90 | return 0;
91 | }
92 |
93 | }
94 |
--------------------------------------------------------------------------------
/src/main/java/com/avos/avoscloud/internal/impl/SimplePersistence.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud.internal.impl;
2 |
3 | import java.io.ByteArrayOutputStream;
4 | import java.io.File;
5 | import java.io.FileInputStream;
6 | import java.io.FileNotFoundException;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 |
10 | import com.avos.avoscloud.AVUser;
11 | import com.avos.avoscloud.AVUtils;
12 | import com.avos.avoscloud.internal.InternalPersistence;
13 |
14 | public class SimplePersistence implements InternalPersistence {
15 |
16 | public static SimplePersistence instance() {
17 | synchronized (SimplePersistence.class) {
18 | if (instance == null) {
19 | instance = new SimplePersistence();
20 | }
21 | }
22 | return instance;
23 | }
24 |
25 | protected SimplePersistence() {}
26 |
27 | private static SimplePersistence instance;
28 |
29 | public File getPaasDocumentDir() {
30 |
31 | return null;
32 | }
33 |
34 | public File getCacheDir() {
35 | return null;
36 | }
37 |
38 | public File getCommandCacheDir() {
39 | return null;
40 | }
41 |
42 | public boolean saveContentToFile(String content, File fileForSave) {
43 | return saveContentToFile(content.getBytes(), fileForSave);
44 | }
45 |
46 | public boolean saveContentToFile(byte[] content, File fileForSave) {
47 | FileOutputStream fos = null;
48 | try {
49 | fos = new FileOutputStream(fileForSave);
50 | fos.write(content);
51 | return true;
52 | } catch (IOException e) {
53 | throw new RuntimeException(e);
54 | } finally {
55 | AVUtils.closeQuietly(fos);
56 | }
57 | }
58 |
59 | public void saveToDocumentDir(String content, String folderName, String fileName) {
60 | saveContentToFile(content.getBytes(), new File(folderName, fileName));
61 | }
62 |
63 | public String getFromDocumentDir(String folderName, String fileName) {
64 | return readContentFromFile(new File(folderName, fileName));
65 | }
66 |
67 | public String readContentFromFile(File fileForRead) {
68 | return new String(readContentBytesFromFile(fileForRead));
69 | }
70 |
71 | public byte[] readContentBytesFromFile(File fileForRead) {
72 | byte[] buffer = null;
73 | FileInputStream fis = null;
74 | ByteArrayOutputStream bos = null;
75 | try {
76 | fis = new FileInputStream(fileForRead);
77 | bos = new ByteArrayOutputStream();
78 | byte[] b = new byte[1024 * 5];
79 | int n;
80 | while ((n = fis.read(b)) != -1) {
81 | bos.write(b, 0, n);
82 | }
83 | buffer = bos.toByteArray();
84 | } catch (FileNotFoundException e) {
85 | throw new RuntimeException(e);
86 | } catch (IOException e) {
87 | throw new RuntimeException(e);
88 | } finally {
89 | AVUtils.closeQuietly(fis);
90 | AVUtils.closeQuietly(bos);
91 | }
92 | return buffer;
93 | }
94 |
95 | public void deleteFile(File file) {
96 | try {
97 | file.deleteOnExit();
98 | } catch (SecurityException e) {
99 | throw new RuntimeException(e);
100 | }
101 | }
102 |
103 | public void savePersistentSettingBoolean(String keyzone, String key, Boolean value) {
104 |
105 | }
106 |
107 | public boolean getPersistentSettingBoolean(String keyzone, String key) {
108 | // TODO Auto-generated method stub
109 | return false;
110 | }
111 |
112 | public boolean getPersistentSettingBoolean(String keyzone, String key, Boolean defaultValue) {
113 | // TODO Auto-generated method stub
114 | return defaultValue;
115 | }
116 |
117 | public void savePersistentSettingInteger(String keyzone, String key, Integer value) {
118 | // TODO Auto-generated method stub
119 |
120 | }
121 |
122 | public Integer getPersistentSettingInteger(String keyzone, String key, Integer defaultValue) {
123 | // TODO Auto-generated method stub
124 | return defaultValue;
125 | }
126 |
127 | public Long getPersistentSettingLong(String keyzone, String key, Long defaultValue) {
128 | // TODO Auto-generated method stub
129 | return defaultValue;
130 | }
131 |
132 | public void savePersistentSettingLong(String keyzone, String key, Long value) {
133 | // TODO Auto-generated method stub
134 |
135 | }
136 |
137 | public void savePersistentSettingString(String keyzone, String key, String value) {
138 |
139 | }
140 |
141 | public String getPersistentSettingString(String keyzone, String key, String defaultValue) {
142 | return defaultValue;
143 | }
144 |
145 | public void removePersistentSettingString(String keyzone, String key) {
146 |
147 | }
148 |
149 | public String removePersistentSettingString(String keyzone, String key, String defaultValue) {
150 | return null;
151 | }
152 |
153 | public void removeKeyZonePersistentSettings(String keyzone) {
154 |
155 | }
156 |
157 | public String getAVFileCachePath() {
158 | // TODO Auto-generated method stub
159 | return null;
160 | }
161 |
162 | public File getAVFileCacheFile(String url) {
163 | // TODO Auto-generated method stub
164 | return null;
165 | }
166 |
167 | public void cleanAVFileCache(int days) {
168 | // TODO Auto-generated method stub
169 |
170 | }
171 |
172 | private AVUser currentUser;
173 |
174 | public void setCurrentUser(AVUser user, boolean clean) {
175 | this.currentUser = user;
176 | }
177 |
178 | public T getCurrentUser(Class userClass) {
179 | if (currentUser != null) {
180 | return (T) AVUser.cast(currentUser, userClass);
181 | } else {
182 | return null;
183 | }
184 |
185 | }
186 |
187 | }
188 |
--------------------------------------------------------------------------------
/src/test/java/com/avos/avoscloud/DisableHookTest.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud;
2 |
3 | import java.util.Arrays;
4 |
5 | import junit.framework.Test;
6 | import junit.framework.TestCase;
7 | import junit.framework.TestSuite;
8 |
9 | public class DisableHookTest extends TestCase {
10 |
11 | public DisableHookTest(String testName) {
12 | super(testName);
13 | }
14 |
15 | @Override
16 | public void setUp() {
17 | TestApp.init();
18 | }
19 |
20 | /**
21 | * @return the suite of tests being tested
22 | */
23 | public static Test suite() {
24 | return new TestSuite(DisableHookTest.class);
25 | }
26 |
27 | public void testSaveHook() throws AVException {
28 | AVObject object = new AVObject("IgnoreHookTest");
29 | object.put("title", "test");
30 | object.save();
31 | object.fetch();
32 | assertEquals(1, object.getInt("byBeforeSave"));
33 | assertEquals(1, object.getInt("byAfterSave"));
34 | }
35 |
36 | public void testSaveHook_disableBeforeHook() throws AVException {
37 | AVObject object = new AVObject("IgnoreHookTest");
38 | object.put("title", "test");
39 | object.disableBeforeHook();
40 | object.save();
41 | object.fetch();
42 | assertNull(object.get("byBeforeSave"));
43 | assertEquals(1, object.getInt("byAfterSave"));
44 | }
45 |
46 | public void testSaveHook_disableAfterHook() throws AVException {
47 | AVObject object = new AVObject("IgnoreHookTest");
48 | object.put("title", "test");
49 | object.disableAfterHook();
50 | object.save();
51 | object.fetch();
52 | assertEquals(1, object.getInt("byBeforeSave"));
53 | assertNull(object.get("byAfterSave"));
54 | }
55 |
56 | public void testUpdateHook() throws AVException {
57 | AVObject object = new AVObject("IgnoreHookTest");
58 | object.put("title", "test");
59 | object.save();
60 | object.put("title", "something");
61 | object.save();
62 | object.fetch();
63 | assertEquals(1, object.getInt("byBeforeSave"));
64 | assertEquals(1, object.getInt("byAfterSave"));
65 | assertEquals(1, object.getInt("byBeforeUpdate"));
66 | assertEquals(1, object.getInt("byAfterUpdate"));
67 | }
68 |
69 | public void testUpdateHook_disableBeforeHook() throws AVException {
70 | AVObject object = new AVObject("IgnoreHookTest");
71 | object.put("title", "test");
72 | object.save();
73 | object.put("title", "something");
74 | object.disableBeforeHook();
75 | object.save();
76 | object.fetch();
77 | assertEquals(1, object.getInt("byBeforeSave"));
78 | assertEquals(1, object.getInt("byAfterSave"));
79 | assertNull(object.get("byBeforeUpdate"));
80 | assertEquals(1, object.getInt("byAfterUpdate"));
81 | }
82 |
83 | public void testUpdateHook_disableAfterHook() throws AVException {
84 | AVObject object = new AVObject("IgnoreHookTest");
85 | object.put("title", "test");
86 | object.save();
87 | object.put("title", "something");
88 | object.disableAfterHook();
89 | object.save();
90 | object.fetch();
91 | assertEquals(1, object.getInt("byBeforeSave"));
92 | assertEquals(1, object.getInt("byAfterSave"));
93 | assertEquals(1, object.getInt("byBeforeUpdate"));
94 | assertNull(object.get("byAfterUpdate"));
95 | }
96 |
97 | public void testHook_haveChildren_disableHook() throws AVException {
98 | AVObject child1 = new AVObject("IgnoreHookTest");
99 | child1.put("title", "child1");
100 | child1.disableBeforeHook();
101 |
102 | AVObject object = new AVObject("IgnoreHookTest");
103 | object.put("title", "test");
104 | object.disableAfterHook();
105 |
106 | object.put("child1", child1);
107 |
108 | object.save();
109 |
110 | object.fetch();
111 | assertEquals(1, object.getInt("byBeforeSave"));
112 | assertNull(object.get("byAfterSave"));
113 |
114 | child1.fetch();
115 | assertNull(child1.get("byBeforeSave"));
116 | assertEquals(1, child1.getInt("byAfterSave"));
117 |
118 | child1.put("title", "child1 something");
119 | object.put("child1", child1);
120 |
121 | AVObject child2 = new AVObject("IgnoreHookTest");
122 | child2.put("title", "child2");
123 | child2.disableAfterHook();
124 |
125 | object.put("child2", child2);
126 |
127 | object.save();
128 |
129 | object.fetch();
130 | assertEquals(1, object.getInt("byBeforeUpdate"));
131 | assertNull(object.get("byAfterUpdate"));
132 |
133 | child1.fetch();
134 | assertNull(child1.get("byBeforeUpdate"));
135 | assertEquals(1, child1.getInt("byAfterUpdate"));
136 |
137 | child2.fetch();
138 | assertEquals(1, child2.getInt("byBeforeSave"));
139 | assertNull(child2.get("byAfterSave"));
140 | }
141 |
142 | public void testDeleteHook_disableBeforeHook() throws AVException {
143 | AVObject object = new AVObject("IgnoreHookTest");
144 | object.put("title", "test");
145 | object.save();
146 | object.fetch();
147 | object.put("title", "something");
148 | object.disableBeforeHook();
149 | object.delete();
150 | }
151 |
152 | public void testDeleteHook_deleteAll() throws AVException {
153 | AVObject object = new AVObject("IgnoreHookTest");
154 | object.put("title", "object1");
155 | object.save();
156 |
157 | try {
158 | AVObject.deleteAll(Arrays.asList(object));
159 | fail("should throw 'Cloud Code vaildation failed' exception.");
160 | } catch (AVException e) {
161 | assertTrue(e.getMessage()
162 | .startsWith("Cloud Code validation failed. Error detail : Error from beforeDelete"));
163 | }
164 |
165 | AVObject object1 = new AVObject("IgnoreHookTest");
166 | object1.put("title", "object1");
167 | object1.ignoreHook(AVObject.Hook.beforeDelete);
168 | object1.save();
169 |
170 | AVObject object2 = new AVObject("IgnoreHookTest");
171 | object2.put("title", "object2");
172 | object2.disableBeforeHook();
173 | object2.save();
174 |
175 | AVObject object3 = new AVObject("IgnoreHookTest");
176 | object3.put("title", "object2");
177 | object3.disableBeforeHook();
178 | object3.save();
179 |
180 | AVObject.deleteAll(Arrays.asList(object1, object2, object3));
181 | }
182 |
183 | }
184 |
--------------------------------------------------------------------------------
/src/test/java/com/avos/avoscloud/TestApp.java:
--------------------------------------------------------------------------------
1 | package com.avos.avoscloud;
2 |
3 | import com.avos.avoscloud.internal.InternalConfigurationController;
4 | import com.avos.avoscloud.internal.InternalLogger;
5 | import com.avos.avoscloud.internal.impl.DefaultAppRouter;
6 | import com.avos.avoscloud.internal.impl.JavaAppConfiguration;
7 | import com.avos.avoscloud.internal.impl.Log4j2Implementation;
8 | import com.avos.avoscloud.internal.impl.SimplePersistence;
9 |
10 | public class TestApp {
11 |
12 | public static void init() {
13 | TestApp.init("uu2P5gNTxGhjyaJGAPPnjCtJ-gzGzoHsz", "j5lErUd6q7LhPD8CXhfmA2Rg",
14 | "atXAmIVlQoBDBLqumMgzXhcY", "rTXH9hotZfAJjtFOQqwfEHpC", true);
15 | }
16 |
17 | public static void init(String applicationId, String clientKey, String masterKey, String hookKey,
18 | boolean isCN) {
19 | System.setProperty("LEANCLOUD_APP_HOOK_KEY", hookKey);
20 | JavaAppConfiguration configuration = JavaAppConfiguration.instance();
21 | configuration.setIsCN(isCN);
22 | configuration.setApplicationId(applicationId);
23 | configuration.setClientKey(clientKey);
24 | configuration.setMasterKey(masterKey);
25 |
26 | InternalLogger logger = Log4j2Implementation.instance();
27 | logger.setDebugEnabled(true);
28 |
29 | new InternalConfigurationController.Builder().setAppConfiguration(configuration)
30 | .setAppRouter(DefaultAppRouter.instance()).setInternalLogger(logger)
31 | .setInternalPersistence(SimplePersistence.instance())
32 | .build();
33 | InternalConfigurationController.globalInstance().getAppRouter().updateServerHosts();
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/src/test/resources/log4j2.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------