// $Header: /cvs/gled-1.2/GledCore/Glasses/ZKing.cxx,v 1.8 2005/03/11 17:50:15 matevz Exp $

// Copyright (C) 1999-2005, Matevz Tadel. All rights reserved.
// This file is part of GLED, released under GNU General Public License version 2.
// For the licensing terms see $GLEDSYS/LICENSE or http://www.gnu.org/.

//________________________________________________________________________
// ZKing
//
// A King controls top level chunks of ID space. A sun-space of each Saturn
// is ruled over by a King.
// King creates a dummy queen (set to mQueen) for proper ref-counting.
// Fire-space of each Saturn is ruled by a ZFireKing.
//
// BlessMIR() method is much less restrictive than the Queen version
// as Kings provide services for managing dependencies and mirroring
// of queens. Visibility of arguments is the sole concern of this
// method. Further checking is (and should be) provided in each
// respective method.
//________________________________________________________________________

#include "ZKing.h"
#include <Glasses/ZQueen.h>
#include "ZKing.c7"
#include <Glasses/ZEunuch.h>
#include <Glasses/SaturnInfo.h>
#include <Stones/ZComet.h>

ClassImp(ZKing)

/**************************************************************************/

 void ZKing::_init()
{
  mSaturnInfo = 0;
  mLightType = LT_Undef;
  mMapNoneTo = ZMirFilter::R_Allow;
}

/**************************************************************************/

 ZKing::~ZKing()
{
  delete mQueen;
}

/**************************************************************************/

 void ZKing::AdEnlightenment()
{
  PARENT_GLASS::AdEnlightenment();
  // Create a dummy queen for reference counting and emitting Rays.
  mQueen = new ZQueen(GForm("Concubine of %s", GetName()));
  mQueen->mSaturn = mSaturn;
  mQueen->mZeroRCPolicy = ZQueen::ZRCP_Ignore;
  mQueen->mKing = this;
}

/**************************************************************************/

 void ZKing::BlessMIR(ZMIR& mir)
{
  // Performs dependenciy check of context arguments and access
  // authorization.

  static string _eh("ZKing::BlessMIR ");

  // Dependency check
  // Mild version ... just assert args in moon or sun space.
  // Further could restrict args to queens + lenses of mandatory queens.
  if(mir.Beta) {
    if(mir.BetaID > mMaxID) {
      throw(_eh + GForm("beta '%s', id=%d: dependency check failed.",
			mir.Beta->GetName(), mir.BetaID));
    }
  }
  if(mir.Gamma) {
    if(mir.GammaID > mMaxID) {
      throw(_eh + GForm("gamma '%s', id=%d: dependency check failed.",
			    mir.Gamma->GetName(), mir.GammaID));
    }
  }

  // Authorization

  // Allow everything if UseAuth is false
  if(mSaturn->GetSaturnInfo()->GetUseAuth() == false) {
    return;
  }

  // Always allow SunAbsolute access
  if(mir.Caller->HasIdentity(mSaturn->mSunInfo->GetPrimaryIdentity())) {
    return;
  }

  UChar_t result = (mGuard != 0) ? mGuard->FilterMIR(mir) : ZMirFilter::R_None;
  if( result == ZMirFilter::R_Deny ||
      (result == ZMirFilter::R_None && mMapNoneTo == ZMirFilter::R_Deny))
    {
      throw(_eh + "access denied");
    }
}

/**************************************************************************/

 void ZKing::Enthrone(ZQueen* queen)
{
  ID_t w = queen->GetIDSpan();
  if(mMaxID==mMaxUsedID || mMaxID - mMaxUsedID < queen->mIDSpan) {
    assert(0);    
  }
  queen->mKing   = this;
  queen->mSaturn = mSaturn;
  queen->mMinID = mMaxUsedID + 1;
  mMaxUsedID += queen->mIDSpan;
  queen->mMaxID = mMaxUsedID;
  queen->bootstrap();
  Add(queen);

  // !!!! should broadcast to all moons
}

 void ZKing::StarToQueen(ZComet* comet, ID_t span)
{
  // In principle, loading of queen with wider id-span than needed.
  // Perhaps could be even useful.
}

/**************************************************************************/

 ZComet* ZKing::MakeComet()
{
  // Produces Comet of type ST_King.
  // Contains the King, all its Queens and their Dependencies.
  // Used for producing snapshot of a King-space to be sent to a Moon.

  ZComet* comet = new ZComet(GetName(), GForm("Comet[King] of %s", GetName()));
  comet->mType = ZComet::CT_King;
  comet->mKing = this;

  ReadLock();
  comet->AddGlass(this);
  lpZGlass_t queens; Copy(queens);
  for(lpZGlass_i i=queens.begin(); i!=queens.end(); ++i) {
    ZQueen* q = dynamic_cast<ZQueen*>(*i);
    assert(q!=0);
    comet->AddGlass(q);
    comet->AddGlass(q->GetDeps());
  }
  ReadUnlock();

  return comet;
}

/**************************************************************************/
// Mirroring of Queens
/**************************************************************************/

 void ZKing::reflect_queen(ZQueen* queen_to_mirror, SaturnInfo* moon)
{
  // Actual activation of a queen.
  // If moon == mSaturn->GetSaturnInfo() and queen is not activated,
  //    check deps, send beams, mark the queens.
  // If moon in my moons, then:
  //   if(have the queen active) push it along
  //   else forward the request and mark thingies (queen and the new reflector).

  static string _eh("ZKing::reflect_queen() ");

  assert_MIR_presence(_eh);

  if(moon == mSaturn->GetSaturnInfo()) {
    // Request came from self ... must beam it upwards, if necessary.

    if(queen_to_mirror->GetRuling()) {
      throw(_eh + "queen is already ruling");
    }
    if(queen_to_mirror->GetAwaitingSceptre()) {
      throw(_eh + "queen is awaiting sceptre");
    }

    // Here should check dependencies etc.
    // or perhaps later prior to streaming

    mSaturn->RefQueenLoadCnd().Lock();
    mSaturn->SetQueenLoadNum(mSaturn->GetQueenLoadNum() + 1);
    mSaturn->RefQueenLoadCnd().Broadcast();
    mSaturn->RefQueenLoadCnd().Unlock();


    queen_to_mirror->SetAwaitingSceptre(true);
    // Request_mirror
    auto_ptr<ZMIR> mir(S_reflect_queen(queen_to_mirror, moon));
    mir->SetCaller(mSaturn->GetSaturnInfo());
    mir->SetRecipient(moon->GetMaster());
    mSaturn->PostMIR(mir);

  } else {
    // Request should be coming from direct moon.
    // Must serve it or forward it.

    if(!mSaturn->IsMoon(moon)) {
      throw(_eh + "moon neither this Saturn nor its direct Moon");
    }

    if(queen_to_mirror->GetRuling()) {

      queen_to_mirror->WriteLock();
      auto_ptr<ZMIR> mir(this->S_activate_queen(queen_to_mirror));
      mir->SetCaller(mSaturn->GetSaturnInfo());
      mir->SetRecipient(moon);
      queen_to_mirror->CreateReflection(*mir);
      queen_to_mirror->add_reflector(moon);
      queen_to_mirror->WriteUnlock();
      ISdebug(0, GForm("%s Sending queen '%s' to moon '%s'; length=%d",
		       _eh.c_str(), queen_to_mirror->GetName(),
		       moon->GetName(), mir->Length()));
      mSaturn->PostMIR(mir);
      moon->hQueens.insert(queen_to_mirror);

    } else if(queen_to_mirror->GetAwaitingSceptre()) {

      queen_to_mirror->add_reflector(moon);

    } else {

      // Here should check dependencies etc.
      queen_to_mirror->SetAwaitingSceptre(true);
      queen_to_mirror->add_reflector(moon);
      // Request_mirror
      auto_ptr<ZMIR> mir(S_reflect_queen(queen_to_mirror,
					 mSaturn->GetSaturnInfo()));
      mir->SetCaller(mSaturn->GetSaturnInfo());
      mir->SetRecipient(mSaturn->GetSaturnInfo()->GetMaster());
      mSaturn->PostMIR(mir);

    }

  }
}

 void ZKing::activate_queen(ZQueen* queen)
{
  // A response from upper Saturn, containing whatever was attached
  // by ZQueen::CreateReflection().

  // assert queen awaiting sceptre.
  // Invoke it upon reflection.
  // Check, if the queen has any aspiring reflectors ... forward the beam to them

  static string _eh("ZKing::activate_queen() ");

  ZMIR* mir = assert_MIR_presence(_eh);

  if(!queen->GetAwaitingSceptre()) {
    throw(_eh + "queen " + queen->GetName() + " is NOT awaiting sceptre");
  }

  queen->InvokeReflection(*mir);
  queen->SetAwaitingSceptre(false);

  ISmess(GForm("%s queen '%s' arrived for king '%s'",
	       _eh.c_str(), queen->GetName(), GetName()));

  mSaturn->RefQueenLoadCnd().Lock();
  mSaturn->SetQueenLoadNum(mSaturn->GetQueenLoadNum() - 1);
  mSaturn->RefQueenLoadCnd().Broadcast();
  mSaturn->RefQueenLoadCnd().Unlock();

  // Broadcast beams
  if(!queen->mReflectors.empty()) {
    mSaturn->BroadcastBeamMIR(*mir, queen->mReflectors);
    for(lpSaturnInfo_i r=queen->mReflectors.begin(); r!=queen->mReflectors.end(); ++r) {
      (*r)->hQueens.insert(queen);
    }
  }
}

 void ZKing::unreflect_queen(ZQueen* queen_to_leave, SaturnInfo* moon)
{
  // Ignore gloriously. Deps first.
}

 void ZKing::receive_eunuch()
{
  // Receives an eunuch.

  static string _eh("ZKing::receive_eunuch ");
  ZMIR* mir = assert_MIR_presence(_eh, ZGlass::MC_IsBeam);

  ZEunuch* e = GledNS::StreamLensByGlass<ZEunuch*>(*mir);
  if(e == 0)
    throw(_eh + "MIR not followed by an eunuch.");
  
  
}


/**************************************************************************/


ROOT page - Home page - Class index - Class Hierarchy - Top of the page

This page has been automatically generated. If you have any comments or suggestions about the page layout send a mail to ROOT support, or contact the developers with any questions or problems regarding ROOT.