rforce-raygao 1.0.0

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.
Files changed (50) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/History.txt +29 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +18 -0
  6. data/Rakefile +53 -0
  7. data/VERSION +1 -0
  8. data/bugs/issue-09d998dc3f9d6e8928598fd5d9c6627102dedd65.yaml +18 -0
  9. data/bugs/issue-1b668248120eb4fd055f0ea6b75ff807f6955936.yaml +22 -0
  10. data/bugs/issue-3ef7a7c5c7e38fb76e1f53e1b67f45559e21b104.yaml +18 -0
  11. data/bugs/issue-a7a87cb98d29943a49d1608adb68475838ad2e65.yaml +22 -0
  12. data/bugs/issue-c92d34e10038ba6b9acfd7e3dfb2b154e463baba.yaml +29 -0
  13. data/bugs/project.yaml +16 -0
  14. data/lib/rforce-raygao.rb +3 -0
  15. data/lib/rforce.rb +87 -0
  16. data/lib/rforce/binding.rb +255 -0
  17. data/lib/rforce/binding.rb.zip +0 -0
  18. data/lib/rforce/method_keys.rb +14 -0
  19. data/lib/rforce/soap_pullable.rb +93 -0
  20. data/lib/rforce/soap_response.rb +12 -0
  21. data/lib/rforce/soap_response_expat.rb +35 -0
  22. data/lib/rforce/soap_response_hpricot.rb +75 -0
  23. data/lib/rforce/soap_response_rexml.rb +34 -0
  24. data/lib/rforce/version.rb +3 -0
  25. data/rforce-raygao.gemspec +95 -0
  26. data/spec/rforce_spec.rb +105 -0
  27. data/spec/soap-response.xml +5928 -0
  28. data/spec/spec.opts +1 -0
  29. data/spec/spec_helper.rb +66 -0
  30. data/tasks/timing.rake +21 -0
  31. data/test/helper.rb +10 -0
  32. data/test/test_rforce-raygao.rb +31 -0
  33. data/wsdl/README.html +23 -0
  34. data/wsdl/README.txt +22 -0
  35. data/wsdl/ca.pem +36 -0
  36. data/wsdl/default.rb +1627 -0
  37. data/wsdl/defaultDriver.rb +179 -0
  38. data/wsdl/orderedhash.rb +254 -0
  39. data/wsdl/partner.wsdl.xml +1858 -0
  40. data/wsdl/sample/create.rb +37 -0
  41. data/wsdl/sample/describeGlobal.rb +28 -0
  42. data/wsdl/sample/describeSObjects.rb +34 -0
  43. data/wsdl/sample/getServerTimestamp.rb +27 -0
  44. data/wsdl/sample/query.rb +31 -0
  45. data/wsdl/sample/queryMore.rb +32 -0
  46. data/wsdl/sample/retrieve.rb +32 -0
  47. data/wsdl/sforceDriver.rb +43 -0
  48. data/wsdl/soap/property +1 -0
  49. data/wsdl/wsdl.rb +121 -0
  50. metadata +134 -0
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
@@ -0,0 +1,22 @@
1
+ ## MAC OS
2
+ .DS_Store
3
+
4
+ ## TEXTMATE
5
+ *.tmproj
6
+ tmtags
7
+
8
+ ## EMACS
9
+ *~
10
+ \#*
11
+ .\#*
12
+
13
+ ## VIM
14
+ *.swp
15
+
16
+ ## PROJECT::GENERAL
17
+ nbproject
18
+ coverage
19
+ rdoc
20
+ pkg
21
+
22
+ ## PROJECT::SPECIFIC
@@ -0,0 +1,29 @@
1
+ == 0.4 2010-01-21
2
+
3
+ * 1 minor enhancement:
4
+ * Fixed bug in search for XML libraries
5
+
6
+ == 0.4 2010-01-21
7
+
8
+ * 1 minor enhancement:
9
+ * Moved RubyGems dependencies into the gemspec where they belong
10
+
11
+ == 0.3 2009-04-16
12
+
13
+ * 1 minor enhancement:
14
+ * Updated for Ruby 1.9
15
+
16
+ == 0.2.1 2008-07-04
17
+
18
+ * 1 minor enhancement:
19
+ * Updated examples for SalesForce API v10
20
+
21
+ == 0.2.0 2008-07-03
22
+
23
+ * 1 major enhancement:
24
+ * Incorporated fixes from ActiveSalesforce project
25
+
26
+ == 0.1.0 2005-09-02
27
+
28
+ * 1 major enhancement:
29
+ * Initial release
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Raymond Gao
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,18 @@
1
+ = rforce-raygao
2
+
3
+ This is a temporary patch of the RForce 0.4.1, increased the DEFAULT_BATCH_SIZE
4
+ from 10 to 2000.
5
+
6
+ == Note on Patches/Pull Requests
7
+
8
+ * Fork the project.
9
+ * Make your feature addition or bug fix.
10
+ * Add tests for it. This is important so I don't break it in a
11
+ future version unintentionally.
12
+ * Commit, do not mess with rakefile, version, or history.
13
+ (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
14
+ * Send me a pull request. Bonus points for topic branches.
15
+
16
+ == Copyright
17
+
18
+ Copyright (c) 2010 Raymond Gao. See LICENSE for details.
@@ -0,0 +1,53 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gem|
7
+ gem.name = "rforce-raygao"
8
+ gem.summary = %Q{An temporary patch of the RForce 0.4.1, increased the DEFAULT_BATCH_SIZE from 10 to 2000}
9
+ gem.description = %Q{An temporary patch of the RForce 0.4.1, increased the DEFAULT_BATCH_SIZE from 10 to 2000, max allowed by the SF platform, see Web Services API guide for detail. }
10
+ gem.email = "raygao2000@yahoo.com"
11
+ gem.homepage = "http://github.com/raygao/rforce-raygao"
12
+ gem.authors = ["Raymond Gao"]
13
+ # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
14
+ gem.add_dependency('oauth', '=0.4.4')
15
+ end
16
+ Jeweler::GemcutterTasks.new
17
+ rescue LoadError
18
+ puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/test_*.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+ begin
29
+ require 'rcov/rcovtask'
30
+ Rcov::RcovTask.new do |test|
31
+ test.libs << 'test'
32
+ test.pattern = 'test/**/test_*.rb'
33
+ test.verbose = true
34
+ end
35
+ rescue LoadError
36
+ task :rcov do
37
+ abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
38
+ end
39
+ end
40
+
41
+ task :test => :check_dependencies
42
+
43
+ task :default => :test
44
+
45
+ require 'rake/rdoctask'
46
+ Rake::RDocTask.new do |rdoc|
47
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
48
+
49
+ rdoc.rdoc_dir = 'rdoc'
50
+ rdoc.title = "rforce-raygao #{version}"
51
+ rdoc.rdoc_files.include('README*')
52
+ rdoc.rdoc_files.include('lib/**/*.rb')
53
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
@@ -0,0 +1,18 @@
1
+ --- !ditz.rubyforge.org,2008-03-06/issue
2
+ title: Investigate libxml
3
+ desc: The libxml-ruby project just released an updated gem, and it's reputed to be fast and stable. We should investigate it as an alternative parser.
4
+ type: :feature
5
+ component: rforce
6
+ release:
7
+ reporter: Luigi Montanez <luigi.montanez@gmail.com>
8
+ status: :unstarted
9
+ disposition:
10
+ creation_time: 2008-07-23 17:15:33.479204 Z
11
+ references: []
12
+
13
+ id: 09d998dc3f9d6e8928598fd5d9c6627102dedd65
14
+ log_events:
15
+ - - 2008-07-23 17:15:36.027132 Z
16
+ - Ian Dees <undees@gmail.com>
17
+ - created
18
+ - ""
@@ -0,0 +1,22 @@
1
+ --- !ditz.rubyforge.org,2008-03-06/issue
2
+ title: Ruby 1.9 compatibility
3
+ desc: Syntax, specs, and functional.
4
+ type: :task
5
+ component: rforce
6
+ release: "0.3"
7
+ reporter: Ian Dees <undees@gmail.com>
8
+ status: :closed
9
+ disposition: :fixed
10
+ creation_time: 2009-04-16 06:27:47.790789 Z
11
+ references: []
12
+
13
+ id: 1b668248120eb4fd055f0ea6b75ff807f6955936
14
+ log_events:
15
+ - - 2009-04-16 06:27:51.734012 Z
16
+ - Ian Dees <undees@gmail.com>
17
+ - created
18
+ - ""
19
+ - - 2009-04-16 19:27:46.187665 Z
20
+ - Ian Dees <undees@gmail.com>
21
+ - closed with disposition fixed
22
+ - Support REXML and Hpricot on 1.9, degrade gracefully.
@@ -0,0 +1,18 @@
1
+ --- !ditz.rubyforge.org,2008-03-06/issue
2
+ title: Do something with expand()
3
+ desc: expand() was just dumped into the RForce namespace as a minimal step in the direction of testability. There's probably a much better home for it.
4
+ type: :task
5
+ component: rforce
6
+ release:
7
+ reporter: Ian Dees <undees@gmail.com>
8
+ status: :unstarted
9
+ disposition:
10
+ creation_time: 2008-07-23 17:16:45.714702 Z
11
+ references: []
12
+
13
+ id: 3ef7a7c5c7e38fb76e1f53e1b67f45559e21b104
14
+ log_events:
15
+ - - 2008-07-23 17:16:47.083713 Z
16
+ - Ian Dees <undees@gmail.com>
17
+ - created
18
+ - ""
@@ -0,0 +1,22 @@
1
+ --- !ditz.rubyforge.org,2008-03-06/issue
2
+ title: Binding#call_remote should use parse()
3
+ desc: Search for uses of the old API (SoapResponse#new) and replace with the new API (SoapResponse#parse).
4
+ type: :bugfix
5
+ component: rforce
6
+ release: "0.3"
7
+ reporter: Ian Dees <undees@gmail.com>
8
+ status: :closed
9
+ disposition: :fixed
10
+ creation_time: 2008-07-28 05:37:21.978938 Z
11
+ references: []
12
+
13
+ id: a7a87cb98d29943a49d1608adb68475838ad2e65
14
+ log_events:
15
+ - - 2008-07-28 05:37:24.755692 Z
16
+ - Ian Dees <undees@gmail.com>
17
+ - created
18
+ - ""
19
+ - - 2008-07-28 05:39:29.817686 Z
20
+ - Ian Dees <undees@gmail.com>
21
+ - closed issue with disposition fixed
22
+ - Done.
@@ -0,0 +1,29 @@
1
+ --- !ditz.rubyforge.org,2008-03-06/issue
2
+ title: Select XML parser at runtime
3
+ desc: |-
4
+ XML parsing is done by three different classes: SoapResponse, SoapResponseHpricot, and SoapResponseExpat. The Binding class, in a holdover from the old days, is hard-coded to use SoapResponse.
5
+
6
+ At the very least, we should scan the installed libraries / gems and choose the fastest one available. We might also allow Binding's initializer to pass in a specific parser.
7
+ type: :task
8
+ component: rforce
9
+ release: "0.3"
10
+ reporter: Ian Dees <undees@gmail.com>
11
+ status: :closed
12
+ disposition: :fixed
13
+ creation_time: 2008-07-23 17:10:22.283059 Z
14
+ references: []
15
+
16
+ id: c92d34e10038ba6b9acfd7e3dfb2b154e463baba
17
+ log_events:
18
+ - - 2008-07-23 17:10:29.352269 Z
19
+ - Ian Dees <undees@gmail.com>
20
+ - created
21
+ - ""
22
+ - - 2008-07-28 05:37:48.378891 Z
23
+ - Ian Dees <undees@gmail.com>
24
+ - assigned to release 0.3 from unassigned
25
+ - ""
26
+ - - 2008-07-28 05:39:05.294916 Z
27
+ - Ian Dees <undees@gmail.com>
28
+ - closed issue with disposition fixed
29
+ - Used the simple fix of seeing which constants are defined and assigning SoapResponse based on that.
@@ -0,0 +1,16 @@
1
+ --- !ditz.rubyforge.org,2008-03-06/project
2
+ name: rforce
3
+ version: "0.3"
4
+ components:
5
+ - !ditz.rubyforge.org,2008-03-06/component
6
+ name: rforce
7
+ releases:
8
+ - !ditz.rubyforge.org,2008-03-06/release
9
+ name: "0.3"
10
+ status: :unreleased
11
+ release_time:
12
+ log_events:
13
+ - - 2008-07-28 05:35:54.153742 Z
14
+ - Ian Dees <undees@gmail.com>
15
+ - created
16
+ - Will be ready for ActiveSalesforce.
@@ -0,0 +1,3 @@
1
+ #require File.dirname(__FILE__) + '/rforce.rb'
2
+ require 'rforce'
3
+ puts '***rforce-raygao.rb is loaded***'
@@ -0,0 +1,87 @@
1
+ =begin
2
+ Copyright (c) 2005-2010 Ian Dees and contributors
3
+
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in
12
+ all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
21
+ =end
22
+
23
+ # RForce is a simple Ruby binding to the SalesForce CRM system.
24
+ # Rather than enforcing adherence to the sforce.com schema,
25
+ # RForce assumes you are familiar with the API. Ruby method names
26
+ # become SOAP method names. Nested Ruby hashes become nested
27
+ # XML elements.
28
+ #
29
+ # Example:
30
+ #
31
+ # binding = RForce::Binding.new 'https://www.salesforce.com/services/Soap/u/10.0'
32
+ # binding.login 'username', 'password'
33
+ # answer = binding.search(
34
+ # :searchString =>
35
+ # 'find {Some Account Name} in name fields returning account(id)')
36
+ # account_id = answer.searchResponse.result.searchRecords.record.Id
37
+ #
38
+ # opportunity = {
39
+ # :accountId => account_id,
40
+ # :amount => "10.00",
41
+ # :name => "New sale",
42
+ # :closeDate => "2005-09-01",
43
+ # :stageName => "Closed Won"
44
+ # }
45
+ #
46
+ # binding.create 'sObject {"xsi:type" => "Opportunity"}' => opportunity
47
+ #
48
+
49
+ require 'rforce/binding'
50
+ require 'rforce/soap_response'
51
+
52
+ module RForce
53
+ # Expand Ruby data structures into XML.
54
+ def expand(builder, args, xmlns = nil)
55
+ # Nest arrays: [:a, 1, :b, 2] => [[:a, 1], [:b, 2]]
56
+ if (args.class == Array)
57
+ args.each_index{|i| args[i, 2] = [args[i, 2]]}
58
+ end
59
+
60
+ args.each do |key, value|
61
+ attributes = xmlns ? {:xmlns => xmlns} : {}
62
+
63
+ # If the XML tag requires attributes,
64
+ # the tag name will contain a space
65
+ # followed by a string representation
66
+ # of a hash of attributes.
67
+ #
68
+ # e.g. 'sObject {"xsi:type" => "Opportunity"}'
69
+ # becomes <sObject xsi:type="Opportunity>...</sObject>
70
+ if key.is_a? String
71
+ key, modifier = key.split(' ', 2)
72
+
73
+ attributes.merge!(eval(modifier)) if modifier
74
+ end
75
+
76
+ # Create an XML element and fill it with this
77
+ # value's sub-items.
78
+ case value
79
+ when Hash, Array then
80
+ builder.tag!(key, attributes) do expand builder, value; end
81
+
82
+ when String then
83
+ builder.tag!(key, attributes) { builder.text! value }
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,255 @@
1
+ require 'net/https'
2
+ require 'uri'
3
+ require 'zlib'
4
+ require 'stringio'
5
+ require 'rexml/document'
6
+ require 'builder'
7
+ require 'oauth'
8
+
9
+ module RForce
10
+ # Implements the connection to the SalesForce server.
11
+ class Binding
12
+ include RForce
13
+
14
+ # Increase the maximum fetch size to 2000, as allowed by Salesforce
15
+ # Added by Raymond Gao
16
+ DEFAULT_BATCH_SIZE = 2000
17
+ attr_accessor :batch_size, :url, :assignment_rule_id, :use_default_rule, :update_mru, :client_id, :trigger_user_email,
18
+ :trigger_other_email, :trigger_auto_response_email
19
+
20
+ # Fill in the guts of this typical SOAP envelope
21
+ # with the session ID and the body of the SOAP request.
22
+ Envelope = <<-HERE
23
+ <?xml version="1.0" encoding="utf-8" ?>
24
+ <soap:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema"
25
+ xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
26
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
27
+ xmlns:partner="urn:partner.soap.sforce.com">
28
+ xmlns:spartner="urn:sobject.partner.soap.sforce.com">
29
+ <soap:Header>
30
+ <partner:SessionHeader soap:mustUnderstand='1'>
31
+ <partner:sessionId>%s</partner:sessionId>
32
+ </partner:SessionHeader>
33
+ <partner:QueryOptions soap:mustUnderstand='1'>
34
+ <partner:batchSize>%d</partner:batchSize>
35
+ </partner:QueryOptions>
36
+ %s
37
+ </soap:Header>
38
+ <soap:Body>
39
+ %s
40
+ </soap:Body>
41
+ </soap:Envelope>
42
+ HERE
43
+
44
+ AssignmentRuleHeaderUsingRuleId = '<partner:AssignmentRuleHeader soap:mustUnderstand="1"><partner:assignmentRuleId>%s</partner:assignmentRuleId></partner:AssignmentRuleHeader>'
45
+ AssignmentRuleHeaderUsingDefaultRule = '<partner:AssignmentRuleHeader soap:mustUnderstand="1"><partner:useDefaultRule>true</partner:useDefaultRule></partner:AssignmentRuleHeader>'
46
+ MruHeader = '<partner:MruHeader soap:mustUnderstand="1"><partner:updateMru>true</partner:updateMru></partner:MruHeader>'
47
+ ClientIdHeader = '<partner:CallOptions soap:mustUnderstand="1"><partner:client>%s</partner:client></partner:CallOptions>'
48
+
49
+ # Connect to the server securely. If you pass an oauth hash, it
50
+ # must contain the keys :consumer_key, :consumer_secret,
51
+ # :access_token, :access_secret, and :login_url.
52
+ def initialize(url, sid = nil, oauth = nil)
53
+ @session_id = sid
54
+ @oauth = oauth
55
+ @batch_size = DEFAULT_BATCH_SIZE
56
+
57
+ init_server(url)
58
+ end
59
+
60
+
61
+ def show_debug
62
+ ENV['SHOWSOAP'] == 'true'
63
+ end
64
+
65
+
66
+ def init_server(url)
67
+ @url = URI.parse(url)
68
+
69
+ if (@oauth)
70
+ consumer = OAuth::Consumer.new \
71
+ @oauth[:consumer_key],
72
+ @oauth[:consumer_secret],
73
+ { :site => url }
74
+
75
+ consumer.http.set_debug_output $stderr if show_debug
76
+
77
+ @server = OAuth::AccessToken.new \
78
+ consumer,
79
+ @oauth[:access_token],
80
+ @oauth[:access_secret]
81
+
82
+ class << @server
83
+ alias_method :post2, :post
84
+ end
85
+ else
86
+ @server = Net::HTTP.new(@url.host, @url.port)
87
+ @server.use_ssl = @url.scheme == 'https'
88
+ @server.verify_mode = OpenSSL::SSL::VERIFY_NONE
89
+
90
+ # run ruby with -d or env variable SHOWSOAP=true to see SOAP wiredumps.
91
+ @server.set_debug_output $stderr if show_debug
92
+ end
93
+ end
94
+
95
+
96
+ # Log in to the server with a user name and password, remembering
97
+ # the session ID returned to us by SalesForce.
98
+ def login(user, password)
99
+ @user = user
100
+ @password = password
101
+
102
+ response = call_remote(:login, [:username, user, :password, password])
103
+
104
+ raise "Incorrect user name / password [#{response.fault}]" unless response.loginResponse
105
+
106
+ result = response[:loginResponse][:result]
107
+ @session_id = result[:sessionId]
108
+
109
+ init_server(result[:serverUrl])
110
+
111
+ response
112
+ end
113
+
114
+ # Log in to the server with OAuth, remembering
115
+ # the session ID returned to us by SalesForce.
116
+ def login_with_oauth
117
+ result = @server.post @oauth[:login_url], '', {}
118
+
119
+ case result
120
+ when Net::HTTPSuccess
121
+ doc = REXML::Document.new result.body
122
+ @session_id = doc.elements['*/sessionId'].text
123
+ server_url = doc.elements['*/serverUrl'].text
124
+ init_server server_url
125
+
126
+ return {:sessionId => @sessionId, :serverUrl => server_url}
127
+ when Net::HTTPUnauthorized
128
+ raise 'Invalid OAuth tokens'
129
+ else
130
+ raise 'Unexpected error: #{response.inspect}'
131
+ end
132
+ end
133
+
134
+ # Call a method on the remote server. Arguments can be
135
+ # a hash or (if order is important) an array of alternating
136
+ # keys and values.
137
+ def call_remote(method, args)
138
+
139
+ urn, soap_url = block_given? ? yield : ["urn:partner.soap.sforce.com", @url.path]
140
+
141
+ # Create XML text from the arguments.
142
+ expanded = ''
143
+ @builder = Builder::XmlMarkup.new(:target => expanded)
144
+ expand(@builder, {method => args}, urn)
145
+
146
+ extra_headers = ""
147
+ extra_headers << (AssignmentRuleHeaderUsingRuleId % assignment_rule_id) if assignment_rule_id
148
+ extra_headers << AssignmentRuleHeaderUsingDefaultRule if use_default_rule
149
+ extra_headers << MruHeader if update_mru
150
+ extra_headers << (ClientIdHeader % client_id) if client_id
151
+
152
+ if trigger_user_email or trigger_other_email or trigger_auto_response_email
153
+ extra_headers << '<partner:EmailHeader soap:mustUnderstand="1">'
154
+
155
+ extra_headers << '<partner:triggerUserEmail>true</partner:triggerUserEmail>' if trigger_user_email
156
+ extra_headers << '<partner:triggerOtherEmail>true</partner:triggerOtherEmail>' if trigger_other_email
157
+ extra_headers << '<partner:triggerAutoResponseEmail>true</partner:triggerAutoResponseEmail>' if trigger_auto_response_email
158
+
159
+ extra_headers << '</partner:EmailHeader>'
160
+ end
161
+
162
+ # Fill in the blanks of the SOAP envelope with our
163
+ # session ID and the expanded XML of our request.
164
+ request = (Envelope % [@session_id, @batch_size, extra_headers, expanded])
165
+
166
+ # reset the batch size for the next request
167
+ @batch_size = DEFAULT_BATCH_SIZE
168
+
169
+ # gzip request
170
+ request = encode(request)
171
+
172
+ headers = {
173
+ 'Connection' => 'Keep-Alive',
174
+ 'Content-Type' => 'text/xml',
175
+ 'SOAPAction' => '""',
176
+ 'User-Agent' => 'activesalesforce rforce/1.0'
177
+ }
178
+
179
+ unless show_debug
180
+ headers['Accept-Encoding'] = 'gzip'
181
+ headers['Content-Encoding'] = 'gzip'
182
+ end
183
+
184
+ # Send the request to the server and read the response.
185
+ response = @server.post2(soap_url, request.lstrip, headers)
186
+
187
+ # decode if we have encoding
188
+ content = decode(response)
189
+
190
+ # Check to see if INVALID_SESSION_ID was raised and try to relogin in
191
+ if method != :login and @session_id and content =~ /sf:INVALID_SESSION_ID/
192
+ login(@user, @password)
193
+
194
+ # repackage and rencode request with the new session id
195
+ request = (Envelope % [@session_id, @batch_size, extra_headers, expanded])
196
+ request = encode(request)
197
+
198
+ # Send the request to the server and read the response.
199
+ response = @server.post2(soap_url, request.lstrip, headers)
200
+
201
+ content = decode(response)
202
+ end
203
+
204
+ SoapResponse.new(content).parse
205
+ end
206
+
207
+
208
+ # decode gzip
209
+ def decode(response)
210
+ encoding = response['Content-Encoding']
211
+
212
+ # return body if no encoding
213
+ if !encoding then return response.body end
214
+
215
+ # decode gzip
216
+ case encoding.strip
217
+ when 'gzip' then
218
+ begin
219
+ gzr = Zlib::GzipReader.new(StringIO.new(response.body))
220
+ decoded = gzr.read
221
+ ensure
222
+ gzr.close
223
+ end
224
+ decoded
225
+ else
226
+ response.body
227
+ end
228
+ end
229
+
230
+
231
+ # encode gzip
232
+ def encode(request)
233
+ return request if show_debug
234
+
235
+ begin
236
+ ostream = StringIO.new
237
+ gzw = Zlib::GzipWriter.new(ostream)
238
+ gzw.write(request)
239
+ ostream.string
240
+ ensure
241
+ gzw.close
242
+ end
243
+ end
244
+
245
+
246
+ # Turns method calls on this object into remote SOAP calls.
247
+ def method_missing(method, *args)
248
+ unless args.size == 1 && [Hash, Array].include?(args[0].class)
249
+ raise 'Expected 1 Hash or Array argument'
250
+ end
251
+
252
+ call_remote method, args[0]
253
+ end
254
+ end
255
+ end