<commit_before>#include "TChain.h"
#include "TTree.h"
#include "TH1D.h"
#include "TF1.h"
#include "TCanvas.h"
#include "TObjArray.h"

#include "AliAnalysisTask.h"
#include "AliAnalysisManager.h"

#include "AliESDEvent.h"
#include "AliESDInputHandler.h"

#include "AliT0CalibOffsetChannelsTask.h"

//#include "AliCDBMetaData.h"
//#include "AliCDBId.h"
//#include "AliCDBEntry.h"
//#include "AliCDBManager.h"
//#include "AliCDBStorage.h"

// Task should calculate channels offset
// Authors: Alla

ClassImp(AliT0CalibOffsetChannelsTask)
//________________________________________________________________________
AliT0CalibOffsetChannelsTask::AliT0CalibOffsetChannelsTask()
  : AliAnalysisTaskSE(),  fESD(0x0), fTzeroObject(0x0),
  fTzeroORA(0x0), fTzeroORC(0x0), fResolution(0x0), fTzeroORAplusORC(0x0),
  fRunNumber(0)
{
  // Constructor

  for( int ip=0; ip < 24; ip++){
    fTimeDiff[ip] = 0;
    fCFD[ip]      = 0;
    fCDBdelays[ip]= 0;
    fCDBcfds[ip]= 0;
    fCDBT0s[ip]= 0;
  }

  // Define input and output slots here
  // Input slot #0 works with a TChain
  //  DefineInput(0,  TChain::Class());
  //  DefineOutput(1, TObjArray::Class());
}

//________________________________________________________________________
AliT0CalibOffsetChannelsTask::AliT0CalibOffsetChannelsTask(const char *name)
  : AliAnalysisTaskSE(name), fESD(0), fTzeroObject(0),
  fTzeroORA(0x0), fTzeroORC(0x0), fResolution(0x0), fTzeroORAplusORC(0x0),
    fRunNumber(0)
{
  // Constructor

  for( int ip=0; ip < 24; ip++){
    fTimeDiff[ip] = 0;
    fCFD[ip]      = 0;
    fCDBdelays[ip]= 0;
    fCDBcfds[ip]= 0;
    fCDBT0s[ip]= 0;

  }

  // Define input and output slots here
  // Input slot #0 works with a TChain
  DefineInput(0, TChain::Class());
  DefineOutput(1, TObjArray::Class());
  // Output slot #0 id reserved by the base class for AOD
  // Output slot #1 writes into a TH1 container
}

//________________________________________________________________________
AliT0CalibOffsetChannelsTask::~AliT0CalibOffsetChannelsTask()
{
  // Destructor
  // printf("AliT0CalibOffsetChannels~AliT0CalibOffsetChannels() ");
  delete fTzeroORA;
  delete fTzeroORC;
  delete fResolution;
  delete fTzeroORAplusORC;
  for( Int_t  ip=0; ip < 24; ip++){
    delete fTimeDiff[ip];
    delete fCFD[ip];
  }

  delete fTzeroObject;
}

//________________________________________________________________________
/*void AliT0CalibOffsetChannelsTaskX::ConnectInputData(Option_t *) {
  //
  //
  //
  TTree* tree=dynamic_cast<TTree*>(GetInputData(0));
  if (!tree) {
    printf("ERROR: Could not read chain from input slot 0");
  }
  else {
    AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*> (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());
    if (!esdH) {
      printf ("ERROR: Could not get ESDInputHandler");
    }
    else {
      fESD = esdH->GetEvent();
      printf ("*** CONNECTED NEW EVENT ****");
    }
  }
}
*/
//________________________________________________________________________
void AliT0CalibOffsetChannelsTask::UserCreateOutputObjects()
{
  // Create histograms
  for (Int_t i=0; i<24; i++) {
    fTimeDiff[i]   = new TH1F (Form("CFD1minCFD%d",i+1),"fTimeDiff",150, -300, 300);
    fCFD[i]        = new TH1F(Form("CFD%d",i+1),"CFD",250, 2000, 3000);//6000, 7000);
    //    fCFD[i]        = new TH1F(Form("CFD%d",i+1),"CFD",250, -1000, 1000);//6000, 7000);
  }

  fTzeroORAplusORC = new TH1F("fTzeroORAplusORC","ORA+ORC /2",200,-2500,2500);   //or A plus or C
  fResolution      = new TH1F("fResolution","fResolution",400,-2500,2500);// or A minus or C spectrum
  fTzeroORA        = new TH1F("fTzeroORA","fTzeroORA",200,-2500,2500);// or A spectrum
  fTzeroORC        = new TH1F("fTzeroORC","fTzeroORC",200,-2500,2500);// or C spectrum

  fTzeroObject     = new TObjArray(0);
  fTzeroObject->SetOwner(kTRUE);

  for (Int_t i=0; i<24; i++)
    fTzeroObject->AddAtAndExpand(fTimeDiff[i],i);

  for (Int_t i=0; i<24; i++)
    fTzeroObject->AddAtAndExpand(fCFD[i],i+24); //24 - 48

  fTzeroObject->AddAtAndExpand(fTzeroORAplusORC, 48);
  fTzeroObject->AddAtAndExpand(fResolution, 49);
  fTzeroObject->AddAtAndExpand(fTzeroORA, 50);
  fTzeroObject->AddAtAndExpand(fTzeroORC, 51);

  PostData(1, fTzeroObject);
  // Called once
}

//________________________________________________________________________
void AliT0CalibOffsetChannelsTask::UserExec(Option_t *)
{
  // Main loop
  // Called for each event

  // Post output data.
  fESD = dynamic_cast<AliESDEvent*>(InputEvent());
  if (!fESD) {
    printf("ERROR: fESD not available\n");
    return;
  }

  fRunNumber =  fESD->GetRunNumber() ;

  const Double32_t* time = fESD->GetT0time();
  const Double32_t* amp = fESD->GetT0amplitude();
  Double32_t diff;
  for (Int_t i=0; i<12; i++) {
    if( time[i] !=0  && amp[i]>0.1 ){
      fCFD[i]->Fill( time[i] );
      //  printf(" time %f ocdb %f \n", time[i],fCDBcfds[i]);

      if(  time[0] != 0 ) {
	diff =  time[i]-time[0] + fCDBdelays[i];
	fTimeDiff[i]->Fill( diff);
      }
    }
  }
  for (Int_t i=12; i<24; i++) {
    if( time[i] != 0 && amp[i]>0.1) {
      fCFD[i]->Fill( time[i]);
      //  printf(" time %f ocdb %f \n", time[i],fCDBcfds[i]);
       if( time[12] != 0 ) {
	diff =  time[i]-time[12] + fCDBdelays[i];
	fTimeDiff[i]->Fill( diff);
      }
    }
  }
  const Double32_t* mean = fESD->GetT0TOF();
  Double32_t meanTOF = mean[0] +  fCDBT0s[0];
  Double32_t orA = mean[1]  +  fCDBT0s[1];
  Double32_t orC = mean[2] +  fCDBT0s[2];

  if(orA<9999) fTzeroORA->Fill(orA);
  if(orC<9999) fTzeroORC->Fill(orC);
  if(orA<9999 && orC<9999) fResolution->Fill((orA-orC)/2.);
  if(orA<9999 && orC<9999) fTzeroORAplusORC->Fill(meanTOF);

  //  printf("%f   %f  %f\n",orA,orC,meanTOF);
  PostData(1, fTzeroObject);
}
 //________________________________________________________________________
void AliT0CalibOffsetChannelsTask::Terminate(Option_t *)
{

   // Called once at the end of the query
}

<commit_msg>coverity fixed<commit_after>#include "TChain.h"
#include "TTree.h"
#include "TH1D.h"
#include "TF1.h"
#include "TCanvas.h"
#include "TObjArray.h"

#include "AliAnalysisTask.h"
#include "AliAnalysisManager.h"

#include "AliESDEvent.h"
#include "AliESDInputHandler.h"

#include "AliT0CalibOffsetChannelsTask.h"

//#include "AliCDBMetaData.h"
//#include "AliCDBId.h"
//#include "AliCDBEntry.h"
//#include "AliCDBManager.h"
//#include "AliCDBStorage.h"

// Task should calculate channels offset
// Authors: Alla

ClassImp(AliT0CalibOffsetChannelsTask)
//________________________________________________________________________
AliT0CalibOffsetChannelsTask::AliT0CalibOffsetChannelsTask()
  : AliAnalysisTaskSE(),  fESD(0x0), fTzeroObject(0x0),
  fTzeroORA(0x0), fTzeroORC(0x0), fResolution(0x0), fTzeroORAplusORC(0x0),
  fRunNumber(0)
{
  // Constructor

  for( int ip=0; ip < 24; ip++){
    fTimeDiff[ip] = 0;
    fCFD[ip]      = 0;
    fCDBdelays[ip]= 0;
    fCDBcfds[ip]= 0;
    if (ip<5 ) fCDBT0s[ip]= 0;
  }

  // Define input and output slots here
  // Input slot #0 works with a TChain
  //  DefineInput(0,  TChain::Class());
  //  DefineOutput(1, TObjArray::Class());
}

//________________________________________________________________________
AliT0CalibOffsetChannelsTask::AliT0CalibOffsetChannelsTask(const char *name)
  : AliAnalysisTaskSE(name), fESD(0), fTzeroObject(0),
  fTzeroORA(0x0), fTzeroORC(0x0), fResolution(0x0), fTzeroORAplusORC(0x0),
    fRunNumber(0)
{
  // Constructor

  for( int ip=0; ip < 24; ip++){
    fTimeDiff[ip] = 0;
    fCFD[ip]      = 0;
    fCDBdelays[ip]= 0;
    fCDBcfds[ip]= 0;
    if (ip<5 ) fCDBT0s[ip]= 0;

  }

  // Define input and output slots here
  // Input slot #0 works with a TChain
  DefineInput(0, TChain::Class());
  DefineOutput(1, TObjArray::Class());
  // Output slot #0 id reserved by the base class for AOD
  // Output slot #1 writes into a TH1 container
}

//________________________________________________________________________
AliT0CalibOffsetChannelsTask::~AliT0CalibOffsetChannelsTask()
{
  // Destructor
  // printf("AliT0CalibOffsetChannels~AliT0CalibOffsetChannels() ");
  delete fTzeroORA;
  delete fTzeroORC;
  delete fResolution;
  delete fTzeroORAplusORC;
  for( Int_t  ip=0; ip < 24; ip++){
    delete fTimeDiff[ip];
    delete fCFD[ip];
  }

  delete fTzeroObject;
}

//________________________________________________________________________
/*void AliT0CalibOffsetChannelsTaskX::ConnectInputData(Option_t *) {
  //
  //
  //
  TTree* tree=dynamic_cast<TTree*>(GetInputData(0));
  if (!tree) {
    printf("ERROR: Could not read chain from input slot 0");
  }
  else {
    AliESDInputHandler *esdH = dynamic_cast<AliESDInputHandler*> (AliAnalysisManager::GetAnalysisManager()->GetInputEventHandler());
    if (!esdH) {
      printf ("ERROR: Could not get ESDInputHandler");
    }
    else {
      fESD = esdH->GetEvent();
      printf ("*** CONNECTED NEW EVENT ****");
    }
  }
}
*/
//________________________________________________________________________
void AliT0CalibOffsetChannelsTask::UserCreateOutputObjects()
{
  // Create histograms
  for (Int_t i=0; i<24; i++) {
    fTimeDiff[i]   = new TH1F (Form("CFD1minCFD%d",i+1),"fTimeDiff",150, -300, 300);
    fCFD[i]        = new TH1F(Form("CFD%d",i+1),"CFD",250, 2000, 3000);//6000, 7000);
    //    fCFD[i]        = new TH1F(Form("CFD%d",i+1),"CFD",250, -1000, 1000);//6000, 7000);
  }

  fTzeroORAplusORC = new TH1F("fTzeroORAplusORC","ORA+ORC /2",200,-2500,2500);   //or A plus or C
  fResolution      = new TH1F("fResolution","fResolution",400,-2500,2500);// or A minus or C spectrum
  fTzeroORA        = new TH1F("fTzeroORA","fTzeroORA",200,-2500,2500);// or A spectrum
  fTzeroORC        = new TH1F("fTzeroORC","fTzeroORC",200,-2500,2500);// or C spectrum

  fTzeroObject     = new TObjArray(0);
  fTzeroObject->SetOwner(kTRUE);

  for (Int_t i=0; i<24; i++)
    fTzeroObject->AddAtAndExpand(fTimeDiff[i],i);

  for (Int_t i=0; i<24; i++)
    fTzeroObject->AddAtAndExpand(fCFD[i],i+24); //24 - 48

  fTzeroObject->AddAtAndExpand(fTzeroORAplusORC, 48);
  fTzeroObject->AddAtAndExpand(fResolution, 49);
  fTzeroObject->AddAtAndExpand(fTzeroORA, 50);
  fTzeroObject->AddAtAndExpand(fTzeroORC, 51);

  PostData(1, fTzeroObject);
  // Called once
}

//________________________________________________________________________
void AliT0CalibOffsetChannelsTask::UserExec(Option_t *)
{
  // Main loop
  // Called for each event

  // Post output data.
  fESD = dynamic_cast<AliESDEvent*>(InputEvent());
  if (!fESD) {
    printf("ERROR: fESD not available\n");
    return;
  }

  fRunNumber =  fESD->GetRunNumber() ;

  const Double32_t* time = fESD->GetT0time();
  const Double32_t* amp = fESD->GetT0amplitude();
  Double32_t diff;
  for (Int_t i=0; i<12; i++) {
    if( time[i] !=0  && amp[i]>0.1 ){
      fCFD[i]->Fill( time[i] );
      //  printf(" time %f ocdb %f \n", time[i],fCDBcfds[i]);

      if(  time[0] != 0 ) {
	diff =  time[i]-time[0] + fCDBdelays[i];
	fTimeDiff[i]->Fill( diff);
      }
    }
  }
  for (Int_t i=12; i<24; i++) {
    if( time[i] != 0 && amp[i]>0.1) {
      fCFD[i]->Fill( time[i]);
      //  printf(" time %f ocdb %f \n", time[i],fCDBcfds[i]);
       if( time[12] != 0 ) {
	diff =  time[i]-time[12] + fCDBdelays[i];
	fTimeDiff[i]->Fill( diff);
      }
    }
  }
  const Double32_t* mean = fESD->GetT0TOF();
  Double32_t meanTOF = mean[0] +  fCDBT0s[0];
  Double32_t orA = mean[1]  +  fCDBT0s[1];
  Double32_t orC = mean[2] +  fCDBT0s[2];

  if(orA<9999) fTzeroORA->Fill(orA);
  if(orC<9999) fTzeroORC->Fill(orC);
  if(orA<9999 && orC<9999) fResolution->Fill((orA-orC)/2.);
  if(orA<9999 && orC<9999) fTzeroORAplusORC->Fill(meanTOF);

  //  printf("%f   %f  %f\n",orA,orC,meanTOF);
  PostData(1, fTzeroObject);
}
 //________________________________________________________________________
void AliT0CalibOffsetChannelsTask::Terminate(Option_t *)
{

   // Called once at the end of the query
}

<|endoftext|>


<commit_before>// $Id$
// Category: geometry
// by I. Hrivnacova, 27.07.2000
//
// See the class description in the header file.

#include "TG4XMLGeometryGenerator.h"
#include "TG4XMLConvertor.h"
#include "TG4Globals.h"

#include <G4Material.hh>
#include <G4VSolid.hh>
#include <G4LogicalVolume.hh>
#include <G4VPhysicalVolume.hh>
#include <G4PVPlacement.hh>
#include <G4PVReplica.hh>
#include <G4ThreeVector.hh>
#include <G4RotationMatrix.hh>

#include <g4std/iomanip>
#include <g4std/vector>

TG4XMLGeometryGenerator* TG4XMLGeometryGenerator::fgInstance = 0;

TG4XMLGeometryGenerator::TG4XMLGeometryGenerator()
{
//
  if (fgInstance) {
    TG4Globals::Exception(
      "TG4XMLGeometryGenerator: attempt to create two instances of singleton.");
  }

  fConvertor = new TG4XMLConvertor(fOutFile);
}

TG4XMLGeometryGenerator::TG4XMLGeometryGenerator(const TG4XMLGeometryGenerator& right)
{
//
  TG4Globals::Exception(
    "TG4XMLGeometryGenerator: attempt to copy singleton.");
}

TG4XMLGeometryGenerator::~TG4XMLGeometryGenerator() {
//
}

// operators

TG4XMLGeometryGenerator&
TG4XMLGeometryGenerator::operator=(const TG4XMLGeometryGenerator& right)
{
  // check assignement to self
  if (this == &right) return *this;

  TG4Globals::Exception(
    "Attempt to assign TG4XMLGeometryGenerator singleton.");

  return *this;
}

// private methods

void TG4XMLGeometryGenerator::CutName(G4String& name) const
{
// Removes spaces after the name if present.
// ---

  G4int i = name.length();
  while (name(--i) == ' ') name = name(0,i);
}

void TG4XMLGeometryGenerator::ProcessSolids(G4LogicalVolume* lv)
{
// Writes all solids of given logical volume.
// ---

  G4VSolid* solid = lv->GetSolid();
  G4String lvName = lv->GetName();
  G4String material = lv->GetMaterial()->GetName();
  fConvertor->WriteSolid(lvName, solid, material);

  // store the name of logical volume in the set
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  // process daughters
  G4int nofDaughters = lv->GetNoDaughters();
  if (nofDaughters>0)
    for (G4int i=0; i<nofDaughters; i++) {
      //G4cout << "processing " << i << "th daughter of "
      //       << lv->GetName() << G4endl;
      G4LogicalVolume* lvd = lv->GetDaughter(i)->GetLogicalVolume();
      G4String lvdName = lvd->GetName();

      if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
        // process lvd only if it was not yet processed
        ProcessSolids(lvd);
      }
    }
}

void TG4XMLGeometryGenerator::ProcessMaterials(G4LogicalVolume* lv)
{
// Writes all materials of given logical volume.
// ---

  G4Material* material = lv->GetMaterial();

  // check if this material was already written
  G4bool written = false;
  G4String name = material->GetName();
  CutName(name);
  if (fMaterialNames.find(name) != fMaterialNames.end()) written = true;

  if (!written) {
    fConvertor->WriteMaterial(material);
    fMaterialNames.insert(fMaterialNames.begin(), name);
  }

  // store the name of logical volume in the set
  G4String lvName = lv->GetName();
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  G4int nofDaughters = lv->GetNoDaughters();
  if (nofDaughters>0)
    for (G4int i=0; i<nofDaughters; i++) {
      G4LogicalVolume* lvd = lv->GetDaughter(i)->GetLogicalVolume();
      G4String lvdName = lvd->GetName();

      if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
        // process lvd only if it was not yet processed
        ProcessMaterials(lvd);
      }
    }
}

void TG4XMLGeometryGenerator::ProcessRotations(G4LogicalVolume* lv)
{
// Writes all rotation matrices of given logical volume.
// ---

  G4String lvName = lv->GetName();

  // store the name of logical volume in the set
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  G4int nofDaughters = lv->GetNoDaughters();

  if (nofDaughters>0) {
    G4int i;
    for (i=0; i<nofDaughters; i++) {

      G4VPhysicalVolume* pvd = lv->GetDaughter(i);
      const G4RotationMatrix* kRotation = pvd->GetRotation();
      if (kRotation)
        fConvertor->WriteRotation(kRotation);

      G4LogicalVolume* lvd = pvd->GetLogicalVolume();
      G4String lvdName = lvd->GetName();

      if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
        // process lvd only if it was not yet processed
        ProcessRotations(lvd);
      }
    }
  }
}

void TG4XMLGeometryGenerator::ProcessLogicalVolume(G4LogicalVolume* lv)
{
// Writes logical volume tree.
// ---

  G4int nofDaughters = lv->GetNoDaughters();
  if (nofDaughters == 0) return;

  // open composition
  G4String lvName = lv->GetName();
  G4String name = lvName;
  name.append("_comp");
  fConvertor->OpenComposition(name);

  // write positions
  G4int i;
  for (i=0; i<nofDaughters; i++) {
   // G4cout << "processing " << i << "th daughter of "
   //        << lv->GetName() << G4endl;

    G4VPhysicalVolume* vpvd = lv->GetDaughter(i);
    G4LogicalVolume* lvd = vpvd->GetLogicalVolume();

    // get parameters
    G4String lvName = lvd->GetName();
    G4String compName = lvd->GetName();
    compName.append("_comp");
    G4int nd = lvd->GetNoDaughters();

    G4PVPlacement* pvd = dynamic_cast<G4PVPlacement*>(vpvd);
    if (pvd) {
      // placement
      G4ThreeVector  position = vpvd->GetTranslation();
      const G4RotationMatrix* kMatrix = vpvd->GetObjectRotation();

      if (!kMatrix) {
  	fConvertor->WritePosition(lvName, position);
        // if volume is not leaf node place its logical volume
        if (nd>0)
    	  fConvertor->WritePosition(compName, position);
      }
      else {
  	fConvertor->WritePositionWithRotation(lvName, position, kMatrix);
        if (nd>0)
      	   fConvertor->WritePositionWithRotation(compName, position, kMatrix);
      }
    }
    else {
      G4PVReplica* pvr = dynamic_cast<G4PVReplica*>(vpvd);
      if (pvr) {
        // replica
    	fConvertor->WriteReplica(lvName, pvr);
        // if volume is not leaf node place its logical volume
        if (nd>0)
      	  fConvertor->WriteReplica(compName, pvr);
      }
      else {
        G4String text = "TG4XMLGeometryGenerator::ProcessLogicalVolume: \n";
        text = text + "    Limitation: \n";
        text = text + "    Other physical volumes than PVPlacement and PVReplica";
        text = text + " are not implemented.";
        TG4Globals::Exception(text);
      }
    }
  }

  // close composition
  fConvertor->CloseComposition();
  fConvertor->WriteEmptyLine();

  // store the name of logical volume in the set
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  // process daughters
  for (i=0; i<nofDaughters; i++) {
    G4LogicalVolume* lvd = lv->GetDaughter(i)->GetLogicalVolume();
    G4String lvdName = lvd->GetName();

    if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
      // process lvd only if it was not yet processed
      ProcessLogicalVolume(lvd);
    }
  }
}

void TG4XMLGeometryGenerator::ClearMaterialNames()
{
// Clears the set of material names.
// ---

  fMaterialNames.erase(fMaterialNames.begin(), fMaterialNames.end());
}

void TG4XMLGeometryGenerator::ClearVolumeNames()
{
// Clears the set of volume names.
// ---

  fVolumeNames.erase(fVolumeNames.begin(), fVolumeNames.end());
}

// public methods

void TG4XMLGeometryGenerator::GenerateMaterials(
                        const G4String& version, const G4String& date,
		        const G4String& author,  const G4String dtdVersion,
			G4LogicalVolume* lv)
{
// Generates the XML material element containing
// all materials present in given logical volume.
// ---

  // create section
  fConvertor->OpenMaterials(version, date, author, dtdVersion);
  fConvertor->WriteEmptyLine();

  // process materials
  ProcessMaterials(lv);
  fConvertor->WriteEmptyLine();
  ClearMaterialNames();
  ClearVolumeNames();

  // close section
  fConvertor->CloseMaterials();
  fConvertor->WriteEmptyLine();
}

void TG4XMLGeometryGenerator::GenerateSection(const G4String& name,
                        const G4String& version, const G4String& date,
		        const G4String& author, const G4String& topVolume,
                        G4LogicalVolume* lv)
{
// Generates the XML section element containing
// all geometry objects defined in given logical volume:
// rotation matrices, solids and volumes hierarchy.
// ---

  // create section
  fConvertor->OpenSection(name, version, date, author, topVolume);
  fConvertor->WriteEmptyLine();

  // process rotations
  //ProcessRotations(lv);
  //fConvertor->WriteEmptyLine();
  //ClearRotations();
  //ClearVolumeNames();

  // process solids
  ProcessSolids(lv);
  fConvertor->WriteEmptyLine();
  ClearVolumeNames();

  // process geometry tree
  ProcessLogicalVolume(lv);
  fConvertor->WriteEmptyLine();
  ClearVolumeNames();

  // close section
  fConvertor->CloseSection();
}

void TG4XMLGeometryGenerator::OpenFile(G4String filePath)
{
// Opens output file.
// ---

  fOutFile.open(filePath, G4std::ios::out);

  if (!fOutFile) {
    G4String text = "Cannot open ";
    text = text + filePath;
    TG4Globals::Warning(text);
  }

  // use FORTRAN compatibility output
  fOutFile.setf(G4std::ios::fixed, G4std::ios::floatfield);
}

void TG4XMLGeometryGenerator::CloseFile()
{
// Closes output file.
// ---

  fOutFile.close();
}
<commit_msg>corrected test for presence of rotation in ProcessLogicalVolume()<commit_after>// $Id$
// Category: geometry
// by I. Hrivnacova, 27.07.2000
//
// See the class description in the header file.

#include "TG4XMLGeometryGenerator.h"
#include "TG4XMLConvertor.h"
#include "TG4Globals.h"

#include <G4Material.hh>
#include <G4VSolid.hh>
#include <G4LogicalVolume.hh>
#include <G4VPhysicalVolume.hh>
#include <G4PVPlacement.hh>
#include <G4PVReplica.hh>
#include <G4ThreeVector.hh>
#include <G4RotationMatrix.hh>

#include <g4std/iomanip>
#include <g4std/vector>

TG4XMLGeometryGenerator* TG4XMLGeometryGenerator::fgInstance = 0;

TG4XMLGeometryGenerator::TG4XMLGeometryGenerator()
{
//
  if (fgInstance) {
    TG4Globals::Exception(
      "TG4XMLGeometryGenerator: attempt to create two instances of singleton.");
  }

  fConvertor = new TG4XMLConvertor(fOutFile);
}

TG4XMLGeometryGenerator::TG4XMLGeometryGenerator(const TG4XMLGeometryGenerator& right)
{
//
  TG4Globals::Exception(
    "TG4XMLGeometryGenerator: attempt to copy singleton.");
}

TG4XMLGeometryGenerator::~TG4XMLGeometryGenerator() {
//
}

// operators

TG4XMLGeometryGenerator&
TG4XMLGeometryGenerator::operator=(const TG4XMLGeometryGenerator& right)
{
  // check assignement to self
  if (this == &right) return *this;

  TG4Globals::Exception(
    "Attempt to assign TG4XMLGeometryGenerator singleton.");

  return *this;
}

// private methods

void TG4XMLGeometryGenerator::CutName(G4String& name) const
{
// Removes spaces after the name if present.
// ---

  G4int i = name.length();
  while (name(--i) == ' ') name = name(0,i);
}

void TG4XMLGeometryGenerator::ProcessSolids(G4LogicalVolume* lv)
{
// Writes all solids of given logical volume.
// ---

  G4VSolid* solid = lv->GetSolid();
  G4String lvName = lv->GetName();
  G4String material = lv->GetMaterial()->GetName();
  fConvertor->WriteSolid(lvName, solid, material);

  // store the name of logical volume in the set
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  // process daughters
  G4int nofDaughters = lv->GetNoDaughters();
  if (nofDaughters>0)
    for (G4int i=0; i<nofDaughters; i++) {
      //G4cout << "processing " << i << "th daughter of "
      //       << lv->GetName() << G4endl;
      G4LogicalVolume* lvd = lv->GetDaughter(i)->GetLogicalVolume();
      G4String lvdName = lvd->GetName();

      if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
        // process lvd only if it was not yet processed
        ProcessSolids(lvd);
      }
    }
}

void TG4XMLGeometryGenerator::ProcessMaterials(G4LogicalVolume* lv)
{
// Writes all materials of given logical volume.
// ---

  G4Material* material = lv->GetMaterial();

  // check if this material was already written
  G4bool written = false;
  G4String name = material->GetName();
  CutName(name);
  if (fMaterialNames.find(name) != fMaterialNames.end()) written = true;

  if (!written) {
    fConvertor->WriteMaterial(material);
    fMaterialNames.insert(fMaterialNames.begin(), name);
  }

  // store the name of logical volume in the set
  G4String lvName = lv->GetName();
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  G4int nofDaughters = lv->GetNoDaughters();
  if (nofDaughters>0)
    for (G4int i=0; i<nofDaughters; i++) {
      G4LogicalVolume* lvd = lv->GetDaughter(i)->GetLogicalVolume();
      G4String lvdName = lvd->GetName();

      if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
        // process lvd only if it was not yet processed
        ProcessMaterials(lvd);
      }
    }
}

void TG4XMLGeometryGenerator::ProcessRotations(G4LogicalVolume* lv)
{
// Writes all rotation matrices of given logical volume.
// ---

  G4String lvName = lv->GetName();

  // store the name of logical volume in the set
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  G4int nofDaughters = lv->GetNoDaughters();

  if (nofDaughters>0) {
    G4int i;
    for (i=0; i<nofDaughters; i++) {

      G4VPhysicalVolume* pvd = lv->GetDaughter(i);
      const G4RotationMatrix* kRotation = pvd->GetRotation();
      if (kRotation)
        fConvertor->WriteRotation(kRotation);

      G4LogicalVolume* lvd = pvd->GetLogicalVolume();
      G4String lvdName = lvd->GetName();

      if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
        // process lvd only if it was not yet processed
        ProcessRotations(lvd);
      }
    }
  }
}

void TG4XMLGeometryGenerator::ProcessLogicalVolume(G4LogicalVolume* lv)
{
// Writes logical volume tree.
// ---

  G4int nofDaughters = lv->GetNoDaughters();
  if (nofDaughters == 0) return;

  // open composition
  G4String lvName = lv->GetName();
  G4String name = lvName;
  name.append("_comp");
  fConvertor->OpenComposition(name);

  // write positions
  G4int i;
  for (i=0; i<nofDaughters; i++) {
   // G4cout << "processing " << i << "th daughter of "
   //        << lv->GetName() << G4endl;

    G4VPhysicalVolume* vpvd = lv->GetDaughter(i);
    G4LogicalVolume* lvd = vpvd->GetLogicalVolume();

    // get parameters
    G4String lvName = lvd->GetName();
    G4String compName = lvd->GetName();
    compName.append("_comp");
    G4int nd = lvd->GetNoDaughters();

    G4PVPlacement* pvd = dynamic_cast<G4PVPlacement*>(vpvd);
    if (pvd) {
      // placement
      G4ThreeVector  position = vpvd->GetTranslation();

      if (!vpvd->GetRotation()) {
  	fConvertor->WritePosition(lvName, position);
        // if volume is not leaf node place its logical volume
        if (nd>0)
    	  fConvertor->WritePosition(compName, position);
      }
      else {
        const G4RotationMatrix* kMatrix = vpvd->GetObjectRotation();
  	fConvertor->WritePositionWithRotation(lvName, position, kMatrix);
        if (nd>0)
      	   fConvertor->WritePositionWithRotation(compName, position, kMatrix);
      }
    }
    else {
      G4PVReplica* pvr = dynamic_cast<G4PVReplica*>(vpvd);
      if (pvr) {
        // replica
    	fConvertor->WriteReplica(lvName, pvr);
        // if volume is not leaf node place its logical volume
        if (nd>0)
      	  fConvertor->WriteReplica(compName, pvr);
      }
      else {
        G4String text = "TG4XMLGeometryGenerator::ProcessLogicalVolume: \n";
        text = text + "    Limitation: \n";
        text = text + "    Other physical volumes than PVPlacement and PVReplica";
        text = text + " are not implemented.";
        TG4Globals::Exception(text);
      }
    }
  }

  // close composition
  fConvertor->CloseComposition();
  fConvertor->WriteEmptyLine();

  // store the name of logical volume in the set
  fVolumeNames.insert(fVolumeNames.begin(), lvName);

  // process daughters
  for (i=0; i<nofDaughters; i++) {
    G4LogicalVolume* lvd = lv->GetDaughter(i)->GetLogicalVolume();
    G4String lvdName = lvd->GetName();

    if (fVolumeNames.find(lvdName) == fVolumeNames.end()) {
      // process lvd only if it was not yet processed
      ProcessLogicalVolume(lvd);
    }
  }
}

void TG4XMLGeometryGenerator::ClearMaterialNames()
{
// Clears the set of material names.
// ---

  fMaterialNames.erase(fMaterialNames.begin(), fMaterialNames.end());
}

void TG4XMLGeometryGenerator::ClearVolumeNames()
{
// Clears the set of volume names.
// ---

  fVolumeNames.erase(fVolumeNames.begin(), fVolumeNames.end());
}

// public methods

void TG4XMLGeometryGenerator::GenerateMaterials(
                        const G4String& version, const G4String& date,
		        const G4String& author,  const G4String dtdVersion,
			G4LogicalVolume* lv)
{
// Generates the XML material element containing
// all materials present in given logical volume.
// ---

  // create section
  fConvertor->OpenMaterials(version, date, author, dtdVersion);
  fConvertor->WriteEmptyLine();

  // process materials
  ProcessMaterials(lv);
  fConvertor->WriteEmptyLine();
  ClearMaterialNames();
  ClearVolumeNames();

  // close section
  fConvertor->CloseMaterials();
  fConvertor->WriteEmptyLine();
}

void TG4XMLGeometryGenerator::GenerateSection(const G4String& name,
                        const G4String& version, const G4String& date,
		        const G4String& author, const G4String& topVolume,
                        G4LogicalVolume* lv)
{
// Generates the XML section element containing
// all geometry objects defined in given logical volume:
// rotation matrices, solids and volumes hierarchy.
// ---

  // create section
  fConvertor->OpenSection(name, version, date, author, topVolume);
  fConvertor->WriteEmptyLine();

  // process rotations
  //ProcessRotations(lv);
  //fConvertor->WriteEmptyLine();
  //ClearRotations();
  //ClearVolumeNames();

  // process solids
  ProcessSolids(lv);
  fConvertor->WriteEmptyLine();
  ClearVolumeNames();

  // process geometry tree
  ProcessLogicalVolume(lv);
  fConvertor->WriteEmptyLine();
  ClearVolumeNames();

  // close section
  fConvertor->CloseSection();
}

void TG4XMLGeometryGenerator::OpenFile(G4String filePath)
{
// Opens output file.
// ---

  fOutFile.open(filePath, G4std::ios::out);

  if (!fOutFile) {
    G4String text = "Cannot open ";
    text = text + filePath;
    TG4Globals::Warning(text);
  }

  // use FORTRAN compatibility output
  fOutFile.setf(G4std::ios::fixed, G4std::ios::floatfield);
}

void TG4XMLGeometryGenerator::CloseFile()
{
// Closes output file.
// ---

  fOutFile.close();
}
<|endoftext|>


<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
#include <memory>
#include <string>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include "joynr/JoynrClusterControllerRuntime.h"
#include "joynr/LibjoynrSettings.h"
#include "joynr/system/DiscoveryProxy.h"
#include "joynr/Settings.h"
#include "joynr/types/Version.h"
#include "joynr/system/RoutingTypes/MqttAddress.h"
#include "joynr/system/RoutingTypes/ChannelAddress.h"
#include "joynr/serializer/Serializer.h"

#include "tests/JoynrTest.h"
#include "tests/utils/MockObjects.h"

using namespace joynr;

class SystemServicesDiscoveryTest : public ::testing::Test {
public:
    std::string settingsFilename;
    std::unique_ptr<Settings> settings;
    std::string discoveryDomain;
    std::string discoveryProviderParticipantId;
    std::shared_ptr<JoynrClusterControllerRuntime> runtime;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverHttp;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverMqtt;
    std::shared_ptr<ITransportMessageSender> mockMessageSenderMqtt;
    DiscoveryQos discoveryQos;
    std::shared_ptr<ProxyBuilder<joynr::system::DiscoveryProxy>> discoveryProxyBuilder;
    std::shared_ptr<joynr::system::DiscoveryProxy> discoveryProxy;
    std::int64_t lastSeenDateMs;
    std::int64_t expiryDateMs;
    std::string publicKeyId;

    SystemServicesDiscoveryTest() :
        settingsFilename("test-resources/SystemServicesDiscoveryTest.settings"),
        settings(std::make_unique<Settings>(settingsFilename)),
        discoveryDomain(),
        discoveryProviderParticipantId(),
        runtime(),
        mockMessageReceiverHttp(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageReceiverMqtt(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageSenderMqtt(std::make_shared<MockTransportMessageSender>()),
        discoveryQos(),
        discoveryProxyBuilder(nullptr),
        discoveryProxy(nullptr),
        lastSeenDateMs(-1),
        expiryDateMs(-1),
        publicKeyId("")
    {
        SystemServicesSettings systemSettings(*settings);
        systemSettings.printSettings();
        discoveryDomain = systemSettings.getDomain();
        discoveryProviderParticipantId = systemSettings.getCcDiscoveryProviderParticipantId();

        discoveryQos.setCacheMaxAgeMs(1000);
        discoveryQos.setArbitrationStrategy(DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
        discoveryQos.addCustomParameter("fixedParticipantId", discoveryProviderParticipantId);
        discoveryQos.setDiscoveryTimeoutMs(50);

        std::string httpChannelId("http_SystemServicesDiscoveryTest.ChannelId");
        std::string httpEndPointUrl("http_SystemServicesRoutingTest.endPointUrl");
        std::string mqttTopic("mqtt_SystemServicesRoutingTest.topic");
        std::string mqttBrokerUrl("mqtt_SystemServicesRoutingTest.brokerUrl");

        using system::RoutingTypes::ChannelAddress;
        using system::RoutingTypes::MqttAddress;

        std::string serializedChannelAddress = joynr::serializer::serializeToJson(ChannelAddress(httpEndPointUrl, httpChannelId));
        std::string serializedMqttAddress = joynr::serializer::serializeToJson(MqttAddress(mqttBrokerUrl, mqttTopic));

        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverHttp).get()), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedChannelAddress));
        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverMqtt)), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedMqttAddress));

        //runtime can only be created, after MockCommunicationManager has been told to return
        //a channelId for getReceiveChannelId.
        runtime = std::make_shared<JoynrClusterControllerRuntime>(
                std::move(settings),
                mockMessageReceiverHttp,
                nullptr,
                mockMessageReceiverMqtt,
                mockMessageSenderMqtt);
        // discovery provider is normally registered in JoynrClusterControllerRuntime::create
        runtime->init();
        runtime->registerDiscoveryProvider();
    }

    ~SystemServicesDiscoveryTest(){
        runtime->unregisterDiscoveryProvider();
        runtime->deleteChannel();
        runtime->stopExternalCommunication();
        std::remove(settingsFilename.c_str());
    }

    void SetUp(){
        discoveryProxyBuilder = runtime->createProxyBuilder<joynr::system::DiscoveryProxy>(discoveryDomain);
    }

    void TearDown(){
        // Delete persisted files
        std::remove(ClusterControllerSettings::DEFAULT_LOCAL_CAPABILITIES_DIRECTORY_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_MESSAGE_ROUTER_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_SUBSCRIPTIONREQUEST_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_PARTICIPANT_IDS_PERSISTENCE_FILENAME().c_str());
    }

private:
    DISALLOW_COPY_AND_ASSIGN(SystemServicesDiscoveryTest);
};

TEST_F(SystemServicesDiscoveryTest, discoveryProviderIsAvailable)
{
    JOYNR_EXPECT_NO_THROW(
        discoveryProxy = discoveryProxyBuilder
                ->setMessagingQos(MessagingQos(5000))
                ->setDiscoveryQos(discoveryQos)
                ->build();
    );
}

TEST_F(SystemServicesDiscoveryTest, lookupUnknowParticipantReturnsEmptyResult)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}

TEST_F(SystemServicesDiscoveryTest, add)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    joynr::types::DiscoveryEntryWithMetaInfo discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId,
                true
    );
    expectedResult.push_back(discoveryEntry);

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);
}

TEST_F(SystemServicesDiscoveryTest, remove)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    joynr::types::DiscoveryEntryWithMetaInfo discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId,
                true
    );
    expectedResult.push_back(discoveryEntry);

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);

    try {
        discoveryProxy->remove(participantId);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "remove was not successful";
    }

    result.clear();
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}
<commit_msg>[C++] Fixed SystemServicesDiscoveryTest<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2017 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */
#include <memory>
#include <string>

#include <gtest/gtest.h>
#include <gmock/gmock.h>

#include "joynr/CapabilityUtils.h"
#include "joynr/JoynrClusterControllerRuntime.h"
#include "joynr/LibjoynrSettings.h"
#include "joynr/system/DiscoveryProxy.h"
#include "joynr/Settings.h"
#include "joynr/types/Version.h"
#include "joynr/system/RoutingTypes/MqttAddress.h"
#include "joynr/system/RoutingTypes/ChannelAddress.h"
#include "joynr/serializer/Serializer.h"

#include "tests/JoynrTest.h"
#include "tests/utils/MockObjects.h"

using namespace joynr;

class SystemServicesDiscoveryTest : public ::testing::Test {
public:
    std::string settingsFilename;
    std::unique_ptr<Settings> settings;
    std::string discoveryDomain;
    std::string discoveryProviderParticipantId;
    std::shared_ptr<JoynrClusterControllerRuntime> runtime;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverHttp;
    std::shared_ptr<ITransportMessageReceiver> mockMessageReceiverMqtt;
    std::shared_ptr<ITransportMessageSender> mockMessageSenderMqtt;
    DiscoveryQos discoveryQos;
    std::shared_ptr<ProxyBuilder<joynr::system::DiscoveryProxy>> discoveryProxyBuilder;
    std::shared_ptr<joynr::system::DiscoveryProxy> discoveryProxy;
    std::int64_t lastSeenDateMs;
    std::int64_t expiryDateMs;
    std::string publicKeyId;

    SystemServicesDiscoveryTest() :
        settingsFilename("test-resources/SystemServicesDiscoveryTest.settings"),
        settings(std::make_unique<Settings>(settingsFilename)),
        discoveryDomain(),
        discoveryProviderParticipantId(),
        runtime(),
        mockMessageReceiverHttp(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageReceiverMqtt(std::make_shared<MockTransportMessageReceiver>()),
        mockMessageSenderMqtt(std::make_shared<MockTransportMessageSender>()),
        discoveryQos(),
        discoveryProxyBuilder(nullptr),
        discoveryProxy(nullptr),
        lastSeenDateMs(-1),
        expiryDateMs(-1),
        publicKeyId("")
    {
        SystemServicesSettings systemSettings(*settings);
        systemSettings.printSettings();
        discoveryDomain = systemSettings.getDomain();
        discoveryProviderParticipantId = systemSettings.getCcDiscoveryProviderParticipantId();

        discoveryQos.setCacheMaxAgeMs(1000);
        discoveryQos.setArbitrationStrategy(DiscoveryQos::ArbitrationStrategy::FIXED_PARTICIPANT);
        discoveryQos.addCustomParameter("fixedParticipantId", discoveryProviderParticipantId);
        discoveryQos.setDiscoveryTimeoutMs(50);

        std::string httpChannelId("http_SystemServicesDiscoveryTest.ChannelId");
        std::string httpEndPointUrl("http_SystemServicesRoutingTest.endPointUrl");
        std::string mqttTopic("mqtt_SystemServicesRoutingTest.topic");
        std::string mqttBrokerUrl("mqtt_SystemServicesRoutingTest.brokerUrl");

        using system::RoutingTypes::ChannelAddress;
        using system::RoutingTypes::MqttAddress;

        std::string serializedChannelAddress = joynr::serializer::serializeToJson(ChannelAddress(httpEndPointUrl, httpChannelId));
        std::string serializedMqttAddress = joynr::serializer::serializeToJson(MqttAddress(mqttBrokerUrl, mqttTopic));

        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverHttp).get()), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedChannelAddress));
        EXPECT_CALL(*(std::dynamic_pointer_cast<MockTransportMessageReceiver>(mockMessageReceiverMqtt)), getGlobalClusterControllerAddress())
                .WillRepeatedly(::testing::ReturnRefOfCopy(serializedMqttAddress));

        //runtime can only be created, after MockCommunicationManager has been told to return
        //a channelId for getReceiveChannelId.
        runtime = std::make_shared<JoynrClusterControllerRuntime>(
                std::move(settings),
                mockMessageReceiverHttp,
                nullptr,
                mockMessageReceiverMqtt,
                mockMessageSenderMqtt);
        // discovery provider is normally registered in JoynrClusterControllerRuntime::create
        runtime->init();
        runtime->registerDiscoveryProvider();
        discoveryProxyBuilder = runtime->createProxyBuilder<joynr::system::DiscoveryProxy>(discoveryDomain);
    }

    ~SystemServicesDiscoveryTest(){
        discoveryProxy.reset();
        discoveryProxyBuilder.reset();
        runtime->unregisterDiscoveryProvider();
        runtime->deleteChannel();
        runtime->stopExternalCommunication();
        runtime.reset();

        // Delete persisted files
        std::remove(settingsFilename.c_str());
        std::remove(ClusterControllerSettings::DEFAULT_LOCAL_CAPABILITIES_DIRECTORY_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_MESSAGE_ROUTER_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_SUBSCRIPTIONREQUEST_PERSISTENCE_FILENAME().c_str());
        std::remove(LibjoynrSettings::DEFAULT_PARTICIPANT_IDS_PERSISTENCE_FILENAME().c_str());
    }

private:
    DISALLOW_COPY_AND_ASSIGN(SystemServicesDiscoveryTest);
};

TEST_F(SystemServicesDiscoveryTest, discoveryProviderIsAvailable)
{
    JOYNR_EXPECT_NO_THROW(
        discoveryProxy = discoveryProxyBuilder
                ->setMessagingQos(MessagingQos(5000))
                ->setDiscoveryQos(discoveryQos)
                ->build();
    );
}

TEST_F(SystemServicesDiscoveryTest, lookupUnknowParticipantReturnsEmptyResult)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}

TEST_F(SystemServicesDiscoveryTest, add)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    joynr::types::DiscoveryEntry discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId
    );
    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    auto expectedEntry = util::convert(true, discoveryEntry);
    expectedResult.push_back(expectedEntry);

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);
}

TEST_F(SystemServicesDiscoveryTest, remove)
{
    discoveryProxy = discoveryProxyBuilder
            ->setMessagingQos(MessagingQos(5000))
            ->setDiscoveryQos(discoveryQos)
            ->build();

    std::string domain("SystemServicesDiscoveryTest.Domain.A");
    std::string interfaceName("SystemServicesDiscoveryTest.InterfaceName.A");
    std::string participantId("SystemServicesDiscoveryTest.ParticipantID.A");
    joynr::types::DiscoveryQos discoveryQos(
                5000,                                     // max cache age
                5000,                                     // discovery ttl
                joynr::types::DiscoveryScope::LOCAL_ONLY, // discovery scope
                false                                     // provider must support on change subscriptions
    );
    joynr::types::ProviderQos providerQos(
                std::vector<joynr::types::CustomParameter>(), // custom provider parameters
                1,                                      // priority
                joynr::types::ProviderScope::LOCAL,     // scope for provider registration
                false                                   // provider supports on change subscriptions
    );
    joynr::types::Version providerVersion(47, 11);
    joynr::types::DiscoveryEntry discoveryEntry(
                providerVersion,
                domain,
                interfaceName,
                participantId,
                providerQos,
                lastSeenDateMs,
                expiryDateMs,
                publicKeyId
    );

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> expectedResult;
    auto expectedEntry = util::convert(true, discoveryEntry);
    expectedResult.push_back(expectedEntry);

    try {
        discoveryProxy->add(discoveryEntry);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "add was not successful";
    }

    std::vector<joynr::types::DiscoveryEntryWithMetaInfo> result;
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_EQ(expectedResult, result);

    try {
        discoveryProxy->remove(participantId);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "remove was not successful";
    }

    result.clear();
    try {
        discoveryProxy->lookup(result, {domain}, interfaceName, discoveryQos);
    } catch (const exceptions::JoynrException& e) {
        ADD_FAILURE()<< "lookup was not successful";
    }
    EXPECT_TRUE(result.empty());
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "indirect_reference_table.h"
#include "jni_internal.h"
#include "reference_table.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
#include "thread.h"
#include "utils.h"

#include <cstdlib>

namespace art {

static void AbortMaybe() {
  // If -Xcheck:jni is on, it'll give a more detailed error before aborting.
  if (!Runtime::Current()->GetJavaVM()->check_jni) {
    // Otherwise, we want to abort rather than hand back a bad reference.
    LOG(FATAL) << "JNI ERROR (app bug): see above.";
  }
}

IndirectReferenceTable::IndirectReferenceTable(size_t initialCount,
                                               size_t maxCount, IndirectRefKind desiredKind) {
  CHECK_GT(initialCount, 0U);
  CHECK_LE(initialCount, maxCount);
  CHECK_NE(desiredKind, kSirtOrInvalid);

  table_ = reinterpret_cast<mirror::Object**>(malloc(initialCount * sizeof(const mirror::Object*)));
  CHECK(table_ != NULL);
  memset(table_, 0xd1, initialCount * sizeof(const mirror::Object*));

  slot_data_ = reinterpret_cast<IndirectRefSlot*>(calloc(initialCount, sizeof(IndirectRefSlot)));
  CHECK(slot_data_ != NULL);

  segment_state_.all = IRT_FIRST_SEGMENT;
  alloc_entries_ = initialCount;
  max_entries_ = maxCount;
  kind_ = desiredKind;
}

IndirectReferenceTable::~IndirectReferenceTable() {
  free(table_);
  free(slot_data_);
  table_ = NULL;
  slot_data_ = NULL;
  alloc_entries_ = max_entries_ = -1;
}

// Make sure that the entry at "idx" is correctly paired with "iref".
bool IndirectReferenceTable::CheckEntry(const char* what, IndirectRef iref, int idx) const {
  const mirror::Object* obj = table_[idx];
  IndirectRef checkRef = ToIndirectRef(obj, idx);
  if (UNLIKELY(checkRef != iref)) {
    LOG(ERROR) << "JNI ERROR (app bug): attempt to " << what
               << " stale " << kind_ << " " << iref
               << " (should be " << checkRef << ")";
    AbortMaybe();
    return false;
  }
  return true;
}

IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) {
  IRTSegmentState prevState;
  prevState.all = cookie;
  size_t topIndex = segment_state_.parts.topIndex;

  DCHECK(obj != NULL);
  // TODO: stronger sanity check on the object (such as in heap)
  DCHECK_ALIGNED(reinterpret_cast<uintptr_t>(obj), 8);
  DCHECK(table_ != NULL);
  DCHECK_LE(alloc_entries_, max_entries_);
  DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);

  if (topIndex == alloc_entries_) {
    // reached end of allocated space; did we hit buffer max?
    if (topIndex == max_entries_) {
      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
                 << "(max=" << max_entries_ << ")\n"
                 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
    }

    size_t newSize = alloc_entries_ * 2;
    if (newSize > max_entries_) {
      newSize = max_entries_;
    }
    DCHECK_GT(newSize, alloc_entries_);

    table_ = reinterpret_cast<mirror::Object**>(realloc(table_, newSize * sizeof(mirror::Object*)));
    slot_data_ = reinterpret_cast<IndirectRefSlot*>(realloc(slot_data_,
                                                            newSize * sizeof(IndirectRefSlot)));
    if (table_ == NULL || slot_data_ == NULL) {
      LOG(FATAL) << "JNI ERROR (app bug): unable to expand "
                 << kind_ << " table (from "
                 << alloc_entries_ << " to " << newSize
                 << ", max=" << max_entries_ << ")\n"
                 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
    }

    // Clear the newly-allocated slot_data_ elements.
    memset(slot_data_ + alloc_entries_, 0, (newSize - alloc_entries_) * sizeof(IndirectRefSlot));

    alloc_entries_ = newSize;
  }

  // We know there's enough room in the table.  Now we just need to find
  // the right spot.  If there's a hole, find it and fill it; otherwise,
  // add to the end of the list.
  IndirectRef result;
  int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
  if (numHoles > 0) {
    DCHECK_GT(topIndex, 1U);
    // Find the first hole; likely to be near the end of the list.
    mirror::Object** pScan = &table_[topIndex - 1];
    DCHECK(*pScan != NULL);
    while (*--pScan != NULL) {
      DCHECK_GE(pScan, table_ + prevState.parts.topIndex);
    }
    UpdateSlotAdd(obj, pScan - table_);
    result = ToIndirectRef(obj, pScan - table_);
    *pScan = obj;
    segment_state_.parts.numHoles--;
  } else {
    // Add to the end.
    UpdateSlotAdd(obj, topIndex);
    result = ToIndirectRef(obj, topIndex);
    table_[topIndex++] = obj;
    segment_state_.parts.topIndex = topIndex;
  }
  if (false) {
    LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << segment_state_.parts.topIndex
              << " holes=" << segment_state_.parts.numHoles;
  }

  DCHECK(result != NULL);
  return result;
}

void IndirectReferenceTable::AssertEmpty() {
  if (UNLIKELY(begin() != end())) {
    ScopedObjectAccess soa(Thread::Current());
    LOG(FATAL) << "Internal Error: non-empty local reference table\n"
               << MutatorLockedDumpable<IndirectReferenceTable>(*this);
  }
}

// Verifies that the indirect table lookup is valid.
// Returns "false" if something looks bad.
bool IndirectReferenceTable::GetChecked(IndirectRef iref) const {
  if (UNLIKELY(iref == NULL)) {
    LOG(WARNING) << "Attempt to look up NULL " << kind_;
    return false;
  }
  if (UNLIKELY(GetIndirectRefKind(iref) == kSirtOrInvalid)) {
    LOG(ERROR) << "JNI ERROR (app bug): invalid " << kind_ << " " << iref;
    AbortMaybe();
    return false;
  }

  int topIndex = segment_state_.parts.topIndex;
  int idx = ExtractIndex(iref);
  if (UNLIKELY(idx >= topIndex)) {
    LOG(ERROR) << "JNI ERROR (app bug): accessed stale " << kind_ << " "
               << iref << " (index " << idx << " in a table of size " << topIndex << ")";
    AbortMaybe();
    return false;
  }

  if (UNLIKELY(table_[idx] == NULL)) {
    LOG(ERROR) << "JNI ERROR (app bug): accessed deleted " << kind_ << " " << iref;
    AbortMaybe();
    return false;
  }

  if (UNLIKELY(!CheckEntry("use", iref, idx))) {
    return false;
  }

  return true;
}

static int Find(mirror::Object* direct_pointer, int bottomIndex, int topIndex,
                mirror::Object** table) {
  for (int i = bottomIndex; i < topIndex; ++i) {
    if (table[i] == direct_pointer) {
      return i;
    }
  }
  return -1;
}

bool IndirectReferenceTable::ContainsDirectPointer(mirror::Object* direct_pointer) const {
  return Find(direct_pointer, 0, segment_state_.parts.topIndex, table_) != -1;
}

// Removes an object. We extract the table offset bits from "iref"
// and zap the corresponding entry, leaving a hole if it's not at the top.
// If the entry is not between the current top index and the bottom index
// specified by the cookie, we don't remove anything. This is the behavior
// required by JNI's DeleteLocalRef function.
// This method is not called when a local frame is popped; this is only used
// for explicit single removals.
// Returns "false" if nothing was removed.
bool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) {
  IRTSegmentState prevState;
  prevState.all = cookie;
  int topIndex = segment_state_.parts.topIndex;
  int bottomIndex = prevState.parts.topIndex;

  DCHECK(table_ != NULL);
  DCHECK_LE(alloc_entries_, max_entries_);
  DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);

  int idx = ExtractIndex(iref);

  JavaVMExt* vm = Runtime::Current()->GetJavaVM();
  if (GetIndirectRefKind(iref) == kSirtOrInvalid &&
      Thread::Current()->SirtContains(reinterpret_cast<jobject>(iref))) {
    LOG(WARNING) << "Attempt to remove local SIRT entry from IRT, ignoring";
    return true;
  }
  if (GetIndirectRefKind(iref) == kSirtOrInvalid && vm->work_around_app_jni_bugs) {
    mirror::Object* direct_pointer = reinterpret_cast<mirror::Object*>(iref);
    idx = Find(direct_pointer, bottomIndex, topIndex, table_);
    if (idx == -1) {
      LOG(WARNING) << "Trying to work around app JNI bugs, but didn't find " << iref << " in table!";
      return false;
    }
  }

  if (idx < bottomIndex) {
    // Wrong segment.
    LOG(WARNING) << "Attempt to remove index outside index area (" << idx
                 << " vs " << bottomIndex << "-" << topIndex << ")";
    return false;
  }
  if (idx >= topIndex) {
    // Bad --- stale reference?
    LOG(WARNING) << "Attempt to remove invalid index " << idx
                 << " (bottom=" << bottomIndex << " top=" << topIndex << ")";
    return false;
  }

  if (idx == topIndex-1) {
    // Top-most entry.  Scan up and consume holes.

    if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) {
      return false;
    }

    table_[idx] = NULL;
    int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
    if (numHoles != 0) {
      while (--topIndex > bottomIndex && numHoles != 0) {
        if (false) {
          LOG(INFO) << "+++ checking for hole at " << topIndex-1
                    << " (cookie=" << cookie << ") val=" << table_[topIndex - 1];
        }
        if (table_[topIndex-1] != NULL) {
          break;
        }
        if (false) {
          LOG(INFO) << "+++ ate hole at " << (topIndex - 1);
        }
        numHoles--;
      }
      segment_state_.parts.numHoles = numHoles + prevState.parts.numHoles;
      segment_state_.parts.topIndex = topIndex;
    } else {
      segment_state_.parts.topIndex = topIndex-1;
      if (false) {
        LOG(INFO) << "+++ ate last entry " << topIndex - 1;
      }
    }
  } else {
    // Not the top-most entry.  This creates a hole.  We NULL out the
    // entry to prevent somebody from deleting it twice and screwing up
    // the hole count.
    if (table_[idx] == NULL) {
      LOG(INFO) << "--- WEIRD: removing null entry " << idx;
      return false;
    }
    if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) {
      return false;
    }

    table_[idx] = NULL;
    segment_state_.parts.numHoles++;
    if (false) {
      LOG(INFO) << "+++ left hole at " << idx << ", holes=" << segment_state_.parts.numHoles;
    }
  }

  return true;
}

void IndirectReferenceTable::VisitRoots(RootVisitor* visitor, void* arg) {
  for (auto ref : *this) {
    *ref = visitor(const_cast<mirror::Object*>(*ref), arg);
    DCHECK(*ref != nullptr);
  }
}

void IndirectReferenceTable::Dump(std::ostream& os) const {
  os << kind_ << " table dump:\n";
  ReferenceTable::Table entries(table_, table_ + Capacity());
  // Remove NULLs.
  for (int i = entries.size() - 1; i >= 0; --i) {
    if (entries[i] == NULL) {
      entries.erase(entries.begin() + i);
    }
  }
  ReferenceTable::Dump(os, entries);
}

}  // namespace art
<commit_msg>am 7a761d8c: Merge "Change IndirectReferenceTable::Add null DCHECK to CHECK."<commit_after>/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "indirect_reference_table.h"
#include "jni_internal.h"
#include "reference_table.h"
#include "runtime.h"
#include "scoped_thread_state_change.h"
#include "thread.h"
#include "utils.h"

#include <cstdlib>

namespace art {

static void AbortMaybe() {
  // If -Xcheck:jni is on, it'll give a more detailed error before aborting.
  if (!Runtime::Current()->GetJavaVM()->check_jni) {
    // Otherwise, we want to abort rather than hand back a bad reference.
    LOG(FATAL) << "JNI ERROR (app bug): see above.";
  }
}

IndirectReferenceTable::IndirectReferenceTable(size_t initialCount,
                                               size_t maxCount, IndirectRefKind desiredKind) {
  CHECK_GT(initialCount, 0U);
  CHECK_LE(initialCount, maxCount);
  CHECK_NE(desiredKind, kSirtOrInvalid);

  table_ = reinterpret_cast<mirror::Object**>(malloc(initialCount * sizeof(const mirror::Object*)));
  CHECK(table_ != NULL);
  memset(table_, 0xd1, initialCount * sizeof(const mirror::Object*));

  slot_data_ = reinterpret_cast<IndirectRefSlot*>(calloc(initialCount, sizeof(IndirectRefSlot)));
  CHECK(slot_data_ != NULL);

  segment_state_.all = IRT_FIRST_SEGMENT;
  alloc_entries_ = initialCount;
  max_entries_ = maxCount;
  kind_ = desiredKind;
}

IndirectReferenceTable::~IndirectReferenceTable() {
  free(table_);
  free(slot_data_);
  table_ = NULL;
  slot_data_ = NULL;
  alloc_entries_ = max_entries_ = -1;
}

// Make sure that the entry at "idx" is correctly paired with "iref".
bool IndirectReferenceTable::CheckEntry(const char* what, IndirectRef iref, int idx) const {
  const mirror::Object* obj = table_[idx];
  IndirectRef checkRef = ToIndirectRef(obj, idx);
  if (UNLIKELY(checkRef != iref)) {
    LOG(ERROR) << "JNI ERROR (app bug): attempt to " << what
               << " stale " << kind_ << " " << iref
               << " (should be " << checkRef << ")";
    AbortMaybe();
    return false;
  }
  return true;
}

IndirectRef IndirectReferenceTable::Add(uint32_t cookie, mirror::Object* obj) {
  IRTSegmentState prevState;
  prevState.all = cookie;
  size_t topIndex = segment_state_.parts.topIndex;

  CHECK(obj != NULL);
  // TODO: stronger sanity check on the object (such as in heap)
  DCHECK_ALIGNED(reinterpret_cast<uintptr_t>(obj), 8);
  DCHECK(table_ != NULL);
  DCHECK_LE(alloc_entries_, max_entries_);
  DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);

  if (topIndex == alloc_entries_) {
    // reached end of allocated space; did we hit buffer max?
    if (topIndex == max_entries_) {
      LOG(FATAL) << "JNI ERROR (app bug): " << kind_ << " table overflow "
                 << "(max=" << max_entries_ << ")\n"
                 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
    }

    size_t newSize = alloc_entries_ * 2;
    if (newSize > max_entries_) {
      newSize = max_entries_;
    }
    DCHECK_GT(newSize, alloc_entries_);

    table_ = reinterpret_cast<mirror::Object**>(realloc(table_, newSize * sizeof(mirror::Object*)));
    slot_data_ = reinterpret_cast<IndirectRefSlot*>(realloc(slot_data_,
                                                            newSize * sizeof(IndirectRefSlot)));
    if (table_ == NULL || slot_data_ == NULL) {
      LOG(FATAL) << "JNI ERROR (app bug): unable to expand "
                 << kind_ << " table (from "
                 << alloc_entries_ << " to " << newSize
                 << ", max=" << max_entries_ << ")\n"
                 << MutatorLockedDumpable<IndirectReferenceTable>(*this);
    }

    // Clear the newly-allocated slot_data_ elements.
    memset(slot_data_ + alloc_entries_, 0, (newSize - alloc_entries_) * sizeof(IndirectRefSlot));

    alloc_entries_ = newSize;
  }

  // We know there's enough room in the table.  Now we just need to find
  // the right spot.  If there's a hole, find it and fill it; otherwise,
  // add to the end of the list.
  IndirectRef result;
  int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
  if (numHoles > 0) {
    DCHECK_GT(topIndex, 1U);
    // Find the first hole; likely to be near the end of the list.
    mirror::Object** pScan = &table_[topIndex - 1];
    DCHECK(*pScan != NULL);
    while (*--pScan != NULL) {
      DCHECK_GE(pScan, table_ + prevState.parts.topIndex);
    }
    UpdateSlotAdd(obj, pScan - table_);
    result = ToIndirectRef(obj, pScan - table_);
    *pScan = obj;
    segment_state_.parts.numHoles--;
  } else {
    // Add to the end.
    UpdateSlotAdd(obj, topIndex);
    result = ToIndirectRef(obj, topIndex);
    table_[topIndex++] = obj;
    segment_state_.parts.topIndex = topIndex;
  }
  if (false) {
    LOG(INFO) << "+++ added at " << ExtractIndex(result) << " top=" << segment_state_.parts.topIndex
              << " holes=" << segment_state_.parts.numHoles;
  }

  DCHECK(result != NULL);
  return result;
}

void IndirectReferenceTable::AssertEmpty() {
  if (UNLIKELY(begin() != end())) {
    ScopedObjectAccess soa(Thread::Current());
    LOG(FATAL) << "Internal Error: non-empty local reference table\n"
               << MutatorLockedDumpable<IndirectReferenceTable>(*this);
  }
}

// Verifies that the indirect table lookup is valid.
// Returns "false" if something looks bad.
bool IndirectReferenceTable::GetChecked(IndirectRef iref) const {
  if (UNLIKELY(iref == NULL)) {
    LOG(WARNING) << "Attempt to look up NULL " << kind_;
    return false;
  }
  if (UNLIKELY(GetIndirectRefKind(iref) == kSirtOrInvalid)) {
    LOG(ERROR) << "JNI ERROR (app bug): invalid " << kind_ << " " << iref;
    AbortMaybe();
    return false;
  }

  int topIndex = segment_state_.parts.topIndex;
  int idx = ExtractIndex(iref);
  if (UNLIKELY(idx >= topIndex)) {
    LOG(ERROR) << "JNI ERROR (app bug): accessed stale " << kind_ << " "
               << iref << " (index " << idx << " in a table of size " << topIndex << ")";
    AbortMaybe();
    return false;
  }

  if (UNLIKELY(table_[idx] == NULL)) {
    LOG(ERROR) << "JNI ERROR (app bug): accessed deleted " << kind_ << " " << iref;
    AbortMaybe();
    return false;
  }

  if (UNLIKELY(!CheckEntry("use", iref, idx))) {
    return false;
  }

  return true;
}

static int Find(mirror::Object* direct_pointer, int bottomIndex, int topIndex,
                mirror::Object** table) {
  for (int i = bottomIndex; i < topIndex; ++i) {
    if (table[i] == direct_pointer) {
      return i;
    }
  }
  return -1;
}

bool IndirectReferenceTable::ContainsDirectPointer(mirror::Object* direct_pointer) const {
  return Find(direct_pointer, 0, segment_state_.parts.topIndex, table_) != -1;
}

// Removes an object. We extract the table offset bits from "iref"
// and zap the corresponding entry, leaving a hole if it's not at the top.
// If the entry is not between the current top index and the bottom index
// specified by the cookie, we don't remove anything. This is the behavior
// required by JNI's DeleteLocalRef function.
// This method is not called when a local frame is popped; this is only used
// for explicit single removals.
// Returns "false" if nothing was removed.
bool IndirectReferenceTable::Remove(uint32_t cookie, IndirectRef iref) {
  IRTSegmentState prevState;
  prevState.all = cookie;
  int topIndex = segment_state_.parts.topIndex;
  int bottomIndex = prevState.parts.topIndex;

  DCHECK(table_ != NULL);
  DCHECK_LE(alloc_entries_, max_entries_);
  DCHECK_GE(segment_state_.parts.numHoles, prevState.parts.numHoles);

  int idx = ExtractIndex(iref);

  JavaVMExt* vm = Runtime::Current()->GetJavaVM();
  if (GetIndirectRefKind(iref) == kSirtOrInvalid &&
      Thread::Current()->SirtContains(reinterpret_cast<jobject>(iref))) {
    LOG(WARNING) << "Attempt to remove local SIRT entry from IRT, ignoring";
    return true;
  }
  if (GetIndirectRefKind(iref) == kSirtOrInvalid && vm->work_around_app_jni_bugs) {
    mirror::Object* direct_pointer = reinterpret_cast<mirror::Object*>(iref);
    idx = Find(direct_pointer, bottomIndex, topIndex, table_);
    if (idx == -1) {
      LOG(WARNING) << "Trying to work around app JNI bugs, but didn't find " << iref << " in table!";
      return false;
    }
  }

  if (idx < bottomIndex) {
    // Wrong segment.
    LOG(WARNING) << "Attempt to remove index outside index area (" << idx
                 << " vs " << bottomIndex << "-" << topIndex << ")";
    return false;
  }
  if (idx >= topIndex) {
    // Bad --- stale reference?
    LOG(WARNING) << "Attempt to remove invalid index " << idx
                 << " (bottom=" << bottomIndex << " top=" << topIndex << ")";
    return false;
  }

  if (idx == topIndex-1) {
    // Top-most entry.  Scan up and consume holes.

    if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) {
      return false;
    }

    table_[idx] = NULL;
    int numHoles = segment_state_.parts.numHoles - prevState.parts.numHoles;
    if (numHoles != 0) {
      while (--topIndex > bottomIndex && numHoles != 0) {
        if (false) {
          LOG(INFO) << "+++ checking for hole at " << topIndex-1
                    << " (cookie=" << cookie << ") val=" << table_[topIndex - 1];
        }
        if (table_[topIndex-1] != NULL) {
          break;
        }
        if (false) {
          LOG(INFO) << "+++ ate hole at " << (topIndex - 1);
        }
        numHoles--;
      }
      segment_state_.parts.numHoles = numHoles + prevState.parts.numHoles;
      segment_state_.parts.topIndex = topIndex;
    } else {
      segment_state_.parts.topIndex = topIndex-1;
      if (false) {
        LOG(INFO) << "+++ ate last entry " << topIndex - 1;
      }
    }
  } else {
    // Not the top-most entry.  This creates a hole.  We NULL out the
    // entry to prevent somebody from deleting it twice and screwing up
    // the hole count.
    if (table_[idx] == NULL) {
      LOG(INFO) << "--- WEIRD: removing null entry " << idx;
      return false;
    }
    if (!vm->work_around_app_jni_bugs && !CheckEntry("remove", iref, idx)) {
      return false;
    }

    table_[idx] = NULL;
    segment_state_.parts.numHoles++;
    if (false) {
      LOG(INFO) << "+++ left hole at " << idx << ", holes=" << segment_state_.parts.numHoles;
    }
  }

  return true;
}

void IndirectReferenceTable::VisitRoots(RootVisitor* visitor, void* arg) {
  for (auto ref : *this) {
    *ref = visitor(const_cast<mirror::Object*>(*ref), arg);
    DCHECK(*ref != nullptr);
  }
}

void IndirectReferenceTable::Dump(std::ostream& os) const {
  os << kind_ << " table dump:\n";
  ReferenceTable::Table entries(table_, table_ + Capacity());
  // Remove NULLs.
  for (int i = entries.size() - 1; i >= 0; --i) {
    if (entries[i] == NULL) {
      entries.erase(entries.begin() + i);
    }
  }
  ReferenceTable::Dump(os, entries);
}

}  // namespace art
<|endoftext|>