Skip to content
xc_solr.module 90.2 KiB
Newer Older
tombui's avatar
tombui committed
<?php
/**
 * @file
 * The module used for being a connector between Apache Solr server and Drupal Toolkit.
 * We use a modified version of the SolrPhpClient to access Solr webservices.
 *
 * The information about Solr servers are stored in xc_solr_server table in MySQL.
 *
 * @copyright (c) 2010-2011 eXtensible Catalog Organization
 */

/**
 * @addtogroup global variables
 * @{
 */
global $_xc_solr_obj;
global $_xc_solr_indexing_statistics;
global $_xc_solr_batch_remove;
global $_xc_solr_batch_documents;
global $_xc_solr_processed_record_count;
/**
 * @} End of "addtogroup global variables".
 */

require_once 'SolrPhpClient/Apache/Solr/DocumentXc.php';
require_once 'SolrPhpClient/Apache/Solr/ResponseXc.php';
Kiraly Peter's avatar
Kiraly Peter committed
require_once 'SolrPhpClient/Apache/Solr/ServiceXc.php';
tombui's avatar
tombui committed
require_once 'SolrPhpClient/Apache/Solr/Drupal_Apache_Solr_ServiceXc.php';
Kiraly Peter's avatar
Kiraly Peter committed

tombui's avatar
tombui committed
require_once 'xc_solr_date.inc';
Kiraly Peter's avatar
Kiraly Peter committed

tombui's avatar
tombui committed
/**
 * Number of documents belongs to one Solr::addDocuments() operation
 * @var int
 */
define('XC_BATCH_SIZE', 200);

/**
 * The number of documents after a commit operation triggered
 * @var int
 */
define('XC_COMMIT_SIZE', 1000);

/**
 * The number of document used in batch when reindexing
 * @var int
 */
define('XC_BULK_REINDEX_LIMIT', 50);

/**
 * Permission for administering XC Solr
 * @var String
 */
define('ADMINISTER_XC_SOLR', 'administer xc solr');

define('XC_SOLR_PROCESS_ALL', 'all');
define('XC_SOLR_PROCESS_CHANGES_ONLY', 'changes only');

Kiraly Peter's avatar
Kiraly Peter committed
/**
 * Phases of batch process
 */
if (!defined('XC_PHASE_PREPARATION')) {
  define('XC_PHASE_PREPARATION', 1);
  define('XC_PHASE_LOAD', 2);
  define('XC_PHASE_NORMALIZATION', 3);
}

Kiraly Peter's avatar
Kiraly Peter committed
define('XC_SOLR_SERVICE_DEFAULT', 1);
define('XC_SOLR_SERVICE_DRUPAL', 2);

tombui's avatar
tombui committed
/**
 * Implementation of hook_help()
 * @param $path
 * @param $arg
 * @return unknown_type
 */
function xc_solr_help($path, $arg) {
  $output = '';
  switch ($path) {
    case "admin/help#xc_solr" :
      $output = '<p>'
        . t('Integrates !solr into XC modules. Solr installation:',
          array('!solr' => l(t('Apache Solr'), 'http://lucene.apache.org/solr')));
      $steps = array(
        t('download Apache Solr from Solr !download_page',
          array('!download_page' => l(t('download page'), 'http://www.apache.org/dyn/closer.cgi/lucene/solr/'))),
        t('unzip it to a convenient place'),
        t("copy drupal/sites/all/modules/xc/xc_solr/schema.xml to Solr's example/solr/conf"),
        t('run solr with java -jar example/start.jar'),
        t('test Solr accessibility at !url',
          array('!url' => l('localhost:8983', 'http://localhost:8983/solr')))
      );
tombui's avatar
tombui committed
      $output .= theme('item_list', array('items' => $steps));
tombui's avatar
tombui committed
      $output .= t('More information at !url', array('!url' => l(t('Solr homepage'),
        'http://lucene.apache.org/solr')));
      $output .= '</p>';
      break;

    case 'admin/xc/solr/facet_stat' :
      $output = t('This page gives you information about whats happens during the facet creation. This table collect information from each faceted search. The columns of the table: ');
Kiraly Peter's avatar
Kiraly Peter committed
      $output .= theme('item_list', array('items' => array(
tombui's avatar
tombui committed
        t('total - the total time taken'),
        t('UI - the user interface which was applied'),
        t('hits - the number of hits'),
        t('prepare - the time taken for the preparation of facet parameters'),
        t('all solr - the time taken from sending the parameters, to receiving all results'),
        t('solr - the time taken purely for Solr query - reported by Solr itself'),
        t('display - the time taken for displaying facets'),
Kiraly Peter's avatar
Kiraly Peter committed
      )));
tombui's avatar
tombui committed
      break;
  }
  return $output;
} // xc_solr_help

/**
 * Implementation of hook_perm()
 * Valid permissions for this module
 * @return (Array)
 *   An array of valid permissions for the XC Solr module
 */
function xc_solr_perm() {
  return array(
    ADMINISTER_XC_SOLR
  );
}

/**
 * Implementation of hook_menu().
 * @return array The menu array
 */
function xc_solr_menu() {
  $items['admin/xc/solr'] = array(
    'title' => 'Solr Setup and Indexing',
    'description' => 'Tell Drupal about your Apache Solr server. Prerequisite: Install Solr on the same computer as Drupal following the instructions included with XC and from the Apache Solr site.',
    'file' => 'system.admin.inc',
    'file path' => drupal_get_path('module', 'system'),
    'page callback' => 'system_admin_menu_block_page',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'weight' => 0,
  );
  $items['admin/xc/solr/server'] = array(
    'title' => 'Solr servers',
    'description' => 'Create, modify, and view Solr servers used for metadata
      storage and search',
    'page callback' => 'xc_solr_server_list',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'weight' => 0,
  );

  $items['admin/xc/solr/proxy'] = array(
    'title' => 'Solr proxy',
    'description' => 'If you don\'t have direct access to your Solr server,use this form to check queries',
    'page callback' => 'xc_solr_proxy',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'weight' => 1,
  );

  $items['admin/xc/solr/info'] = array(
    'title' => 'Information about Solr index',
    'description' => 'Information about Solr index.',
    'page callback' => 'xc_solr_info',
    'file' => 'xc_solr.info.inc',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'weight' => 2,
  );

  $items['admin/xc/solr/optimize'] = array(
    'title' => 'Optimize Solr index',
    'description' => 'Optimize Solr index.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xc_solr_xc_optimize_all_form'),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'weight' => 4,
  );

  $items['admin/xc/solr/field_type'] = array(
    'title' => 'Solr field types',
    'description' => 'Registry of dynamic Solr fields.',
    'page callback' => 'xc_solr_field_type_list',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'xc_solr_field_type.inc',
    'weight' => 5,
  );

  $items['admin/xc/solr/search_stat'] = array(
    'title' => 'Statistics about searches',
    'description' => 'Statistics about searches.',
    'page callback' => 'xc_solr_search_statistics',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'xc_solr.info.inc',
    'weight' => 6,
  );

  $items['admin/xc/solr/facet_stat'] = array(
    'title' => 'Statistics about facets',
    'description' => 'Statistics about facets.',
    'page callback' => 'xc_solr_facet_statistics',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'xc_solr.info.inc',
    'weight' => 7,
  );

  $items['admin/xc/solr/batch_stat'] = array(
    'title' => 'Statistics about harvest',
    'description' => 'Statistics about harvest.',
    'page callback' => 'xc_solr_onestop_indexer_batch_statistics',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    // 'file' => 'xc_solr.info.inc',
    'weight' => 7,
  );

  $items['admin/xc/solr/delete_content'] = array(
    'title' => 'Delete content',
    'description' => 'Delete all Solr content.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xc_solr_xc_delete_all_form'),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'weight' => 8,
  );

  $items['admin/xc/solr/server/list'] = array(
    'title' => 'List',
    'description' => 'Listing of Solr servers',
    'page callback' => 'xc_solr_server_list',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 0,
  );
  $items['admin/xc/solr/server/add'] = array(
    'title' => 'Add server',
    'description' => 'Register a new Solr server',
    'page callback' => 'xc_solr_server_add',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
  );
  $items['admin/xc/solr/server/%xc_solr_server'] = array(
    'title callback' => 'xc_solr_server_title',
    'title arguments' => array(4),
    'description' => 'View the properties of a Solr server',
    'page callback' => 'xc_solr_server_view',
    'page arguments' => array(4),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_CALLBACK,
  );
  $items['admin/xc/solr/server/%xc_solr_server/view'] = array(
    'title' => 'View',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/xc/solr/server/%xc_solr_server/edit'] = array(
    'title' => 'Edit',
    'description' => 'Edit the properties of a Solr server',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xc_solr_server_edit_form', 4),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_LOCAL_TASK,
    'weight' => -9,
  );

  $items['admin/xc/solr/field_type/list'] = array(
    'title' => 'List Solr field types',
    'description' => 'List of Solr field types',
    'page callback' => 'xc_solr_field_type_list',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
    'file' => 'xc_solr_field_type.inc',
  );
  $items['admin/xc/solr/field_type/add'] = array(
    'title' => 'Add a new Solr field type',
    'description' => 'Add a new Solr field type',
    'page callback' => 'xc_solr_field_type_add',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_LOCAL_TASK,
    'file' => 'xc_solr_field_type.inc',
  );
  $items['admin/xc/solr/field_type/reorder'] = array(
    'title' => 'Reorder',
    'description' => 'Reorder Solr field types table',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xc_solr_field_type_reorder_form'),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_LOCAL_TASK,
    'file' => 'xc_solr_field_type.inc',
  );
  $items['admin/xc/solr/field_type/%xc_solr_field_type'] = array(
    'title' => 'Show Solr field type',
    'description' => 'Show Solr field type',
    'title callback'  => 'xc_solr_field_type_title',
    'title arguments' => array(4),
    'page callback'   => 'xc_solr_field_type_view',
    'page arguments'  => array(4),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'xc_solr_field_type.inc',
  );
  $items['admin/xc/solr/field_type/%xc_solr_field_type/view'] = array(
    'title' => 'View',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -10,
  );
  $items['admin/xc/solr/field_type/%xc_solr_field_type/edit'] = array(
    'title' => 'Edit',
    'description' => 'Edit Solr field type',
    'page callback' => 'drupal_get_form',
    'page arguments'  => array('xc_solr_field_type_edit_form', 4),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_LOCAL_TASK,
    'weight' => 1,
    'file' => 'xc_solr_field_type.inc',
  );

  $items['admin/xc/solr/field_type/%xc_solr_field_type/add'] = array(
    'title' => 'Add new Solr field type',
    'description' => 'Add new Solr field type',
    'page callback' => 'xc_solr_field_type_add',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_LOCAL_TASK,
    'weight' => 2,
    'file' => 'xc_solr_field_type.inc',
  );

  $items['admin/xc/solr/indexlist'] = array(
    'title' => 'List fields to index',
    'description' => 'List fields to index.',
    'page callback' => 'xc_solr_show_fields2index_list',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'xc_solr.index.inc',
  );
  $items['admin/xc/solr/onestop'] = array(
    'title' => 'Run one-stop indexer',
    'description' => 'Run one-stop indexer.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('xc_solr_onestop_indexer_batch_launcher_form', NULL),
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
    'file' => 'xc_solr.index.inc',
  );

  $items['admin/xc/solr/onestop_stat'] = array(
    'title' => 'Get one-stop indexer stat',
    'description' => 'Get one-stop indexer stat.',
    'page callback' => 'xc_solr_onestop_indexer_batch_finished',
    'access arguments' => array(ADMINISTER_XC_SOLR),
    'type' => MENU_NORMAL_ITEM,
  );

  return $items;
}

/**
 * Implementation of hook_theme().
 *
 * List of themes defined in xc_solr modules
 */
function xc_solr_theme() {
Kiraly Peter's avatar
Kiraly Peter committed

tombui's avatar
tombui committed
  $themes = array(
    'xc_solr_field_type_reorder_form' => array(
      'arguments' => array(
        'form' => array()
      ),
      'file' => 'xc_solr_field_type.inc',
    ),
  );

  return $themes;
}

/**
 * Get all Solr server database records.
 * The server's fields are: sid, location_id (id for metadata source), name,
 * host, port, path, description
 *
 * @return (Array)
 *   The array of Solr id (sid) - Solr DB record object pairs
 */
function xc_solr_get_servers($update = FALSE) {
  static $servers = array();

  if (empty($servers) || $update == TRUE) {
    $sql = 'SELECT * FROM {xc_solr_servers}';
    $result = db_query($sql);
    //while ($solr = db_fetch_object($result)) {
    foreach ($result as $solr) {
      $servers[$solr->sid] = $solr;
    }
  }

  return $servers;
}

function xc_solr_server_title($sid) {
  $solr = xc_solr_server_load($sid);
  return $solr->name;
}

function xc_solr_get_url($sid) {
  $solr = xc_solr_server_load($sid);
  $url = 'http://' . check_plain($solr->host) . ':'. check_plain($solr->port) . check_plain($solr->path);
  return $url;
}

function xc_solr_server_list() {
  $headers = array(t('Name'), t('URL'), array('data' => t('Operations'),
    'colspan' => 2));
  $rows = array();
  $servers = xc_solr_get_servers();

  drupal_set_title(t('Solr servers'));

  foreach ($servers as $solr) {
    $url = xc_solr_get_url($solr->sid);
    $rows[] = array(
      check_plain($solr->name),
      l($url, check_url($url)),
      l(t('view'), 'admin/xc/solr/server/' . $solr->sid),
      l(t('edit'), 'admin/xc/solr/server/' . $solr->sid . '/edit')
    );
  }
  return theme('table', array('header' => $headers, 'rows' => $rows));
tombui's avatar
tombui committed
}

function xc_solr_server_view($solr) {
  $headers = array(t('Property'), t('Value'));
  $rows = array();

  $rows[] = array(t('Name'), check_plain($solr->name));
  $rows[] = array(t('Host'), check_plain($solr->host));
  $rows[] = array(t('Port'), check_plain($solr->port));
  $rows[] = array(t('Path'), check_plain($solr->path));
  $rows[] = array(t('URL'), check_url(xc_solr_get_url($solr->sid)));
  $rows[] = array(t('Description'), check_plain($solr->description));

  drupal_set_title(check_plain($solr->name));
  return theme('table', array('header' => $headers, 'rows' => $rows));
tombui's avatar
tombui committed
}

// -- BEGINING of add repository functions

/**
 * Add a new server
 * @return string The add server page with a form
 */
function xc_solr_server_add() {
  drupal_set_title(t('Solr servers'));
  return drupal_get_form('xc_solr_server_add_form');
}

/**
 * The add repository form object
 * @return array
 */
function xc_solr_server_add_form() {
  $form['name'] = array(
    '#title' => t('Name'),
    '#type' => 'textfield',
    '#description' => 'The name of the Solr server',
  );

  $form['host'] = array(
    '#title' => t('Host'),
    '#type' => 'textfield',
    '#description' => 'The host of the Solr server',
    '#default_value' => 'localhost',
  );

  $form['port'] = array(
    '#title' => t('Port'),
    '#type' => 'textfield',
    '#description' => 'The port of the Solr server',
    '#default_value' => '8983',
  );

  $form['path'] = array(
    '#title' => t('Path'),
    '#type' => 'textfield',
    '#description' => 'The path of the Solr server',
    '#default_value' => '/solr',
  );

  $form['description'] = array(
    '#title' => t('Description'),
    '#type' => 'textarea',
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Add server'),
  );

  return $form;
}

/**
 * Validate the new repository form
 * @param $form
 * @param $form_state
 * @return unknown_type
 */
function xc_solr_server_add_form_validate($form, &$form_state) {
  if (empty($form_state['values']['name'])
    || $form_state['values']['name'] == '') {
    form_set_error('name', t('Name shouldn\'t be empty'));
  }
  if (empty($form_state['values']['host'])
    || $form_state['values']['host'] == '') {
    form_set_error('name', t('Host shouldn\t be empty'));
  }
  if (empty($form_state['values']['port'])
    || $form_state['values']['port'] == '') {
    form_set_error('name', t('Port shouldn\'t be empty'));
  }
  if (empty($form_state['values']['path'])
    || $form_state['values']['path'] == '') {
    form_set_error('name', t('Path shouldn\t be empty'));
  }
}

/**
 * Handle post-validation form submission of new repository form
 * @param $form
 * @param $form_state
 * @return unknown_type
 */
function xc_solr_server_add_form_submit($form, &$form_state) {
Kiraly Peter's avatar
Kiraly Peter committed

tombui's avatar
tombui committed
  $solr = new stdClass();
tombui's avatar
tombui committed
  $solr->name = check_plain($form_state['values']['name']);
  $solr->host = check_plain($form_state['values']['host']);
  $solr->port = check_plain($form_state['values']['port']);
  $solr->path = check_plain($form_state['values']['path']);
  $solr->description = check_plain($form_state['values']['description']);

  $ret_val = drupal_write_record('xc_solr_servers', $solr);
  if ($ret_val == SAVED_NEW) {
    drupal_set_message(t('Solr server "%name" added', array('%name' => $solr->name)));
    $form_state['redirect'] = 'admin/xc/solr/server/list';
  }
  else {
    drupal_set_message(t('Unexpected error. Failed to create new Solr server.'));
  }
}

// -- END of add server funtions

function xc_solr_server_edit_form($form,&$form_state,$solr) {
tombui's avatar
tombui committed
  $form = xc_solr_server_add_form();
  $form['sid'] = array(
    '#type'  => 'hidden',
    '#value' => $solr->sid
  );
  $form['name']['#default_value'] = $solr->name;
  $form['host']['#default_value'] = $solr->host;
  $form['port']['#default_value'] = $solr->port;
  $form['path']['#default_value'] = $solr->path;
  $form['description']['#default_value'] = $solr->description;

  $form['submit']['#value'] = t('Save');
  $form['delete'] = array(
    '#type' => 'submit',
    '#value' => t('Delete'),
  );
  return $form;
}

function xc_solr_server_edit_form_validate($form, &$form_state) {
  xc_solr_server_add_form_validate($form, $form_state);
}

function xc_solr_server_edit_form_submit($form, &$form_state) {
  $solr = new stdClass();
  //$solr = new stdClass();
  $solr->sid  = check_plain($form_state['values']['sid']);
  $solr->name = check_plain($form_state['values']['name']);
  $solr->host = check_plain($form_state['values']['host']);
  $solr->port = check_plain($form_state['values']['port']);
  $solr->path = check_plain($form_state['values']['path']);
  $solr->description = check_plain($form_state['values']['description']);

  if ($form_state['clicked_button']['#value'] == t('Delete')) {
    $result = db_delete('xc_solr_servers')
Kiraly Peter's avatar
Kiraly Peter committed
              ->condition('sid', $solr->sid)
              ->execute();
    if ($result == 1) {
tombui's avatar
tombui committed
      drupal_set_message(t('%name removed', array('%name' => $solr->name)));
      $form_state['redirect'] = 'admin/xc/solr/server/list';
    }
    else {
Kiraly Peter's avatar
Kiraly Peter committed
      drupal_set_message(t('Unexpected error. Deletion removed %count server.',
        array('%name' => $record->name)));
  elseif ($form_state['clicked_button']['#value'] == t('Save')) {
tombui's avatar
tombui committed
    $result = drupal_write_record('xc_solr_servers', $solr, 'sid');

    if ($result == SAVED_UPDATED) {
      drupal_set_message(t('%name modified', array('%name' => $solr->name)));
      $form_state['redirect'] = 'admin/xc/solr/server/list';
    }
    else {
      drupal_set_message(t('Unexpected error. Failed to modify server.'));
    }
  }
}

/**
 * Implementation of hook_xc_location()
 * @see _xc_location
 */
function xc_solr_xc_location($op, $location, $params = array()) {
  switch ($op) {
    case 'types':
      $sid  = (isset($location->location_id)) ? xc_solr_get_sid($location->location_id) : FALSE;

      $types['solr'] = array(
        'name'        => ($sid
           ? t('Apache Solr server at %path', array('%path' => xc_solr_get_url($sid)))
           : t('Apache Solr server')),
        'description' => t('Store and retrieve metadata elements to and from Apache Solr servers'),
        'module'      => 'xc_solr',
        'help'        => t('Store and retrieve metadata elements to and from Apache Solr servers'),
        'default'     => TRUE
      );
      return $types;
      break;
    case 'view':
    case 'load':
      break;
    case 'form':
      break;
    case 'create':
    case 'update':
      // no information to update
      break;
    case 'purge':
      // delete all metadata in Solr server
      $sid  = xc_solr_get_sid($location->location_id);
      $solr = xc_solr_server_load($sid);
      xc_solr_server_unset($solr);
      break;
    case 'delete':
      // delete everything AND unregister Solr server
      break;
  }
}

function xc_solr_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'devel_generate_content_form') {
    /*
    $form['add_upload']['#type'] = 'hidden';
    $form['add_terms']['#type'] = 'hidden';
    $form['add_alias']['#type'] = 'hidden';
    // $form['num_nodes']['#type'] = 'hidden';
    $form['num_nodes']['#default_value'] = 0;
    $form['max_comments']['#type'] = 'hidden';
    $form['kill_content']['#default_value'] = 1;
    $form['time_range']['#type'] = 'hidden';
    $form['title_length']['#type'] = 'hidden';
    // */
  }
  elseif ($form_id == 'xc_location_form') {
    $step     = &$form_state['storage']['step'];
    $location = &$form_state['storage']['location'];

    if ($step == 2 && $location->has_solr_type) {
      $sid = isset($location->location_id) ? xc_solr_get_sid($location->location_id) : FALSE;
      if ($sid) {
        $current_solr = xc_solr_server_load($sid);
      }
      if (!$sid || empty($current_solr)) {
        $current_solr = (object)array(
          'host' => 'localhost',
          'port' => 8983,
          'path' => '/solr'
        );
      }

      $form['solr']['solr_host'] = array(
        '#title' => t('Host'),
        '#type' => 'textfield',
        '#description' => 'The host of the Solr server',
        '#default_value' => $current_solr->host,
        '#required' => TRUE
      );

      $form['solr']['solr_port'] = array(
        '#title' => t('Port'),
        '#type' => 'textfield',
        '#description' => 'The port of the Solr server',
        '#default_value' => $current_solr->port,
        '#required' => TRUE
      );

      $form['solr']['solr_path'] = array(
        '#title' => t('Path'),
        '#type' => 'textfield',
        '#description' => 'The path of the Solr server',
        '#default_value' => $current_solr->path,
        '#required' => TRUE
      );

      $form['#validate'][] = 'xc_solr_location_validate';
      $form['#submit'][] = 'xc_solr_location_submit';
    }
  }
}

function xc_solr_location_validate($form, &$form_state) {
  $step     = &$form_state['storage']['step'];
  $location = &$form_state['storage']['location'];

  if ($step == 2 && $location->has_solr_type) {
    // Nothing needed
    $form_state['solr_storage'] = &$form_state['storage'];
  }
}

function xc_solr_location_submit($form, &$form_state) {
  $step     = &$form_state['solr_storage']['step'];
  $location = &$form_state['solr_storage']['location'];

  if ($step > 2 && $location->has_solr_type) {
    $solr = new stdClass();
    $solr->sid         = xc_solr_get_sid($location->location_id);
    $solr->location_id = $location->location_id;
    $solr->host        = $form_state['values']['solr_host'];
    $solr->port        = $form_state['values']['solr_port'];
    $solr->path        = $form_state['values']['solr_path'];
    xc_solr_server_set($solr);
    unset($form_state['solr_storage']);
  }
}

function xc_solr_server_set($solr) {
tombui's avatar
tombui committed
  //TODO from Tom, need to convert to D7
tombui's avatar
tombui committed
  $sql = 'SELECT sid FROM {xc_solr_servers} WHERE sid = :d';

  $update = empty($solr->sid)
    ? FALSE
    : db_query($sql, array(':d' =>$solr->sid))->fetchField();
tombui's avatar
tombui committed

  if ($update) {
    $result = drupal_write_record('xc_solr_servers', $solr, 'sid');
  }
  else {
    unset($solr->sid);
    $result = drupal_write_record('xc_solr_servers', $solr);
  }

  if (!$result) {
Kiraly Peter's avatar
Kiraly Peter committed
    drupal_set_message(t('Unexpected error. Unable to register Solr server'), 'error');
tombui's avatar
tombui committed
  }
}

function xc_solr_server_unset($solr) {
  $sql = 'DELETE FROM {xc_solr_servers} WHERE storage_id = :d';
  $result = db_query($sql, array(':d' => $solr->sid));
  if ($result) {
    drupal_set_message(t('Apache Solr server removed'));
  }
  else {
    drupal_set_message(t('Unexpected error. Failed to remove server.'), 'error');
  }
}

function xc_solr_get_location_id($sid) {
  static $cache;
  if (empty($cache[$sid])) {
    $sql = 'SELECT location_id FROM {xc_solr_servers} WHERE sid = :d';
tombui's avatar
tombui committed
    // TODO from Tom, need to check db_result for D7
tombui's avatar
tombui committed
    $cache[$sid] = db_result(db_query($sql, array(':d' => $sid)));
  }
  return $cache[$sid];
}

/**
 * Get the Solr record identifier attached to a location id
 * @param $location_id (int) The location record's identifier
 * @return (int) The Solr record identifier
 */
function xc_solr_get_sid($location_id) {
  static $cache;
  if (empty($cache[$location_id])) {
    $sql = 'SELECT sid FROM {xc_solr_servers} WHERE location_id = :d';
    $cache[$location_id] = db_query($sql, array(':d' => $location_id))->fetchField();
tombui's avatar
tombui committed
  }
  return $cache[$location_id];
}

/**
 * Implementation of hook_xc_remove().
 *
 * Remove an object from the storage (here from Solr).
 *
 * @param (Object) $object
 *   XCEntity object
 * @param (Array) $locations
 * @param (Array) $params
 */
function xc_solr_xc_remove(&$object, $locations, $params = array()) {
  global $_xc_solr_batch_remove;
  /**
   * Flags whether the locations array is saved into a Drupal variable
   */
  static $location_saved;

  if (!empty($object)) {
    $_xc_solr_batch_remove[] = $object->metadata_id;
    if (!empty($locations) && !isset($location_saved)) {
      variable_set('xc_solr_remove_lat_locations', $locations);
      $location_saved = TRUE;
    }
  }

  if (count($_xc_solr_batch_remove) == XC_BATCH_SIZE
      || (isset($params['do_check_size']) && $params['do_check_size'] === FALSE)) {

    if (empty($locations) && $params['do_check_size'] === FALSE) {
      $locations = variable_get('xc_solr_remove_lat_locations', array());
    }

    if (empty($locations) && !empty($params['solr servers'])) {
      $solr_servers = $params['solr servers'];
    }
    else {
      $solr_servers = xc_solr_locations2solrs($locations);
    }

    foreach ($solr_servers as $solr) {
      if (is_null($solr)) {
        xc_log_info('solr', '$solr is NULL');
        continue;
      }

      try {
        $query = 'metadata_id_s:("' . join('" OR "', $_xc_solr_batch_remove) . '")';
        xc_log_info('solr', 'delete ' . $query);
        $solr->deleteByQuery($query);
      }
      catch (Exception $e) {
        xc_log_error('xc_solr', t('Problems during deletion: %e',
          array('%e' => $e->getMessage())));
      }
    }
    $_xc_solr_batch_remove = array();

    if (!empty($locations)) {
      variable_set('xc_solr_remove_lat_locations', $locations);
    }
  }
}

/**
 * Checking whether the Solr instance is running or not.
 *
 * @param $locations (Array)
 *   Array of storage location objects
 * @return (Array) An array of state reports. The key of the array is the
 *   location id, the value is an associative array, having the following keys:
 *   'url' (String) the URL of Solr,
 *   'running' (Boolean) TRUE is Solr is running, FALSE if Solr is stopped
 *   'response_time' (float) The response time of Solr (in the case it is
 *   running).
 */
function xc_solr_ping($locations) {
  global $_xc_solr_obj;

  $results = array();
  foreach ($locations as $location) {
    if (!$location->has_solr_type) {
      continue;
    }
    $sid = xc_solr_get_sid($location->location_id);
    $current_solr = $_xc_solr_obj[$sid];
    if (is_null($current_solr)) {
      continue;
    }
    $results[$location->location_id]['url'] = $current_solr->getUrl();
    try {
      $result = $current_solr->ping();
      if ($result === FALSE) {
        $results[$location->location_id]['running'] = FALSE;
      }
      else {
        $results[$location->location_id]['response_time'] = $result;
        $results[$location->location_id]['running'] = TRUE;
      }
    }
    catch (Exception $e) {
      xc_log_error('xc_solr', t('Problems during deletion: %e', array('%e' => $e->getMessage())));
      $results[$location->location_id]['running'] = FALSE;
    }
  }
  return $results;
}

/**
 * Implementation of hook_xc_store
 * @param $object
 * @param $location
 * @param $params
 * @return unknown_type
 */
function xc_solr_xc_store(&$object, $locations, $params = array()) {
  global $_xc_solr_batch_documents, $times, $_oaiharvester_statistics;

  $t0 = microtime(TRUE);
  if (!isset($_xc_solr_batch_documents)) {
     $_xc_solr_batch_documents = array();
  }
  if (!isset($times)) {
    $times = array(
      'record_count' => 0,
      'total'    => 0.0,
      'solarize' => 0.0,
      'document' => 0.0,
      'batch'    => 0.0,
    );
  }

  $solrs = xc_solr_locations2solrs($locations);
  $t1 = microtime(TRUE);
  $times['solarize'] += $t1 - $t0;

  if (!empty($solrs)) {
    $t_to_document = microtime(TRUE);
    require_once('xc_solr.index.inc');
tombui's avatar
tombui committed
    $document = xc_solr_metadata_to_solr_factory($object, 'iterate over indexes');
    $t_to_document2 = microtime(TRUE);
    xc_oaiharvester_statistics_set('02 bridge/03 _xc_store/06 hook_xc_store/solr_xc_store/01 create Solr document', abs($t_to_document2 - $t_to_document));
    xc_oaiharvester_statistics_set('toSolr', abs($t_to_document2 - $t_to_document));
    $_xc_solr_batch_documents[] = $document;
  }
  $t2 = microtime(TRUE);
  $times['document'] += $t2 - $t1;

  $indexed = FALSE;
  if (XC_BATCH_SIZE == 0 || XC_BATCH_SIZE == count($_xc_solr_batch_documents)) {
    xc_log_info('solr', 'call batch index: ' . count($_xc_solr_batch_documents));
    $times['record_count'] += count($_xc_solr_batch_documents);
    _xc_solr_batch_index(TRUE, $solrs, '02 bridge/03 _xc_store/06 hook_xc_store/solr_xc_store');
    $indexed = TRUE;

    // cleanups
    foreach ($_xc_solr_batch_documents as $_document) {
      unset($_document);
    }

    $_xc_solr_batch_documents = array();
  }
  $t3 = microtime(TRUE);
  $times['batch'] += ($t3 - $t2);
  $times['total'] += ($t3 - $t0);

  if ($indexed) {
    xc_log_info('xc_solr',
      t('Number of documents: %count, total time: %total, prepare Solr servers: %solarize (%solarize-pc%), creating Solr documents: %document (%document-pc%), save Solr documents: %batch (%batch-pc)%',
        array(
          '%count'       => $times['record_count'],
          '%total'       => sprintf("%01.2f", $times['total']),
          '%solarize'    => sprintf("%01.2f", $times['solarize']),
          '%solarize-pc' => sprintf("%01.2f", ($times['solarize'] * 100 / $times['total'])),
          '%document'    => sprintf("%01.2f", $times['document']),
          '%document-pc' => sprintf("%01.2f", ($times['document'] * 100 / $times['total'])),
          '%batch'       => sprintf("%01.2f", $times['batch']),
          '%batch-pc'    => sprintf("%01.2f", ($times['batch'] * 100 / $times['total']))
        )
      )
    );
  }
  xc_oaiharvester_statistics_set('02 bridge/03 _xc_store/06 hook_xc_store/solr_xc_store', abs($t3 - $t0));
}


function xc_solr_get_solr_field_name($field, $suffix = -1) {
  static $cache;
  if (!isset($cache[$field][$suffix])) {
    $cache[$field][$suffix] = str_replace(':', '__', $field) . ($suffix != -1 ? $suffix : '');
  }
  return $cache[$field][$suffix];
}

/**
 * Add field to a Solr document
 *
 * @param $document (Object)