App Engine Python SDK version 1.7.4 (2)
[gae.git] / java / src / main / com / google / appengine / api / taskqueue / TaskHandle.java
blob2cba55fc309fa7a699ad257309b7a7948bedc6eb
1 // Copyright 2010 Google Inc. All rights reserved.
2 package com.google.appengine.api.taskqueue;
4 import java.io.IOException;
5 import java.io.ObjectInputStream;
6 import java.io.Serializable;
7 import java.io.UnsupportedEncodingException;
8 import java.net.URLDecoder;
9 import java.util.ArrayList;
10 import java.util.List;
11 import java.util.Map;
13 /**
14 * Created from {@link Queue#add(TaskOptions)}. Contains the
15 * task name (generated if otherwise unspecified), task ETA (computed if
16 * not specified) and queue name. The queue name and task name
17 * uniquely identify the task for an application.
20 public final class TaskHandle implements Serializable {
21 private static final long serialVersionUID = -2578988193753847512L;
22 private String taskName;
23 private String queueName;
24 private long etaUsec;
25 private long etaMillis;
26 private Integer retryCount;
27 private TaskOptions options;
29 TaskHandle(TaskOptions options, String queueName,Integer retryCount) {
30 validateTaskName(options.getTaskName());
31 QueueApiHelper.validateQueueName(queueName);
32 this.queueName = queueName;
33 this.retryCount = retryCount;
34 this.taskName = null;
35 this.etaMillis = 0;
36 this.options = new TaskOptions(options);
37 setEtaUsecFromOptions(this.options);
40 public TaskHandle(TaskOptions options, String queueName) {
41 this(options, queueName, 0);
44 /**
45 * @deprecated Use {@link TaskHandle#TaskHandle(TaskOptions, String)}
47 @Deprecated
48 public TaskHandle(String name, String queueName, long etaMillis) {
49 this(TaskOptions.Builder.withTaskName(name).etaMillis(etaMillis),
50 queueName, null);
53 private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
54 in.defaultReadObject();
55 if (options == null) {
56 options = TaskOptions.Builder.withTaskName(taskName).etaMillis(etaMillis);
57 taskName = null;
58 etaMillis = 0;
60 if (etaUsec == 0 && options.getEtaMillis() != null) {
61 setEtaUsecFromOptions(options);
65 @Override
66 public int hashCode() {
67 final int prime = 31;
68 int result = options.hashCode();
69 result = result * prime + queueName.hashCode();
70 result = result * prime + (retryCount == null ? 0 : retryCount.intValue());
71 result = result * prime + (int) (etaUsec ^ (etaUsec >>> 32));
72 return result;
75 @Override
76 public boolean equals(Object obj) {
77 if (this == obj) return true;
78 if (obj == null) return false;
79 if (getClass() != obj.getClass()) return false;
80 TaskHandle other = (TaskHandle) obj;
81 if (options == null) {
82 if (other.options != null) return false;
83 } else if (!options.equals(other.options)) return false;
84 if (queueName == null) {
85 if (other.queueName != null) return false;
86 } else if (!queueName.equals(other.queueName)) return false;
87 if (retryCount == null) {
88 if (other.retryCount != null) return false;
89 } else if (!retryCount.equals(other.retryCount)) return false;
90 if (etaUsec != other.etaUsec) {
91 return false;
93 return true;
96 @Override
97 public String toString() {
98 return "TaskHandle[options=" + options.toString() + "queueName=" + queueName
99 + ", retryCount=" + retryCount + ", etaMillis = " + etaMillis
100 + ", etaUsec = " + etaUsec + "]";
104 * Checks the name of this task matches QueueConstants.TASK_NAME_PATTERN
106 * @throws IllegalArgumentException
108 static void validateTaskName(String taskName) {
109 if (taskName == null || taskName.length() == 0 ||
110 !QueueConstants.TASK_NAME_PATTERN.matcher(taskName).matches()) {
111 throw new IllegalArgumentException(
112 "Task name does not match expression " + QueueConstants.TASK_NAME_REGEX +
113 "; given taskname: '" + taskName + "'");
118 * Returns the name of this task. This may have been generated
119 * by a call to {@link Queue#add()} if the name was not otherwise specified.
121 public String getName() {
122 return options.getTaskName();
126 * Returns the name of the queue that this task was submitted into.
128 public String getQueueName() {
129 return queueName;
133 * Returns a time comparable to {@link System#currentTimeMillis()} when
134 * this task is scheduled for execution.
136 public long getEtaMillis() {
137 return options.getEtaMillis();
141 * Set the time comparable to {@link System#currentTimeMillis()} when
142 * this task is scheduled for execution. For pull tasks this value specifies
143 * the lease expiration time.
145 void etaMillis(long etaMillis) {
146 options.etaMillis(etaMillis);
147 etaUsec = etaMillis * 1000;
151 * Returns the time when the task is scheduled for execution to microsecond
152 * precision. For pull tasks this value specifies the lease expiration time.
153 * Microsecond precision is required for the lease verification check when
154 * modifying the task lease.
156 long getEtaUsec() {
157 return etaUsec;
161 * Set the time for when this task is scheduled for execution to microsecond
162 * precision. For pull tasks this value specifies the lease expiraion time.
164 TaskHandle etaUsec(long etaUsec) {
165 this.etaUsec = etaUsec;
166 options.etaMillis(etaUsec / 1000);
167 return this;
171 * Returns number of leases that had been performed on this task.
172 * Can return {@code null}.
174 public Integer getRetryCount() {
175 return retryCount;
179 * Returns binary payload data of this task.
180 * Can return {@code null}.
182 public byte[] getPayload() {
183 return options.getPayload();
187 * Returns tag of this task. Can return {@code null}.
188 * @throws UnsupportedEncodingException
190 public String getTag() throws UnsupportedEncodingException {
191 return options.getTag();
195 * Returns tag of this task. Can return {@code null}.
197 public byte[] getTagAsBytes() {
198 return options.getTagAsBytes();
201 private void setEtaUsecFromOptions(TaskOptions options) {
202 if (options != null && options.getEtaMillis() != null) {
203 etaUsec = options.getEtaMillis() * 1000;
204 } else {
205 etaUsec = 0;
209 static final class KeyValuePair implements Map.Entry<String, String> {
210 private final String key;
211 private String value;
213 public KeyValuePair(String key, String value) {
214 this.key = key;
215 this.value = value;
218 public String getKey() {
219 return key;
222 public String getValue() {
223 return value;
226 public String setValue(String v) {
227 String old = value;
228 value = v;
229 return old;
232 public int hashCode() {
233 int prime = 31;
234 int result = 0;
235 result = prime * result + key.hashCode();
236 result = prime * result + value.hashCode();
237 return result;
240 public boolean equals(Object o) {
241 if (this == o) return true;
242 if (o == null || !(o instanceof KeyValuePair)) return false;
243 KeyValuePair that = (KeyValuePair) o;
244 return key.equals(that.key) && value.equals(that.value);
249 * Attempts to decode the {@code payload} byte array in our {@code options}
250 * into a list of Map.Entry<String, String>.
252 * @throws UnsupportedEncodingException if the payload cannot be decoded as a
253 * {@code application/x-www-form-urlencoded} string.
254 * @throws UnsupportedOperationException if the {@code options} has no payload
255 * or the payload bytes could not be interpreted as application/x-www-form-urlencoded
256 * key-value pairs.
258 public List<Map.Entry<String, String>> extractParams()
259 throws UnsupportedEncodingException, UnsupportedOperationException {
260 String payload = new String(getPayload());
261 String[] paramStrings = payload.split("&");
263 List<Map.Entry<String, String>> result = new ArrayList<Map.Entry<String, String>>();
264 for (String param : paramStrings) {
265 String[] kv = param.split("=", 2);
266 if (kv.length != 2) {
267 throw new UnsupportedOperationException(
268 "Payload " + payload + " failed to decode as application/x-www-form-urlencoded pairs. "
269 + param + " Length" + kv.length);
271 result.add(new KeyValuePair(URLDecoder.decode(kv[0], "UTF-8"),
272 URLDecoder.decode(kv[1], "UTF-8")));
274 return result;