/[drupal]/contributions/modules/apachesolr/Drupal_Apache_Solr_Service.php
ViewVC logotype

Contents of /contributions/modules/apachesolr/Drupal_Apache_Solr_Service.php

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.5 - (show annotations) (download) (as text)
Mon Jun 29 23:23:06 2009 UTC (4 months, 4 weeks ago) by pwolanin
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +19 -4 lines
File MIME type: text/x-php
sync with DRUPAL-6--1
1 <?php
2 require_once 'SolrPhpClient/Apache/Solr/Service.php';
3
4 /**
5 * PHP 5.1 compatability code.
6 */
7 if (!function_exists('json_decode')) {
8 // Zend files include other files.
9 set_include_path(dirname(__FILE__) . PATH_SEPARATOR . get_include_path());
10 require_once 'Zend/Json/Decoder.php';
11
12 /**
13 * Substitute for missing PHP built-in function.
14 */
15 function json_decode($string) {
16 return Zend_Json_Decoder::decode($string, 0);
17 }
18 }
19
20 class Drupal_Apache_Solr_Service extends Apache_Solr_Service {
21
22 protected $luke;
23 protected $luke_cid;
24 protected $stats;
25 const LUKE_SERVLET = 'admin/luke';
26 const STATS_SERVLET = 'admin/stats.jsp';
27
28 /**
29 * Call the /admin/ping servlet, to test the connection to the server.
30 *
31 * @param $timeout
32 * maximum time to wait for ping in seconds, -1 for unlimited (default 2).
33 * @return
34 * (float) seconds taken to ping the server, FALSE if timeout occurs.
35 */
36 public function ping($timeout = 2) {
37 $start = microtime(TRUE);
38
39 if ($timeout <= 0.0) {
40 $timeout = -1;
41 }
42 // Attempt a HEAD request to the solr ping url.
43 list($data, $headers) = $this->_makeHttpRequest($this->_pingUrl, 'HEAD', array(), null, $timeout);
44 $response = new Apache_Solr_Response($data, $headers);
45
46 if ($response->getHttpStatus() == 200) {
47 return microtime(TRUE) - $start;
48 }
49 else {
50 return FALSE;
51 }
52 }
53
54 /**
55 * Sets $this->luke with the meta-data about the index from admin/luke.
56 */
57 protected function setLuke($num_terms = 0) {
58 if (empty($this->luke[$num_terms])) {
59 $url = $this->_constructUrl(self::LUKE_SERVLET, array('numTerms' => "$num_terms", 'wt' => self::SOLR_WRITER));
60 $this->luke[$num_terms] = $this->_sendRawGet($url);
61 cache_set($this->luke_cid, $this->luke);
62 }
63 }
64
65 /**
66 * Get just the field meta-data about the index.
67 */
68 public function getFields($num_terms = 0) {
69 return $this->getLuke($num_terms)->fields;
70 }
71
72 /**
73 * Get meta-data about the index.
74 */
75 public function getLuke($num_terms = 0) {
76 if (!isset($this->luke[$num_terms])) {
77 $this->setLuke($num_terms);
78 }
79 return $this->luke[$num_terms];
80 }
81
82 /**
83 * Sets $this->stats with the information about the Solr Core form /admin/stats.jsp
84 */
85 protected function setStats() {
86 $data = $this->getLuke();
87 // Only try to get stats if we have connected to the index.
88 if (empty($this->stats) && isset($data->index->numDocs)) {
89 $url = $this->_constructUrl(self::STATS_SERVLET);
90 $this->stats_cid = "apachesolr:stats:" . md5($url);
91 $cache = cache_get($this->stats_cid);
92 if (isset($cache->data)) {
93 $this->stats = simplexml_load_string($cache->data);
94 }
95 else {
96 $response = $this->_sendRawGet($url);
97 $this->stats = simplexml_load_string($response->getRawResponse());
98 cache_set($this->stats_cid, $response->getRawResponse());
99 }
100 }
101 }
102
103 /**
104 * Get information about the Solr Core.
105 *
106 * Returns a Simple XMl document
107 */
108 public function getStats() {
109 if (!isset($this->stats)) {
110 $this->setStats();
111 }
112 return $this->stats;
113 }
114
115 /**
116 * Get summary information about the Solr Core.
117 */
118 public function getStatsSummary() {
119 $stats = $this->getStats();
120 $summary = array(
121 '@pending_docs' => '',
122 '@autocommit_time_seconds' => '',
123 '@autocommit_time' => '',
124 '@deletes_by_id' => '',
125 '@deletes_by_query' => '',
126 '@deletes_total' => '',
127 );
128
129 if (!empty($stats)) {
130 $docs_pending_xpath = $stats->xpath('//stat[@name="docsPending"]');
131 $summary['@pending_docs'] = (int) trim($docs_pending_xpath[0]);
132 $max_time_xpath = $stats->xpath('//stat[@name="autocommit maxTime"]');
133 $max_time = (int) trim(current($max_time_xpath));
134 // Convert to seconds.
135 $summary['@autocommit_time_seconds'] = $max_time / 1000;
136 $summary['@autocommit_time'] = format_interval($max_time / 1000);
137 $deletes_id_xpath = $stats->xpath('//stat[@name="deletesById"]');
138 $summary['@deletes_by_id'] = (int) trim($deletes_id_xpath[0]);
139 $deletes_query_xpath = $stats->xpath('//stat[@name="deletesByQuery"]');
140 $summary['@deletes_by_query'] = (int) trim($deletes_query_xpath[0]);
141 $summary['@deletes_total'] = $summary['@deletes_by_id'] + $summary['@deletes_by_query'];
142 }
143
144 return $summary;
145 }
146
147 /**
148 * Clear cached Solr data.
149 */
150 public function clearCache() {
151 // Don't clear cached data if the server is unavailable.
152 if (@$this->ping()) {
153 $this->_clearCache();
154 }
155 else {
156 throw new Exception('No Solr instance available when trying to clear the cache.');
157 }
158 }
159
160 protected function _clearCache() {
161 cache_clear_all("apachesolr:luke:", 'cache', TRUE);
162 cache_clear_all("apachesolr:stats:", 'cache', TRUE);
163 $this->luke = array();
164 $this->stats = NULL;
165 }
166
167 /**
168 * Clear the cache whenever we commit changes.
169 *
170 * @see Apache_Solr_Service::commit()
171 */
172 public function commit($optimize = TRUE, $waitFlush = TRUE, $waitSearcher = TRUE, $timeout = 3600) {
173 parent::commit($optimize, $waitFlush, $waitSearcher, $timeout);
174 $this->_clearCache();
175 }
176
177 /**
178 * Construct the Full URLs for the three servlets we reference
179 *
180 * @see Apache_Solr_Service::_initUrls()
181 */
182 protected function _initUrls() {
183 parent::_initUrls();
184 $this->_lukeUrl = $this->_constructUrl(self::LUKE_SERVLET, array('numTerms' => '0', 'wt' => self::SOLR_WRITER));
185 }
186
187 /**
188 * Put Luke meta-data from the cache into $this->luke when we instantiate.
189 *
190 * @see Apache_Solr_Service::__construct()
191 */
192 public function __construct($host = 'localhost', $port = 8180, $path = '/solr/') {
193 parent::__construct($host, $port, $path);
194 $this->luke_cid = "apachesolr:luke:" . md5($this->_lukeUrl);
195 $cache = cache_get($this->luke_cid);
196 if (isset($cache->data)) {
197 $this->luke = $cache->data;
198 }
199 }
200
201 /**
202 * Central method for making a get operation against this Solr Server
203 *
204 * @see Apache_Solr_Service::_sendRawGet()
205 */
206 protected function _sendRawGet($url, $timeout = FALSE) {
207 list ($data, $headers) = $this->_makeHttpRequest($url, 'GET', array(), '', $timeout);
208 $response = new Apache_Solr_Response($data, $headers, $this->_createDocuments, $this->_collapseSingleValueArrays);
209 $code = (int) $response->getHttpStatus();
210 if ($code != 200) {
211 $message = $response->getHttpStatusMessage();
212 if ($code >= 400 && $code != 403 && $code != 404) {
213 // Add details, like Solr's exception message.
214 $message .= $response->getRawResponse();
215 }
216 throw new Exception('"' . $code . '" Status: ' . $message);
217 }
218 return $response;
219 }
220
221 /**
222 * Central method for making a post operation against this Solr Server
223 *
224 * @see Apache_Solr_Service::_sendRawGet()
225 */
226 protected function _sendRawPost($url, $rawPost, $timeout = FALSE, $contentType = 'text/xml; charset=UTF-8') {
227 if (variable_get('apachesolr_read_only', 0)) {
228 throw new Exception('Operating in read-only mode; updates are disabled.');
229 }
230 $request_headers = array('Content-Type' => $contentType);
231 list ($data, $headers) = $this->_makeHttpRequest($url, 'POST', $request_headers, $rawPost, $timeout);
232 $response = new Apache_Solr_Response($data, $headers, $this->_createDocuments, $this->_collapseSingleValueArrays);
233 $code = (int) $response->getHttpStatus();
234 if ($code != 200) {
235 $message = $response->getHttpStatusMessage();
236 if ($code >= 400 && $code != 403 && $code != 404) {
237 // Add details, like Solr's exception message.
238 $message .= $response->getRawResponse();
239 }
240 throw new Exception('"' . $code . '" Status: ' . $message);
241 }
242 return $response;
243 }
244
245 protected function _makeHttpRequest($url, $method = 'GET', $headers = array(), $content = '', $timeout = FALSE) {
246 // Set a response timeout
247 if ($timeout) {
248 $default_socket_timeout = ini_set('default_socket_timeout', $timeout);
249 }
250 $result = drupal_http_request($url, $headers, $method, $content);
251 // Restore the response timeout
252 if ($timeout) {
253 ini_set('default_socket_timeout', $default_socket_timeout);
254 }
255
256 // This will no longer be needed after http://drupal.org/node/345591 is committed
257 $responses = array(
258 0 => 'Request failed',
259 100 => 'Continue', 101 => 'Switching Protocols',
260 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content',
261 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 307 => 'Temporary Redirect',
262 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Time-out', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Request Entity Too Large', 414 => 'Request-URI Too Large', 415 => 'Unsupported Media Type', 416 => 'Requested range not satisfiable', 417 => 'Expectation Failed',
263 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Time-out', 505 => 'HTTP Version not supported'
264 );
265
266 if (!isset($result->code) || $result->code < 0) {
267 $result->code = 0;
268 }
269
270 if (isset($result->error)) {
271 $responses[0] .= ': ' . check_plain($result->error);
272 }
273
274 if (!isset($result->data)) {
275 $result->data = '';
276 }
277
278 if (!isset($responses[$result->code])) {
279 $result->code = floor($result->code / 100) * 100;
280 }
281
282 $protocol = "HTTP/1.1";
283 $headers[] = "{$protocol} {$result->code} {$responses[$result->code]}";
284 if (isset($result->headers)) {
285 foreach ($result->headers as $name => $value) {
286 $headers[] = "$name: $value";
287 }
288 }
289 return array($result->data, $headers);
290 }
291 }

  ViewVC Help
Powered by ViewVC 1.1.2