Bivio::Biz::Model::Lock
# Copyright (c) 1999-2011 bivio Software, Inc. All rights reserved. # $Id$ package Bivio::Biz::Model::Lock; use strict; use Bivio::Base 'Biz.PropertyModel'; use Bivio::IO::Trace; our($_TRACE); my($_GENERAL) = b_use('Auth.Realm')->get_general->get('id'); my($_PI) = b_use('Type.PrimaryId'); my($_SQL_READ_ONLY) = b_use('SQL.Connection')->is_read_only; my($_D) = b_use('Bivio.Die'); sub acquire { my($self, $realm_id) = @_; $realm_id ||= $self->req('auth_id'); $self->throw_die( 'ALREADY_EXISTS', { message => 'duplicate lock: use acquire_unless_exists', entity => $realm_id, }, ) if $self->is_acquired($realm_id); $self->throw_die('ALREADY_EXISTS', 'cannot reuse lock instance') if _map_txn_resources($self, sub {shift == $self ? 1 : ()}); my($values) = {realm_id => $realm_id}; _read_request_input($self); my($die) = $_D->catch(sub {$self->create($values)}); if ($die) { if ($die->get('code')->equals_by_name('DB_CONSTRAINT')) { my($attrs) = $die->unsafe_get('attrs'); $self->throw_die('DB_ERROR', $values) if ref($attrs) && ref($attrs->{type_error}) && $attrs->{type_error}->equals_by_name('EXISTS'); } $die->throw_die; # DOES NOT RETURN } _trace($self) if $_TRACE; $self->req->push_txn_resource($self); return; } sub acquire_general { return shift->acquire($_GENERAL); } sub acquire_general_unless_exists { return shift->acquire_unless_exists($_GENERAL); } sub acquire_unless_exists { my($self, $realm_id) = @_; $self->acquire($realm_id) unless $self->is_acquired($realm_id); return; } sub execute { my($proto, $req) = @_; $proto->new($req)->acquire; return; } sub execute_auth_user { my($proto, $req) = @_; $proto->new($req)->acquire($req->get('auth_user_id')); return; } sub execute_general { my($proto, $req) = @_; $proto->new($req)->acquire_general; return; } sub execute_unless_acquired { my($proto, $req) = @_; $proto->new($req)->acquire_unless_exists; return; } sub handle_commit { my($self) = @_; $self->release; return; } sub handle_rollback { my($self) = @_; $self->delete_from_request; return; } sub internal_initialize { return { version => 1, table_name => 'lock_t', columns => { realm_id => ['PrimaryId', 'PRIMARY_KEY'], }, auth_id => 'realm_id', }; } sub is_acquired { my($self, $realm_id) = @_; $realm_id ||= $self->req('auth_id'); return _map_txn_resources( $self, sub {_is_equal(shift, $realm_id) ? 1 : ()}, ) ? 1 : 0; } sub is_general_acquired { my($self) = @_; return $self->is_acquired($_GENERAL); } sub release { my($self) = @_; _trace($self) if $_TRACE; $self->throw_die('DIE', 'lock is not loaded') unless $self->is_loaded; $self->req->delete_txn_resource($self); $self->throw_die('UPDATE_COLLISION') unless $self->delete || $_SQL_READ_ONLY; return; } sub release_all { my($self) = @_; _map_txn_resources( $self, sub { shift->release; return; }, ); return; } sub _is_equal { my($other, $realm_id) = @_; return $_PI->is_equal( $other->get('realm_id'), $realm_id || $other->req('auth_id'), ); } sub _map_txn_resources { my($self, $op) = @_; return map( $self->is_blesser_of($_) ? $op->($_) : (), @{$self->req('txn_resources')}, ); } sub _read_request_input { my($self) = @_; my($m) = $self->req->is_http_method('post') ? 'get_form' : 'get_content'; $self->req->$m(); return; } 1;