rave 0.1.2-java

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,79 @@
1
+ require 'singleton'
2
+ require 'yaml'
3
+
4
+ module Rave
5
+ module Models
6
+ # Contains Robot data, event handlers and cron jobs.
7
+ class Robot < User
8
+ include Rave::Mixins::DataFormat
9
+ include Rave::Mixins::Controller
10
+ include Singleton
11
+
12
+ CONFIG_FILE = 'config.yaml' # :nodoc:
13
+
14
+ # Version of the robot, as in the yaml config [String]
15
+ def version # :nodoc:
16
+ @version.dup
17
+ end
18
+
19
+ def initialize() # :nodoc:
20
+ config = config_from_file
21
+ super(config)
22
+ @handlers = {}
23
+ @cron_jobs = []
24
+ @version = config[:version] || '1'
25
+ register_default_handlers
26
+ end
27
+
28
+ # Read options from user-edited yaml config file.
29
+ def config_from_file # :nodoc:
30
+ config = YAML::load(File.open(CONFIG_FILE))
31
+ hash = {}
32
+ config['robot'].each_pair { |k, v| hash[k.to_sym] = v }
33
+ hash
34
+ end
35
+
36
+ # Register a handler. Multiple handlers may be applied to a single event.
37
+ # +event_type+:: Must be one of Rave::Models::Event::*::TYPE [String]
38
+ def register_handler(event_type, handler)
39
+ raise Rave::InvalidEventException.new("Unknown event: #{event_type}") unless Rave::Models::Event.valid_type?(event_type)
40
+ raise Rave::InvalidHandlerException.new("Unknown handler: #{handler}") unless self.respond_to?(handler)
41
+ @handlers[event_type] ||= []
42
+ @handlers[event_type] << handler unless @handlers[event_type].include?(handler)
43
+ end
44
+
45
+ #Dispatches events to the appropriate handler
46
+ def handle_event(event, context) # :nodoc:
47
+ #Ignore unhandled events
48
+ if (handlers = @handlers[event.type])
49
+ handlers.each do |handler|
50
+ self.send(handler, event, context)
51
+ end
52
+ end
53
+ end
54
+
55
+ #Registers a cron job
56
+ def register_cron_job(handler, seconds)
57
+ @cron_jobs << { :path => "/_wave/cron/#{handler}", :handler => handler, :seconds => seconds }
58
+ end
59
+
60
+ # Creates a new wave with initial participants set.
61
+ # +participants+:: Humans and/or robots to start in the new wave [Array of String/User]
62
+ # Returns: The new wave, which contains a root wavelet which itself contains a root blip [Wave]
63
+ def create_wavelet(participants)
64
+ @context.create_wavelet(participants)
65
+ end
66
+
67
+ protected
68
+ #Register any handlers that are defined through naming convention
69
+ def register_default_handlers # :nodoc:
70
+ Event.types.each do |type|
71
+ listener = type.downcase.to_sym
72
+ if respond_to?(listener)
73
+ register_handler(type, listener)
74
+ end
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,62 @@
1
+ module Rave
2
+ module Models
3
+ # A wave client, acting as a wave creator, blip contributor and/or a wavelet participant.
4
+ class User < Component
5
+ ROBOT_PATTERN = /@appspot\.com$/ # :nodoc:
6
+ NOBODY_ID = "@@@nobody@@@" # :nodoc: Used as a default in certain circumstances.
7
+
8
+ # Url link to the profile of the User [String].
9
+ # NOTE: Due to a limitation in Wave, for all users except the local robot
10
+ # the url will be empty.
11
+ def profile_url # :nodoc:
12
+ @profile_url.dup
13
+ end
14
+
15
+ # Url link to the image of the User [String].
16
+ # NOTE: Due to a limitation in Wave, for all users except the local robot
17
+ # the url will be empty.
18
+ def image_url # :nodoc:
19
+ @image_url.dup
20
+ end
21
+
22
+ # Unlike other components, Users are never generated [Boolean].
23
+ def generated? # :nodoc:
24
+ false
25
+ end
26
+
27
+ # - :id
28
+ # - :name
29
+ # - :profile_url
30
+ # - :image_url
31
+ # - :context
32
+ def initialize(options = {}) # :nodoc:
33
+ options[:id].downcase! if options[:id]
34
+ super(options)
35
+ @name = options[:name]
36
+ @profile_url = options[:profile_url] || ''
37
+ @image_url = options[:image_url] || ''
38
+ end
39
+
40
+ # Printable name of the User [String].
41
+ # NOTE: Due to a limitation in Wave, for all users except the local robot
42
+ # the name is the same as the @id.
43
+ def name # :nodoc:
44
+ @name || @id
45
+ end
46
+
47
+ # Is the User a robot client rather than a human client? [Boolean]
48
+ def robot? # :nodoc:
49
+ not (@id =~ ROBOT_PATTERN).nil?
50
+ end
51
+
52
+ # Convert to string [String]
53
+ def to_s
54
+ @id
55
+ end
56
+
57
+ def to_json # :nodoc:
58
+ @id.to_json
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,45 @@
1
+ module Rave
2
+ module Models
3
+ # Represents a Wave
4
+ class Wave < Component
5
+ # IDs for all wavelets that are part of the wave [Array of String]
6
+ def wavelet_ids # :nodoc:
7
+ @wavelet_ids.map { |id| id.dup }
8
+ end
9
+
10
+ #Options include:
11
+ # - :wavelet_ids
12
+ # - :id
13
+ def initialize(options = {}) # :nodoc:
14
+ if options[:id].nil? and options[:context]
15
+ super(:id => "#{GENERATED_PREFIX}_wave_#{unique_id}", :context => options[:context])
16
+ else
17
+ super(options)
18
+ end
19
+
20
+ @wavelet_ids = options[:wavelet_ids] || []
21
+ end
22
+
23
+ # All wavelets that are part of the wave [Array of Wavelet]
24
+ def wavelets # :nodoc:
25
+ @wavelet_ids.map { |id| @context.wavelets[id] }
26
+ end
27
+
28
+ # The root wavelet (it will be nil if the event refers to a private subwavelet) [Wavelet]
29
+ def root_wavelet # :nodoc:
30
+ wavelets.find { |wavelet| wavelet and wavelet.root? }
31
+ end
32
+
33
+ def print_structure(indent = 0) # :nodoc:
34
+ str = ''
35
+ str << "#{' ' * indent}Wave:#{@id}\n"
36
+
37
+ wavelets.each do |wavelet|
38
+ str << wavelet.print_structure(indent + 1)
39
+ end
40
+
41
+ str
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,269 @@
1
+ module Rave
2
+ module Models
3
+ # Represents a Wavelet, owned by a Wave
4
+ class Wavelet < Component
5
+ include Rave::Mixins::TimeUtils
6
+ include Rave::Mixins::Logger
7
+
8
+ # Creator of the wavelet if it was generated via an operation.
9
+ GENERATED_CREATOR = "rusty@a.gwave.com" # :nodoc:
10
+
11
+ # Current version number of the wavelet [Integer]
12
+ attr_reader :version
13
+
14
+ # ID of the creator [String]
15
+ def creator_id # :nodoc:
16
+ @creator_id.dup
17
+ end
18
+
19
+ # Time the wavelet was created [Time]
20
+ def creation_time # :nodoc:
21
+ @creation_time.dup
22
+ end
23
+
24
+ # Documents contained within the wavelet [Array of Document]
25
+ def data_documents # :nodoc:
26
+ @data_documents.dup
27
+ end
28
+
29
+ # The last time the wavelet was modified [Time]
30
+ def last_modified_time # :nodoc:
31
+ @last_modified_time.dup
32
+ end
33
+
34
+ # ID for the root blip [String]
35
+ def root_blip_id # :nodoc:
36
+ @root_blip_id.dup
37
+ end
38
+
39
+ # Wavelet title [String]
40
+ def title # :nodoc:
41
+ @title.dup
42
+ end
43
+
44
+ # ID of the wave that the wavelet is a part of [String]
45
+ def wave_id # :nodoc:
46
+ @wave_id.dup
47
+ end
48
+
49
+ # IDs of all those who are currently members of the wavelet [Array of String]
50
+ def participant_ids # :nodoc:
51
+ @participant_ids.map { |id| id.dup }
52
+ end
53
+
54
+ JAVA_CLASS = 'com.google.wave.api.impl.WaveletData'
55
+ ROOT_ID_SUFFIX = "conv+root" #The suffix for the root wavelet in a wave]
56
+ ROOT_ID_REGEXP = /#{Regexp.escape(ROOT_ID_SUFFIX)}$/
57
+
58
+ #
59
+ # Options include:
60
+ # - :creator
61
+ # - :creation_time
62
+ # - :data_documents
63
+ # - :last_modifed_time
64
+ # - :participants
65
+ # - :root_blip_id
66
+ # - :title
67
+ # - :version
68
+ # - :wave_id
69
+ # - :context
70
+ # - :id
71
+ def initialize(options = {}) # :nodoc:
72
+ @participant_ids = options[:participants] || []
73
+
74
+ if options[:id].nil? and options[:context]
75
+ # Generate the wavelet from scratch.
76
+ super(:id => "#{GENERATED_PREFIX}_wavelet_#{unique_id}_#{ROOT_ID_SUFFIX}", :context => options[:context])
77
+
78
+ # Create a wave to live in.
79
+ wave = Wave.new(:wavelet_ids => [@id], :context => @context)
80
+ @wave_id = wave.id
81
+ @context.add_wave(wave)
82
+
83
+ # Ensure the newly created wavelet has a root blip.
84
+ blip = Blip.new(:wave_id => wave.id, :wavelet_id => @id,
85
+ :creator => @context.robot.id, :contributors => [@context.robot.id])
86
+ @context.add_blip(blip)
87
+ @root_blip_id = blip.id
88
+
89
+ @participant_ids.each do |id|
90
+ @context.add_user(:id => id) unless @context.users[id]
91
+ end
92
+
93
+ @creator_id = GENERATED_CREATOR
94
+ @context.add_user(:id => @creator_id) unless @context.users[@creator_id]
95
+ else
96
+ super(options)
97
+ @root_blip_id = options[:root_blip_id]
98
+ @creator_id = options[:creator] || User::NOBODY_ID
99
+ @wave_id = options[:wave_id]
100
+ end
101
+
102
+ @creation_time = time_from_json(options[:creation_time]) || Time.now
103
+ @data_documents = options[:data_documents] || {}
104
+ @last_modified_time = time_from_json(options[:last_modified_time]) || Time.now
105
+ @title = options[:title] || ''
106
+ @version = options[:version] || 0
107
+ end
108
+
109
+ # Users that are currently have access the wavelet [Array of User]
110
+ def participants # :nodoc:
111
+ @participant_ids.map { |p| @context.users[p] }
112
+ end
113
+
114
+ # Users that originally created the wavelet [User]
115
+ def creator # :nodoc:
116
+ @context.users[@creator_id]
117
+ end
118
+
119
+ # Is this the root wavelet for its wave? [Boolean]
120
+ def root? # :nodoc:
121
+ not (id =~ ROOT_ID_REGEXP).nil?
122
+ end
123
+
124
+ #Creates a blip for this wavelet
125
+ # Returns: Gererated blip [Blip]
126
+ def create_blip
127
+ parent = final_blip
128
+ blip = Blip.new(:wave_id => @wave_id, :parent_blip_id => parent.id,
129
+ :wavelet_id => @id, :context => @context)
130
+ parent.add_child_blip(blip)
131
+
132
+ @context.add_operation(:type => Operation::WAVELET_APPEND_BLIP, :wave_id => @wave_id, :wavelet_id => @id, :property => blip)
133
+ blip
134
+ end
135
+
136
+ # Find the last blip in the main thread [Blip]
137
+ def final_blip # :nodoc:
138
+ blip = @context.blips[@root_blip_id]
139
+ if blip
140
+ while blip
141
+ # Find the first blip that is defined, if at all.
142
+ child_blip = blip.child_blips.find { |b| not b.nil? }
143
+ break unless child_blip
144
+ blip = child_blip
145
+ end
146
+ end
147
+ blip
148
+ end
149
+
150
+ # Adds a participant (human or robot) to the wavelet
151
+ # +user+:: User to add, as ID or object [String or User]
152
+ # Returns: The user that was added [User or nil]
153
+ def add_participant(user) # :nodoc:
154
+ id = user.to_s.downcase
155
+ if @participant_ids.include?(id)
156
+ logger.warning("Attempted to add a participant who was already in the wavelet(#{@id}): #{id}")
157
+ return nil
158
+ end
159
+
160
+ # Allow string names to be used as participant.
161
+ user = if @context.users[id]
162
+ @context.users[id]
163
+ else
164
+ @context.add_user(:id => id)
165
+ end
166
+
167
+ @context.add_operation(:type => Operation::WAVELET_ADD_PARTICIPANT,
168
+ :wave_id => @wave_id, :wavelet_id => @id, :property => user)
169
+ @participant_ids << id
170
+
171
+ user
172
+ end
173
+
174
+ # Removes a participant (robot only) from the wavelet.
175
+ # +user+:: User to remove, as ID or object [String or User]
176
+ # Returns: The user that was removed [User or nil]
177
+ def remove_participant(user) # :nodoc:
178
+ id = user.to_s.downcase
179
+ unless @participant_ids.include?(id)
180
+ logger.warning("Attempted to remove a participant who was not in the wavelet(#{@id}): #{id}")
181
+ return nil
182
+ end
183
+
184
+ # Allow string names to be used as participant.
185
+ user = @context.users[id]
186
+
187
+ unless user.robot?
188
+ logger.warning("Attempted to remove a non-robot from wavelet(#{@id}): #{id}")
189
+ return nil
190
+ end
191
+
192
+ if user == @context.robot
193
+ return remove_robot
194
+ end
195
+
196
+ @context.add_operation(:type => Operation::WAVELET_REMOVE_PARTICIPANT,
197
+ :wave_id => @wave_id, :wavelet_id => @id, :property => user)
198
+ @participant_ids.delete id
199
+
200
+ user
201
+ end
202
+
203
+ # Removes the local robot from the wavelet.
204
+ # Returns: The local robot [Robot]
205
+ def remove_robot
206
+ robot = @context.robot
207
+ @context.add_operation(:type => Operation::WAVELET_REMOVE_SELF,
208
+ :wave_id => @wave_id, :wavelet_id => @id)
209
+ @participant_ids.delete robot.id
210
+
211
+ robot
212
+ end
213
+
214
+ #Sets the data document for the wavelet
215
+ #
216
+ # NOT IMPLEMENTED
217
+ def set_data_document(name, data)
218
+ raise NotImplementedError
219
+ end
220
+
221
+ #Set the title
222
+ #
223
+ def title=(title) # :nodoc: Documented by title() as accessor.
224
+ title = title.to_s
225
+ @context.add_operation(:type => Operation::WAVELET_SET_TITLE,
226
+ :wave_id => @wave_id, :wavelet_id => @id, :property => title)
227
+ @title = title
228
+ end
229
+
230
+ # First blip in the wavelet [Blip]
231
+ def root_blip # :nodoc:
232
+ @context.blips[@root_blip_id]
233
+ end
234
+
235
+ # Wave that the wavelet is contained within.
236
+ def wave# :nodoc:
237
+ @context.waves[@wave_id]
238
+ end
239
+
240
+ # *INTERNAL*
241
+ # Convert to json for sending in an operation.
242
+ def to_json # :nodoc:
243
+ {
244
+ 'waveletId' => @id,
245
+ 'javaClass' => JAVA_CLASS,
246
+ 'waveId' => @wave_id,
247
+ 'rootBlipId' => @root_blip_id,
248
+ 'participants' => { "javaClass" => "java.util.ArrayList", "list" => @participant_ids }
249
+ }.to_json
250
+ end
251
+
252
+ # Convert to string.
253
+ def to_s
254
+ text = @title.length > 24 ? "#{@title[0..20]}..." : @title
255
+ "#{super}:#{participants.join(',')}:#{text}"
256
+ end
257
+
258
+ def print_structure(indent = 0) # :nodoc:
259
+ str = "#{' ' * indent}#{to_s}\n"
260
+
261
+ if root_blip
262
+ str << root_blip.print_structure(indent + 1)
263
+ end
264
+
265
+ str
266
+ end
267
+ end
268
+ end
269
+ end