1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | #include <algorithm> |
30 | #include <sstream> |
31 | |
32 | #include <boost/date_time/posix_time/posix_time.hpp> |
33 | |
34 | #include "atom-object.hxx" |
35 | #include "atom-object-type.hxx" |
36 | #include "atom-session.hxx" |
37 | #include "atom-utils.hxx" |
38 | #include "xml-utils.hxx" |
39 | |
40 | using namespace std; |
41 | |
42 | namespace |
43 | { |
44 | class MatchLink |
45 | { |
46 | private: |
47 | string m_rel; |
48 | string m_type; |
49 | |
50 | public: |
51 | MatchLink( string rel, string type ) : m_rel( rel ), m_type( type ) { } |
52 | bool operator() ( AtomLink link ) |
53 | { |
54 | bool matchesRel = link.getRel( ) == m_rel; |
55 | |
56 | |
57 | bool matchesType = m_type.empty( ) || link.getType().empty() || ( link.getType( ) == m_type ); |
58 | return matchesRel && matchesType; |
59 | } |
60 | }; |
61 | } |
62 | |
63 | AtomObject::AtomObject( AtomPubSession* session ) throw ( libcmis::Exception ) : |
64 | m_session( session ), |
65 | m_refreshTimestamp( 0 ), |
66 | m_infosUrl( ), |
67 | m_typeId( ), |
68 | m_typeDescription( ), |
69 | m_properties( ), |
70 | m_allowableActions( ), |
71 | m_links( ) |
72 | { |
73 | } |
74 | |
75 | AtomObject::AtomObject( const AtomObject& copy ) : |
76 | m_session( copy.m_session ), |
77 | m_refreshTimestamp( copy.m_refreshTimestamp ), |
78 | m_infosUrl( copy.m_infosUrl ), |
79 | m_typeId( copy.m_typeId ), |
80 | m_typeDescription( copy.m_typeDescription ), |
81 | m_properties( copy.m_properties ), |
82 | m_allowableActions( copy.m_allowableActions ), |
83 | m_links( copy.m_links ) |
84 | { |
85 | } |
86 | |
87 | AtomObject& AtomObject::operator=( const AtomObject& copy ) |
88 | { |
89 | m_session = copy.m_session; |
90 | m_refreshTimestamp = copy.m_refreshTimestamp; |
91 | m_infosUrl = copy.m_infosUrl; |
92 | m_typeId = copy.m_typeId; |
93 | m_typeDescription = copy.m_typeDescription; |
94 | m_properties = copy.m_properties; |
95 | m_allowableActions = copy.m_allowableActions; |
96 | m_links = copy.m_links; |
97 | |
98 | return *this; |
99 | } |
100 | |
101 | AtomObject::~AtomObject( ) |
102 | { |
103 | } |
104 | |
105 | string AtomObject::getId( ) |
106 | { |
107 | string name; |
108 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:objectId" ) ); |
109 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
110 | name = it->second->getStrings( ).front( ); |
111 | return name; |
112 | } |
113 | |
114 | string AtomObject::getName( ) |
115 | { |
116 | string name; |
117 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:name" ) ); |
118 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
119 | name = it->second->getStrings( ).front( ); |
120 | return name; |
121 | } |
122 | |
123 | vector< string > AtomObject::getPaths( ) |
124 | { |
125 | return vector< string > ( ); |
126 | } |
127 | |
128 | string AtomObject::getBaseType( ) |
129 | { |
130 | string value; |
131 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:baseTypeId" ) ); |
132 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
133 | value = it->second->getStrings( ).front( ); |
134 | return value; |
135 | } |
136 | |
137 | string AtomObject::getType( ) |
138 | { |
139 | string value; |
140 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:objectTypeId" ) ); |
141 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
142 | value = it->second->getStrings( ).front( ); |
143 | return value; |
144 | } |
145 | |
146 | string AtomObject::getCreatedBy( ) |
147 | { |
148 | string value; |
149 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:createdBy" ) ); |
150 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
151 | value = it->second->getStrings( ).front( ); |
152 | return value; |
153 | } |
154 | |
155 | boost::posix_time::ptime AtomObject::getCreationDate( ) |
156 | { |
157 | boost::posix_time::ptime value; |
158 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:creationDate" ) ); |
159 | if ( it != getProperties( ).end( ) && !it->second->getDateTimes( ).empty( ) ) |
160 | value = it->second->getDateTimes( ).front( ); |
161 | return value; |
162 | } |
163 | |
164 | string AtomObject::getLastModifiedBy( ) |
165 | { |
166 | string value; |
167 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:lastModifiedBy" ) ); |
168 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
169 | value = it->second->getStrings( ).front( ); |
170 | return value; |
171 | } |
172 | |
173 | boost::posix_time::ptime AtomObject::getLastModificationDate( ) |
174 | { |
175 | boost::posix_time::ptime value; |
176 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:lastModificationDate" ) ); |
177 | if ( it != getProperties( ).end( ) && !it->second->getDateTimes( ).empty( ) ) |
178 | value = it->second->getDateTimes( ).front( ); |
179 | return value; |
180 | } |
181 | |
182 | bool AtomObject::isImmutable( ) |
183 | { |
184 | bool value = false; |
185 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:isImmutable" ) ); |
186 | if ( it != getProperties( ).end( ) && !it->second->getBools( ).empty( ) ) |
187 | value = it->second->getBools( ).front( ); |
188 | return value; |
189 | } |
190 | |
191 | string AtomObject::getChangeToken( ) |
192 | { |
193 | string value; |
194 | map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).find( string( "cmis:changeToken" ) ); |
195 | if ( it != getProperties( ).end( ) && !it->second->getStrings( ).empty( ) ) |
196 | value = it->second->getStrings( ).front( ); |
197 | return value; |
198 | } |
199 | |
200 | std::map< std::string, libcmis::PropertyPtr >& AtomObject::getProperties( ) |
201 | { |
202 | return m_properties; |
203 | } |
204 | |
205 | void AtomObject::updateProperties( ) throw ( libcmis::Exception ) |
206 | { |
207 | if ( getAllowableActions().get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::UpdateProperties ) ) |
208 | throw libcmis::Exception( string( "UpdateProperties is not allowed on object " ) + getId() ); |
209 | |
210 | xmlBufferPtr buf = xmlBufferCreate( ); |
211 | xmlTextWriterPtr writer = xmlNewTextWriterMemory( buf, 0 ); |
212 | |
213 | xmlTextWriterStartDocument( writer, NULL__null, NULL__null, NULL__null ); |
214 | |
215 | |
216 | AtomObject copy( *this ); |
217 | map< string, libcmis::PropertyPtr >& props = copy.getProperties( ); |
218 | for ( map< string, libcmis::PropertyPtr >::iterator it = props.begin( ); it != props.end( ); ) |
219 | { |
220 | if ( !it->second->getPropertyType( )->isUpdatable( ) ) |
221 | props.erase( it++ ); |
222 | else |
223 | ++it; |
224 | } |
225 | copy.toXml( writer ); |
226 | |
227 | xmlTextWriterEndDocument( writer ); |
228 | string str( ( const char * )xmlBufferContent( buf ) ); |
229 | istringstream is( str ); |
230 | |
231 | xmlFreeTextWriter( writer ); |
232 | xmlBufferFree( buf ); |
233 | |
234 | string respBuf; |
235 | try |
236 | { |
237 | respBuf = getSession( )->httpPutRequest( getInfosUrl( ), is, "application/atom+xml;type=entry" ); |
238 | } |
239 | catch ( const atom::CurlException& e ) |
240 | { |
241 | throw e.getCmisException( ); |
242 | } |
243 | |
244 | xmlDocPtr doc = xmlReadMemory( respBuf.c_str(), respBuf.size(), getInfosUrl().c_str(), NULL__null, 0 ); |
245 | if ( NULL__null == doc ) |
246 | throw libcmis::Exception( "Failed to parse object infos" ); |
247 | |
248 | refreshImpl( doc ); |
249 | xmlFreeDoc( doc ); |
250 | } |
251 | |
252 | libcmis::ObjectTypePtr AtomObject::getTypeDescription( ) |
253 | { |
254 | |
255 | if ( !m_typeDescription.get( ) ) |
256 | m_typeDescription.reset( new AtomObjectType( m_session, m_typeId ) ); |
257 | |
258 | return m_typeDescription; |
259 | } |
260 | |
261 | boost::shared_ptr< libcmis::AllowableActions > AtomObject::getAllowableActions( ) |
262 | { |
263 | return m_allowableActions; |
264 | } |
265 | |
266 | void AtomObject::refreshImpl( xmlDocPtr doc ) throw ( libcmis::Exception ) |
267 | { |
268 | bool createdDoc = ( NULL__null == doc ); |
269 | if ( createdDoc ) |
270 | { |
271 | string buf; |
272 | try |
273 | { |
274 | buf = getSession()->httpGetRequest( getInfosUrl() )->str( ); |
275 | } |
276 | catch ( const atom::CurlException& e ) |
277 | { |
278 | throw e.getCmisException( ); |
279 | } |
280 | |
281 | doc = xmlReadMemory( buf.c_str(), buf.size(), getInfosUrl().c_str(), NULL__null, 0 ); |
282 | |
283 | if ( NULL__null == doc ) |
284 | throw libcmis::Exception( "Failed to parse object infos" ); |
285 | |
286 | } |
287 | |
288 | extractInfos( doc ); |
289 | m_refreshTimestamp = time( NULL__null ); |
290 | |
291 | if ( createdDoc ) |
292 | xmlFreeDoc( doc ); |
293 | } |
294 | |
295 | void AtomObject::remove( bool allVersions ) throw ( libcmis::Exception ) |
296 | { |
297 | if ( getAllowableActions( ).get() && !getAllowableActions()->isAllowed( libcmis::ObjectAction::DeleteObject ) ) |
298 | throw libcmis::Exception( string( "DeleteObject not allowed on object " ) + getId() ); |
299 | |
300 | try |
301 | { |
302 | string deleteUrl = getInfosUrl( ); |
303 | if ( deleteUrl.find( '?' ) != string::npos ) |
304 | deleteUrl += "&"; |
305 | else |
306 | deleteUrl += "?"; |
307 | |
308 | string allVersionsStr = "TRUE"; |
309 | if ( !allVersions ) |
310 | allVersionsStr = "FALSE"; |
311 | deleteUrl += "allVersions=" + allVersionsStr; |
312 | |
313 | m_session->httpDeleteRequest( deleteUrl ); |
314 | } |
315 | catch ( const atom::CurlException& e ) |
316 | { |
317 | throw e.getCmisException( ); |
318 | } |
319 | } |
320 | |
321 | string AtomObject::toString( ) |
322 | { |
323 | stringstream buf; |
324 | |
325 | buf << "Id: " << getId() << endl; |
326 | buf << "Name: " << getName() << endl; |
327 | buf << "Type: " << getType() << endl; |
328 | buf << "Base type: " << getBaseType() << endl; |
329 | buf << "Created on " << boost::posix_time::to_simple_string( getCreationDate() ) |
330 | << " by " << getCreatedBy() << endl; |
331 | buf << "Last modified on " << boost::posix_time::to_simple_string( getLastModificationDate() ) |
332 | << " by " << getLastModifiedBy() << endl; |
333 | buf << "Change token: " << getChangeToken() << endl; |
334 | |
335 | |
336 | static const char* skippedProps[] = { |
337 | "cmis:name", "cmis:baseTypeId", "cmis:objectTypeId", "cmis:createdBy", |
338 | "cmis:creationDate", "cmis:lastModifiedBy", "cmis:lastModificationDate", |
339 | "cmis::changeToken" |
340 | }; |
341 | int skippedCount = sizeof( skippedProps ) / sizeof( char* ); |
342 | |
343 | for ( map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).begin(); |
344 | it != getProperties( ).end( ); ++it ) |
345 | { |
346 | string propId = it->first; |
347 | bool toSkip = false; |
348 | for ( int i = 0; i < skippedCount && !toSkip; ++i ) |
349 | { |
350 | toSkip = propId == skippedProps[i]; |
351 | } |
352 | |
353 | if ( !toSkip ) |
354 | { |
355 | libcmis::PropertyPtr prop = it->second; |
356 | buf << prop->getPropertyType( )->getDisplayName( ) << "( " << prop->getPropertyType()->getId( ) << " ): " << endl; |
357 | vector< string > strValues = prop->getStrings( ); |
358 | for ( vector< string >::iterator valueIt = strValues.begin( ); |
359 | valueIt != strValues.end( ); ++valueIt ) |
360 | { |
361 | buf << "\t" << *valueIt << endl; |
362 | } |
363 | } |
364 | } |
365 | |
366 | return buf.str(); |
367 | } |
368 | |
369 | void AtomObject::toXml( xmlTextWriterPtr writer ) |
370 | { |
371 | xmlTextWriterStartElement( writer, BAD_CAST(xmlChar *)( "atom:entry" ) ); |
372 | xmlTextWriterWriteAttribute( writer, BAD_CAST(xmlChar *)( "xmlns:atom" ), NS_ATOM_URL(xmlChar *)( "http://www.w3.org/2005/Atom" ) ); |
373 | xmlTextWriterWriteAttribute( writer, BAD_CAST(xmlChar *)( "xmlns:cmis" ), NS_CMIS_URL(xmlChar *)( "http://docs.oasis-open.org/ns/cmis/core/200908/" ) ); |
374 | xmlTextWriterWriteAttribute( writer, BAD_CAST(xmlChar *)( "xmlns:cmisra" ), NS_CMISRA_URL(xmlChar *)( "http://docs.oasis-open.org/ns/cmis/restatom/200908/" ) ); |
375 | |
376 | if ( !getCreatedBy( ).empty( ) ) |
377 | { |
378 | xmlTextWriterStartElement( writer, BAD_CAST(xmlChar *)( "atom:author" ) ); |
379 | xmlTextWriterWriteElement( writer, BAD_CAST(xmlChar *)( "atom:name" ), BAD_CAST(xmlChar *)( getCreatedBy( ).c_str( ) ) ); |
380 | xmlTextWriterEndElement( writer ); |
381 | } |
382 | |
383 | xmlTextWriterWriteElement( writer, BAD_CAST(xmlChar *)( "atom:title" ), BAD_CAST(xmlChar *)( getName( ).c_str( ) ) ); |
384 | |
385 | boost::posix_time::ptime now( boost::posix_time::second_clock::universal_time( ) ); |
386 | xmlTextWriterWriteElement( writer, BAD_CAST(xmlChar *)( "atom:updated" ), BAD_CAST(xmlChar *)( libcmis::writeDateTime( now ).c_str( ) ) ); |
387 | |
388 | contentToXml( writer ); |
389 | |
390 | xmlTextWriterStartElement( writer, BAD_CAST(xmlChar *)( "cmisra:object" ) ); |
391 | |
392 | |
393 | xmlTextWriterStartElement( writer, BAD_CAST(xmlChar *)( "cmis:properties" ) ); |
394 | for ( map< string, libcmis::PropertyPtr >::iterator it = getProperties( ).begin( ); |
395 | it != getProperties( ).end( ); ++it ) |
396 | { |
397 | it->second->toXml( writer ); |
398 | } |
399 | xmlTextWriterEndElement( writer ); |
400 | xmlTextWriterEndElement( writer ); |
401 | |
402 | xmlTextWriterEndElement( writer ); |
403 | } |
404 | |
405 | void AtomObject::extractInfos( xmlDocPtr doc ) |
406 | { |
407 | xmlXPathContextPtr xpathCtx = xmlXPathNewContext( doc ); |
408 | |
409 | atom::registerNamespaces( xpathCtx ); |
410 | |
411 | if ( NULL__null != xpathCtx ) |
| |
412 | { |
413 | |
414 | string linksReq( "//atom:link" ); |
415 | xmlXPathObjectPtr xpathObj = xmlXPathEvalExpression( BAD_CAST(xmlChar *)( linksReq.c_str() ), xpathCtx ); |
416 | if ( NULL__null != xpathObj && NULL__null != xpathObj->nodesetval ) |
417 | { |
418 | int size = xpathObj->nodesetval->nodeNr; |
419 | for ( int i = 0; i < size; i++ ) |
420 | { |
421 | xmlNodePtr node = xpathObj->nodesetval->nodeTab[i]; |
422 | try |
423 | { |
424 | AtomLink link( node ); |
425 | m_links.push_back( node ); |
426 | } |
427 | catch ( const libcmis::Exception& ) |
428 | { |
429 | |
430 | } |
431 | } |
432 | } |
433 | xmlXPathFreeObject( xpathObj ); |
434 | |
435 | |
436 | m_infosUrl = getLink( "self", "application/atom+xml;type=entry" )->getHref( ); |
| 2 | | Called C++ object pointer is null |
|
437 | |
438 | |
439 | xpathObj = xmlXPathEvalExpression( BAD_CAST(xmlChar *)( "//cmis:allowableActions" ), xpathCtx ); |
440 | if ( xpathObj && xpathObj->nodesetval && xpathObj->nodesetval->nodeNr > 0 ) |
441 | { |
442 | xmlNodePtr node = xpathObj->nodesetval->nodeTab[0]; |
443 | m_allowableActions.reset( new libcmis::AllowableActions( node ) ); |
444 | } |
445 | xmlXPathFreeObject( xpathObj ); |
446 | |
447 | |
448 | string typeIdReq( "//cmis:propertyId[@propertyDefinitionId='cmis:objectTypeId']/cmis:value/text()" ); |
449 | m_typeId = atom::getXPathValue( xpathCtx, typeIdReq ); |
450 | |
451 | string propertiesReq( "//cmis:properties/*" ); |
452 | xpathObj = xmlXPathEvalExpression( BAD_CAST(xmlChar *)( propertiesReq.c_str() ), xpathCtx ); |
453 | if ( NULL__null != xpathObj && NULL__null != xpathObj->nodesetval ) |
454 | { |
455 | int size = xpathObj->nodesetval->nodeNr; |
456 | for ( int i = 0; i < size; i++ ) |
457 | { |
458 | xmlNodePtr node = xpathObj->nodesetval->nodeTab[i]; |
459 | libcmis::PropertyPtr property = libcmis::parseProperty( node, getTypeDescription( ) ); |
460 | if ( property.get( ) ) |
461 | m_properties.insert( |
462 | std::pair< string, libcmis::PropertyPtr >( |
463 | property->getPropertyType( )->getId(), |
464 | property ) ); |
465 | } |
466 | } |
467 | xmlXPathFreeObject( xpathObj ); |
468 | } |
469 | |
470 | xmlXPathFreeContext( xpathCtx ); |
471 | } |
472 | |
473 | void AtomObject::contentToXml( xmlTextWriterPtr ) |
474 | { |
475 | } |
476 | |
477 | AtomLink* AtomObject::getLink( std::string rel, std::string type ) |
478 | { |
479 | AtomLink* link = NULL__null; |
480 | vector< AtomLink >::iterator it = find_if( m_links.begin(), m_links.end(), MatchLink( rel, type ) ); |
481 | if ( it != m_links.end() ) |
482 | link = &( *it ); |
483 | return link; |
484 | } |
485 | |
486 | AtomLink::AtomLink( xmlNodePtr node ) throw ( libcmis::Exception ): |
487 | m_rel( ), |
488 | m_type( ), |
489 | m_id( ), |
490 | m_href( ) |
491 | { |
492 | m_rel = libcmis::getXmlNodeAttributeValue( node, "rel" ); |
493 | m_href = libcmis::getXmlNodeAttributeValue( node, "href" ); |
494 | |
495 | try |
496 | { |
497 | m_type = libcmis::getXmlNodeAttributeValue( node, "type" ); |
498 | m_id = libcmis::getXmlNodeAttributeValue( node, "id" ); |
499 | } |
500 | catch ( const libcmis::Exception & ) |
501 | { |
502 | |
503 | |
504 | } |
505 | } |