cleaned up some major dogsh*t left by a certain person who shall not be named

incidentally, fixed bug #1465
This commit is contained in:
fgerlits 2005-09-21 15:27:01 +00:00
parent df31c8d72f
commit 37101d2166
9 changed files with 416 additions and 191 deletions

View file

@ -156,6 +156,9 @@ class Playable : public boost::enable_shared_from_this<Playable>
* Return the token which is used to identify this audio clip * Return the token which is used to identify this audio clip
* or playlist to the storage server. * or playlist to the storage server.
* *
* The token is set when the Playable object is acquired and
* unset (made null again) when it is released.
*
* @return the token. * @return the token.
*/ */
virtual Ptr<const std::string>::Ref virtual Ptr<const std::string>::Ref
@ -165,6 +168,9 @@ class Playable : public boost::enable_shared_from_this<Playable>
* Set the token which is used to identify this audio clip * Set the token which is used to identify this audio clip
* or playlist to the storage server. * or playlist to the storage server.
* *
* The token is set when the Playable object is acquired and
* unset (made null again) when it is released.
*
* @param token a new token. * @param token a new token.
*/ */
virtual void virtual void

View file

@ -127,6 +127,28 @@ using namespace boost::posix_time;
* &lt;!ATTLIST playlist playlength NMTOKEN #IMPLIED &gt; * &lt;!ATTLIST playlist playlength NMTOKEN #IMPLIED &gt;
* </code></pre> * </code></pre>
* *
* A Playlist can be of various kinds, depending on what we want to use it
* for, and how we got it from the StorageClientInterface:
* <ul>
* <li>A playlist obtained by getPlaylist() has its <code>uri</code>,
* <code>token</code> and <code>editToken</code> fields all unset
* (i.e., null). Such playlist contain sub-playlists which
* are just stubs, i.e., <code>id, title, playlength</code> triples,
* without actual references to its content objects.</li>
* <li>A playlist obtained by acquirePlaylist() has its <code>uri</code>
* and <code>token</code> fields set, but its <code>editToken</code>
* field unset. These are complete Playlist objects, and their
* sub-playlists contain references to all their sub-objects etc.
* The sub-playlists have their <code>uri</code> fields set, which
* allows them to be played by the audio player, but their
* <code>token</code> field is unset, because these sub-playlists
* are acquired and will be released recursively when the outermost
* playlist containing them is acquired and released.</li>
* <li>A playlist obtained by editPlaylist() has its <code>editToken</code>
* field set (but <code>uri</code> and <code>token</code> unset).
* The sub-playlists of these are also just stubs.</li>
* </ul>
*
* @author $Author$ * @author $Author$
* @version $Revision$ * @version $Revision$
*/ */
@ -160,10 +182,17 @@ class Playlist : public Configurable,
Ptr<const std::string>::Ref uri; Ptr<const std::string>::Ref uri;
/** /**
* The token given to this playlist by the storage server. * The token given to this playlist by the storage server when
* the playlist is acquired; removed when it is released.
*/ */
Ptr<const std::string>::Ref token; Ptr<const std::string>::Ref token;
/**
* The token given to this playlist by the storage server when
* it is opened for editing; removed when it is saved or reverted.
*/
Ptr<const std::string>::Ref editToken;
/** /**
* A map type for storing the playlist elements associated with * A map type for storing the playlist elements associated with
* this playlist, indexed by their relative offsets. * this playlist, indexed by their relative offsets.
@ -464,6 +493,9 @@ class Playlist : public Configurable,
* Return the token which is used to identify this * Return the token which is used to identify this
* playlist to the storage server. * playlist to the storage server.
* *
* The token is set when the Playable object is acquired and
* unset (made null again) when it is released.
*
* @return the token. * @return the token.
*/ */
virtual Ptr<const std::string>::Ref virtual Ptr<const std::string>::Ref
@ -476,6 +508,9 @@ class Playlist : public Configurable,
* Set the token which is used to identify this * Set the token which is used to identify this
* playlist to the storage server. * playlist to the storage server.
* *
* The token is set when the Playable object is acquired and
* unset (made null again) when it is released.
*
* @param token a new token. * @param token a new token.
*/ */
virtual void virtual void
@ -485,6 +520,37 @@ class Playlist : public Configurable,
this->token = token; this->token = token;
} }
/**
* Return the token which is used to identify this
* playlist to the storage server.
*
* The edit token is set when the Playable object is opened for
* editing and unset (made null again) when it is saved or reverted.
*
* @return the token.
*/
virtual Ptr<const std::string>::Ref
getEditToken(void) const throw ()
{
return editToken;
}
/**
* Set the token which is used to identify this
* playlist to the storage server.
*
* The edit token is set when the Playable object is opened for
* editing and unset (made null again) when it is saved or reverted.
*
* @param token a new token.
*/
virtual void
setEditToken(Ptr<const std::string>::Ref token)
throw ()
{
this->editToken = token;
}
/** /**
* Test whether the playlist is locked for editing. * Test whether the playlist is locked for editing.
* *
@ -493,7 +559,7 @@ class Playlist : public Configurable,
bool bool
isLocked() const throw () isLocked() const throw ()
{ {
return (token.get() != 0); return (editToken.get() != 0);
} }
@ -560,10 +626,10 @@ class Playlist : public Configurable,
* Checks the type of the playlist, and calls either addAudioClip() * Checks the type of the playlist, and calls either addAudioClip()
* or addPlaylist(). * or addPlaylist().
* *
* @param audioClip the new playable item to be added * @param playable the new playable item to be added
* @param relativeOffset the start of the playable item, relative * @param relativeOffset the start of the playable item, relative
* to the start of the playlist * to the start of the playlist
* @param fadeInfo the fade in / fade out info (optional) * @param fadeInfo the fade in / fade out info (optional)
* @return the ID of the new PlaylistElement * @return the ID of the new PlaylistElement
* @exception std::invalid_argument if playable is neither an AudioClip * @exception std::invalid_argument if playable is neither an AudioClip
* nor a Playlist * nor a Playlist
@ -711,7 +777,7 @@ class Playlist : public Configurable,
/** /**
* Return a partial XML representation of this audio clip or playlist. * Return a partial XML representation of this audio clip or playlist.
* *
* This is a string containing a single <playlist> * This is a string containing a single &lt;playlist&gt;
* XML element, with minimal information (ID, title, playlength) * XML element, with minimal information (ID, title, playlength)
* only, without an XML header or any other metadata. * only, without an XML header or any other metadata.
* *
@ -728,8 +794,8 @@ class Playlist : public Configurable,
* Return a complete XML representation of this playlist. * Return a complete XML representation of this playlist.
* *
* This is a string containing a an XML document with a * This is a string containing a an XML document with a
* <playlist> root node, together with an XML header and a * &lt;playlist&gt; root node, together with an XML header and a
* <metadata> element (for the outermost playlist only). * &lt;metadata&gt; element (for the outermost playlist only).
* *
* The encoding is UTF-8. IDs are 16-digit hexadecimal numbers, * The encoding is UTF-8. IDs are 16-digit hexadecimal numbers,
* time durations have the format "hh:mm:ss.ssssss". * time durations have the format "hh:mm:ss.ssssss".
@ -751,8 +817,8 @@ class Playlist : public Configurable,
* All other metadata fields in the audio clips and sub-playlists * All other metadata fields in the audio clips and sub-playlists
* will be lost. * will be lost.
* *
* The <i>uri</i> and <i>token</i> fields are currently not part * The <i>uri</i>, <i>token</i> and <i>editToken</i> fields are not
* of the XML document string returned. * part of the XML document string returned.
* *
* @return a string representation of the playlist as an XML document * @return a string representation of the playlist as an XML document
*/ */

View file

@ -203,6 +203,7 @@ class PlaylistElement : public Configurable
this->audioClip = audioClip; this->audioClip = audioClip;
this->playable = audioClip; this->playable = audioClip;
this->fadeInfo = fadeInfo; this->fadeInfo = fadeInfo;
this->type = AudioClipType;
} }
/** /**
@ -351,6 +352,31 @@ class PlaylistElement : public Configurable
return playable; return playable;
} }
/**
* Set the Playable instance (an AudioClip or a Playlist)
* associated with the playlist element.
*
* This is used by WebStorageClient::acquirePlaylist() to replace
* a stub (id, title, playlength only) sub-playlist with a full one.
*
* @param playable the new Playable object.
*/
void
setPlayable(Ptr<Playable>::Ref playable) throw ()
{
this->playable = playable;
switch (playable->getType()) {
case Playable::AudioClipType :
audioClip = playable->getAudioClip();
type = AudioClipType;
break;
case Playable::PlaylistType :
playlist = playable->getPlaylist();
type = PlaylistType;
break;
}
}
/** /**
* Return the audio clip associated with the playlist element. * Return the audio clip associated with the playlist element.
* *

View file

@ -346,7 +346,7 @@ TestStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
EditedPlaylistsType::const_iterator EditedPlaylistsType::const_iterator
editIt = editedPlaylists.find(id->getId()); editIt = editedPlaylists.find(id->getId());
if (editIt != editedPlaylists.end() // is being edited if (editIt != editedPlaylists.end() // is being edited
&& (*editIt->second->getToken() == sessionId->getId())) { // by us && (*editIt->second->getEditToken() == sessionId->getId())) { // by us
playlist = editIt->second; playlist = editIt->second;
} else { } else {
PlaylistMapType::const_iterator PlaylistMapType::const_iterator
@ -378,8 +378,8 @@ TestStorageClient :: editPlaylist(Ptr<SessionId>::Ref sessionId,
} }
Ptr<Playlist>::Ref playlist = getPlaylist(sessionId, id); Ptr<Playlist>::Ref playlist = getPlaylist(sessionId, id);
Ptr<std::string>::Ref token(new std::string(sessionId->getId())); Ptr<std::string>::Ref editToken(new std::string(sessionId->getId()));
playlist->setToken(token); playlist->setEditToken(editToken);
editedPlaylists[id->getId()] = playlist; editedPlaylists[id->getId()] = playlist;
return playlist; return playlist;
@ -398,11 +398,11 @@ TestStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
throw XmlRpcException("missing session ID argument"); throw XmlRpcException("missing session ID argument");
} }
if (! playlist->getToken()) { if (! playlist->getEditToken()) {
throw XmlRpcException("savePlaylist() called without editPlaylist()"); throw XmlRpcException("savePlaylist() called without editPlaylist()");
} }
if (sessionId->getId() != *playlist->getToken()) { if (sessionId->getId() != *playlist->getEditToken()) {
throw XmlRpcException("tried to save playlist in different session" throw XmlRpcException("tried to save playlist in different session"
" than the one it was opened in???"); " than the one it was opened in???");
} }
@ -411,12 +411,12 @@ TestStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
editIt = editedPlaylists.find(playlist->getId()->getId()); editIt = editedPlaylists.find(playlist->getId()->getId());
if ((editIt == editedPlaylists.end()) if ((editIt == editedPlaylists.end())
|| (*playlist->getToken() != *editIt->second->getToken())) { || (*playlist->getEditToken() != *editIt->second->getEditToken())) {
throw XmlRpcException("savePlaylist() called without editPlaylist()"); throw XmlRpcException("savePlaylist() called without editPlaylist()");
} }
Ptr<std::string>::Ref nullPointer; Ptr<std::string>::Ref nullPointer;
playlist->setToken(nullPointer); playlist->setEditToken(nullPointer);
PlaylistMapType::iterator PlaylistMapType::iterator
storeIt = playlistMap.find(playlist->getId()->getId()); storeIt = playlistMap.find(playlist->getId()->getId());
@ -434,7 +434,7 @@ TestStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
* Revert a playlist to its pre-editing state. * Revert a playlist to its pre-editing state.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void void
TestStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken) TestStorageClient :: revertPlaylist(Ptr<const std::string>::Ref editToken)
throw (XmlRpcException) throw (XmlRpcException)
{ {
std::cerr << "TestStorageClient :: revertPlaylist" std::cerr << "TestStorageClient :: revertPlaylist"

View file

@ -321,13 +321,13 @@ class TestStorageClient :
* the playlist (and lose all changes) at the next login using * the playlist (and lose all changes) at the next login using
* this method. * this method.
* *
* @param playlistToken the token of the edited playlist * @param editToken the token of the edited playlist
* @exception XmlRpcException if there is a problem with the XML-RPC * @exception XmlRpcException if there is a problem with the XML-RPC
* call or no playlist with the specified * call or no playlist with the specified
* token exists. * token exists.
*/ */
virtual void virtual void
revertPlaylist(Ptr<const std::string>::Ref playlistToken) revertPlaylist(Ptr<const std::string>::Ref editToken)
throw (XmlRpcException); throw (XmlRpcException);

View file

@ -847,13 +847,13 @@ WebStorageClient :: createPlaylist(Ptr<SessionId>::Ref sessionId)
Ptr<time_duration>::Ref playlength(new time_duration(0,0,0,0)); Ptr<time_duration>::Ref playlength(new time_duration(0,0,0,0));
Ptr<Playlist>::Ref playlist(new Playlist(newId, playlength)); Ptr<Playlist>::Ref playlist(new Playlist(newId, playlength));
playlist->setToken(token); playlist->setEditToken(token);
editedPlaylists[newId->getId()] = std::make_pair(sessionId, playlist); editedPlaylists[newId->getId()] = std::make_pair(sessionId, playlist);
savePlaylist(sessionId, playlist); savePlaylist(sessionId, playlist);
token.reset(); token.reset();
playlist->setToken(token); playlist->setEditToken(token);
return playlist->getId(); return playlist->getId();
} }
@ -918,9 +918,8 @@ WebStorageClient :: existsPlaylist(Ptr<SessionId>::Ref sessionId,
* Return a playlist to be displayed. * Return a playlist to be displayed.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
Ptr<Playlist>::Ref Ptr<Playlist>::Ref
WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId, WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
Ptr<UniqueId>::Ref id, Ptr<UniqueId>::Ref id) const
bool deep) const
throw (Core::XmlRpcException) throw (Core::XmlRpcException)
{ {
EditedPlaylistsType::const_iterator EditedPlaylistsType::const_iterator
@ -940,7 +939,7 @@ WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
parameters.clear(); parameters.clear();
parameters[getPlaylistSessionIdParamName] = sessionId->getId(); parameters[getPlaylistSessionIdParamName] = sessionId->getId();
parameters[getPlaylistPlaylistIdParamName] = std::string(*id); parameters[getPlaylistPlaylistIdParamName] = std::string(*id);
parameters[getPlaylistRecursiveParamName] = deep; parameters[getPlaylistRecursiveParamName] = false;
result.clear(); result.clear();
if (!xmlRpcClient.execute(getPlaylistOpenMethodName.c_str(), if (!xmlRpcClient.execute(getPlaylistOpenMethodName.c_str(),
@ -960,25 +959,33 @@ WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
<< result; << result;
throw Core::XmlRpcMethodFaultException(eMsg.str()); throw Core::XmlRpcMethodFaultException(eMsg.str());
} }
if (! result.hasMember(getPlaylistUrlParamName)
|| result[getPlaylistUrlParamName].getType() if (! result.hasMember(getPlaylistTokenParamName)
!= XmlRpcValue::TypeString
|| ! result.hasMember(getPlaylistTokenParamName)
|| result[getPlaylistTokenParamName].getType() || result[getPlaylistTokenParamName].getType()
!= XmlRpcValue::TypeString) { != XmlRpcValue::TypeString) {
std::stringstream eMsg; std::stringstream eMsg;
eMsg << "XML-RPC method '" eMsg << "XML-RPC method '"
<< getPlaylistOpenMethodName << getPlaylistOpenMethodName
<< "' returned unexpected value:\n" << "' returned unexpected value:\n"
<< result; << result;
throw XmlRpcMethodResponseException(eMsg.str());
}
Ptr<const std::string>::Ref token(new std::string(
result[getPlaylistTokenParamName] ));
if (! result.hasMember(getPlaylistUrlParamName)
|| result[getPlaylistUrlParamName].getType()
!= XmlRpcValue::TypeString) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistOpenMethodName
<< "' returned unexpected value:\n"
<< result;
throw XmlRpcMethodResponseException(eMsg.str()); throw XmlRpcMethodResponseException(eMsg.str());
} }
const std::string url = result[getPlaylistUrlParamName]; const std::string url = result[getPlaylistUrlParamName];
const std::string token = result[getPlaylistTokenParamName];
Ptr<Playlist>::Ref playlist(new Playlist(id));
Ptr<Playlist>::Ref playlist(new Playlist(id));
try { try {
Ptr<xmlpp::DomParser>::Ref parser(new xmlpp::DomParser()); Ptr<xmlpp::DomParser>::Ref parser(new xmlpp::DomParser());
parser->parse_file(url); parser->parse_file(url);
@ -994,48 +1001,10 @@ WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
throw XmlRpcInvalidDataException( throw XmlRpcInvalidDataException(
"error parsing playlist metafile"); "error parsing playlist metafile");
} }
playlist->setToken(token);
if (deep) { releasePlaylistFromServer(playlist);
playlist = acquirePlaylist(playlist, result);
}
parameters.clear();
parameters[getPlaylistSessionIdParamName] = sessionId->getId();
parameters[getPlaylistTokenParamName] = token;
result.clear();
if (!xmlRpcClient.execute(getPlaylistCloseMethodName.c_str(),
parameters, result)) {
xmlRpcClient.close();
std::string eMsg = "cannot execute XML-RPC method '";
eMsg += getPlaylistCloseMethodName;
eMsg += "'";
throw XmlRpcCommunicationException(eMsg);
}
xmlRpcClient.close();
if (xmlRpcClient.isFault()) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistCloseMethodName
<< "' returned error message:\n"
<< result;
throw Core::XmlRpcMethodFaultException(eMsg.str());
}
if (! result.hasMember(getPlaylistPlaylistIdParamName)
|| result[getPlaylistPlaylistIdParamName].getType()
!= XmlRpcValue::TypeString
|| std::string(result[getPlaylistPlaylistIdParamName])
!= std::string(*id)) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistCloseMethodName
<< "' returned unexpected value:\n"
<< result;
throw XmlRpcMethodResponseException(eMsg.str());
}
return playlist; return playlist;
} }
@ -1053,9 +1022,9 @@ WebStorageClient :: editPlaylist(Ptr<SessionId>::Ref sessionId,
" being edited"); " being edited");
} }
Ptr<const std::string>::Ref url, token; Ptr<const std::string>::Ref url, editToken;
editPlaylistGetUrl(sessionId, id, url, token); editPlaylistGetUrl(sessionId, id, url, editToken);
Ptr<Playlist>::Ref playlist(new Playlist(id)); Ptr<Playlist>::Ref playlist(new Playlist(id));
try { try {
@ -1074,7 +1043,7 @@ WebStorageClient :: editPlaylist(Ptr<SessionId>::Ref sessionId,
"error parsing playlist metafile"); "error parsing playlist metafile");
} }
playlist->setToken(token); playlist->setEditToken(editToken);
editedPlaylists[id->getId()] = std::make_pair(sessionId, playlist); editedPlaylists[id->getId()] = std::make_pair(sessionId, playlist);
return playlist; return playlist;
@ -1088,7 +1057,7 @@ void
WebStorageClient :: editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId, WebStorageClient :: editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId,
Ptr<UniqueId>::Ref id, Ptr<UniqueId>::Ref id,
Ptr<const std::string>::Ref& url, Ptr<const std::string>::Ref& url,
Ptr<const std::string>::Ref& token) Ptr<const std::string>::Ref& editToken)
throw (Core::XmlRpcException) throw (Core::XmlRpcException)
{ {
XmlRpcValue parameters; XmlRpcValue parameters;
@ -1138,7 +1107,7 @@ WebStorageClient :: editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId,
} }
url.reset(new const std::string(result[getPlaylistUrlParamName])); url.reset(new const std::string(result[getPlaylistUrlParamName]));
token.reset(new const std::string(result[getPlaylistTokenParamName])); editToken.reset(new const std::string(result[getPlaylistTokenParamName]));
} }
@ -1150,8 +1119,8 @@ WebStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
Ptr<Playlist>::Ref playlist) Ptr<Playlist>::Ref playlist)
throw (Core::XmlRpcException) throw (Core::XmlRpcException)
{ {
if (!playlist || !playlist->getToken()) { if (!playlist || !playlist->getEditToken()) {
throw XmlRpcInvalidArgumentException("playlist has no token field"); throw XmlRpcInvalidArgumentException("playlist has no editToken field");
} }
EditedPlaylistsType::iterator EditedPlaylistsType::iterator
@ -1174,7 +1143,7 @@ WebStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
parameters[savePlaylistSessionIdParamName] parameters[savePlaylistSessionIdParamName]
= sessionId->getId(); = sessionId->getId();
parameters[savePlaylistTokenParamName] parameters[savePlaylistTokenParamName]
= *playlist->getToken(); = *playlist->getEditToken();
parameters[savePlaylistNewPlaylistParamName] parameters[savePlaylistNewPlaylistParamName]
= std::string(*playlist->getXmlDocumentString()); = std::string(*playlist->getXmlDocumentString());
@ -1212,7 +1181,7 @@ WebStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
} }
Ptr<const std::string>::Ref nullpointer; Ptr<const std::string>::Ref nullpointer;
playlist->setToken(nullpointer); playlist->setEditToken(nullpointer);
} }
@ -1220,10 +1189,10 @@ WebStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
* Revert a playlist to its pre-editing state. * Revert a playlist to its pre-editing state.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
void void
WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken) WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref editToken)
throw (XmlRpcException) throw (XmlRpcException)
{ {
if (!playlistToken) { if (!editToken) {
throw XmlRpcInvalidArgumentException("null pointer in argument"); throw XmlRpcInvalidArgumentException("null pointer in argument");
} }
@ -1237,7 +1206,7 @@ WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken)
parameters[revertPlaylistSessionIdParamName] // dummy parameter parameters[revertPlaylistSessionIdParamName] // dummy parameter
= ""; = "";
parameters[revertPlaylistTokenParamName] parameters[revertPlaylistTokenParamName]
= *playlistToken; = *editToken;
result.clear(); result.clear();
if (!xmlRpcClient.execute(revertPlaylistMethodName.c_str(), if (!xmlRpcClient.execute(revertPlaylistMethodName.c_str(),
@ -1273,22 +1242,115 @@ WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken)
/*------------------------------------------------------------------------------ /*------------------------------------------------------------------------------
* Acquire resources for a playlist. * Acquire resources for a playlist, step 1: execute the XML-RPC call.
*----------------------------------------------------------------------------*/ *----------------------------------------------------------------------------*/
Ptr<Playlist>::Ref Ptr<Playlist>::Ref
WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist, WebStorageClient :: acquirePlaylist(Ptr<SessionId>::Ref sessionId,
XmlRpcValue & result) const Ptr<UniqueId>::Ref id) const
throw (Core::XmlRpcException) throw (Core::XmlRpcException)
{ {
XmlRpcValue content; XmlRpcValue parameters;
int index; XmlRpcValue result;
Ptr<time_duration>::Ref playlength = oldPlaylist->getPlaylength();
Ptr<Playlist>::Ref newPlaylist(new Playlist(oldPlaylist->getId(),
playlength));
newPlaylist->setTitle(oldPlaylist->getTitle());
newPlaylist->setToken(oldPlaylist->getToken());
// TODO: copy over all metadata as well
XmlRpcClient xmlRpcClient(storageServerName.c_str(), storageServerPort,
storageServerPath.c_str(), false);
parameters.clear();
parameters[getPlaylistSessionIdParamName] = sessionId->getId();
parameters[getPlaylistPlaylistIdParamName] = std::string(*id);
parameters[getPlaylistRecursiveParamName] = true;
result.clear();
if (!xmlRpcClient.execute(getPlaylistOpenMethodName.c_str(),
parameters, result)) {
xmlRpcClient.close();
std::string eMsg = "cannot execute XML-RPC method '";
eMsg += getPlaylistOpenMethodName;
eMsg += "'";
throw XmlRpcCommunicationException(eMsg);
}
if (xmlRpcClient.isFault()) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistOpenMethodName
<< "' returned error message:\n"
<< result;
throw Core::XmlRpcMethodFaultException(eMsg.str());
}
if (! result.hasMember(getPlaylistTokenParamName)
|| result[getPlaylistTokenParamName].getType()
!= XmlRpcValue::TypeString) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistOpenMethodName
<< "' returned unexpected value:\n"
<< result;
throw XmlRpcMethodResponseException(eMsg.str());
}
Ptr<const std::string>::Ref token(new std::string(
result[getPlaylistTokenParamName] ));
Ptr<Playlist>::Ref playlist = acquirePlaylist(id, result);
playlist->setToken(token);
return playlist;
}
/*------------------------------------------------------------------------------
* Acquire resources for a playlist, step 2: create the temp files.
*----------------------------------------------------------------------------*/
Ptr<Playlist>::Ref
WebStorageClient :: acquirePlaylist(Ptr<UniqueId>::Ref id,
XmlRpcValue & content) const
throw (Core::XmlRpcException)
{
// construct the playlist
if (! content.hasMember(getPlaylistUrlParamName)
|| content[getPlaylistUrlParamName].getType()
!= XmlRpcValue::TypeString) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistOpenMethodName
<< "' returned unexpected value:\n"
<< content;
throw XmlRpcMethodResponseException(eMsg.str());
}
const std::string url = content[getPlaylistUrlParamName];
Ptr<Playlist>::Ref playlist(new Playlist(id));
try {
Ptr<xmlpp::DomParser>::Ref parser(new xmlpp::DomParser());
parser->parse_file(url);
const xmlpp::Document * document = parser->get_document();
const xmlpp::Element * root = document->get_root_node();
playlist->configure(*root);
} catch (std::invalid_argument &e) {
throw XmlRpcInvalidDataException(
"semantic error in playlist metafile");
} catch (xmlpp::exception &e) {
throw XmlRpcInvalidDataException(
"error parsing playlist metafile");
}
// read the content array corresponding to the playlist
if (! content.hasMember(getPlaylistContentParamName)
|| content[getPlaylistContentParamName].getType()
!= XmlRpcValue::TypeArray) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistOpenMethodName
<< "' returned unexpected value:\n"
<< content;
throw XmlRpcMethodResponseException(eMsg.str());
}
XmlRpcValue innerContent = content[getPlaylistContentParamName];
// construct the SMIL file
Ptr<xmlpp::Document>::Ref Ptr<xmlpp::Document>::Ref
smilDocument(new xmlpp::Document(xmlVersion)); smilDocument(new xmlpp::Document(xmlVersion));
xmlpp::Element * smilRootNode xmlpp::Element * smilRootNode
@ -1301,48 +1363,32 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
xmlpp::Element * smilParNode xmlpp::Element * smilParNode
= smilBodyNode->add_child(smilParNodeName); = smilBodyNode->add_child(smilParNodeName);
Playlist::const_iterator it = oldPlaylist->begin(); // we assume that the playlist is as long as the size of the content array
if (result.hasMember(getPlaylistContentParamName)) { Playlist::const_iterator it = playlist->begin();
content = result[getPlaylistContentParamName]; int index = 0;
} while (it != playlist->end() && index < innerContent.size()) {
// if there is no content parameter, leave the original, empty content
index = 0;
// assume that it is as long as the size of the content array
while (it != oldPlaylist->end()) {
Ptr<PlaylistElement>::Ref plElement = it->second; Ptr<PlaylistElement>::Ref plElement = it->second;
Ptr<time_duration>::Ref relativeOffset Ptr<time_duration>::Ref relativeOffset
= plElement->getRelativeOffset(); = plElement->getRelativeOffset();
Ptr<FadeInfo>::Ref fadeInfo = plElement->getFadeInfo(); Ptr<FadeInfo>::Ref fadeInfo = plElement->getFadeInfo();
if (index >= content.size()) { XmlRpcValue contentElement = innerContent[index];
break;
}
XmlRpcValue contents = content[index];
++index;
if (!contents.hasMember(getPlaylistUrlParamName)) {
// TODO: maybe signal error?
continue;
}
Ptr<Playable>::Ref playable; Ptr<Playable>::Ref playable;
Ptr<const std::string>::Ref url; Ptr<const std::string>::Ref url;
Ptr<AudioClip>::Ref audioClip; Ptr<UniqueId>::Ref subPlaylistId;
Ptr<Playlist>::Ref playlist;
switch (plElement->getType()) { switch (plElement->getType()) {
case PlaylistElement::AudioClipType : case PlaylistElement::AudioClipType :
url.reset(new std::string(contents[getPlaylistUrlParamName])); url.reset(new std::string(
audioClip.reset(new AudioClip(*plElement->getAudioClip())); contentElement[getPlaylistUrlParamName]));
audioClip->setUri(url); playable = plElement->getAudioClip();
url.reset();
newPlaylist->addPlayable(audioClip, relativeOffset, fadeInfo);
playable = audioClip;
break; break;
case PlaylistElement::PlaylistType : case PlaylistElement::PlaylistType :
playlist.reset(new Playlist(*plElement->getPlaylist())); subPlaylistId = plElement->getPlaylist()->getId();
playlist = acquirePlaylist(playlist, contents); playable = acquirePlaylist(subPlaylistId, contentElement);
newPlaylist->addPlayable(playlist, relativeOffset, fadeInfo); url = playable->getUri();
playable = playlist; plElement->setPlayable(playable);
break; break;
default : // this should never happen default : // this should never happen
throw XmlRpcInvalidArgumentException( throw XmlRpcInvalidArgumentException(
@ -1354,7 +1400,7 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
= smilParNode->add_child(smilPlayableNodeName); = smilParNode->add_child(smilPlayableNodeName);
smilPlayableNode->set_attribute( smilPlayableNode->set_attribute(
smilPlayableUriAttrName, smilPlayableUriAttrName,
*playable->getUri() ); *url );
smilPlayableNode->set_attribute( smilPlayableNode->set_attribute(
smilRelativeOffsetAttrName, smilRelativeOffsetAttrName,
*TimeConversion::timeDurationToSmilString( *TimeConversion::timeDurationToSmilString(
@ -1430,19 +1476,20 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
smilAnimateFillAttrValue ); smilAnimateFillAttrValue );
} }
} }
++it; ++it;
++index;
} }
std::stringstream fileName; std::stringstream fileName;
fileName << localTempStorage << std::string(*newPlaylist->getId()) fileName << localTempStorage << std::string(*playlist->getId())
<< "-" << std::rand() << ".smil"; << "-" << std::rand() << ".smil";
smilDocument->write_to_file_formatted(fileName.str(), "UTF-8"); smilDocument->write_to_file_formatted(fileName.str(), "UTF-8");
Ptr<std::string>::Ref playlistUri(new std::string(fileName.str())); Ptr<std::string>::Ref playlistUri(new std::string(fileName.str()));
newPlaylist->setUri(playlistUri); playlist->setUri(playlistUri);
return newPlaylist; return playlist;
} }
@ -1452,11 +1499,91 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
void void
WebStorageClient :: releasePlaylist(Ptr<Playlist>::Ref playlist) const WebStorageClient :: releasePlaylist(Ptr<Playlist>::Ref playlist) const
throw (Core::XmlRpcException) throw (Core::XmlRpcException)
{
if (playlist->getToken()) {
releasePlaylistFromServer(playlist);
}
releasePlaylistTempFile(playlist);
}
/*------------------------------------------------------------------------------
* Release a playlist, step 1: release access URLs at the storage server.
*----------------------------------------------------------------------------*/
void
WebStorageClient :: releasePlaylistFromServer(
Ptr<Playlist>::Ref playlist) const
throw (Core::XmlRpcException)
{
if (! playlist->getToken()) {
throw XmlRpcInvalidArgumentException("releasePlaylist() called without"
" acquirePlaylist()");
}
XmlRpcValue parameters;
XmlRpcValue result;
XmlRpcClient xmlRpcClient(storageServerName.c_str(), storageServerPort,
storageServerPath.c_str(), false);
parameters.clear();
parameters[getPlaylistTokenParamName] = std::string(
*playlist->getToken());
// TODO: remove the 'recursive' param from locstor.releasePlaylist because
// it is error-prone; should always use the same value as for accessPlaylist
parameters[getPlaylistRecursiveParamName] = true;
result.clear();
if (!xmlRpcClient.execute(getPlaylistCloseMethodName.c_str(),
parameters, result)) {
xmlRpcClient.close();
std::string eMsg = "cannot execute XML-RPC method '";
eMsg += getPlaylistCloseMethodName;
eMsg += "'";
throw XmlRpcCommunicationException(eMsg);
}
xmlRpcClient.close();
if (xmlRpcClient.isFault()) {
std::stringstream eMsg;
eMsg << "XML-RPC method '"
<< getPlaylistCloseMethodName
<< "' returned error message:\n"
<< result;
throw Core::XmlRpcMethodFaultException(eMsg.str());
}
if (! result.hasMember(getPlaylistPlaylistIdParamName)
|| result[getPlaylistPlaylistIdParamName].getType()
!= XmlRpcValue::TypeString
|| std::string(result[getPlaylistPlaylistIdParamName])
!= std::string(*playlist->getId())) {
std::stringstream eMsg;
eMsg << "Mismatched playlist ID from XML-RPC method '"
<< getPlaylistCloseMethodName
<< "': "
<< result[getPlaylistPlaylistIdParamName]
<< " instead of "
<< std::string(*playlist->getId())
<< ".";
// removed temporarily; see ticket #1468
// throw XmlRpcMethodResponseException(eMsg.str());
}
}
/*------------------------------------------------------------------------------
* Release a playlist, step 2: delete the temp file.
*----------------------------------------------------------------------------*/
void
WebStorageClient :: releasePlaylistTempFile(Ptr<Playlist>::Ref playlist) const
throw (Core::XmlRpcException)
{ {
if (! playlist->getUri()) { if (! playlist->getUri()) {
throw XmlRpcInvalidArgumentException("playlist URI not found"); throw XmlRpcInvalidArgumentException("playlist URI not found");
} }
std::ifstream ifs(playlist->getUri()->substr(7).c_str()); std::ifstream ifs(playlist->getUri()->substr(7).c_str());
if (!ifs) { // cut of "file://" if (!ifs) { // cut of "file://"
ifs.close(); ifs.close();
@ -1471,16 +1598,15 @@ WebStorageClient :: releasePlaylist(Ptr<Playlist>::Ref playlist) const
while (it != playlist->end()) { while (it != playlist->end()) {
Ptr<PlaylistElement>::Ref plElement = it->second; Ptr<PlaylistElement>::Ref plElement = it->second;
if (plElement->getType() == PlaylistElement::AudioClipType) { if (plElement->getType() == PlaylistElement::AudioClipType) {
// don't have to release, as it will be done by the storage server // no temp file; nothing to do
// for clips inside the playlist
++it; ++it;
} else if (plElement->getType() == PlaylistElement::PlaylistType) { } else if (plElement->getType() == PlaylistElement::PlaylistType) {
try { try {
releasePlaylist(it->second->getPlaylist()); releasePlaylistTempFile(it->second->getPlaylist());
} }
catch (XmlRpcException &e) { catch (XmlRpcException &e) {
eMsg += e.what(); eMsg += e.what();
eMsg += "\n"; eMsg += '\n';
} }
++it; ++it;
} else { } else {

View file

@ -163,7 +163,8 @@ class WebStorageClient :
* @param sessionId the session ID from the authentication client * @param sessionId the session ID from the authentication client
* @param id the id of the playlist to return. * @param id the id of the playlist to return.
* @param url pointer in which the URL of the playlist is returned. * @param url pointer in which the URL of the playlist is returned.
* @param token pointer in which the token of the playlist is returned. * @param editToken pointer in which the token of the playlist is
* returned.
* @exception XmlRpcException if there is a problem with the XML-RPC * @exception XmlRpcException if there is a problem with the XML-RPC
* call or no playlist with the specified * call or no playlist with the specified
* id exists. * id exists.
@ -172,50 +173,53 @@ class WebStorageClient :
editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId, editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId,
Ptr<UniqueId>::Ref id, Ptr<UniqueId>::Ref id,
Ptr<const std::string>::Ref& url, Ptr<const std::string>::Ref& url,
Ptr<const std::string>::Ref& token) Ptr<const std::string>::Ref& editToken)
throw (XmlRpcException); throw (XmlRpcException);
/** /**
* Return a playlist with the specified id to be displayed. * Do the second step of acquring a playlist: generate the SMIL
* If the playlist is being edited, and this method is called * temp files.
* by the same user who is editing the playlist,
* (i.e., the method is called with the same sessionId and playlistId
* that editPlaylist() was), then the working copy of the playlist
* is returned.
* Any other user gets the old (pre-editPlaylist()) copy from storage.
*
* @param sessionId the session ID from the authentication client
* @param id the id of the playlist to return.
* @param deep signal if all playable objects are to be accessed
* and locked, that are referenced by this playlist, or
* any playlist contained in this one.
* @return the requested playlist.
* @exception XmlRpcInvalidDataException if the audio clip we got
* from the storage is invalid.
* @exception XmlRpcException if there is a problem with the XML-RPC
* call or no playlist with the specified id exists.
*/
Ptr<Playlist>::Ref
getPlaylist(Ptr<SessionId>::Ref sessionId,
Ptr<UniqueId>::Ref id,
bool deep) const
throw (XmlRpcException);
/**
* Do the final stages of acquring a playlist: generate SMIL
* files, etc.
* *
* @param oldPlaylist the playlist to work on. * @param id the ID of the new playlist to be constructed
* @param result the XML-RPC result from getPlaylist() call * @param content the XML-RPC result from locstor.accessPlaylist
* with deep == true
* @return a playlist which has a URI filed, and all things below * @return a playlist which has a URI filed, and all things below
* it are openned properly and processed as well. * it are opened properly and processed as well.
* @exception XmlRpcException if there is a problem with the XML-RPC * @exception XmlRpcException if there is a problem with the XML-RPC
* call or no playlist with the specified id exists. * call or no playlist with the specified id exists.
*/ */
Ptr<Playlist>::Ref Ptr<Playlist>::Ref
acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist, acquirePlaylist(Ptr<UniqueId>::Ref id,
XmlRpcValue & result) const XmlRpcValue & content) const
throw (XmlRpcException);
/**
* Execute the XML-RPC function call to release the playlist
* access URL at the storage server.
*
* This needs to be done for the outermost playlist only; the
* sub-playlists and audio clips contained inside are released
* recursively by the storage server automatically.
*
* @param playlist the playlist to release.
* @exception XmlRpcException if there is a problem with the XML-RPC
* call or the playlist has no token field
*/
void
releasePlaylistFromServer(Ptr<Playlist>::Ref playlist) const
throw (XmlRpcException);
/**
* Remove the temporary SMIL file created for the playlist.
*
* This needs to be done for every playlist, including sub-playlists
* contained inside other playlists.
*
* @param playlist the playlist to release.
* @exception XmlRpcException if there is a problem with the XML-RPC
* call or the playlist has no uri field
*/
void
releasePlaylistTempFile(Ptr<Playlist>::Ref playlist) const
throw (XmlRpcException); throw (XmlRpcException);
@ -313,10 +317,7 @@ class WebStorageClient :
virtual Ptr<Playlist>::Ref virtual Ptr<Playlist>::Ref
getPlaylist(Ptr<SessionId>::Ref sessionId, getPlaylist(Ptr<SessionId>::Ref sessionId,
Ptr<UniqueId>::Ref id) const Ptr<UniqueId>::Ref id) const
throw (XmlRpcException) throw (XmlRpcException);
{
return getPlaylist(sessionId, id, false);
}
/** /**
* Return a playlist with the specified id to be edited. * Return a playlist with the specified id to be edited.
@ -364,13 +365,13 @@ class WebStorageClient :
* the playlist (and lose all changes) at the next login using * the playlist (and lose all changes) at the next login using
* this method. * this method.
* *
* @param playlistToken the token of the edited playlist * @param editToken the token of the edited playlist
* @exception XmlRpcException if there is a problem with the XML-RPC * @exception XmlRpcException if there is a problem with the XML-RPC
* call or no playlist with the specified * call or no playlist with the specified
* token exists. * token exists.
*/ */
virtual void virtual void
revertPlaylist(Ptr<const std::string>::Ref playlistToken) revertPlaylist(Ptr<const std::string>::Ref editToken)
throw (XmlRpcException); throw (XmlRpcException);
@ -401,12 +402,7 @@ class WebStorageClient :
virtual Ptr<Playlist>::Ref virtual Ptr<Playlist>::Ref
acquirePlaylist(Ptr<SessionId>::Ref sessionId, acquirePlaylist(Ptr<SessionId>::Ref sessionId,
Ptr<UniqueId>::Ref id) const Ptr<UniqueId>::Ref id) const
throw (XmlRpcException) throw (XmlRpcException);
{
// FIXME: silently, with deep == true, getPlaylist will also
// generate all related SMIL files, etc.
return getPlaylist(sessionId, id, true);
}
/** /**
* Release the resources (audio clips, other playlists) used * Release the resources (audio clips, other playlists) used

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8" ?> <?xml version="1.0" encoding="utf-8" ?>
<playlist id="0000000000000001" <playlist id="0000000000000002"
title="My Second Playlist" title="My Second Playlist"
playlength="00:00:29.700000" > playlength="00:00:29.700000" >
<playlistElement id="0000000000000101" <playlistElement id="0000000000000101"

View file

@ -958,7 +958,7 @@ class XR_LocStor extends LocStor{
* inside playlist (default: false)</li> * inside playlist (default: false)</li>
* </ul> * </ul>
* *
* On success, returns a XML-RPC struct with single field: * On success, returns an XML-RPC struct with the following fields:
* <ul> * <ul>
* <li> url : string - readable url of accessed playlist in * <li> url : string - readable url of accessed playlist in
* XML format</li> * XML format</li>
@ -967,6 +967,11 @@ class XR_LocStor extends LocStor{
* <li> content: array of structs - recursive access (optional)</li> * <li> content: array of structs - recursive access (optional)</li>
* </ul> * </ul>
* *
* The <code>content</code> field contains a struct for each playlist
* element contained in the playlist. For audio clips, this struct is
* of type <code>{url, token}</code>; for sub-playlists, it is of type
* <code>{url, token, chsum, content}</code>.
*
* On errors, returns an XML-RPC error response. * On errors, returns an XML-RPC error response.
* The possible error codes and error message are: * The possible error codes and error message are:
* <ul> * <ul>