...
 
Commits (238)
......@@ -17,30 +17,30 @@ What to check?
- after installation finally finished you have the following default values:
XC Metadata module
1) default metadata storage location (admin/xc/metadata/location)
2) Dublin Core and XC schema formats (admin/xc/metadata/format)
1) default metadata storage location (admin/config/xc/metadata/location)
2) Dublin Core and XC schema formats (admin/config/xc/metadata/format)
XC Index module
1) Fullfilled Attribute handling tables:
XC work attributes (admin/xc/index/attribute/work)
XC expression attributes (admin/xc/index/attribute/expression)
XC manifestation attributes (admin/xc/index/attribute/manifestation)
XC holdings attributes (admin/xc/index/attribute/holdings)
XC item attributes (admin/xc/index/attribute/item)
XC work attributes (admin/config/xc/index/attribute/work)
XC expression attributes (admin/config/xc/index/attribute/expression)
XC manifestation attributes (admin/config/xc/index/attribute/manifestation)
XC holdings attributes (admin/config/xc/index/attribute/holdings)
XC item attributes (admin/config/xc/index/attribute/item)
2) Filled field indexing tables:
OAI DC fields (admin/xc/index/field_type/oai_dc)
XC schema fields (admin/xc/index/field_type/xc)
3) You have a fullfilled 'Manage facets' page (admin/xc/index/facets), with 'Format'
OAI DC fields (admin/config/xc/index/field_type/oai_dc)
XC schema fields (admin/config/xc/index/field_type/xc)
3) You have a fullfilled 'Manage facets' page (admin/config/xc/index/facets), with 'Format'
and 'Type of content' facets as conditional ones
OAI Harvester module
1) If you installed Drupal with XC profile you should have at least one
repository in the list of repositories page (admin/xc/harvester/repository)
repository in the list of repositories page (admin/config/xc/harvester/repository)
2) If you installed Drupal with XC profile you should have at least one
schedule in Scheduled harvests page (admin/xc/harvester/schedule)
schedule in Scheduled harvests page (admin/config/xc/harvester/schedule)
XC Browse module
1) You should have the definition of four Browse pages at (admin/xc/browse). The
1) You should have the definition of four Browse pages at (admin/config/xc/browse). The
first should have four tabs (a.k.a. content panes).
2) You should access these four Browse pages at xc_browse.
......
INTALLATION Guide for the Drupal Toolkit installation package
For more information, please consult the Drupal Handbook pages like
......@@ -378,7 +379,7 @@ Setup Drupal Toolkit if you have an existing Drupal installed
- create storage
-- go to eXtensible Catalog (XC) > Metadata > Storage locations > Add location
(admin/xc/metadata/location/add)
(admin/config/xc/metadata/location/add)
-- fill the form:
Name: default
Description: default location
......@@ -391,7 +392,7 @@ Description: default location
-- click Add storage location
- setup NCIP
-- go to NCIP > NCIP providers > Add NCIP provider (admin/xc/ncip/provider/add)
-- go to NCIP > NCIP providers > Add NCIP provider (admin/config/xc/ncip/provider/add)
-- fill the form:
Name: Rush Rhees Library
Description: University of Rochester, Rush Rhees Library, NCIP provider
......@@ -404,21 +405,21 @@ Value: University of Rochester
-- click Add NCIP provider
- register an OAI-PMH repository
-- go to OAI Harvester > Repositories > Add Repository (admin/xc/harvester/repository/add)
-- go to OAI Harvester > Repositories > Add Repository (admin/config/xc/harvester/repository/add)
-- fill the form:
Name: MST 90
Url: http://128.151.244.133:8080/MST/MARCToXCTransformation-Service/oaiRepository
-- click Submit and validate
- setup ILS (this connects NCIP instances to field in a metadata record)
-- go to eXtensible Catalog (XC) > ILS settings > Add new ILS settings (admin/xc/ils/add)
-- go to eXtensible Catalog (XC) > ILS settings > Add new ILS settings (admin/config/xc/ils/add)
-- fill the form:
OAI provider: MST 90 (this field will be deleted soon)
NCIP server: Rush Rhees Library
Bib identifier field: xc:recordID_NRU
- create a scheduled harvest
-- go to OAI Harvester > Scheduled harvests > Add scheduled harvest (admin/xc/harvester/schedule/step1)
-- go to OAI Harvester > Scheduled harvests > Add scheduled harvest (admin/config/xc/harvester/schedule/step1)
-- fill the form:
Select repository: MST 90 (default, and only one)
Schedule: weekly
......@@ -431,14 +432,14 @@ Choose Parsing Mode: Regular expression based
Since the next steps require Solr running, be sure, that you started Solr.
- launch scheduled harvest manually
-- Go to OAI Harvester > Scheduled harvests > MST 90 - Weekly (admin/xc/harvester/schedule/[x]/start)
-- Go to OAI Harvester > Scheduled harvests > MST 90 - Weekly (admin/config/xc/harvester/schedule/[x]/start)
(where [x] is a number refering to the ID of the harvester. If you follow this
guide, the identifier will be 1, so the path will be admin/xc/harvester/schedule/1/start)
guide, the identifier will be 1, so the path will be admin/config/xc/harvester/schedule/1/start)
-- click Harvest
It will take for a while.
- re-structure index
-- Go to eXtensible Catalog (XC) > Solr > de-FRBR-ize index (admin/xc/solr/defrbrize_index)
-- Go to eXtensible Catalog (XC) > Solr > de-FRBR-ize index (admin/config/xc/solr/defrbrize_index)
The metadata are stored in the following tables:
- xc_entity_properties
......
......@@ -29,7 +29,7 @@ the included patch for Drupal core. Information about applying patches to
Drupal can be found at: http://drupal.org/patch/apply
You will need the "patch" application and knowledge of using your operating
systems command line. All this information can be found by following the
system's command line. All this information can be found by following the
previous link.
If you have all the requirements to apply the patch on your system, follow
......
name = "EZProxy URL Rewrite"
description = "Rewrite URL links based on a user’s IP address and other advanced options; allowing IP-protected content to be forwarded to an EZProxy or another proxy referral server"
core = "6.x"
package = "eXtensible Catalog (XC) System"
\ No newline at end of file
description = "Rewrite URL links based on a user's IP address and other advanced options; allowing IP-protected content to be forwarded to an EZProxy or another proxy referral server"
core = 7.x
package = "eXtensible Catalog (XC) System"
dependencies[] = xc
dependencies[] = xc_util
......@@ -6,6 +6,11 @@
* @copyright (c) 2010-2011 eXtensible Catalog Organization
*/
/**
* Implements of hook_uninstall().
*
* Removes module's variables
*/
function ezproxy_url_rewrite_uninstall() {
variable_del('ezproxy_url_rewrite_enabled');
variable_del('ezproxy_url_rewrite_javascript_enabled');
......
......@@ -20,7 +20,7 @@ About the NCIP Module
The NCIP module is an extensible API that allows developers to create
applications that communicate via the NCIP protocol.
The NCIP modules API creates, configures, and manages NCIP applications,
The NCIP module's API creates, configures, and manages NCIP applications,
connections, and messages. It also provides a simple user interface for listing
and modifying default NCIP settings as well as application and provider-specific
settings.
......@@ -35,8 +35,7 @@ The NCIP module provides an API for creating and managing NCIP applications,
connections, and messages:
- An application initiates or responds to connections to communicate with
other applications
- A connection is either a single TCP connection or a collection of HTTP
requests between two applications
- A connection is a collection of HTTP requests between two applications
- A message is an XML document encoded according to UTF-8 specifications
and streamed as-is over a connection
......@@ -47,73 +46,51 @@ three classes are:
- NCIPConnection
- NCIPMessage
NCIPApplication objects manage a collection of connections and stores specific
properties of the application, such as its “from” agency and system ID and
authentication, application profile type, and whether it will initiate or
respond to messages sent over a connection.
NCIPApplication objects manage a collection of connections and stores
specific properties of the application, such as the supported NCIP version,
“from” agency and system ID, and other message header options for authentication
and application profile type.
NCIPConnection objects belong to an NCIPApplication object and manage and
facilitate the transport of a collection of messages and stores specific
properties of the application on the opposite end, such as its “to” agency
and system ID and authentication and whether it will initiate or respond to
messages sent over the connection.
NCIPConnection objects belong to an NCIPApplication object and are of a
particular type specifying whether it is initiating or responding. These
objects facilitate the transport of messages to and from applications, and
store specific properties of the connected application, such as its “to” agency
and system ID and other message header options for authentication.
NCIPMessage objects should belong to an NCIPConnection object, but in rare
situations may not. A message gone rouge can exist outside the scope of an
NCIPConnection object, and therefore, completely outside the scope of an
NCIPApplication object.
situations, they may not. These objects manage the content of an XML document,
allowing it to be edited in a more intuitive manner and transformed to and from
an XML string, SimpleXMLElement object, DOMDocument object, or NCIPMessage
object.
NCIPMessage objects manage the content of the XML document, allowing it to be
edited in a more intuitive manner and transformed to and from an XML string,
XML array structure, DOMDocument object, or another NCIPMessage object.
Implementation Profiles
-----------------------
On its own, the NCIP module does not implement any NCIP services (or verbs); it
only facilitates the processes necessary to implement those services. This work
must be done by other modules that take advantage of the NCIP module’s features
and API. An example of such module is the NCIP Provider module, included with
the Drupal Toolkit.
Implementation profiles would allow the NCIP module to automatically support
multiple NCIP services, data elements, and schemes as well as multiple versions
of the NCIP protocol.
These configuration scripts are made up of namespaced functions, similar to
Drupal hooks. These functions should be within [profile_name].inc files that
are manually placed in the /ncip/profiles folder.
Two implementation profiles come with the NCIP module by default:
- NCIP Z39-83
- XC NCIP Implementation
Each function within the profile returns a complex array structure either
specifying information about the profile or returning information about the
profile’s services, data elements, or schemes.
Currently, the two profiles serve as an example for future profile structures;
however, they are not used at all in the NCIP module. This feature may perhaps
show up in future versions of the NCIP module.
Implementation
--------------
On its own, the NCIP module does not implement any NCIP services (or verbs);
it only builds the foundation necessary to communicate over this protocol in
Drupal. Other modules must then take advantage of the NCIP module's features
and API to construct or parse messages sent or received to and from NCIP
applications. An example of such module is the NCIP Provider module, included
with the Drupal Toolkit.
Current Features
----------------
The module currently acts as an initiating application, with the capabilities
to send and receive messages to and from applications over an HTTP connection.
The module currently can create applications only with initiating connections
that expect a response after messages have been sent via HTTP. It supports all
current versions of the NCIP protocol.
Future Features
---------------
In the future, the NCIP module would likely be able to act as both an initiating
and responding application, support HTTP 1.1 and TCP connections, and make more
use of implementation profiles.
In the future, the NCIP module may support both an initiating and responding
connections, connect via TCP, or make use of implementation profiles.
Developer Information
---------------------
See the code documentation for more information on how to use the NCIP
modules API.
module's API.
About the eXtensible Catalog
......
......@@ -49,7 +49,7 @@ class NCIPApplication {
public static function install($namespace, $profile = 'ncip', $version = 2,
$module = 'ncip', $title = '', $description = '') {
if (!in_array($version,array(1,1.01,2,2.01))) { // valid versions
if (!in_array($version, array(1, 1.01, 2, 2.01))) { // valid versions
drupal_set_message(t('NCIP Version Invalid. Unable to install namespace %ns.',
array('%ns' => $namespace)), 'error');
return false;
......@@ -81,7 +81,11 @@ class NCIPApplication {
*/
public static function uninstall($namespace) {
$sql = "DELETE FROM {ncip_application} WHERE namespace = '%s'";
if (db_query($sql, $namespace)) {
// TODO Please review the conversion of this statement to the D7 database API syntax.
/* db_query($sql, $namespace) */
if (db_delete('ncip_application')
->condition('namespace', $namespace)
->execute()) {
return TRUE;
}
else {
......@@ -101,7 +105,7 @@ class NCIPApplication {
*/
public static function load($namespace) {
$sql = "SELECT namespace FROM {ncip_application} WHERE namespace = '%s'";
if (db_result(db_query($sql, $namespace))) {
if (db_query("SELECT namespace FROM {ncip_application} WHERE namespace = :namespace", array(':namespace' => $namespace))->fetchField()) {
self::$applications[$namespace] = empty(self::$applications[$namespace])
? new NCIPApplication($namespace)
: self::$applications[$namespace];
......@@ -120,7 +124,13 @@ class NCIPApplication {
application_profile_type
FROM {ncip_application}
WHERE namespace = '%s'";
$application = db_fetch_object(db_query($sql, $namespace));
$application = db_query("SELECT namespace, profile, version, module, title, description,
from_system_id, from_system_authentication, from_agency_id,
from_agency_authentication, on_behalf_of_agency,
application_profile_type
FROM {ncip_application}
WHERE namespace = :namespace", array(':namespace' => $namespace))->fetchObject();
if ($application) {
$this->namespace = $application->namespace;
$this->profile = $application->profile;
......@@ -156,15 +166,29 @@ class NCIPApplication {
from_agency_authentication = '%s', on_behalf_of_agency = '%s',
application_profile_type = '%s'
WHERE namespace = '%s'";
db_query($sql, $this->title, $this->description,
serialize($this->from_system_id), $this->from_system_authentication,
serialize($this->from_agency_id), $this->from_agency_authentication,
serialize($this->on_behalf_of_agency),
serialize($this->application_profile_type), $this->namespace);
// TODO Please review the conversion of this statement to the D7 database API syntax.
/* db_query($sql, $this->title, $this->description, serialize($this->from_system_id), $this->from_system_authentication, serialize($this->from_agency_id), $this->from_agency_authentication, serialize($this->on_behalf_of_agency), serialize($this->application_profile_type), $this->namespace) */
db_update('ncip_application')
->fields(array(
'title' => $this->title,
'description' => $this->description,
'from_system_id' => serialize($this->from_system_id),
'from_system_authentication' => $this->from_system_authentication,
'from_agency_id' => serialize($this->from_agency_id),
'from_agency_authentication' => $this->from_agency_authentication,
'on_behalf_of_agency' => serialize($this->on_behalf_of_agency),
'application_profile_type' => serialize($this->application_profile_type),
))
->condition('namespace', $this->namespace)
->execute();
// Destroy all connections
$sql = "DELETE FROM {ncip_connection} WHERE application = '%s'";
db_query($sql, $this->namespace);
// TODO Please review the conversion of this statement to the D7 database API syntax.
/* db_query($sql, $this->namespace) */
db_delete('ncip_connection')
->condition('application', $this->namespace)
->execute();
}
/**
......@@ -204,6 +228,7 @@ class NCIPApplication {
$record->to_agency_id = serialize(array());
$record->use_session = TRUE;
$record->use_cookies = TRUE;
$record->last_modification = time();
$result = drupal_write_record('ncip_connection', $record);
if ($result) {
$connection_id = $record->connection_id;
......@@ -226,7 +251,12 @@ class NCIPApplication {
}
$sql = "DELETE FROM {ncip_connection}
WHERE connection_id = %d AND application = '%s'";
db_query($sql, $connection_id, $this->namespace);
// TODO Please review the conversion of this statement to the D7 database API syntax.
/* db_query($sql, $connection_id, $this->namespace) */
db_delete('ncip_connection')
->condition('connection_id', $connection_id)
->condition('application', $this->namespace)
->execute();
unset($this->connections[$connection_id]);
}
......@@ -239,11 +269,15 @@ class NCIPApplication {
* NCIPConnection object
*/
public function load_connection($connection_id) {
if (!($this->connections[$connection_id] instanceof NCIPConnection)) {
if (!isset($this->connections[$connection_id])
|| !($this->connections[$connection_id] instanceof NCIPConnection)) {
$sql = "SELECT connection_id
FROM {ncip_connection}
WHERE connection_id = %d AND application = '%s'";
if (!db_result(db_query($sql, $connection_id, $this->namespace))) {
WHERE connection_id = :connection_id AND application = :application";
if (!db_query($sql, array(
':connection_id' => $connection_id,
':application' => $this->namespace)
)->fetchField()) {
return FALSE;
}
$this->connections[$connection_id] = new NCIPConnection($this, $connection_id);
......@@ -254,7 +288,10 @@ class NCIPApplication {
/** Getters and setters **/
public function set_from_system_id($scheme, $value) {
$this->from_system_id = array('scheme' => $scheme, 'value' => $value);
$this->from_system_id = array(
'scheme' => $scheme,
'value' => $value,
);
}
public function get_from_system_id() {
......@@ -270,7 +307,10 @@ class NCIPApplication {
}
public function set_from_agency_id($scheme, $value) {
$this->from_agency_id = array('scheme' => $scheme, 'value' => $value);
$this->from_agency_id = array(
'scheme' => $scheme,
'value' => $value,
);
}
public function get_from_agency_id() {
......@@ -288,7 +328,7 @@ class NCIPApplication {
public function set_application_profile_type($scheme, $value) {
$this->application_profile_type = array(
'scheme' => $scheme,
'value' => $value
'value' => $value,
);
}
......@@ -299,7 +339,7 @@ class NCIPApplication {
public function set_on_behalf_of_agency($scheme, $value) {
$this->on_behalf_of_agency = array(
'scheme' => $scheme,
'value' => $value
'value' => $value,
);
}
......@@ -316,7 +356,7 @@ class NCIPApplication {
}
public function get_module() {
return $this->modules;
return $this->module;
}
public function get_profile() {
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
name = "NCIP"
description = "Client and library for NISO Circulation Interchange Protocol (NCIP/Z39.83)"
core = "6.x"
package = "eXtensible Catalog (XC) System"
\ No newline at end of file
core = 7.x
package = "eXtensible Catalog (XC) System"
dependencies[] = xc_util
files[] = lib/NCIPApplication.php
files[] = lib/NCIPConnection.php
files[] = lib/NCIPMessage.php
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -13,7 +13,7 @@ function xc_ncip_info() {
$info['xc'] = array(
'name' => 'XC NCIP Implementation',
'description' => t('XC NCIP provider'),
'required' => array('ncip')
'required' => array('ncip'),
);
return $info;
}
......@@ -25,7 +25,7 @@ function xc_ncip_services(&$services) {
$services['xc'] = array(
'XCLookupUserService' => array(
'name' => t('XC Lookup User Service'),
'description' => t('This service is used to look up information about a user. It is almost identical to the Lookup User Service, but allows additional information to be queried which is not exposed by the NCIP standard. The only required parameter is the users unique identifier.'),
'description' => t('This service is used to look up information about a user. It is almost identical to the Lookup User Service, but allows additional information to be queried which is not exposed by the NCIP standard. The only required parameter is the user\'s unique identifier.'),
'type' => NCIP_LOOKUP_SERVICE,
'messages' => array(
NCIP_INITIATION_MESSAGE => array(
......@@ -44,9 +44,9 @@ function xc_ncip_services(&$services) {
'RecalledItemsDesired' => array(),
'UserFiscalAccountDesired' => array(),
'MessagesDesired ' => array(),
)
)
)
),
),
),
),
NCIP_RESPONSE_MESSAGE => array(
'XCLookupUserResponse' => array(
......@@ -55,12 +55,12 @@ function xc_ncip_services(&$services) {
'required' => array(
'Problem' => array(
'conditions' => array(
NCIP_USAGE_OR => array('UniqueUserId')
)
NCIP_USAGE_OR => array('UniqueUserId'),
),
),
'UniqueUserId' => array(
'conditions' => array(
NCIP_USAGE_OR => array('Problem')
NCIP_USAGE_OR => array('Problem'),
),
),
),
......@@ -70,11 +70,11 @@ function xc_ncip_services(&$services) {
'RecalledItem' => array(),
'UserFiscalAccount' => array(),
'RecalledItem' => array(),
)
)
)
)
)
),
),
),
),
),
),
'XCGetAvailabilityService' => array(
'name' => t('XC Get Availability Service'),
......@@ -88,8 +88,8 @@ function xc_ncip_services(&$services) {
'required' => array(
'UniqueItemId' => array(),
),
)
)
),
),
),
NCIP_RESPONSE_MESSAGE => array(
'XCGetAvailabilityResponse' => array(
......@@ -98,19 +98,19 @@ function xc_ncip_services(&$services) {
'required' => array(
'Problem' => array(
'conditions' => array(
NCIP_USAGE_OR => array('XCItemAvailability')
)
NCIP_USAGE_OR => array('XCItemAvailability'),
),
),
'XCItemAvailability' => array(
'conditions' => array(
NCIP_USAGE_OR => array('Problem')
NCIP_USAGE_OR => array('Problem'),
),
),
),
)
)
)
)
),
),
),
),
),
'XCOpenURLRequestItemService' => array(
'name' => t('XC Open URL Request Item Service'),
......@@ -124,13 +124,13 @@ function xc_ncip_services(&$services) {
'required' => array(
'AuthenticationInput' => array(
'conditions' => array(
NCIP_USAGE_OR => array('UniqueUserId')
)
NCIP_USAGE_OR => array('UniqueUserId'),
),
),
'UniqueUserId' => array(
'conditions' => array(
NCIP_USAGE_OR => array('AuthenticationInput')
)
NCIP_USAGE_OR => array('AuthenticationInput'),
),
),
'OpenUrlQueryString' => array(),
),
......@@ -138,9 +138,9 @@ function xc_ncip_services(&$services) {
'PickupExpiryDate' => array(),
'ShippingInformation' => array(),
'ShippingInstructions' => array(),
)
)
)
),
),
),
),
NCIP_RESPONSE_MESSAGE => array(
'XCOpenURLRequestItemResponse' => array(
......@@ -149,24 +149,24 @@ function xc_ncip_services(&$services) {
'required' => array(
'Problem' => array(
'conditions' => array(
NCIP_USAGE_OR => array('XCItemAvailability')
)
NCIP_USAGE_OR => array('XCItemAvailability'),
),
),
'UniqueUserId' => array(
'conditions' => array(
NCIP_USAGE_OR => array('Problem')
NCIP_USAGE_OR => array('Problem'),
),
),
'UniqueRequestId' => array(
'conditions' => array(
NCIP_USAGE_OR => array('Problem')
NCIP_USAGE_OR => array('Problem'),
),
),
),
)
)
)
)
),
),
),
),
),
'XCOpenURLRenewItemService' => array(
'name' => t('XC Open URL Renew Item Service'),
......@@ -180,13 +180,13 @@ function xc_ncip_services(&$services) {
'required' => array(
'AuthenticationInput' => array(
'conditions' => array(
NCIP_USAGE_OR => array('UniqueUserId')
)
NCIP_USAGE_OR => array('UniqueUserId'),
),
),
'UniqueUserId' => array(
'conditions' => array(
NCIP_USAGE_OR => array('AuthenticationInput')
)
NCIP_USAGE_OR => array('AuthenticationInput'),
),
),
'OpenUrlQueryString' => array(),
),
......@@ -194,9 +194,9 @@ function xc_ncip_services(&$services) {
'UniqueItemId' => array(),
'DesiredDateForReturn' => array(),
'DesiredDateDue' => array(),
)
)
)
),
),
),
),
NCIP_RESPONSE_MESSAGE => array(
'XCOpenURLRenewItemResponse' => array(
......@@ -208,11 +208,11 @@ function xc_ncip_services(&$services) {
'requested' => array(
'DateDue' => array(),
'DesiredDateForReturn' => array(),
)
)
)
)
)
),
),
),
),
),
),
);
return $services;
......@@ -248,27 +248,27 @@ function xc_ncip_data_elements(&$data_elements) {
'type' => NCIP_COMPLEX_ELEMENT,
'data elements' => array(
'DatePlaced' => array(
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE,
),
'PickupDate' => array(
'usage' => NCIP_USAGE_ZERO_OR_ONE
'usage' => NCIP_USAGE_ZERO_OR_ONE,
),
'UniqueItemId' => array(
'usage' => NCIP_USAGE_ZERO_OR_ONE,
),
)
),
),
'XCItemAvailability' => array(
'name' => t('XC Item Availability'),
'type' => NCIP_COMPLEX_ELEMENT,
'data elements' => array(
'ItemId' => array(
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE,
),
'Availability' => array(
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE
)
)
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE,
),
),
),
'ItemId' => array(
'name' => t('Item Id'),
......@@ -293,11 +293,11 @@ function xc_ncip_data_elements(&$data_elements) {
);
$data_elements['Problem']['data elements']['ErrorCode'] = array(
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE,
);
$data_elements['Problem']['data elements']['ErrorMessage'] = array(
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE
'usage' => NCIP_USAGE_ONE_AND_ONLY_ONE,
);
return $data_elements;
......@@ -310,4 +310,3 @@ function xc_ncip_schemes(&$schemes) {
$schemes['xc'] = array();
return $schemes;
}
@CHARSET "UTF-8";
#time_statistics .collapsed td span { color: cornflowerblue; }
#time_statistics td, #time_statistics th {text-align: right; }
#time_statistics td.label, #time_statistics th.label {text-align: left; }
@CHARSET "UTF-8";
#oaiharvester-schedule-edit-form fieldset#edit-schedule label {
display: inline;
}
This diff is collapsed.
/**
* Collapses a hierarchial table's rows on click
*/
(function ($) {
$(document).ready(function() {
$('#time_statistics tbody tr td.label').css('cursor', 'pointer');
$('#time_statistics tbody tr').click(function() {
var collapsed = $(this).hasClass('collapsed');
var id = '^' + $(this).attr('id') + '/';
var hasChild = false;
// Finds and hides/shows children. It is a child if it's id starts as the parent's id.
$('#time_statistics tbody tr').each(function (index, domEle) {
if (typeof $(domEle).attr('id') != 'undefined' && $(domEle).attr('id').match(id)) {
hasChild = true;
if (collapsed) {
$(domEle).show();
}
else {
$(domEle).hide();
}
}
});
// Changes its own class.
if (hasChild) {
if (collapsed) {
$(this).removeClass('collapsed');
}
else {
$(this).addClass('collapsed');
}
}
});
});
}(jQuery));
\ No newline at end of file
......@@ -38,4 +38,7 @@ interface IOAIParser {
/** Get the statistics */
public function getStatistics();
}
\ No newline at end of file
/** Get the errors regarding to XML malformadness */
public function getParserErrors();
}
......@@ -19,17 +19,42 @@ class OAIDomParser implements IOAIParser {
private $httpCode;
private $httpErrorMsg;
private $statistics;
private $parserErrors = array();
function __construct($content, $httpCode = 200) {
$t0 = microtime(TRUE);
$this->httpCode = $httpCode;
if (strlen(trim($content)) == 0) {
$parserErrors[] = t('The XML to parse is an empty string.');
xc_log_error('DOMParser', 'The XML to parse is an empty string.');
return;
}
$oaiDom = new SimpleXMLIterator($content);
$this->statistics['response'] = microtime(TRUE) - $t0;
$this->statistics['records'] = '';
$this->oai = $oaiDom;
$this->httpCode = $httpCode;
if (!$oaiDom) {
$lines = explode("\n", $content);
$errors = libxml_get_errors();
foreach ($errors as $error) {
$output = $lines[$error->line - 1] . "<br />\n";
$output .= str_repeat('-', $error->column) . "^<br />\n";
switch ($error->level) {
case LIBXML_ERR_WARNING: $level = t('Warning'); break;
case LIBXML_ERR_ERROR: $level = t('Error'); break;
case LIBXML_ERR_FATAL: $level = t('Fatal error'); break;
}
$output .= $level . ' ' . $error->code . ': ' . $error->message . ' (' . $error->line . ':' . $error->column . ')';
$parserErrors[] = $output;
}
libxml_clear_errors();
}
}
function hasErrors() {
return isset($this->oai->error) || ((int)$this->httpCode != 200);
return isset($this->oai->error);
}
function listErrors() {
......@@ -52,14 +77,14 @@ class OAIDomParser implements IOAIParser {
}
function getRecordCount() {
if ($this->recordCount == -1) {
$this->recordCount = $this->oai->ListRecords->record->count();
if ($this->recordCount == -1 && isset($this->oai->ListRecords->record)) {
$this->recordCount = $this->oai->ListRecords->record->count();
}
return $this->recordCount;
}
function hasResumptionToken() {
$token = (string)$this->oai->ListRecords->resumptionToken;
$token = (string) $this->oai->ListRecords->resumptionToken;
return !empty($token);
}
......@@ -78,11 +103,11 @@ class OAIDomParser implements IOAIParser {
$token = $this->oai->ListRecords->resumptionToken;
return array(
'attributes' => array(
'completeListSize' => (int)$token->attributes()->completeListSize,
'cursor' => (int)$token->attributes()->cursor,
'expirationDate' => (string)$token->attributes()->expirationDate,
'completeListSize' => (int) $token->attributes()->completeListSize,
'cursor' => (int) $token->attributes()->cursor,
'expirationDate' => (string) $token->attributes()->expirationDate,
),
'text' => (string)$token
'text' => (string) $token,
);
}
......@@ -95,31 +120,58 @@ class OAIDomParser implements IOAIParser {
}
function parseRecord($record) {
$specs = array();
foreach ($record->header->setSpec as $spec) {
$specs[] = (string)$spec;
}
$dom = dom_import_simplexml($record->metadata);
foreach ($dom->childNodes as $childNode) {
if ($childNode->nodeType == XML_ELEMENT_NODE) {
$metadata = array(
'namespaceURI' => preg_replace('/\/$/', '', $childNode->namespaceURI),
'childNode' => $childNode,
);
break;
try {
$status = isset($record->header->attributes()->status) ? $record->header->attributes()->status : FALSE;
$identifier = (string) $record->header->identifier[0];
$specs = array();
foreach ($record->header->setSpec as $spec) {
$specs[] = (string) $spec;
}
}
return array(
'header' => array(
'@status' => isset($record->header->attributes()->status) ? $record->header->attributes()->status : FALSE,
'identifier' => (string)$record->header->identifier[0],
'datestamp' => (string)$record->header->datestamp[0],
'setSpec' => $specs
),
'metadata' => $metadata,
'about' => isset($record->abouts) ? $record->abouts : FALSE
);
if (!$record->metadata) {
$errorMsq = sprintf('[id: %s, status: %s] Error while parsing XML "%s"', $identifier, $status, $record->metadata);
$this->parserErrors[] = $errorMsq;
xc_log_error('DOMParser', $errorMsq);
}
else {
$dom = dom_import_simplexml($record->metadata);
if ($dom === FALSE) {
$errorMsq = sprintf('[id: %s, status: %s] Error while parsing XML "%s"', $identifier, $status, $record->metadata);
$this->parserErrors[] = $errorMsq;
xc_log_error('DOMParser', $errorMsq);
}
elseif (!$dom->hasChildNodes()) {
$errorMsq = sprintf('No children in metadata: [id: %s, status: %s] xml: "%s"', $identifier, $status, htmlentities($record->metadata));
$this->parserErrors[] = $errorMsq;
xc_log_error('DOMParser', $errorMsq);
}
else {
foreach ($dom->childNodes as $childNode) {
if ($childNode->nodeType == XML_ELEMENT_NODE) {
$metadata = array(
'namespaceURI' => preg_replace('/\/$/', '', $childNode->namespaceURI),
'childNode' => $childNode,
);
break;
}
}
}
}
return array(
'header' => array(
'@status' => $status,
'identifier' => $identifier,
'datestamp' => (string) $record->header->datestamp[0],
'setSpec' => $specs,
),
'metadata' => $metadata,
'about' => isset($record->abouts) ? $record->abouts : FALSE,
);
} catch (Exception $e) {
drupal_set_message('hadnodechild', 'error');
}
}
function getStatistics($type = 'all') {
......@@ -127,12 +179,15 @@ class OAIDomParser implements IOAIParser {
case 'all':
return $this->statistics; break;
case 'response':
return $this->statistics['response'];
return $this->statistics['response']; break;
case 'records':
return $this->statistics['records'];
return $this->statistics['records']; break;
default:
return;
}
}
}
\ No newline at end of file
function getParserErrors() {
return $this->parserErrors;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -6,6 +6,34 @@
* @copyright (c) 2010-2011 eXtensible Catalog Organization
*/
/**
* @addtogroup global variables
* @{
*/
/**
* The collector of the time based statistics of the harvesting.
* @var (array)
*/
global $_oaiharvester_statistics;
/**
* Flag indicates whether or not the current harvesting process is an initial
* harvesting or an incremental one.
* @var (boolean)
*/
global $_oaiharvester_is_initial_harvest;
/**
* Flag indicates whether the harvesting should produce some debugging log entries.
* @var (boolean)
*/
global $_oaiharvester_need_debug;
/**
* @} End of "addtogroup global variables".
*/
/**
* @addtogroup hooks
* @{
......@@ -42,7 +70,7 @@
* </li>
* </ul>
* @param int $schedule_id
* The schedules ID
* The schedule's ID
*/
function hook_oaiharvester_process_record($record, $schedule_id) {
// processing the record
......@@ -111,7 +139,7 @@ function hook_oaiharvester_harvest_finished($success, $results, $operations) {
*
* @param $schedule_id (int)
* The identifier of the schedule. Drupal adds batch sets to this schedule.
* The sets will run after the schedules main operations.
* The sets will run after the schedule's main operations.
*
* @return (array)
* An array of Batch definitions
......@@ -120,25 +148,25 @@ function hook_oaiharvester_additional_harvest_steps($schedule_id) {
//
return array(
array(
'operations' => array(
array($function1, $param1_1, $param1_2),
array($function2, $param2_1, $param2_2),
),
'title' => t($title1),
'init_message' => t($init_message1),
'progress_message' => t($progress_message1),
'finished' => $finishing_function1,
'operations' => array(
array($function1, $param1_1, $param1_2),
array($function2, $param2_1, $param2_2),
),
'title' => $title1,
'init_message' => $init_message1,
'progress_message' => $progress_message1,
'finished' => $finishing_function1,
),
array(
'operations' => array(
array($function3, $param3_1, $param3_2),
array($function4, $param4_1, $param4_2),
),
'title' => t($title1),
'init_message' => t($init_message1),
'progress_message' => t($progress_message1),
'finished' => $finishing_function1,
)
'operations' => array(
array($function3, $param3_1, $param3_2),
array($function4, $param4_1, $param4_2),
),
'title' => $title2,
'init_message' => $init_message2,
'progress_message' => $progress_message2,
'finished' => $finishing_function2,
),
);
}
......@@ -156,16 +184,46 @@ function hook_oaiharvester_harvest_starting($schedule_ids) {
* Respond to the event that a batch has been started
*
* @param $parameters (array)
* The harvest parameters.
*/
function hook_oaiharvester_batch_started($parameters) {
}
/**
* Respond to the event that a batch has been processed.
* Triggered after a step (a pair of set-metadata format) has been harvested.
* OAI-PMH data providers might split the collections into parts, for example
* a library may have 'books', 'journals'. The OAI-PMH protocoll calls them 'sets'.
* According to the protocoll it is not possible to request multiple sets in one
* harvest, so if you want to harvest multiple sets, Drupal Toolkit will create
* "steps" at the background. Each steps harvests one set. So if the admin
* select "books" and "journals", Drupal will harvest books, then trigger this
* hook, then harvest journals, and trigger this hook again, and finally, since
* this was the last step it calls hook_oaiharvester_batch_processed.
*
* @param $has_errors (boolean)
* Flag denoting whether the harvest had errors.
* @param $original_parameters (array)
* The associative array of the harvest parameters.
* @param $start_time (int)
* Timestamp of harvest start time.
*/
function hook_oaiharvester_step_processed($has_errors, $original_parameters, $start_time) {
}
/**
* Triggered after the whole harvester batch has been processed (all steps of
* the sets-metadata formats pairs has been harvested). So this hook is invoked
* only one time contrary to hook_oaiharvester_step_processed which is called
* multiple time if there were multiple set-format pairs.
*
* @param $sets
* @param $current_operation
* @param $sets (array)
* All the batch sets. Each set is an array with two elements, where the first
* element is the name of the function, the second element is the list of
* parameters as an array.
* @param $current_operation_id (int)
* The current operation's identifier, which actually is the index of the operation in the sets array.
* @param $schedule_id (int)
* The schedule ID
*/
......@@ -176,7 +234,7 @@ function hook_oaiharvester_batch_processed($sets, $current_operation, $schedule_
/**
* Add additional rows to the properties page of the schedule.
*
* When you made modification of the schedules form, you would like to view
* When you made modification of the schedule's form, you would like to view
* your properties and their values at the schedule properties page
* (admin/xc/harvester/schedule/%schedule_id). This hook returns additional properties
* of the schedule as an array of label-value arrays.
......@@ -190,12 +248,24 @@ function hook_oaiharvester_batch_processed($sets, $current_operation, $schedule_
function hook_oaiharvester_schedule_view($schedule_id) {
//
return array(
array(t('Storage locations'), theme('item_list', $location_links)),
array(t('Is Solr running?'), theme('item_list', $ping_report)),
array(t("Run 'preparing metadata for search' step?"), $steps_label)
array(t('Storage locations'), theme('item_list', array('items' => $location_links))),
array(t('Is Solr running?'), theme('item_list', array('items' => $ping_report))),
array(t("Run 'preparing metadata for search' step?"), $steps_label),
);
}
/**
* Extends the harvest report with additional information. Called when a report is
* beeing displayed. A module can add additional keys to oaiharvester_batch
* record's "report" column (which is an associative array) during the harvest.
* The main purpose of this function is to format those raw data.
*
* @param $reports (array)
* The content of oaiharvester_batch record's "report" column.
*/
function hook_oaiharvester_harvest_report_view($reports) {
}
/**
* @} End of "addtogroup hooks".
*/
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
name = "OAI Harvester"
description = "OAI-PMH Harvester"
core = 6.x
core = 7.x
package = "eXtensible Catalog (XC) System"
dependencies[] = xc_util
\ No newline at end of file
dependencies[] = xc
dependencies[] = xc_util
files[] = lib/IOAIParser.php
files[] = lib/OAIDomParser.php
files[] = lib/OAIHarvester.php
files[] = lib/OAIRegexParser.php
files[] = lib/class.CurlUtils.php
files[] = tests/oaiharvester.test
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.