appengine-apis 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|