xref: /haiku/src/kits/support/ArchivingManagers.cpp (revision d374a27286b8a52974a97dba0d5966ea026a665d)
1 /*
2  * Copyright (c) 2010, Haiku, Inc.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Alex Wilson (yourpalal2@gmail.com)
7  */
8 
9 #include "ArchivingManagers.h"
10 
11 #include <syslog.h>
12 #include <typeinfo>
13 
14 
15 namespace BPrivate {
16 namespace Archiving {
17 	const char* kArchivableField = "_managed_archivable";
18 	const char* kManagedField = "_managed_archive";
19 }
20 }
21 
22 
23 using namespace BPrivate::Archiving;
24 
25 
26 BArchiveManager*
27 BManagerBase::ArchiveManager(const BMessage* archive)
28 {
29 	BManagerBase* manager = ManagerPointer(archive);
30 	if (!manager)
31 		return NULL;
32 
33 	if (manager->fType == ARCHIVE_MANAGER)
34 		return static_cast<BArchiveManager*>(manager);
35 
36 	debugger("Overlapping managed unarchive/archive sessions.");
37 	return NULL;
38 }
39 
40 
41 BUnarchiveManager*
42 BManagerBase::UnarchiveManager(const BMessage* archive)
43 {
44 	BManagerBase* manager = ManagerPointer(archive);
45 	if (!manager)
46 		return NULL;
47 
48 	if (manager->fType == UNARCHIVE_MANAGER)
49 		return static_cast<BUnarchiveManager*>(manager);
50 
51 	debugger("More calls to BUnarchiver::PrepareArchive()"
52 		" than BUnarchivers created.");
53 
54 	return NULL;
55 }
56 
57 
58 // #pragma mark -
59 
60 
61 struct BArchiveManager::ArchiveInfo {
62 	ArchiveInfo()
63 		:
64 		token(-1),
65 		archive(NULL)
66 	{
67 	}
68 
69 
70 	~ArchiveInfo()
71 	{
72 		delete archive;
73 	}
74 
75 
76 	int32		token;
77 	BMessage*	archive;
78 };
79 
80 
81 BArchiveManager::BArchiveManager(const BArchiver* creator)
82 	:
83 	BManagerBase(creator->ArchiveMessage(), BManagerBase::ARCHIVE_MANAGER),
84 	fTokenMap(),
85 	fCreator(creator),
86 	fError(B_OK)
87 {
88 }
89 
90 
91 BArchiveManager::~BArchiveManager()
92 {
93 	fTopLevelArchive->AddBool(kManagedField, true);
94 }
95 
96 
97 status_t
98 BArchiveManager::GetTokenForArchivable(BArchivable* archivable, int32& _token)
99 {
100 	if (!archivable) {
101 		_token = NULL_TOKEN;
102 		return B_OK;
103 	}
104 
105 	TokenMap::iterator it = fTokenMap.find(archivable);
106 
107 	if (it == fTokenMap.end())
108 		return B_ENTRY_NOT_FOUND;
109 
110 	_token = it->second.token;
111 	return B_OK;
112 }
113 
114 
115 status_t
116 BArchiveManager::ArchiveObject(BArchivable* archivable,
117 	bool deep, int32& _token)
118 {
119 	if (!archivable) {
120 		_token = NULL_TOKEN;
121 		return B_OK;
122 	}
123 
124 	ArchiveInfo& info = fTokenMap[archivable];
125 
126 	status_t err = B_OK;
127 
128 	if (!info.archive) {
129 		info.archive = new BMessage();
130 		info.token = fTokenMap.size() - 1;
131 
132 		MarkArchive(info.archive);
133 		err = archivable->Archive(info.archive, deep);
134 	}
135 
136 	if (err != B_OK) {
137 		fTokenMap.erase(archivable);
138 			// info.archive gets deleted here
139 		_token = NULL_TOKEN;
140 	} else
141 		_token = info.token;
142 
143 	return err;
144 }
145 
146 
147 bool
148 BArchiveManager::IsArchived(BArchivable* archivable)
149 {
150 	if (!archivable)
151 		return true;
152 
153 	return fTokenMap.find(archivable) != fTokenMap.end();
154 }
155 
156 
157 status_t
158 BArchiveManager::ArchiverLeaving(const BArchiver* archiver, status_t err)
159 {
160 	if (fError == B_OK)
161 		fError = err;
162 
163 	if (archiver == fCreator && fError == B_OK) {
164 		// first, we must sort the objects into the order they were archived in
165 		typedef std::pair<BMessage*, const BArchivable*> ArchivePair;
166 		ArchivePair pairs[fTokenMap.size()];
167 
168 		for(TokenMap::iterator it = fTokenMap.begin(), end = fTokenMap.end();
169 				it != end; it++) {
170 			ArchiveInfo& info = it->second;
171 			pairs[info.token].first = info.archive;
172 			pairs[info.token].second = it->first;
173 
174 			// make sure fTopLevelArchive isn't deleted
175 			if (info.archive == fTopLevelArchive)
176 				info.archive = NULL;
177 		}
178 
179 		int32 count = fTokenMap.size();
180 		for (int32 i = 0; i < count; i++) {
181 			const ArchivePair& pair = pairs[i];
182 			fError = pair.second->AllArchived(pair.first);
183 
184 			if (fError == B_OK && i > 0) {
185 				fError = fTopLevelArchive->AddMessage(kArchivableField,
186 					pair.first);
187 			}
188 
189 			if (fError != B_OK) {
190 				syslog(LOG_ERR, "AllArchived failed for object of type %s.",
191 					typeid(*pairs[i].second).name());
192 				break;
193 			}
194 		}
195 	}
196 
197 	if (archiver == fCreator)
198 		delete this;
199 
200 	return fError;
201 }
202 
203 
204 void
205 BArchiveManager::RegisterArchivable(const BArchivable* archivable)
206 {
207 	if (fTokenMap.size() == 0) {
208 		ArchiveInfo& info = fTokenMap[archivable];
209 		info.archive = fTopLevelArchive;
210 		info.token = 0;
211 	}
212 }
213 
214 
215 // #pragma mark -
216 
217 
218 struct BUnarchiveManager::ArchiveInfo {
219 	ArchiveInfo()
220 		:
221 		archivable(NULL),
222 		archive(),
223 		adopted(false)
224 	{
225 	}
226 
227 	bool
228 	operator<(const ArchiveInfo& other)
229 	{
230 		return archivable < other.archivable;
231 	}
232 
233 	BArchivable*	archivable;
234 	BMessage		archive;
235 	bool			adopted;
236 };
237 
238 
239 // #pragma mark -
240 
241 
242 BUnarchiveManager::BUnarchiveManager(BMessage* archive)
243 	:
244 	BManagerBase(archive, BManagerBase::UNARCHIVE_MANAGER),
245 	fObjects(NULL),
246 	fObjectCount(0),
247 	fTokenInProgress(0),
248 	fRefCount(0),
249 	fError(B_OK)
250 {
251 	archive->GetInfo(kArchivableField, NULL, &fObjectCount);
252 	fObjectCount++;
253 		// root object needs a spot too
254 	fObjects = new ArchiveInfo[fObjectCount];
255 
256 	// fObjects[0] is a placeholder for the object that started
257 	// this unarchiving session.
258 	for (int32 i = 0; i < fObjectCount - 1; i++) {
259 		BMessage* into = &fObjects[i + 1].archive;
260 		status_t err = archive->FindMessage(kArchivableField, i, into);
261 		MarkArchive(into);
262 
263 		if (err != B_OK)
264 			syslog(LOG_ERR, "Failed to find managed archivable");
265 	}
266 }
267 
268 
269 BUnarchiveManager::~BUnarchiveManager()
270 {
271 	delete[] fObjects;
272 }
273 
274 
275 status_t
276 BUnarchiveManager::GetArchivableForToken(int32 token,
277 	BUnarchiver::ownership_policy owning, BArchivable*& _archivable)
278 {
279 	if (token >= fObjectCount)
280 		return B_BAD_VALUE;
281 
282 	if (token < 0) {
283 		_archivable = NULL;
284 		return B_OK;
285 	}
286 
287 	status_t err = B_OK;
288 	ArchiveInfo& info = fObjects[token];
289 	if (!info.archivable) {
290 		if (fRefCount > 0) {
291 			fTokenInProgress = token;
292 			if(!instantiate_object(&info.archive))
293 				err = B_ERROR;
294 		} else {
295 			syslog(LOG_ERR, "Object requested from AllUnarchived()"
296 				" was not previously instantiated");
297 			err = B_ERROR;
298 		}
299 	}
300 
301 	if (!info.adopted && owning == BUnarchiver::B_ASSUME_OWNERSHIP)
302 		info.adopted = true;
303 	else if (info.adopted && owning == BUnarchiver::B_ASSUME_OWNERSHIP)
304 		debugger("Cannot assume ownership of an object that is already owned");
305 
306 	_archivable = info.archivable;
307 	return err;
308 }
309 
310 
311 bool
312 BUnarchiveManager::IsInstantiated(int32 token)
313 {
314 	if (token < 0 || token >= fObjectCount)
315 		return false;
316 	return fObjects[token].archivable;
317 }
318 
319 
320 void
321 BUnarchiveManager::RegisterArchivable(BArchivable* archivable)
322 {
323 	if (!archivable)
324 		debugger("Cannot register NULL pointer");
325 
326 	fObjects[fTokenInProgress].archivable = archivable;
327 	archivable->fArchivingToken = fTokenInProgress;
328 }
329 
330 
331 status_t
332 BUnarchiveManager::UnarchiverLeaving(const BUnarchiver* unarchiver,
333 	status_t err)
334 {
335 	if (--fRefCount >= 0 && fError == B_OK)
336 		fError = err;
337 
338 	if (fRefCount != 0)
339 		return fError;
340 
341 	if (fError == B_OK) {
342 		BArchivable* archivable = fObjects[0].archivable;
343 		if (archivable) {
344 			fError = archivable->AllUnarchived(fTopLevelArchive);
345 			archivable->fArchivingToken = NULL_TOKEN;
346 		}
347 
348 		for (int32 i = 1; i < fObjectCount && fError == B_OK; i++) {
349 			archivable = fObjects[i].archivable;
350 			if (archivable) {
351 				fError = archivable->AllUnarchived(&fObjects[i].archive);
352 				archivable->fArchivingToken = NULL_TOKEN;
353 			}
354 		}
355 		if (fError != B_OK) {
356 			syslog(LOG_ERR, "Error in AllUnarchived"
357 				" method of object of type %s", typeid(*archivable).name());
358 		}
359 	}
360 
361 	if (fError != B_OK) {
362 		syslog(LOG_ERR, "An error occured during unarchival, cleaning up.");
363 		for (int32 i = 1; i < fObjectCount; i++) {
364 			if (!fObjects[i].adopted)
365 				delete fObjects[i].archivable;
366 		}
367 	}
368 
369 	delete this;
370 	return fError;
371 }
372 
373 
374 void
375 BUnarchiveManager::RelinquishOwnership(BArchivable* archivable)
376 {
377 	int32 token = NULL_TOKEN;
378 	if (archivable)
379 		token = archivable->fArchivingToken;
380 
381 	if (token < 0 || token >= fObjectCount
382 		|| fObjects[token].archivable != archivable)
383 		return;
384 
385 	fObjects[token].adopted = false;
386 }
387 
388 
389 void
390 BUnarchiveManager::AssumeOwnership(BArchivable* archivable)
391 {
392 	int32 token = NULL_TOKEN;
393 	if (archivable)
394 		token = archivable->fArchivingToken;
395 
396 	if (token < 0 || token >= fObjectCount
397 		|| fObjects[token].archivable != archivable)
398 		return;
399 
400 	if (!fObjects[token].adopted)
401 		fObjects[token].adopted = true;
402 	else {
403 		debugger("Cannot assume ownership of an object that is already owned");
404 	}
405 }
406 
407 
408 void
409 BUnarchiveManager::Acquire()
410 {
411 	if (fRefCount >= 0)
412 		fRefCount++;
413 }
414