The COUNTER Reports Web Service

From Plnwiki

Provides COUNTER reports of content serving activity in the LOCKSS daemon.

It provides the same COUNTER reports that may be obtained through the LOCKSS Daemon Administration web interface.
Its API is here.

COUNTER (Counting Online Usage of NeTworked Electronic Resources) is an international organization that sets standards for the recording and reporting of online usage statistics of library assets.

For additional information, see

The most recently published standard is the Release 4 of the COUNTER Code of Practice for e-Resources document, dated April 2012; this is the specification being followed by the LOCKSS software.


The COUNTER Reports web service WSDL (Web Services Description Language) file, an XML file that describes the functionality of a web service, can be obtained from the LOCKSS web application; if the application is running on port 8081 of localhost, the URL


will display the WSDL file of the COUNTER Reports web service.

The WSDL file is particularly useful to automatically generate client stubs and other artifacts.

For Java, two tools that are widely available are wsimport and wsdl2java.

For Python, there is wsdl2py.


The source of the data in the COUNTER reports are the requests for content processed through the LOCKSS system.

To be able to record the request for content, it is necessary that both COUNTER reports and metadata indexing are enabled and that the metadata of the AU that corresponds to the requested content has been extracted and indexed.

The following configuration parameters are required:

Even if COUNTER reports and metadata indexing are enabled, if the AU metadata has not been indexed by the time the content request arrives to the LOCKSS system, the LOCKSS software will not be able to identify the request as one that is significant for the COUNTER reports and it will serve the content but it will not record it, so it will not appear in any subsequent COUNTER reports.

After a content request is recorded as such in LOCKSS, it needs to be aggregated before it can appear in COUNTER reports. The aggregation process occurs in the background at specified configurable intervals, hourly by default.

Any content requests that arrive between the last aggregation process and the time of generation of a COUNTER report will not be included in the report, even if they should be included in it. They are not lost permanently, though; they will appear in future reports generated after the next aggregation process.

For performance reasons, if a report is requested multiple times during the same day with identical parameters, the report is generated only the first time, before being saved and downloaded; subsequent requests result in the same report being downloaded without being re-generated first.


The following is an example of a web service client that generates a Journal 1L COUNTER report for the year of 2013 in comma-separated format:

import javax.xml.namespace.QName;


public class CounterReportsWsExample {
  private static final String USER_NAME = "lockss-u";
  private static final String PASSWORD = "lockss-p";
  private static final String ADDRESS_LOCATION =
  private static final String TARGET_NAMESPACE =
  private static final String SERVICE_NAME = "CounterReportsServiceImplService";

   * The main method.
   * @param args
   *          A String[] with the command line arguments.
   * @throws Exception
  public static void main(String args[]) throws Exception {
    CounterReportsWsExample example = new CounterReportsWsExample();

    // Authenticate.

    // Get a proxy for the service.
    Service service = Service.create(new URL(ADDRESS_LOCATION), new QName(
    CounterReportsService proxy = service.getPort(CounterReportsService.class);

    // Specify the parameters of the COUNTER report to be generated.
    CounterReportParams params = new CounterReportParams();

    // Generate the COUNTER report.
    CounterReportResult result = proxy.getCounterReport(params);
    System.out.println("result = " + result);

    String reportFileName = result.getFileName();
    File reportFile = new File("/tmp", reportFileName);
    System.out.println("reportFile = " + reportFile.getAbsolutePath());

    // Write the received file.
    InputStream dhis = null;
    FileOutputStream fos = null;
    byte[] buffer = new byte[1024 * 1024];
    int bytesRead = 0;

    try {
      dhis = result.getDataHandler().getInputStream();
      fos = new FileOutputStream(reportFile);

      while ((bytesRead = != -1) {
	fos.write(buffer, 0, bytesRead);
    } finally {
      if (dhis != null) {
	try {
	} catch (IOException ioe) {
	      .println("Exception caught closing DataHandler input stream.");

      if (fos != null) {

   * Sets the authenticator that will be used by the networking code when the
   * HTTP server asks for authentication.
  private void authenticate() {
    Authenticator.setDefault(new Authenticator() {
      protected PasswordAuthentication getPasswordAuthentication() {
	return new PasswordAuthentication(USER_NAME, PASSWORD.toCharArray());