appengine-apis 0.0.8 → 0.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Manifest.txt +5 -0
- data/README.rdoc +2 -0
- data/lib/appengine-apis.rb +1 -1
- data/lib/appengine-apis/datastore.rb +41 -14
- data/lib/appengine-apis/datastore_types.rb +194 -5
- data/lib/appengine-apis/labs/taskqueue.rb +266 -0
- data/lib/appengine-apis/tempfile.rb +52 -0
- data/lib/appengine-apis/urlfetch.rb +4 -0
- data/lib/appengine-apis/xmpp.rb +283 -0
- data/spec/datastore_spec.rb +55 -1
- data/spec/datastore_types_spec.rb +125 -0
- data/spec/spec_helper.rb +3 -1
- data/spec/taskqueue_spec.rb +110 -0
- data/spec/urlfetch_spec.rb +5 -0
- data/spec/xmpp_spec.rb +223 -0
- metadata +9 -2
data/Manifest.txt
CHANGED
@@ -6,6 +6,7 @@ lib/appengine-apis.rb
|
|
6
6
|
lib/appengine-apis/apiproxy.rb
|
7
7
|
lib/appengine-apis/datastore.rb
|
8
8
|
lib/appengine-apis/datastore_types.rb
|
9
|
+
lib/appengine-apis/labs/taskqueue.rb
|
9
10
|
lib/appengine-apis/local_boot.rb
|
10
11
|
lib/appengine-apis/logger.rb
|
11
12
|
lib/appengine-apis/mail.rb
|
@@ -15,6 +16,8 @@ lib/appengine-apis/sdk.rb
|
|
15
16
|
lib/appengine-apis/testing.rb
|
16
17
|
lib/appengine-apis/urlfetch.rb
|
17
18
|
lib/appengine-apis/users.rb
|
19
|
+
lib/appengine-apis/xmpp.rb
|
20
|
+
lib/appengine-apis/tempfile.rb
|
18
21
|
script/console
|
19
22
|
script/destroy
|
20
23
|
script/generate
|
@@ -25,6 +28,8 @@ spec/mail_spec.rb
|
|
25
28
|
spec/memcache_spec.rb
|
26
29
|
spec/spec.opts
|
27
30
|
spec/spec_helper.rb
|
31
|
+
spec/taskqueue_spec.rb
|
28
32
|
spec/urlfetch_spec.rb
|
29
33
|
spec/users_spec.rb
|
34
|
+
spec/xmpp_spec.rb
|
30
35
|
tasks/rspec.rake
|
data/README.rdoc
CHANGED
@@ -22,6 +22,8 @@ See these classes for an overview of each API:
|
|
22
22
|
- AppEngine::Memcache
|
23
23
|
- AppEngine::URLFetch
|
24
24
|
- AppEngine::Datastore
|
25
|
+
- AppEngine::XMPP
|
26
|
+
- AppEngine::Labs::TaskQueue
|
25
27
|
|
26
28
|
Unless you're implementing your own ORM, you probably want to use the
|
27
29
|
DataMapper API instead of the lower level AppEngine::Datastore API.
|
data/lib/appengine-apis.rb
CHANGED
@@ -236,6 +236,21 @@ module Datastore
|
|
236
236
|
raise TransactionFailed
|
237
237
|
end
|
238
238
|
|
239
|
+
# call-seq:
|
240
|
+
# Datastore.allocate_ids(kind, num)
|
241
|
+
# Datastore.allocate_ids(parent, kind, num)
|
242
|
+
#
|
243
|
+
# Ids are allocated within a namespace defined by a parent key and a kind.
|
244
|
+
# This method allocates a contiguous range of unique ids of size num
|
245
|
+
# within the namespace defined by the given parent key and the given kind.
|
246
|
+
#
|
247
|
+
# Returns a KeyRange representing the range of allocated ids.
|
248
|
+
def allocate_ids(*args)
|
249
|
+
convert_exceptions do
|
250
|
+
@@db.allocate_ids(*args)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
239
254
|
def extract_tx(args) # :nodoc:
|
240
255
|
tx = :none
|
241
256
|
keys = args[0]
|
@@ -406,8 +421,8 @@ module Datastore
|
|
406
421
|
end
|
407
422
|
|
408
423
|
# Returns the number of entities that currently match this query.
|
409
|
-
def count
|
410
|
-
pquery.
|
424
|
+
def count(transaction=:current)
|
425
|
+
pquery(transaction).count_entities
|
411
426
|
end
|
412
427
|
|
413
428
|
# Retrieves the one and only result for the {@code Query}.
|
@@ -417,9 +432,9 @@ module Datastore
|
|
417
432
|
#
|
418
433
|
# Returns the single, matching result, or nil if no entities match
|
419
434
|
#
|
420
|
-
def entity
|
435
|
+
def entity(transaction=:current)
|
421
436
|
Datastore.convert_exceptions do
|
422
|
-
pquery.as_single_entity
|
437
|
+
pquery(transaction).as_single_entity
|
423
438
|
end
|
424
439
|
end
|
425
440
|
|
@@ -429,9 +444,9 @@ module Datastore
|
|
429
444
|
#
|
430
445
|
# See #convert_options for supported options
|
431
446
|
def each(options={}, &proc) # :yields: entity
|
432
|
-
options = convert_options(options)
|
447
|
+
transaction, options = convert_options(options)
|
433
448
|
Datastore.convert_exceptions do
|
434
|
-
pquery.as_iterator(options).each(&proc)
|
449
|
+
pquery(transaction).as_iterator(options).each(&proc)
|
435
450
|
end
|
436
451
|
end
|
437
452
|
|
@@ -440,9 +455,9 @@ module Datastore
|
|
440
455
|
# See #convert_options for supported options
|
441
456
|
#
|
442
457
|
def iterator(options={})
|
443
|
-
options = convert_options(options)
|
458
|
+
transaction, options = convert_options(options)
|
444
459
|
Datastore.convert_exceptions do
|
445
|
-
pquery.as_iterator(options)
|
460
|
+
pquery(transaction).as_iterator(options)
|
446
461
|
end
|
447
462
|
end
|
448
463
|
|
@@ -451,17 +466,21 @@ module Datastore
|
|
451
466
|
# datastore.
|
452
467
|
#
|
453
468
|
def fetch(options={})
|
454
|
-
options = convert_options(options)
|
469
|
+
transaction, options = convert_options(options)
|
455
470
|
Datastore.convert_exceptions do
|
456
|
-
pquery.as_list(options)
|
471
|
+
pquery(transaction).as_list(options)
|
457
472
|
end
|
458
473
|
end
|
459
474
|
|
460
475
|
# Returns a Java.ComGoogleAppengineApiDatastore.PreparedQuery
|
461
476
|
# for this query.
|
462
477
|
#
|
463
|
-
def pquery
|
464
|
-
@pquery ||=
|
478
|
+
def pquery(transaction=:current)
|
479
|
+
@pquery ||= if transaction != :current
|
480
|
+
Datastore.service.prepare(transaction, @query)
|
481
|
+
else
|
482
|
+
Datastore.service.prepare(@query)
|
483
|
+
end
|
465
484
|
end
|
466
485
|
|
467
486
|
# Returns a Java.ComGoogleAppengineApiDatastore.Query for this query.
|
@@ -481,9 +500,17 @@ module Datastore
|
|
481
500
|
# Determines the internal chunking strategy of the iterator
|
482
501
|
# returned by #iterator. This affects only the performance of
|
483
502
|
# the query, not the actual results returned.
|
503
|
+
# [:transaction]
|
504
|
+
# Transaction in which the query should run. Only supported
|
505
|
+
# for ancestor queries. Uses the current transaction if not
|
506
|
+
# specified.
|
484
507
|
#
|
485
508
|
def convert_options(options)
|
486
|
-
|
509
|
+
transaction = :current
|
510
|
+
return [transaction, options] if options.java_kind_of? FetchOptions
|
511
|
+
if options.include? :transaction
|
512
|
+
transaction = options.delete(:transaction)
|
513
|
+
end
|
487
514
|
limit = options.delete(:limit)
|
488
515
|
offset = options.delete(:offset)
|
489
516
|
chunk_size = options.delete(:chunk) || FetchOptions::DEFAULT_CHUNK_SIZE
|
@@ -493,7 +520,7 @@ module Datastore
|
|
493
520
|
options = FetchOptions::Builder.with_chunk_size(chunk_size)
|
494
521
|
options.offset(offset) if offset
|
495
522
|
options.limit(limit) if limit
|
496
|
-
options
|
523
|
+
[transaction, options]
|
497
524
|
end
|
498
525
|
|
499
526
|
def inspect
|
@@ -23,11 +23,11 @@ require 'java'
|
|
23
23
|
|
24
24
|
class Time
|
25
25
|
def to_java
|
26
|
-
java.util.Date.new(tv_sec * 1000 + tv_usec / 1000)
|
26
|
+
java.util.Date.new(tv_sec * 1000 + tv_usec / 1000.0)
|
27
27
|
end
|
28
28
|
|
29
29
|
def self.new_from_java(date)
|
30
|
-
at(date.time / 1000)
|
30
|
+
at(date.time / 1000.0)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -117,6 +117,135 @@ module AppEngine
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
+
# An RFC2822 email address. Makes no attempt at validation.
|
121
|
+
class Email < String
|
122
|
+
def to_java
|
123
|
+
JavaDatastore::Email.new(self.to_java_string)
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.new_from_java(email)
|
127
|
+
self.new(email.getEmail)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# A tag, ie a descriptive word or phrase. Entities may be tagged by users,
|
132
|
+
# and later returned by a queries for that tag. Tags can also be used for
|
133
|
+
# ranking results (frequency), photo captions, clustering, activity, etc.
|
134
|
+
#
|
135
|
+
# More details: http://www.zeldman.com/daily/0405d.shtml
|
136
|
+
class Category < String
|
137
|
+
def to_java
|
138
|
+
JavaDatastore::Category.new(self.to_java_string)
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.new_from_java(category)
|
142
|
+
self.new(category.getCategory)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# A human-readable phone number. No validation is performed because phone
|
147
|
+
# numbers have many different formats - local, long distance, domestic,
|
148
|
+
# international, internal extension, TTY, VOIP, SMS, and alternative
|
149
|
+
# networks like Skype, XFire and Roger Wilco. They all have their own
|
150
|
+
# numbering and addressing formats.
|
151
|
+
class PhoneNumber < String
|
152
|
+
def to_java
|
153
|
+
JavaDatastore::PhoneNumber.new(self.to_java_string)
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.new_from_java(phone)
|
157
|
+
self.new(phone.getNumber)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# A human-readable mailing address. Mailing address formats vary widely so
|
162
|
+
# no validation is performed.
|
163
|
+
class PostalAddress < String
|
164
|
+
def to_java
|
165
|
+
JavaDatastore::PostalAddress.new(self.to_java_string)
|
166
|
+
end
|
167
|
+
|
168
|
+
def self.new_from_java(address)
|
169
|
+
self.new(address.getAddress)
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
Rating = JavaDatastore::Rating
|
174
|
+
|
175
|
+
# A user-provided integer rating for a piece of content. Normalized to a
|
176
|
+
# 0-100 scale.
|
177
|
+
class Rating
|
178
|
+
# Raises ArgumentError if rating < 0 or rating > 100.
|
179
|
+
def self.new(rating)
|
180
|
+
if rating < MIN_VALUE || rating > MAX_VALUE
|
181
|
+
raise ArgumentError, "rating must be no smaller than #{MIN_VALUE} " +
|
182
|
+
"and no greater than #{MAX_VALUE} (received #{rating})"
|
183
|
+
end
|
184
|
+
super(rating)
|
185
|
+
end
|
186
|
+
|
187
|
+
alias to_i rating
|
188
|
+
|
189
|
+
def to_s
|
190
|
+
rating.to_s
|
191
|
+
end
|
192
|
+
|
193
|
+
def inspect
|
194
|
+
"#<Rating #{rating}>"
|
195
|
+
end
|
196
|
+
|
197
|
+
if false
|
198
|
+
MIN_VALUE = 0
|
199
|
+
MAX_VALUE = 100
|
200
|
+
def rating; end
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
IMHandle = JavaDatastore::IMHandle
|
205
|
+
|
206
|
+
# An instant messaging handle. Includes both an address and its protocol.
|
207
|
+
# The protocol value is either a standard IM scheme (legal scheme values are
|
208
|
+
# :sip, :xmpp, :unknown or a URL identifying the IM network for the
|
209
|
+
# protocol (eg http://aim.com/).
|
210
|
+
class IMHandle
|
211
|
+
SCHEMES = {
|
212
|
+
:sip => Scheme.sip,
|
213
|
+
:xmpp => Scheme.xmpp,
|
214
|
+
:unknown => Scheme.unknown
|
215
|
+
}.freeze
|
216
|
+
|
217
|
+
def self.new(protocol, address)
|
218
|
+
begin
|
219
|
+
protocol = SCHEMES[protocol] || java.net.URL.new(protocol)
|
220
|
+
rescue java.net.MalformedURLException => ex
|
221
|
+
raise ArgumentError, ex.message
|
222
|
+
end
|
223
|
+
super
|
224
|
+
end
|
225
|
+
|
226
|
+
if false
|
227
|
+
def protocol; end
|
228
|
+
def address; end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
GeoPt = JavaDatastore::GeoPt
|
233
|
+
|
234
|
+
# A geographical point, specified by float latitude and longitude
|
235
|
+
# coordinates. Often used to integrate with mapping sites like Google Maps.
|
236
|
+
class GeoPt
|
237
|
+
def self.new(latitude, longitude)
|
238
|
+
super
|
239
|
+
rescue java.lang.IllegalArgumentException => ex
|
240
|
+
raise ArgumentError, ex.message
|
241
|
+
end
|
242
|
+
|
243
|
+
if false
|
244
|
+
def latitude; end
|
245
|
+
def longitude; end
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
120
249
|
Key = JavaDatastore::Key
|
121
250
|
|
122
251
|
# The primary key for a datastore entity.
|
@@ -219,6 +348,39 @@ module AppEngine
|
|
219
348
|
end
|
220
349
|
end
|
221
350
|
|
351
|
+
KeyRange = JavaDatastore::KeyRange
|
352
|
+
|
353
|
+
# Represents a range of unique datastore identifiers from
|
354
|
+
# start.id to end.id inclusive. The Keys returned by an
|
355
|
+
# instance of this class have been consumed in the datastore's
|
356
|
+
# id-space and are guaranteed never to be reused.
|
357
|
+
#
|
358
|
+
# This class can be used to construct Entity Entities with
|
359
|
+
# Keys that have specific id values without fear of the datastore
|
360
|
+
# creating new records with those same ids at a later date. This can be
|
361
|
+
# helpful as part of a data migration or large bulk upload where you may
|
362
|
+
# need to preserve existing ids and relationships between entities.
|
363
|
+
class KeyRange
|
364
|
+
include Enumerable
|
365
|
+
|
366
|
+
if false
|
367
|
+
# The first Key in the range.
|
368
|
+
def start; end;
|
369
|
+
|
370
|
+
# The last Key in the range.
|
371
|
+
def end; end;
|
372
|
+
|
373
|
+
# The size of the range.
|
374
|
+
def size; end;
|
375
|
+
end
|
376
|
+
|
377
|
+
def each
|
378
|
+
iterator.each do |key|
|
379
|
+
yield key
|
380
|
+
end
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
222
384
|
Entity = JavaDatastore::Entity
|
223
385
|
|
224
386
|
# Entity is the fundamental unit of data storage. It has an
|
@@ -237,12 +399,36 @@ module AppEngine
|
|
237
399
|
JavaDatastore::Blob => Blob,
|
238
400
|
JavaDatastore::ShortBlob => ByteString,
|
239
401
|
JavaDatastore::Link => Link,
|
402
|
+
JavaDatastore::Email => Email,
|
403
|
+
JavaDatastore::Category => Category,
|
404
|
+
JavaDatastore::PhoneNumber => PhoneNumber,
|
405
|
+
JavaDatastore::PostalAddress => PostalAddress,
|
240
406
|
java.util.Date => Time,
|
241
407
|
}.freeze
|
242
408
|
|
243
409
|
alias :inspect :to_string
|
244
410
|
alias :== :equals?
|
245
411
|
|
412
|
+
if false
|
413
|
+
# Create a new Entity with the specified kind and parent Entity. The
|
414
|
+
# instantiated Entity will have anincomplete Key when this constructor
|
415
|
+
# returns. The Key will remain incomplete until you put the Entity,
|
416
|
+
# after which time the Key will have its id set.
|
417
|
+
def initialize(kind, parent=nil); end
|
418
|
+
|
419
|
+
# Create a new Entity with the specified kind, key name, and parent
|
420
|
+
# Entity. The instantiated Entity will have a complete Key when this
|
421
|
+
# constructor returns. The Key's name field will be set to the value of
|
422
|
+
# key_name.
|
423
|
+
def initialize(kind, key_name, parent=nil); end
|
424
|
+
|
425
|
+
# Create a new Entity uniquely identified by the provided Key.
|
426
|
+
# Creating an entity for the purpose of insertion (as opposed
|
427
|
+
# to update) with a key that has its id field set is strongly
|
428
|
+
# discouraged unless the key was returned by a KeyRange.
|
429
|
+
def initialize(key); end
|
430
|
+
end
|
431
|
+
|
246
432
|
# Returns the property with the specified name.
|
247
433
|
def get_property(name)
|
248
434
|
name = name.to_s if name.kind_of? Symbol
|
@@ -333,8 +519,9 @@ module AppEngine
|
|
333
519
|
end
|
334
520
|
end
|
335
521
|
|
336
|
-
SPECIAL_RUBY_TYPES = [Time, Text, Blob, ByteString, Link
|
337
|
-
|
522
|
+
SPECIAL_RUBY_TYPES = [Time, Text, Blob, ByteString, Link, Email,
|
523
|
+
Category, PhoneNumber, PostalAddress].freeze
|
524
|
+
|
338
525
|
def Datastore.ruby_to_java(value) # :nodoc:
|
339
526
|
if SPECIAL_RUBY_TYPES.include? value.class
|
340
527
|
value.to_java
|
@@ -357,6 +544,8 @@ module AppEngine
|
|
357
544
|
yield
|
358
545
|
rescue java.lang.IllegalArgumentException => ex
|
359
546
|
raise ArgumentError, ex.message
|
547
|
+
rescue java.lang.NullPointerException => ex
|
548
|
+
raise ArgumentError, ex.message
|
360
549
|
rescue java.util.ConcurrentModificationException => ex
|
361
550
|
raise TransactionFailed, ex.message
|
362
551
|
rescue java.util.NoSuchElementException => ex
|
@@ -368,7 +557,7 @@ module AppEngine
|
|
368
557
|
rescue JavaDatastore::DatastoreFailureException => ex
|
369
558
|
raise InternalError, ex.message
|
370
559
|
rescue JavaDatastore::EntityNotFoundException => ex
|
371
|
-
raise
|
560
|
+
raise EntityNotFound, ex.message
|
372
561
|
rescue JavaDatastore::PreparedQuery::TooManyResultsException => ex
|
373
562
|
raise TooManyResults, ex.message
|
374
563
|
end
|
@@ -0,0 +1,266 @@
|
|
1
|
+
#!/usr/bin/ruby1.8 -w
|
2
|
+
#
|
3
|
+
# Copyright:: Copyright 2009 Google Inc.
|
4
|
+
# Original Author:: Ryan Brown (mailto:ribrdb@google.com)
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
# Task Queue API.
|
19
|
+
#
|
20
|
+
# Enables an application to queue background work for itself. Work is done
|
21
|
+
# through webhooks that process tasks pushed from a queue. Tasks will execute in
|
22
|
+
# best-effort order of ETA. Webhooks that fail will cause tasks to be retried at
|
23
|
+
# a later time. Multiple queues may exist with independent throttling controls.
|
24
|
+
#
|
25
|
+
# Webhook URLs may be specified directly for Tasks, or the default URL scheme
|
26
|
+
# may be used, which will translate Task names into URLs relative to a Queue's
|
27
|
+
# base path. A default queue is also provided for simple usage.
|
28
|
+
|
29
|
+
require 'appengine-apis/datastore_types'
|
30
|
+
|
31
|
+
module AppEngine
|
32
|
+
module Labs
|
33
|
+
module TaskQueue
|
34
|
+
import com.google.appengine.api.labs.taskqueue.QueueFactory
|
35
|
+
import com.google.appengine.api.labs.taskqueue.TaskOptions
|
36
|
+
|
37
|
+
import com.google.appengine.api.labs.taskqueue.TaskAlreadyExistsException
|
38
|
+
import com.google.appengine.api.labs.taskqueue.TransientFailureException
|
39
|
+
import com.google.appengine.api.labs.taskqueue.InternalFailureException
|
40
|
+
import com.google.appengine.api.labs.taskqueue.TaskAlreadyExistsException
|
41
|
+
import com.google.appengine.api.labs.taskqueue.UnsupportedTranslationException
|
42
|
+
|
43
|
+
class TaskAlreadyExistsError < StandardError; end
|
44
|
+
class TransientFailureError < StandardError; end
|
45
|
+
class InternalError < StandardError; end
|
46
|
+
|
47
|
+
Blob = AppEngine::Datastore::Blob
|
48
|
+
|
49
|
+
# Represents a single Task on a queue.
|
50
|
+
class Task
|
51
|
+
|
52
|
+
# Initializer.
|
53
|
+
#
|
54
|
+
# All parameters are optional.
|
55
|
+
#
|
56
|
+
# Options:
|
57
|
+
# [:payload] The payload data for this Task that will be delivered to
|
58
|
+
# the webhook as the HTTP request body. This is only allowed for
|
59
|
+
# POST and PUT methods. Assumed to be UTF-8 unless it is a Blob.
|
60
|
+
# [:bytes] Binary payload data for this Task.
|
61
|
+
# [:countdown]: Time in seconds into the future that this Task should
|
62
|
+
# execute. Defaults to zero.
|
63
|
+
# [:eta] Absolute time when the Task should execute. Must be a Time
|
64
|
+
# object. May not be specified if 'countdown' is also supplied.
|
65
|
+
# [:headers] Hash of headers to pass to the webhook. Values in the
|
66
|
+
# hash may be enumerable to indicate repeated header fields.
|
67
|
+
# [:method]: HTTP method to use when accessing the webhook. Defaults
|
68
|
+
# to 'POST'.
|
69
|
+
# [:name] Name to give the Task; if not specified, a name will be
|
70
|
+
# auto-generated when added to a queue and assigned to this object.
|
71
|
+
# [:params]: Hash of parameters to use for this Task.
|
72
|
+
# For POST requests these params will be encoded as
|
73
|
+
# 'application/x-www-form-urlencoded' and set to the payload.
|
74
|
+
# For all other methods, the parameters will be converted to a
|
75
|
+
# query string. May not be specified if the URL already
|
76
|
+
# contains a query string.
|
77
|
+
# [:url] Relative URL where the webhook that should handle this task is
|
78
|
+
# located for this application. May have a query string unless
|
79
|
+
# this is a POST method.
|
80
|
+
#
|
81
|
+
# Raises:
|
82
|
+
# InvalidTaskError if any of the parameters are invalid;
|
83
|
+
# InvalidTaskNameError if the task name is invalid; InvalidUrlError if
|
84
|
+
# the task URL is invalid or too long; TaskTooLargeError if the task with
|
85
|
+
# its payload is too large.
|
86
|
+
def initialize(payload=nil, options={})
|
87
|
+
if payload.kind_of? Hash
|
88
|
+
options, payload = payload, nil
|
89
|
+
elsif payload.kind_of? TaskOptions
|
90
|
+
@task_options = payload
|
91
|
+
return
|
92
|
+
end
|
93
|
+
options = options.dup
|
94
|
+
if payload.kind_of? Blob
|
95
|
+
options[:bytes] = payload
|
96
|
+
elsif payload
|
97
|
+
options[:payload] = payload
|
98
|
+
end
|
99
|
+
@task_options = convert_options(options)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Returns whether this Task has been enqueued.
|
103
|
+
#
|
104
|
+
# Note: This will not check if this Task already exists in the queue.
|
105
|
+
def enqueued?
|
106
|
+
!!@handle
|
107
|
+
end
|
108
|
+
|
109
|
+
# Adds this Task to a queue
|
110
|
+
#
|
111
|
+
# Args:
|
112
|
+
# - queue: Name of the queue where this Task should be added. (optional)
|
113
|
+
#
|
114
|
+
def add(queue=nil)
|
115
|
+
queue = Queue.new(queue) unless Queue.kind_of? Queue
|
116
|
+
@handle = queue.java_queue.add(_task)
|
117
|
+
self
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns the Time when this Task will execute.
|
121
|
+
def eta
|
122
|
+
Time.at(@handle.eta_millis / 1000.0) if @handle
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns the name of this Task.
|
126
|
+
#
|
127
|
+
# Will be nil if using an auto-assigned Task name and this Task has
|
128
|
+
# not yet been added to a Queue.
|
129
|
+
def name
|
130
|
+
@handle.name if @handle
|
131
|
+
end
|
132
|
+
|
133
|
+
# Returns the name of the Queue where this Task was enqueued.
|
134
|
+
def queue
|
135
|
+
@handle.queue_name if @handle
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def convert_options(options)
|
140
|
+
TaskQueue.convert_exceptions do
|
141
|
+
task = TaskOptions::Builder.with_defaults
|
142
|
+
if bytes = options.delete(:bytes)
|
143
|
+
task.payload(bytes.to_java_bytes, 'application/octet-stream')
|
144
|
+
end
|
145
|
+
if payload = options.delete(:payload)
|
146
|
+
task.payload(payload)
|
147
|
+
end
|
148
|
+
if countdown = options.delete(:countdown)
|
149
|
+
millis = (countdown * 1000).round
|
150
|
+
task.countdown_millis(millis)
|
151
|
+
end
|
152
|
+
if @eta = options.delete(:eta)
|
153
|
+
millis = @eta.tv_sec * 1000 + @eta.tv_usec / 1000.0
|
154
|
+
task.eta_millis(millis)
|
155
|
+
end
|
156
|
+
if headers = options.delete(:headers)
|
157
|
+
headers.each do |key, value|
|
158
|
+
if value.kind_of? Array
|
159
|
+
value = value.join(",")
|
160
|
+
end
|
161
|
+
task.header(key, value)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
if method = options.delete(:method)
|
165
|
+
method = TaskOptions::Method.value_of(method.to_s.upcase)
|
166
|
+
task.method(method)
|
167
|
+
end
|
168
|
+
if name = options.delete(:name)
|
169
|
+
task.task_name(name)
|
170
|
+
end
|
171
|
+
if params = options.delete(:params)
|
172
|
+
params.each do |name, param|
|
173
|
+
if param.kind_of? Blob
|
174
|
+
param = param.to_java_bytes
|
175
|
+
end
|
176
|
+
task.param(name, param)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
if url = options.delete(:url)
|
180
|
+
task.url(url)
|
181
|
+
end
|
182
|
+
task
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def _task
|
187
|
+
@task_options
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
# Represents a Queue.
|
193
|
+
class Queue
|
194
|
+
@queues = {}
|
195
|
+
|
196
|
+
# Returns the named Queue, or the default queue if name is nil.
|
197
|
+
#
|
198
|
+
# The returned Queue object may not necessarily refer
|
199
|
+
# to an existing queue. Queues must be configured before
|
200
|
+
# they may be used. Attempting to use a non-existing queue name
|
201
|
+
# may result in errors at the point of use of the Queue object,
|
202
|
+
# not when creating it.
|
203
|
+
def initialize(name=nil)
|
204
|
+
TaskQueue.convert_exceptions do
|
205
|
+
if name.nil?
|
206
|
+
@queue = QueueFactory.default_queue
|
207
|
+
else
|
208
|
+
@queue = QueueFactory.get_queue(name)
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
def self.new(name=nil)
|
214
|
+
@queues[name] ||= super
|
215
|
+
end
|
216
|
+
|
217
|
+
# Submits a task to this queue.
|
218
|
+
def add(task=nil)
|
219
|
+
if task.nil?
|
220
|
+
Task.new.add(self)
|
221
|
+
elsif task.java_kind_of? TaskOptions
|
222
|
+
Task.new(task).add(self)
|
223
|
+
else
|
224
|
+
task.add(self)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Returns the name of this queue.
|
229
|
+
def name
|
230
|
+
@queue.queue_name
|
231
|
+
end
|
232
|
+
|
233
|
+
def java_queue
|
234
|
+
@queue
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
# Convenience method will create a Task and add it to the default queue.
|
239
|
+
#
|
240
|
+
# Args:
|
241
|
+
# - args: Passed to the Task constructor.
|
242
|
+
#
|
243
|
+
# Returns:
|
244
|
+
# - The Task that was added to the queue.
|
245
|
+
def self.add(*args)
|
246
|
+
Task.new(*args).add
|
247
|
+
end
|
248
|
+
|
249
|
+
def self.convert_exceptions
|
250
|
+
begin
|
251
|
+
yield
|
252
|
+
rescue java.lang.IllegalArgumentException => ex
|
253
|
+
raise ArgumentError, ex.message
|
254
|
+
rescue UnsupportedTranslationException => ex
|
255
|
+
raise ArgumentError, ex.message
|
256
|
+
rescue TaskAlreadyExistsException => ex
|
257
|
+
raise TaskAlreadExistsError, ex.message
|
258
|
+
rescue InternalFailureException => ex
|
259
|
+
raise InternalError, ex.message
|
260
|
+
rescue TransientFailureException => ex
|
261
|
+
raise TransientFailureError, ex.message
|
262
|
+
end
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
end
|