Commit a08d113d authored by Steven Murray's avatar Steven Murray
Browse files

Acs, Manual and Scsi library slots now inherit from LibrarySlot

parent b1c3768d
......@@ -47,7 +47,7 @@ protected:
ArgcvList m_argsList;
/**
* Creates a duplicate string usin the new operator.
* Creates a duplicate string using the new operator.
*/
char *dupString(const char *str) {
const size_t len = strlen(str);
......
......@@ -58,15 +58,13 @@ void castor::legacymsg::RmcProxyTcpIp::mountTapeReadOnly(
void castor::legacymsg::RmcProxyTcpIp::mountTapeReadWrite(
const std::string &vid, const mediachanger::ScsiLibrarySlot &librarySlot) {
try {
const mediachanger::ScsiLibrarySlot parsedSlot(librarySlot);
RmcMountMsgBody rqstBody;
rqstBody.uid = geteuid();
rqstBody.gid = getegid();
castor::utils::copyString(rqstBody.vid, vid);
rqstBody.drvOrd = parsedSlot.getDrvOrd();
rqstBody.drvOrd = librarySlot.getDrvOrd();
rmcSendRecvNbAttempts(RMC_MAXATTEMPTS, parsedSlot.getRmcHostName(),
rmcSendRecvNbAttempts(RMC_MAXATTEMPTS, librarySlot.getRmcHostName(),
rqstBody);
} catch(castor::exception::Exception &ne) {
castor::exception::Exception ex;
......@@ -84,16 +82,14 @@ void castor::legacymsg::RmcProxyTcpIp::mountTapeReadWrite(
void castor::legacymsg::RmcProxyTcpIp::dismountTape(const std::string &vid,
const mediachanger::ScsiLibrarySlot &librarySlot) {
try {
const mediachanger::ScsiLibrarySlot parsedSlot(librarySlot);
RmcUnmountMsgBody rqstBody;
rqstBody.uid = geteuid();
rqstBody.gid = getegid();
castor::utils::copyString(rqstBody.vid, vid);
rqstBody.drvOrd = parsedSlot.getDrvOrd();
rqstBody.drvOrd = librarySlot.getDrvOrd();
rqstBody.force = 0;
rmcSendRecvNbAttempts(RMC_MAXATTEMPTS, parsedSlot.getRmcHostName(),
rmcSendRecvNbAttempts(RMC_MAXATTEMPTS, librarySlot.getRmcHostName(),
rqstBody);
} catch(castor::exception::Exception &ne) {
castor::exception::Exception ex;
......
......@@ -28,111 +28,50 @@
// constructor
//------------------------------------------------------------------------------
castor::mediachanger::AcsLibrarySlot::AcsLibrarySlot() throw():
LibrarySlot(TAPE_LIBRARY_TYPE_ACS),
m_acs(0),
m_lsm(0),
m_panel(0),
m_drive(0) {
m_str = librarySlotToString(0, 0, 0, 0);
}
//------------------------------------------------------------------------------
// constructor
// librarySlotToString
//------------------------------------------------------------------------------
castor::mediachanger::AcsLibrarySlot::AcsLibrarySlot(const std::string &str) {
const std::string errMsg("Failed to construct AcsLibrarySlot");
std::vector<std::string> components;
castor::utils::splitString(str, ',', components);
if(4 != components.size()) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": Invalid number of components"
": expected=4, actual=" << components.size();
throw ex;
}
// check for acs in the beginning
const std::string &acsWithACS_NUMBERStr = components[0];
if(0 != acsWithACS_NUMBERStr.find("acs")) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": Invalid tape library-slot format"
": expected=acsACS_NUMBER, actual=" << acsWithACS_NUMBERStr;
throw ex;
}
const std::string::size_type indexOfACS_NUMBER = 3; // skip acs
const std::string &acsStr = acsWithACS_NUMBERStr.substr(indexOfACS_NUMBER);
const std::string &lsmStr = components[1];
const std::string &panStr = components[2];
const std::string &drvStr = components[3];
// Each of the 4 components must be between 1 and than 3 characters long
if(1 > acsStr.length() || 3 < acsStr.length()) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": Invalid ACS_NUMBER string length"
": expected=1..3, actual=" << acsStr.length();
throw ex;
}
if(1 > lsmStr.length() || 3 < lsmStr.length()) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": Invalid LSM_NUMBER string length"
": expected=1..3, actual=" << lsmStr.length();
throw ex;
}
if(1 > panStr.length() || 3 < panStr.length()) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": Invalid PANEL_NUMBER string length"
": expected=1..3, actual=" << panStr.length();
throw ex;
}
if(1 > drvStr.length() || 3 < drvStr.length()) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": Invalid TRANSPORT_NUMBER string length"
": expected=1..3, actual=" << drvStr.length();
throw ex;
}
std::string castor::mediachanger::AcsLibrarySlot::librarySlotToString(
const uint32_t acs, const uint32_t lsm, const uint32_t panel,
const uint32_t drive) const {
std::ostringstream oss;
oss << "acs" << acs << "," << lsm << "," << panel << "," << drive;
return oss.str();
}
// Each of the 4 components must only contain numerals
if(!onlyContainsNumerals(acsStr)) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": ACS_NUMBER must only contain numerals:"
" value=" << acsStr;
throw ex;
}
if(!onlyContainsNumerals(lsmStr)) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": LSM_NUMBER must only contain numerals:"
" value=" << acsStr;
throw ex;
}
if(!onlyContainsNumerals(panStr)) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": PANEL_NUMBER must only contain numerals:"
" value=" << acsStr;
throw ex;
}
if(!onlyContainsNumerals(drvStr)) {
castor::exception::InvalidArgument ex;
ex.getMessage() << errMsg << ": TRANSPORT__NUMBER must only contain "
"numerals: value=" << acsStr;
throw ex;
}
//------------------------------------------------------------------------------
// constructor
//------------------------------------------------------------------------------
castor::mediachanger::AcsLibrarySlot::AcsLibrarySlot(const uint32_t acs,
const uint32_t lsm, const uint32_t panel, const uint32_t drive) throw():
LibrarySlot(TAPE_LIBRARY_TYPE_ACS),
m_acs(acs),
m_lsm(lsm),
m_panel(panel),
m_drive(drive) {
m_str = librarySlotToString(acs, lsm, panel, drive);
}
m_acs = atoi(acsStr.c_str());
m_lsm = atoi(lsmStr.c_str());
m_panel = atoi(panStr.c_str());
m_drive = atoi(drvStr.c_str());
//------------------------------------------------------------------------------
// destructor
//------------------------------------------------------------------------------
castor::mediachanger::AcsLibrarySlot::~AcsLibrarySlot() throw() {
}
//------------------------------------------------------------------------------
// onlyContainsNumerals
//------------------------------------------------------------------------------
bool castor::mediachanger::AcsLibrarySlot::onlyContainsNumerals(
const std::string &str) const throw() {
for(std::string::const_iterator itor = str.begin(); itor != str.end();
itor++) {
if(*itor < '0' || *itor > '9') {
return false;
}
}
return true;
// clone
//------------------------------------------------------------------------------
castor::mediachanger::LibrarySlot *castor::mediachanger::AcsLibrarySlot::
clone() {
return new AcsLibrarySlot(*this);
}
//------------------------------------------------------------------------------
......@@ -162,14 +101,3 @@ uint32_t castor::mediachanger::AcsLibrarySlot::getPanel() const throw () {
uint32_t castor::mediachanger::AcsLibrarySlot::getDrive() const throw () {
return m_drive;
}
//------------------------------------------------------------------------------
// str
//------------------------------------------------------------------------------
std::string castor::mediachanger::AcsLibrarySlot::str() const {
std::ostringstream oss;
oss << "acs=" << m_acs << " lsm=" << m_lsm << " panel=" << m_panel <<
" drive=" << m_drive;
return oss.str();
}
......@@ -22,9 +22,9 @@
#pragma once
#include "castor/exception/InvalidArgument.hpp"
#include "castor/mediachanger/LibrarySlot.hpp"
#include <stdint.h>
#include <string>
namespace castor {
namespace mediachanger {
......@@ -32,7 +32,7 @@ namespace mediachanger {
/**
* Class reprsenting a slot in an ACS tape-library.
*/
class AcsLibrarySlot {
class AcsLibrarySlot: public LibrarySlot {
public:
/**
......@@ -43,53 +43,53 @@ public:
/**
* Constructor.
*
* This method throws a castor::exception::InvalidArgument if the specified
* string representation is invalid.
*
* @param The string representation of a slot in an ACS tape-library in format
* acsACS_NUMBER,LSM_NUMBER,PANEL_NUMBER,TRANSPORT_NUMBER
* @param acs The acs component of the library slot.
* @param lsm The lsm component of the library slot.
* @param panel The panel component of the library slot.
* @param drive The drive component of the library slot.
*/
AcsLibrarySlot(const uint32_t acs, const uint32_t lsm,
const uint32_t panel, const uint32_t drive) throw();
/**
* Destructor.
*/
AcsLibrarySlot(const std::string &str);
~AcsLibrarySlot() throw();
/**
* Returns true if the specified string only contains numerals else false.
* Creates a clone of this object.
*
* @return True if the specified string only contains numerals else false.
* @return The clone.
*/
bool onlyContainsNumerals(const std::string &str) const throw();
LibrarySlot *clone();
/**
* Gets the acs component of the library slot.
*
* @return the acs component of the library slot.
*/
uint32_t getAcs() const throw ();
uint32_t getAcs() const throw();
/**
* Gets the lsm component of the library slot.
*
* @return the lsm component of the library slot.
*/
uint32_t getLsm() const throw ();
uint32_t getLsm() const throw();
/**
* Gets the panel component of the library slot.
*
* @return the panel component of the library slot.
*/
uint32_t getPanel() const throw ();
uint32_t getPanel() const throw();
/**
* Gets the drive component of the library slot.
*
* @return the drive component of the library slot.
*/
uint32_t getDrive() const throw ();
/**
* Returns the representation of the slot.
*/
std::string str() const;
uint32_t getDrive() const throw();
private:
......@@ -113,8 +113,19 @@ private:
*/
uint32_t m_drive;
/**
* Returns the string representation of the specified ACS library slot.
*
* @param acs The acs component of the library slot.
* @param lsm The lsm component of the library slot.
* @param panel The panel component of the library slot.
* @param drive The drive component of the library slot.
* @return The string representation.
*/
std::string librarySlotToString(const uint32_t acs, const uint32_t lsm,
const uint32_t panel, const uint32_t drive) const;
}; // class AcsProxy
} // namespace mediachanger
} // namespace castor
......@@ -24,6 +24,7 @@
#include "castor/mediachanger/AcsLibrarySlot.hpp"
#include <gtest/gtest.h>
#include <memory>
namespace unitTests {
......@@ -37,45 +38,37 @@ protected:
}
};
TEST_F(castor_mediachanger_AcsLibrarySlotTest, goodDayParsing) {
TEST_F(castor_mediachanger_AcsLibrarySlotTest, goodDay) {
using namespace castor::mediachanger;
AcsLibrarySlot slot;
ASSERT_EQ(std::string("acs=0 lsm=0 panel=0 drive=0"), slot.str());
ASSERT_EQ((uint32_t)0, slot.getAcs());
ASSERT_EQ((uint32_t)0, slot.getLsm());
ASSERT_EQ((uint32_t)0, slot.getPanel());
ASSERT_EQ((uint32_t)0, slot.getDrive());
const std::string str = "acs11,22,33,44";
ASSERT_NO_THROW(slot = AcsLibrarySlot(str));
ASSERT_EQ(std::string("acs=11 lsm=22 panel=33 drive=44"), slot.str());
AcsLibrarySlot slot(11, 22, 33, 44);
ASSERT_EQ(TAPE_LIBRARY_TYPE_ACS, slot.getLibraryType());
ASSERT_EQ(std::string("acs11,22,33,44"), slot.str());
ASSERT_EQ((uint32_t)11, slot.getAcs());
ASSERT_EQ((uint32_t)22, slot.getLsm());
ASSERT_EQ((uint32_t)33, slot.getPanel());
ASSERT_EQ((uint32_t)44, slot.getDrive());
}
TEST_F(castor_mediachanger_AcsLibrarySlotTest, badDayParsing) {
TEST_F(castor_mediachanger_AcsLibrarySlotTest, clone) {
using namespace castor::mediachanger;
const std::string str = "nonsense";
ASSERT_THROW(AcsLibrarySlot slot(str), castor::exception::InvalidArgument);
const std::string strAcs = "asc0,1,2,3";
ASSERT_THROW(AcsLibrarySlot slot(strAcs), castor::exception::InvalidArgument);
const std::string strACS_NUMBER = "acssd1,1,2,3";
ASSERT_THROW(AcsLibrarySlot slot(strACS_NUMBER), castor::exception::InvalidArgument);
const std::string strLsm = "acs0,1111,2,3";
ASSERT_THROW(AcsLibrarySlot slot(strLsm), castor::exception::InvalidArgument);
const std::string strPanel = "acs0,111,ABC,3";
ASSERT_THROW(AcsLibrarySlot slot(strPanel), castor::exception::InvalidArgument);
const std::string strDrive = "acs0,111,222,3 ";
ASSERT_THROW(AcsLibrarySlot slot(strDrive), castor::exception::InvalidArgument);
std::auto_ptr<AcsLibrarySlot> slot1;
ASSERT_NO_THROW(slot1.reset(new AcsLibrarySlot(11, 22, 33, 44)));
ASSERT_EQ(TAPE_LIBRARY_TYPE_ACS, slot1->getLibraryType());
ASSERT_EQ(std::string("acs11,22,33,44"), slot1->str());
ASSERT_EQ((uint32_t)11, slot1->getAcs());
ASSERT_EQ((uint32_t)22, slot1->getLsm());
ASSERT_EQ((uint32_t)33, slot1->getPanel());
ASSERT_EQ((uint32_t)44, slot1->getDrive());
std::auto_ptr<AcsLibrarySlot> slot2;
ASSERT_NO_THROW(slot2.reset((AcsLibrarySlot*)slot1->clone()));
ASSERT_EQ(TAPE_LIBRARY_TYPE_ACS, slot2->getLibraryType());
ASSERT_EQ(std::string("acs11,22,33,44"), slot2->str());
ASSERT_EQ((uint32_t)11, slot2->getAcs());
ASSERT_EQ((uint32_t)22, slot2->getLsm());
ASSERT_EQ((uint32_t)33, slot2->getPanel());
ASSERT_EQ((uint32_t)44, slot2->getDrive());
}
} // namespace unitTests
......@@ -21,7 +21,8 @@ cmake_minimum_required (VERSION 2.6)
set (MEDIA_CHANGER_LIB_SRC_FILES
AcsLibrarySlot.cpp
GenericLibrarySlot.cpp
LibrarySlot.cpp
LibrarySlotParser.cpp
ManualLibrarySlot.cpp
MediaChangerFacade.cpp
MmcProxy.cpp
......
......@@ -32,7 +32,7 @@ namespace mediachanger {
* Class containing the code common to the parsed command-line of the ACS
* command-line tools provided by CASTOR.
*/
struct CmdLine {
class CmdLine {
protected:
/**
......
......@@ -45,10 +45,11 @@ public:
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
* @param mc Object representing the API of the media changer.
* @param mc Interface to the media changer.
*/
CmdLineTool(std::istream &inStream, std::ostream &outStream,
std::ostream &errStream, MediaChangerFacade &mc) throw();
std::ostream &errStream, MediaChangerFacade &mc)
throw();
/**
* Pure-virtual destructor to guarantee this class is abstract.
......@@ -73,7 +74,7 @@ protected:
std::ostream &m_err;
/**
* Object representing the API of the media changer.
* Interface to the media changer.
*/
MediaChangerFacade &m_mc;
......
......@@ -25,6 +25,7 @@
#include <getopt.h>
#include <iostream>
#include <memory>
//------------------------------------------------------------------------------
// constructor
......@@ -51,20 +52,22 @@ void castor::mediachanger::DismountCmd::exceptionThrowingMain(const int argc,
// Display the usage message to standard out and exit with success if the
// user requested help
if(m_cmdLine.help) {
m_out << DismountCmdLine::getUsage();
if(m_cmdLine.getHelp()) {
m_out << m_cmdLine.getUsage();
return;
}
// Setup debug mode to be on or off depending on the command-line arguments
m_debugBuf.setDebug(m_cmdLine.debug);
m_debugBuf.setDebug(m_cmdLine.getDebug());
m_dbg << "VID = " << m_cmdLine.vid << std::endl;
m_dbg << "DRIVE_SLOT = " << m_cmdLine.driveLibrarySlot.str() << std::endl;
m_dbg << "VID = " << m_cmdLine.getVid() << std::endl;
m_dbg << "DRIVE_SLOT = " << m_cmdLine.getDriveLibrarySlot().str() <<
std::endl;
if(m_cmdLine.force) {
m_mc.forceDismountTape(m_cmdLine.vid, m_cmdLine.driveLibrarySlot);
if(m_cmdLine.getForce()) {
m_mc.forceDismountTape(m_cmdLine.getVid(),
m_cmdLine.getDriveLibrarySlot());
} else {
m_mc.dismountTape(m_cmdLine.vid, m_cmdLine.driveLibrarySlot);
m_mc.dismountTape(m_cmdLine.getVid(), m_cmdLine.getDriveLibrarySlot());
}
}
......@@ -47,7 +47,7 @@ public:
* @param inStream Standard input stream.
* @param outStream Standard output stream.
* @param errStream Standard error stream.
* @param mc Object representing the API of the media changer.
* @param mc Interface to the media changer.
*/
DismountCmd(std::istream &inStream, std::ostream &outStream,
std::ostream &errStream, MediaChangerFacade &mc) throw();
......
......@@ -24,6 +24,7 @@
#include "castor/exception/Exception.hpp"
#include "castor/exception/MissingOperand.hpp"
#include "castor/mediachanger/DismountCmdLine.hpp"
#include "castor/mediachanger/LibrarySlotParser.hpp"
#include <getopt.h>
......@@ -31,9 +32,10 @@
// constructor
//-----------------------------------------------------------------------------
castor::mediachanger::DismountCmdLine::DismountCmdLine() throw():
debug(false),
help(false),
force(false) {
m_debug(false),
m_help(false),
m_driveLibrarySlot(0),
m_force(false) {
}
//------------------------------------------------------------------------------
......@@ -41,9 +43,10 @@ castor::mediachanger::DismountCmdLine::DismountCmdLine() throw():
//------------------------------------------------------------------------------
castor::mediachanger::DismountCmdLine::DismountCmdLine(const int argc,
char *const *const argv):
debug(false),
help(false),
force(false) {
m_debug(false),
m_help(false),
m_driveLibrarySlot(0),
m_force(false) {
static struct option longopts[] = {
{"debug", 0, NULL, 'd'},
......@@ -62,7 +65,7 @@ castor::mediachanger::DismountCmdLine::DismountCmdLine(const int argc,
}
// There is no need to continue parsing when the help option is set
if(help) {
if(m_help) {
return;
}
......@@ -77,13 +80,60 @@ castor::mediachanger::DismountCmdLine::DismountCmdLine(const int argc,
}
// Parse the VID command-line argument
vid = argv[optind];
m_vid = argv[optind];
// Move on to the next command-line argument
optind++;
// Parse the DRIVE_SLOT command-line argument
driveLibrarySlot = GenericLibrarySlot(argv[optind]);
const std::string driveLibrarySlot = argv[optind];
m_driveLibrarySlot = LibrarySlotParser::parse(driveLibrarySlot);
}
//-----------------------------------------------------------------------------
// copy constructor
//-----------------------------------------------------------------------------
castor::mediachanger::DismountCmdLine::DismountCmdLine(
const DismountCmdLine &obj):
m_debug(obj.m_debug),
m_help(obj.m_help),
m_driveLibrarySlot(0 == obj.m_driveLibrarySlot ? 0 :
obj.m_driveLibrarySlot->clone()),
m_force(obj.m_force) {
}
//-----------------------------------------------------------------------------
// destructor
//-----------------------------------------------------------------------------
castor::mediachanger::DismountCmdLine::~DismountCmdLine() throw() {
delete m_driveLibrarySlot;
}
//------------------------------------------------------------------------------
// assignment operator
//------------------------------------------------------------------------------
castor::mediachanger::DismountCmdLine &castor::mediachanger::DismountCmdLine::
operator=(const DismountCmdLine &rhs) {
// If this is not a self assigment
if(this != &rhs) {
// Avoid a memory leak
delete(m_driveLibrarySlot);
m_debug = rhs.m_debug;
m_help = rhs.m_help;
m_force = rhs.m_force;
m_driveLibrarySlot = 0 == rhs.m_driveLibrarySlot ? 0 :
rhs.m_driveLibrarySlot->clone();
}
return *this;
}
//------------------------------------------------------------------------------
// getForce
//------------------------------------------------------------------------------
bool castor::mediachanger::DismountCmdLine::getForce() const throw() {
return m_force;
}
//------------------------------------------------------------------------------
......@@ -92,13 +142,13 @@ castor::mediachanger::DismountCmdLine::DismountCmdLine(const int argc,
void castor::mediachanger::DismountCmdLine::processOption(const int opt) {
switch(opt) {
case 'd':