[%# A template for a service base code.
    ===================================

    Expected/recognized parameters:

      obj         ... a service definition, type MOSES::MOBY::Def::Service
      ref         ... a CODE returning ref() of the given argument
-%]      
    [%- MACRO is_simple (entry) BLOCK %]
	[%- ref (entry) == 'MOSES::MOBY::Def::PrimaryDataSimple' %]
    [%- END -%]
#-----------------------------------------------------------------
# Authority:    [% obj.authority %]
# Service name: [% obj.name %]
# Generated:    [% USE Date (format = '%d-%b-%Y %H:%M:%S %Z') %][% Date.format %]
# Contact: Martin Senger <martin.senger@gmail.com> or
#          Edward Kawas <edward.kawas@gmail.com>
#-----------------------------------------------------------------

#-----------------------------------------------------------------
# Prepare for getting data from a request and for setting data
# to a response (using a 'personalized' MOSES::MOBY::Job class)
#----------------------------------------------------------------- 

package MOSES::MOBY::Job::[% obj.module_name %];

use MOSES::MOBY::Package;
no strict;
use vars qw( @ISA );
@ISA = qw( MOSES::MOBY::Job );
use strict;

{
    my %_allowed =
	(
	 # inputs
	 [%- FOREACH input IN obj.inputs %]
         '[% input.name %]' => { readonly => 1, type => 
	 [%- IF is_simple(input) %]'[% input.datatype.module_name %]'
	 [%- ELSE %]'[% input.elements.0.datatype.module_name %]', is_array => 1
	 [%- END %] },
	 [%- END %]

	 # outputs
	 [% FOREACH output IN obj.outputs %]
	 '[%- output.name %]' => { type => 
	 [%- IF is_simple(output) %]'[% output.datatype.module_name %]'
	 [%- ELSE %]'[% output.elements.0.datatype.module_name %]', is_array => 1
	 [%- END %] },
	 [%- END %]

	 );

    sub _accessible {
	my ($self, $attr) = @_;
	exists $_allowed{$attr} or $self->SUPER::_accessible ($attr);
    }
    sub _attr_prop {
	my ($self, $attr_name, $prop_name) = @_;
	my $attr = $_allowed {$attr_name};
	return ref ($attr) ? $attr->{$prop_name} : $attr if $attr;
	return $self->SUPER::_attr_prop ($attr_name, $prop_name);
    }
    sub _getter {
	my ($self, $attr_name) = @_;
	return $self->SUPER::_getter ($attr_name)
	    unless exists $_allowed{$attr_name};
	return $self->getData ($attr_name)->data;
    }
    sub _setter {
	my ($self, $attr_name, $attr_type, $value) = @_;
	if (exists $_allowed{$attr_name}) {
	    $self->setData ($value, $attr_name, $attr_type);
	} else {
	    $self->SUPER::_setter ($attr_name, $attr_type, $value);
	}
    }
    sub _adder {
	my ($self, $attr_name, $attr_type, @values) = @_;
	if (exists $_allowed{$attr_name}) {
	    $self->addData ($attr_name, $attr_type, @values);
	} else {
	    $self->SUPER::_adder ($attr_name, $attr_type, @values);
	}
    }
}

#-----------------------------------------------------------------
# Service
#----------------------------------------------------------------- 

package [% obj.module_name %];

use MOSES::MOBY::Base;
use MOSES::MOBY::Service::ServiceBase;
no strict;
use vars qw( @ISA );
@ISA = qw( MOSES::MOBY::Service::ServiceBase );
use FindBin qw( $Bin );
use lib $Bin;
use MOSES::MOBY::Parser;
use MOSES::MOBY::Generators::GenTypes;
use strict;

#-----------------------------------------------------------------
# [% obj.name %]
#   the main method; corresponds to the name of this web service
#----------------------------------------------------------------- 
sub [% obj.name %] {
    my ($self, $data) = @_;

    Log::Log4perl::NDC->push ($$);
    $LOG->info ('*** REQUEST START *** ' . $self->log_request);

    no warnings 'newline';
    my $in_testing_mode = (-f $data);
    use warnings 'newline';
    if ($LOG->is_debug) {
       if ($in_testing_mode) {
	   open (RAWXML, "<$data") or $LOG->logdie ("Cannot open $data: $!\n");
	   $LOG->debug ("Input raw data:\n" . join ('', <RAWXML>));
	   close RAWXML;
       } else {
	   $LOG->debug ("Input raw data (first 1000 characters):\n" . substr ($data, 0, 1000));
       }
    }

    $self->default_throw_with_stack (0) unless $in_testing_mode;

    my $in_package;
    eval {
	my $parser = $self->create_parser
	    ( lowestKnownDataTypes => { [% FOREACH input IN obj.inputs %]'[% input.name %]' => 
					[%- IF is_simple(input) %]'[% input.datatype.name %]',
				        [%- ELSE %]'[% input.elements.0.datatype.name %]',
				        [%- END %]
				        [%- END %] },
	      loadDataTypes        => [ qw( [% FOREACH input IN obj.inputs %]
					[%- IF is_simple(input) %] [% input.datatype.name %]
			                [%- ELSE %] [% input.elements.0.datatype.name %]
			                [%- END %]
			                [%- END %] [% FOREACH output IN obj.outputs %]
			                [%- IF is_simple(output) %] [% output.datatype.name %]
			                [%- ELSE %] [% output.elements.0.datatype.name %]
			                [%- END %]
			                [%- END %] ) ]);
	$in_package = $parser->parse ( method => $in_testing_mode ? 'file' : 'string',
				       data   => $data );
    };
    # error in creating parser, or parsing input
    if ($@) {
	$LOG->logdie ($@) if $in_testing_mode;
	my $out_package = new MOSES::MOBY::Package
	    (exceptions => MOSES::MOBY::ServiceException->error ($@));
	$LOG->error ($self->format_stack ($@));
	$LOG->info ('*** FATAL ERROR RESPONSE BACK ***');
	Log::Log4perl::NDC->pop();
	return $self->finish_output ($out_package);
    }

    # no data at all - consider it 'ping'
    if ($in_package->size == 0) {
	$LOG->info ('*** RESPONSE PING BACK *** ');
	Log::Log4perl::NDC->pop();
	if ($in_testing_mode) {
	    return $in_package->toXML->toString(1);
	} else {
	    return $self->finish_output ($in_package);
	}
    }
	
    # re-bless input, prepare output
    my ($out_package) = new MOSES::MOBY::Package;
    foreach my $job (@{ $in_package->jobs }) {
	bless ($job, 'MOSES::MOBY::Job::[% obj.module_name %]');
	my $response_job = new MOSES::MOBY::Job::[% obj.module_name %] (jid => $job->jid);
 	$response_job->_context ($out_package);
	$out_package->add_jobs ($response_job);
    }
    $out_package->authority ('[% obj.authority %]');

    # do something (this service main task)
    eval { $self->process_all ($in_package, $out_package) };
    # error thrown by the implementation class
    if ($@) {
	$LOG->logdie ($@) if $in_testing_mode;
	$out_package->add_exceptions (MOSES::MOBY::ServiceException->error ($@));
	$LOG->error ($self->format_stack ($@));
	$LOG->info ('*** REQUEST TERMINATED RESPONSE BACK ***');
	Log::Log4perl::NDC->pop();
	return $self->finish_output ($out_package);
    }

    # return result
    $LOG->info ('*** RESPONSE READY *** ');
    if ($in_testing_mode) {
	Log::Log4perl::NDC->pop();
       return $out_package->toXML->toString(1);
    } else {
	if ($LOG->is_debug) {
	    my $soap_output = $self->finish_output ($out_package);
	    $LOG->debug ("Output raw data (first 1000 characters): " .
			 substr ($soap_output->{_value}->[0], 0, 1000)) if ref($soap_output) =~ m|^HASH|;
	   $LOG->debug ("Output raw data (first 1000 characters): " .
             substr ($soap_output, 0, 1000)) unless ref($soap_output) =~ m|^HASH|;
	    Log::Log4perl::NDC->pop();
	    return $soap_output;
	} else {
	    Log::Log4perl::NDC->pop();
	    return $self->finish_output ($out_package);
	}
    }
}

1;