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:
parent
df31c8d72f
commit
37101d2166
9 changed files with 416 additions and 191 deletions
|
@ -156,6 +156,9 @@ class Playable : public boost::enable_shared_from_this<Playable>
|
|||
* Return the token which is used to identify this audio clip
|
||||
* 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.
|
||||
*/
|
||||
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
|
||||
* 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.
|
||||
*/
|
||||
virtual void
|
||||
|
|
|
@ -127,6 +127,28 @@ using namespace boost::posix_time;
|
|||
* <!ATTLIST playlist playlength NMTOKEN #IMPLIED >
|
||||
* </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$
|
||||
* @version $Revision$
|
||||
*/
|
||||
|
@ -160,10 +182,17 @@ class Playlist : public Configurable,
|
|||
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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
* this playlist, indexed by their relative offsets.
|
||||
|
@ -464,6 +493,9 @@ class Playlist : public Configurable,
|
|||
* Return the token which is used to identify this
|
||||
* 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.
|
||||
*/
|
||||
virtual Ptr<const std::string>::Ref
|
||||
|
@ -476,6 +508,9 @@ class Playlist : public Configurable,
|
|||
* Set the token which is used to identify this
|
||||
* 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.
|
||||
*/
|
||||
virtual void
|
||||
|
@ -485,6 +520,37 @@ class Playlist : public Configurable,
|
|||
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.
|
||||
*
|
||||
|
@ -493,7 +559,7 @@ class Playlist : public Configurable,
|
|||
bool
|
||||
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()
|
||||
* or addPlaylist().
|
||||
*
|
||||
* @param audioClip the new playable item to be added
|
||||
* @param relativeOffset the start of the playable item, relative
|
||||
* to the start of the playlist
|
||||
* @param fadeInfo the fade in / fade out info (optional)
|
||||
* @param playable the new playable item to be added
|
||||
* @param relativeOffset the start of the playable item, relative
|
||||
* to the start of the playlist
|
||||
* @param fadeInfo the fade in / fade out info (optional)
|
||||
* @return the ID of the new PlaylistElement
|
||||
* @exception std::invalid_argument if playable is neither an AudioClip
|
||||
* nor a Playlist
|
||||
|
@ -711,7 +777,7 @@ class Playlist : public Configurable,
|
|||
/**
|
||||
* 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 <playlist>
|
||||
* XML element, with minimal information (ID, title, playlength)
|
||||
* 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.
|
||||
*
|
||||
* This is a string containing a an XML document with a
|
||||
* <playlist> root node, together with an XML header and a
|
||||
* <metadata> element (for the outermost playlist only).
|
||||
* <playlist> root node, together with an XML header and a
|
||||
* <metadata> element (for the outermost playlist only).
|
||||
*
|
||||
* The encoding is UTF-8. IDs are 16-digit hexadecimal numbers,
|
||||
* 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
|
||||
* will be lost.
|
||||
*
|
||||
* The <i>uri</i> and <i>token</i> fields are currently not part
|
||||
* of the XML document string returned.
|
||||
* The <i>uri</i>, <i>token</i> and <i>editToken</i> fields are not
|
||||
* part of the XML document string returned.
|
||||
*
|
||||
* @return a string representation of the playlist as an XML document
|
||||
*/
|
||||
|
|
|
@ -203,6 +203,7 @@ class PlaylistElement : public Configurable
|
|||
this->audioClip = audioClip;
|
||||
this->playable = audioClip;
|
||||
this->fadeInfo = fadeInfo;
|
||||
this->type = AudioClipType;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -351,6 +352,31 @@ class PlaylistElement : public Configurable
|
|||
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.
|
||||
*
|
||||
|
|
|
@ -346,7 +346,7 @@ TestStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
EditedPlaylistsType::const_iterator
|
||||
editIt = editedPlaylists.find(id->getId());
|
||||
if (editIt != editedPlaylists.end() // is being edited
|
||||
&& (*editIt->second->getToken() == sessionId->getId())) { // by us
|
||||
&& (*editIt->second->getEditToken() == sessionId->getId())) { // by us
|
||||
playlist = editIt->second;
|
||||
} else {
|
||||
PlaylistMapType::const_iterator
|
||||
|
@ -378,8 +378,8 @@ TestStorageClient :: editPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
}
|
||||
|
||||
Ptr<Playlist>::Ref playlist = getPlaylist(sessionId, id);
|
||||
Ptr<std::string>::Ref token(new std::string(sessionId->getId()));
|
||||
playlist->setToken(token);
|
||||
Ptr<std::string>::Ref editToken(new std::string(sessionId->getId()));
|
||||
playlist->setEditToken(editToken);
|
||||
|
||||
editedPlaylists[id->getId()] = playlist;
|
||||
return playlist;
|
||||
|
@ -398,11 +398,11 @@ TestStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
throw XmlRpcException("missing session ID argument");
|
||||
}
|
||||
|
||||
if (! playlist->getToken()) {
|
||||
if (! playlist->getEditToken()) {
|
||||
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"
|
||||
" than the one it was opened in???");
|
||||
}
|
||||
|
@ -411,12 +411,12 @@ TestStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
editIt = editedPlaylists.find(playlist->getId()->getId());
|
||||
|
||||
if ((editIt == editedPlaylists.end())
|
||||
|| (*playlist->getToken() != *editIt->second->getToken())) {
|
||||
|| (*playlist->getEditToken() != *editIt->second->getEditToken())) {
|
||||
throw XmlRpcException("savePlaylist() called without editPlaylist()");
|
||||
}
|
||||
|
||||
Ptr<std::string>::Ref nullPointer;
|
||||
playlist->setToken(nullPointer);
|
||||
playlist->setEditToken(nullPointer);
|
||||
|
||||
PlaylistMapType::iterator
|
||||
storeIt = playlistMap.find(playlist->getId()->getId());
|
||||
|
@ -434,7 +434,7 @@ TestStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
* Revert a playlist to its pre-editing state.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
TestStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken)
|
||||
TestStorageClient :: revertPlaylist(Ptr<const std::string>::Ref editToken)
|
||||
throw (XmlRpcException)
|
||||
{
|
||||
std::cerr << "TestStorageClient :: revertPlaylist"
|
||||
|
|
|
@ -321,13 +321,13 @@ class TestStorageClient :
|
|||
* the playlist (and lose all changes) at the next login using
|
||||
* 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
|
||||
* call or no playlist with the specified
|
||||
* token exists.
|
||||
*/
|
||||
virtual void
|
||||
revertPlaylist(Ptr<const std::string>::Ref playlistToken)
|
||||
revertPlaylist(Ptr<const std::string>::Ref editToken)
|
||||
throw (XmlRpcException);
|
||||
|
||||
|
||||
|
|
|
@ -847,13 +847,13 @@ WebStorageClient :: createPlaylist(Ptr<SessionId>::Ref sessionId)
|
|||
|
||||
Ptr<time_duration>::Ref playlength(new time_duration(0,0,0,0));
|
||||
Ptr<Playlist>::Ref playlist(new Playlist(newId, playlength));
|
||||
playlist->setToken(token);
|
||||
playlist->setEditToken(token);
|
||||
|
||||
editedPlaylists[newId->getId()] = std::make_pair(sessionId, playlist);
|
||||
savePlaylist(sessionId, playlist);
|
||||
|
||||
token.reset();
|
||||
playlist->setToken(token);
|
||||
playlist->setEditToken(token);
|
||||
|
||||
return playlist->getId();
|
||||
}
|
||||
|
@ -918,9 +918,8 @@ WebStorageClient :: existsPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
* Return a playlist to be displayed.
|
||||
*----------------------------------------------------------------------------*/
|
||||
Ptr<Playlist>::Ref
|
||||
WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id,
|
||||
bool deep) const
|
||||
WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id) const
|
||||
throw (Core::XmlRpcException)
|
||||
{
|
||||
EditedPlaylistsType::const_iterator
|
||||
|
@ -940,7 +939,7 @@ WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
parameters.clear();
|
||||
parameters[getPlaylistSessionIdParamName] = sessionId->getId();
|
||||
parameters[getPlaylistPlaylistIdParamName] = std::string(*id);
|
||||
parameters[getPlaylistRecursiveParamName] = deep;
|
||||
parameters[getPlaylistRecursiveParamName] = false;
|
||||
|
||||
result.clear();
|
||||
if (!xmlRpcClient.execute(getPlaylistOpenMethodName.c_str(),
|
||||
|
@ -960,25 +959,33 @@ WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
<< result;
|
||||
throw Core::XmlRpcMethodFaultException(eMsg.str());
|
||||
}
|
||||
if (! result.hasMember(getPlaylistUrlParamName)
|
||||
|| result[getPlaylistUrlParamName].getType()
|
||||
!= XmlRpcValue::TypeString
|
||||
|| ! result.hasMember(getPlaylistTokenParamName)
|
||||
|
||||
if (! result.hasMember(getPlaylistTokenParamName)
|
||||
|| result[getPlaylistTokenParamName].getType()
|
||||
!= XmlRpcValue::TypeString) {
|
||||
std::stringstream eMsg;
|
||||
eMsg << "XML-RPC method '"
|
||||
<< getPlaylistOpenMethodName
|
||||
<< "' returned unexpected value:\n"
|
||||
<< result;
|
||||
<< getPlaylistOpenMethodName
|
||||
<< "' returned unexpected value:\n"
|
||||
<< 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());
|
||||
}
|
||||
|
||||
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 {
|
||||
Ptr<xmlpp::DomParser>::Ref parser(new xmlpp::DomParser());
|
||||
parser->parse_file(url);
|
||||
|
@ -994,48 +1001,10 @@ WebStorageClient :: getPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
throw XmlRpcInvalidDataException(
|
||||
"error parsing playlist metafile");
|
||||
}
|
||||
playlist->setToken(token);
|
||||
|
||||
if (deep) {
|
||||
playlist = acquirePlaylist(playlist, result);
|
||||
}
|
||||
|
||||
parameters.clear();
|
||||
parameters[getPlaylistSessionIdParamName] = sessionId->getId();
|
||||
parameters[getPlaylistTokenParamName] = token;
|
||||
releasePlaylistFromServer(playlist);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -1053,9 +1022,9 @@ WebStorageClient :: editPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
" 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));
|
||||
try {
|
||||
|
@ -1074,7 +1043,7 @@ WebStorageClient :: editPlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
"error parsing playlist metafile");
|
||||
}
|
||||
|
||||
playlist->setToken(token);
|
||||
playlist->setEditToken(editToken);
|
||||
editedPlaylists[id->getId()] = std::make_pair(sessionId, playlist);
|
||||
|
||||
return playlist;
|
||||
|
@ -1088,7 +1057,7 @@ void
|
|||
WebStorageClient :: editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id,
|
||||
Ptr<const std::string>::Ref& url,
|
||||
Ptr<const std::string>::Ref& token)
|
||||
Ptr<const std::string>::Ref& editToken)
|
||||
throw (Core::XmlRpcException)
|
||||
{
|
||||
XmlRpcValue parameters;
|
||||
|
@ -1138,7 +1107,7 @@ WebStorageClient :: editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId,
|
|||
}
|
||||
|
||||
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)
|
||||
throw (Core::XmlRpcException)
|
||||
{
|
||||
if (!playlist || !playlist->getToken()) {
|
||||
throw XmlRpcInvalidArgumentException("playlist has no token field");
|
||||
if (!playlist || !playlist->getEditToken()) {
|
||||
throw XmlRpcInvalidArgumentException("playlist has no editToken field");
|
||||
}
|
||||
|
||||
EditedPlaylistsType::iterator
|
||||
|
@ -1174,7 +1143,7 @@ WebStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
parameters[savePlaylistSessionIdParamName]
|
||||
= sessionId->getId();
|
||||
parameters[savePlaylistTokenParamName]
|
||||
= *playlist->getToken();
|
||||
= *playlist->getEditToken();
|
||||
parameters[savePlaylistNewPlaylistParamName]
|
||||
= std::string(*playlist->getXmlDocumentString());
|
||||
|
||||
|
@ -1212,7 +1181,7 @@ WebStorageClient :: savePlaylist(Ptr<SessionId>::Ref sessionId,
|
|||
}
|
||||
|
||||
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.
|
||||
*----------------------------------------------------------------------------*/
|
||||
void
|
||||
WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken)
|
||||
WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref editToken)
|
||||
throw (XmlRpcException)
|
||||
{
|
||||
if (!playlistToken) {
|
||||
if (!editToken) {
|
||||
throw XmlRpcInvalidArgumentException("null pointer in argument");
|
||||
}
|
||||
|
||||
|
@ -1237,7 +1206,7 @@ WebStorageClient :: revertPlaylist(Ptr<const std::string>::Ref playlistToken)
|
|||
parameters[revertPlaylistSessionIdParamName] // dummy parameter
|
||||
= "";
|
||||
parameters[revertPlaylistTokenParamName]
|
||||
= *playlistToken;
|
||||
= *editToken;
|
||||
|
||||
result.clear();
|
||||
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
|
||||
WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
|
||||
XmlRpcValue & result) const
|
||||
WebStorageClient :: acquirePlaylist(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id) const
|
||||
throw (Core::XmlRpcException)
|
||||
{
|
||||
XmlRpcValue content;
|
||||
int index;
|
||||
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
|
||||
XmlRpcValue parameters;
|
||||
XmlRpcValue result;
|
||||
|
||||
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
|
||||
smilDocument(new xmlpp::Document(xmlVersion));
|
||||
xmlpp::Element * smilRootNode
|
||||
|
@ -1301,48 +1363,32 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
|
|||
xmlpp::Element * smilParNode
|
||||
= smilBodyNode->add_child(smilParNodeName);
|
||||
|
||||
Playlist::const_iterator it = oldPlaylist->begin();
|
||||
if (result.hasMember(getPlaylistContentParamName)) {
|
||||
content = result[getPlaylistContentParamName];
|
||||
}
|
||||
// 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()) {
|
||||
// we assume that the playlist is as long as the size of the content array
|
||||
Playlist::const_iterator it = playlist->begin();
|
||||
int index = 0;
|
||||
while (it != playlist->end() && index < innerContent.size()) {
|
||||
Ptr<PlaylistElement>::Ref plElement = it->second;
|
||||
Ptr<time_duration>::Ref relativeOffset
|
||||
= plElement->getRelativeOffset();
|
||||
Ptr<FadeInfo>::Ref fadeInfo = plElement->getFadeInfo();
|
||||
|
||||
if (index >= content.size()) {
|
||||
break;
|
||||
}
|
||||
XmlRpcValue contents = content[index];
|
||||
++index;
|
||||
if (!contents.hasMember(getPlaylistUrlParamName)) {
|
||||
// TODO: maybe signal error?
|
||||
continue;
|
||||
}
|
||||
XmlRpcValue contentElement = innerContent[index];
|
||||
|
||||
Ptr<Playable>::Ref playable;
|
||||
Ptr<const std::string>::Ref url;
|
||||
Ptr<AudioClip>::Ref audioClip;
|
||||
Ptr<Playlist>::Ref playlist;
|
||||
Ptr<UniqueId>::Ref subPlaylistId;
|
||||
|
||||
switch (plElement->getType()) {
|
||||
case PlaylistElement::AudioClipType :
|
||||
url.reset(new std::string(contents[getPlaylistUrlParamName]));
|
||||
audioClip.reset(new AudioClip(*plElement->getAudioClip()));
|
||||
audioClip->setUri(url);
|
||||
url.reset();
|
||||
newPlaylist->addPlayable(audioClip, relativeOffset, fadeInfo);
|
||||
playable = audioClip;
|
||||
url.reset(new std::string(
|
||||
contentElement[getPlaylistUrlParamName]));
|
||||
playable = plElement->getAudioClip();
|
||||
break;
|
||||
case PlaylistElement::PlaylistType :
|
||||
playlist.reset(new Playlist(*plElement->getPlaylist()));
|
||||
playlist = acquirePlaylist(playlist, contents);
|
||||
newPlaylist->addPlayable(playlist, relativeOffset, fadeInfo);
|
||||
playable = playlist;
|
||||
subPlaylistId = plElement->getPlaylist()->getId();
|
||||
playable = acquirePlaylist(subPlaylistId, contentElement);
|
||||
url = playable->getUri();
|
||||
plElement->setPlayable(playable);
|
||||
break;
|
||||
default : // this should never happen
|
||||
throw XmlRpcInvalidArgumentException(
|
||||
|
@ -1354,7 +1400,7 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
|
|||
= smilParNode->add_child(smilPlayableNodeName);
|
||||
smilPlayableNode->set_attribute(
|
||||
smilPlayableUriAttrName,
|
||||
*playable->getUri() );
|
||||
*url );
|
||||
smilPlayableNode->set_attribute(
|
||||
smilRelativeOffsetAttrName,
|
||||
*TimeConversion::timeDurationToSmilString(
|
||||
|
@ -1430,19 +1476,20 @@ WebStorageClient :: acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
|
|||
smilAnimateFillAttrValue );
|
||||
}
|
||||
}
|
||||
++it;
|
||||
++it;
|
||||
++index;
|
||||
}
|
||||
|
||||
std::stringstream fileName;
|
||||
fileName << localTempStorage << std::string(*newPlaylist->getId())
|
||||
fileName << localTempStorage << std::string(*playlist->getId())
|
||||
<< "-" << std::rand() << ".smil";
|
||||
|
||||
smilDocument->write_to_file_formatted(fileName.str(), "UTF-8");
|
||||
|
||||
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
|
||||
WebStorageClient :: releasePlaylist(Ptr<Playlist>::Ref playlist) const
|
||||
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()) {
|
||||
throw XmlRpcInvalidArgumentException("playlist URI not found");
|
||||
}
|
||||
|
||||
|
||||
std::ifstream ifs(playlist->getUri()->substr(7).c_str());
|
||||
if (!ifs) { // cut of "file://"
|
||||
ifs.close();
|
||||
|
@ -1471,16 +1598,15 @@ WebStorageClient :: releasePlaylist(Ptr<Playlist>::Ref playlist) const
|
|||
while (it != playlist->end()) {
|
||||
Ptr<PlaylistElement>::Ref plElement = it->second;
|
||||
if (plElement->getType() == PlaylistElement::AudioClipType) {
|
||||
// don't have to release, as it will be done by the storage server
|
||||
// for clips inside the playlist
|
||||
// no temp file; nothing to do
|
||||
++it;
|
||||
} else if (plElement->getType() == PlaylistElement::PlaylistType) {
|
||||
try {
|
||||
releasePlaylist(it->second->getPlaylist());
|
||||
releasePlaylistTempFile(it->second->getPlaylist());
|
||||
}
|
||||
catch (XmlRpcException &e) {
|
||||
eMsg += e.what();
|
||||
eMsg += "\n";
|
||||
eMsg += '\n';
|
||||
}
|
||||
++it;
|
||||
} else {
|
||||
|
|
|
@ -163,7 +163,8 @@ class WebStorageClient :
|
|||
* @param sessionId the session ID from the authentication client
|
||||
* @param id the id of the playlist to return.
|
||||
* @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
|
||||
* call or no playlist with the specified
|
||||
* id exists.
|
||||
|
@ -172,50 +173,53 @@ class WebStorageClient :
|
|||
editPlaylistGetUrl(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id,
|
||||
Ptr<const std::string>::Ref& url,
|
||||
Ptr<const std::string>::Ref& token)
|
||||
Ptr<const std::string>::Ref& editToken)
|
||||
throw (XmlRpcException);
|
||||
|
||||
/**
|
||||
* Return a playlist with the specified id to be displayed.
|
||||
* If the playlist is being edited, and this method is called
|
||||
* 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.
|
||||
* Do the second step of acquring a playlist: generate the SMIL
|
||||
* temp files.
|
||||
*
|
||||
* @param oldPlaylist the playlist to work on.
|
||||
* @param result the XML-RPC result from getPlaylist() call
|
||||
* with deep == true
|
||||
* @param id the ID of the new playlist to be constructed
|
||||
* @param content the XML-RPC result from locstor.accessPlaylist
|
||||
* @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
|
||||
* call or no playlist with the specified id exists.
|
||||
*/
|
||||
Ptr<Playlist>::Ref
|
||||
acquirePlaylist(Ptr<Playlist>::Ref oldPlaylist,
|
||||
XmlRpcValue & result) const
|
||||
acquirePlaylist(Ptr<UniqueId>::Ref id,
|
||||
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);
|
||||
|
||||
|
||||
|
@ -313,10 +317,7 @@ class WebStorageClient :
|
|||
virtual Ptr<Playlist>::Ref
|
||||
getPlaylist(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id) const
|
||||
throw (XmlRpcException)
|
||||
{
|
||||
return getPlaylist(sessionId, id, false);
|
||||
}
|
||||
throw (XmlRpcException);
|
||||
|
||||
/**
|
||||
* 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
|
||||
* 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
|
||||
* call or no playlist with the specified
|
||||
* token exists.
|
||||
*/
|
||||
virtual void
|
||||
revertPlaylist(Ptr<const std::string>::Ref playlistToken)
|
||||
revertPlaylist(Ptr<const std::string>::Ref editToken)
|
||||
throw (XmlRpcException);
|
||||
|
||||
|
||||
|
@ -401,12 +402,7 @@ class WebStorageClient :
|
|||
virtual Ptr<Playlist>::Ref
|
||||
acquirePlaylist(Ptr<SessionId>::Ref sessionId,
|
||||
Ptr<UniqueId>::Ref id) const
|
||||
throw (XmlRpcException)
|
||||
{
|
||||
// FIXME: silently, with deep == true, getPlaylist will also
|
||||
// generate all related SMIL files, etc.
|
||||
return getPlaylist(sessionId, id, true);
|
||||
}
|
||||
throw (XmlRpcException);
|
||||
|
||||
/**
|
||||
* Release the resources (audio clips, other playlists) used
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<playlist id="0000000000000001"
|
||||
<playlist id="0000000000000002"
|
||||
title="My Second Playlist"
|
||||
playlength="00:00:29.700000" >
|
||||
<playlistElement id="0000000000000101"
|
||||
|
|
|
@ -958,7 +958,7 @@ class XR_LocStor extends LocStor{
|
|||
* inside playlist (default: false)</li>
|
||||
* </ul>
|
||||
*
|
||||
* On success, returns a XML-RPC struct with single field:
|
||||
* On success, returns an XML-RPC struct with the following fields:
|
||||
* <ul>
|
||||
* <li> url : string - readable url of accessed playlist in
|
||||
* XML format</li>
|
||||
|
@ -967,6 +967,11 @@ class XR_LocStor extends LocStor{
|
|||
* <li> content: array of structs - recursive access (optional)</li>
|
||||
* </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.
|
||||
* The possible error codes and error message are:
|
||||
* <ul>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue