blob: f064b04f55cd12598a7285def9f0e99fe0182a48 [file] [log] [blame]
require 'thread'
require 'etch/bindings/ruby/support/etch_mutex'
# Map by id and name of IdNames (or subclasses thereof).
#
class IdNameMap
attr :maxAutoCount, true
attr :byId, true
attr :byName, true
attr :autocount, true
# Constructs the IdNameMap.
# @param maxAutoCount the maximum number of automatically
# declared IdNames allowed. Set to 0 if you don't want any,
# but this may prevent working with a slightly different
# version of a service.
#
def initialize( maxAutoCount )
@mutex = EtchMutex.new
@maxAutoCount = maxAutoCount
@byId = Hash.new
@byName = Hash.new
@autocount = 0
end
# Gets the IdName subclass which corresponds to the specified
# id, or creates it if it isn't found and if autoCount <
# maxAutoCount. If created, the IdName is given the name which
# is id.toString().
# @param id the id of an IdName.
# @return the IdName subclass found or created.
#
def get( id )
if ( id.class == String )
# print "getByName() call"
getByName( id )
else
# Check if the synchronization is correct !
@mutex.synchronize do
t = @byId[id]
if (t == nil)
# print "autocount = ", @autocount, "maxAutocount = ", @maxAutoCount
if ( @autocount >= @maxAutoCount )
raise "maxAutoCount would be exceeded"
end
@autocount += 1
var = add( makeNew( id, id.to_s() ) )
return var
end
return t
end
end
end
# Gets the IdName subclass which corresponds to the specified
# name, or creates it if it isn't found and if autoCount <
# maxAutoCount. If created, the IdName is given the id which
# is IdName.hash( name ).
# @param name the name of an IdName.
# @return the IdName subclass found or created.
#
def getByName( name )
@mutex.synchronize do
t = @byName[ name ]
if (t == nil)
if (@autocount >= @maxAutoCount)
raise "maxAutoCount would be exceeded"
end
@autocount += 1
return add( makeNew( IdName.hashit( name ), name ) )
end
return t
end # mutex end
end
# Adds the IdName subclass to the map. If the entry matches
# a current entry (both id and name), then return the current
# entry instead.
#
# @param t the IdName subclass to add.
#
# @return the IdName from the map, either the new one or a current
# one.
#
# @throws IllegalArgumentException if there is a collision with
# id or name, or a collision with id and name where they are not
# associated with the same object.
#
def add( t )
@mutex.synchronize do
# four cases:
# 1) t.id and t.name do not exist (no collision)
# 2) t.id exists but t.name does not (collision)
# 3) t.id does not exist but t.name does (collision)
# 4) t.id and t.name exist (possible collision)
sameId = @byId[ t.xid ]
sameName = @byName[ t.name ]
if ( sameId!=nil || sameName!=nil )
# sameId has the same id as t.
# sameName has the same name as t.
# the only way this isn't a problem is if sameId == sameName,
# because that is the only case where there is a single
# entry which has both the same id and name as t.
if (sameId != sameName)
if (sameId != nil && sameName != nil)
raise "id & name collision"
else
if (sameId != nil)
raise "id collision"
end
if (sameName != nil )
raise "id collision"
end
end
end
return sameId
end
@byId.store( t.xid, t )
@byName.store( t.name, t )
return t
end # mutex end
end
def values()
@mutex.synchronize do
return @byId.values()
end # mutex end
end
# Makes a new subclass of IdName to put in this map.
# @param id the id of the new subclass of IdName.
# @param name the name of the new subclass of IdName.
# @return a newly constructed subclass of IdName to put in
# this map.
#
def makeNew( id, name )
raise "subclasser responsibility"
end
end