5
The remote object factory uses a lease-based system. Remote objects
6
are purged from the pool when the lease expires. Supports inheritance.
10
c++ -o factory factory.cpp stdsoap2.cpp soapC.cpp soapServer.cpp
12
Run (e.g. in the background)
14
where <port> is a available port number, e.g. 18085
16
Copyright (C) 2000-2002 Robert A. van Engelen. All Rights Reserved.
19
#include <sys/stat.h> // for open()
22
#include "factory.nsmap"
24
#define POOLSIZE 1000 // max number of remote objects that can be alive at any instance
26
#define LEASETERM 60 // lease term (in seconds). Also the rate at which objects are purged
28
////////////////////////////////////////////////////////////////////////////////
30
// Factory class maintains pool of objects and can act as a simple ORB
32
////////////////////////////////////////////////////////////////////////////////
36
t__root *ref[POOLSIZE]; // pool of objects (t__root is base class)
37
unsigned int handle; // handle generation counter (is allowed to wrap around 32 bits)
40
unsigned int create(struct soap *soap, enum t__object object, char *name);
41
unsigned int lookup(enum t__object object, char *name);
42
unsigned int rename(unsigned int handle, char *name);
43
void release(unsigned int handle);
44
void purge(struct soap* soap);
45
t__root *get(unsigned int handle);
46
t__root *root(unsigned int handle);
47
t__adder *adder(unsigned int handle);
48
t__counter *counter(unsigned int handle);
49
int save(const char *file);
50
int load(const char *file);
53
// Initialize empty pool and set handle generation counter to 0
55
{ for (int i = 0; i < POOLSIZE; i++)
60
// Remove all objects from pool
62
{ for (int i = 0; i < POOLSIZE; i++)
67
// Create a new object, place it in the pool, and return handle
68
unsigned int Factory::create(struct soap *soap, enum t__object object, char *name)
69
{ for (int i = 0; i < POOLSIZE; i++)
70
if (!ref[++handle % POOLSIZE]) // succeeds if this slot is available
73
handle += POOLSIZE; // make sure handle is never 0 (0 indicates invalid handle)
74
switch (object) // type of object to instantiate
86
{ ref[handle % POOLSIZE] = r; // add object to the pool
87
r->object = object; // save type
88
if (name) // save name (if assigned)
89
{ r->name = (char*)malloc(strlen(name+1));
90
strcpy(r->name, name);
94
r->handle = handle; // keep handle for verification
95
r->renew(); // renew its lease
103
// Lookup the name of an object and return handle
104
unsigned int Factory::lookup(enum t__object object, char *name)
105
{ for (int i = 0; i < POOLSIZE; i++)
106
if (ref[i] && ref[i]->object == object && ref[i]->name && !strcmp(ref[i]->name, name))
108
return ref[i]->handle;
113
// Rename object and return handle if successful
114
unsigned int Factory::rename(unsigned int handle, char *name)
115
{ t__root *r = get(handle);
119
r->name = (char*)malloc(strlen(name)+1);
120
strcpy(r->name, name);
127
// get ref to object from handle
128
t__root *Factory::get(unsigned int handle)
129
{ t__root *r = ref[handle % POOLSIZE];
130
if (r && r->handle == handle)
135
// get ref to root object from handle and renew lease
136
t__root *Factory::root(unsigned int handle)
137
{ t__root *r = get(handle);
143
// get ref to adder object from handle and renew lease
144
t__adder *Factory::adder(unsigned int handle)
145
{ t__adder *a = (t__adder*)get(handle);
147
{ if (a->object == ADDER || a->object == COUNTER)
155
// get ref to counter object from handle and renew lease
156
t__counter *Factory::counter(unsigned int handle)
157
{ t__counter *c = (t__counter*)get(handle);
159
{ if (c->object == COUNTER)
167
// remove all objects from pool whose lease has expired
168
void Factory::purge(struct soap *soap)
169
{ time_t t = time(NULL); // current time
171
for (int i = 0; i < POOLSIZE; i++)
172
{ t__root *r = ref[i];
173
if (r && r->lease < t) // expired?
175
fprintf(stderr, "\nPurging objects:");
177
fprintf(stderr, "%s(%u)\n", r->name, r->handle);
179
fprintf(stderr, "(%u)\n", r->handle);
180
soap_delete(soap, r);
187
// remove object from pool and release slot
188
void Factory::release(unsigned int handle)
189
{ t__root *r = get(handle);
191
ref[handle % POOLSIZE] = NULL;
194
// save object pool to file (or stdout)
195
int Factory::save(const char *file)
196
{ struct soap soap; // use a new local gSOAP environment
200
soap.sendfd = open(file, O_CREAT|O_TRUNC|O_WRONLY, S_IREAD|S_IWRITE);
203
soap_begin_send(&soap);
204
for (int i = 0; i < POOLSIZE; i++)
206
{ ref[i]->soap_serialize(&soap);
207
soap_begin_send(&soap);
208
ref[i]->soap_put(&soap, "item", NULL);
209
soap_end_send(&soap);
218
// load object pool from file (or stdin)
219
int Factory::load(const char *file)
224
soap.recvfd = open(file, O_RDONLY);
227
soap_begin_recv(&soap);
228
for (int i = 0; i < POOLSIZE; i++)
235
{ r = soap_in_t__root(&soap, "item", NULL, NULL); // use the 'in' routine ('get' will also attempt to parse the remaining XML)
237
ref[r->handle % POOLSIZE] = r;
243
if (soap.error != SOAP_OK && soap.error != SOAP_EOF)
244
{ soap_print_fault(&soap, stderr);
245
soap_print_fault_location(&soap, stderr);
247
soap_free(&soap); // do not call soap_end: this would remove all deserialized data
252
////////////////////////////////////////////////////////////////////////////////
254
// Main server program
256
////////////////////////////////////////////////////////////////////////////////
258
int main(int argc, char **argv)
261
Factory factory; // create factory and simple ORB
263
soap.user = (void*)&factory; // associate factory with run-time
264
soap.accept_timeout = 1; // check every second, if not too busy for purging objects
266
{ factory.load("factory.dat"); // if CGI is used, load the entire pool (not very efficient and there may be a competition for access to this file! This is just to demonstrate load/save of the entire pool)
267
factory.purge(&soap);
269
factory.save("factory.dat"); // ... and save afterwards
272
{ m = soap_bind(&soap, NULL, atoi(argv[1]), 100); // use command line argument as port number
274
{ soap_print_fault(&soap, stderr);
277
fprintf(stderr, "Socket connection successful %d\n", m);
278
for (int i = 1; ; i++)
279
{ s = soap_accept(&soap);
282
soap_print_fault(&soap, stderr);
283
else // errnum is 0, which means a timeout has occurred
284
{ factory.purge(&soap); // purge objects whose lease has ran out
289
fprintf(stderr, "%d: accepted %d IP=%d.%d.%d.%d ... ", i, s, (int)(soap.ip>>24)&0xFF, (int)(soap.ip>>16)&0xFF, (int)(soap.ip>>8)&0xFF, (int)soap.ip&0xFF);
291
fprintf(stderr, "served\n");
292
soap_end(&soap); // clean up: this will remove deserialized data
298
////////////////////////////////////////////////////////////////////////////////
300
// Remote factory method implementations
302
////////////////////////////////////////////////////////////////////////////////
304
int ns__create(struct soap *soap, enum t__object object, char *name, enum t__status &status)
305
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
307
soap->header = (struct SOAP_ENV__Header*)soap_malloc(soap, sizeof(struct SOAP_ENV__Header));
309
{ soap->header->h__handle = factory->create(soap, object, name);
310
if (soap->header->h__handle)
313
status = FACTORY_INVALID;
316
status = FACTORY_RETRY;
320
int ns__lookup(struct soap *soap, enum t__object object, char *name, enum t__status &status)
321
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
323
soap->header = (struct SOAP_ENV__Header*)soap_malloc(soap, sizeof(struct SOAP_ENV__Header));
325
{ soap->header->h__handle = factory->lookup(object, name);
326
if (soap->header->h__handle)
329
status = FACTORY_NOTFOUND;
332
status = FACTORY_RETRY;
336
int ns__rename(struct soap *soap, char *name, enum t__status &status)
337
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
339
{ soap->header->h__handle = factory->rename(soap->header->h__handle, name);
340
if (soap->header->h__handle)
343
status = FACTORY_INVALID;
346
status = FACTORY_INVALID;
350
int ns__release(struct soap *soap, enum t__status &status)
351
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
352
if (soap->header && soap->header->h__handle)
353
{ factory->release(soap->header->h__handle);
357
status = FACTORY_INVALID;
361
////////////////////////////////////////////////////////////////////////////////
363
// Remote adder method implementations
365
////////////////////////////////////////////////////////////////////////////////
367
int ns__set(struct soap *soap, double val, enum t__status &status)
368
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
370
{ t__adder *adder = factory->adder(soap->header->h__handle);
376
status = FACTORY_INVALID;
379
status = FACTORY_INVALID;
383
int ns__get(struct soap *soap, double &val)
384
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
387
{ t__adder *adder = factory->adder(soap->header->h__handle);
394
int ns__add(struct soap *soap, double val, enum t__status &status)
395
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
397
{ t__adder *adder = factory->adder(soap->header->h__handle);
403
status = FACTORY_INVALID;
406
status = FACTORY_INVALID;
410
////////////////////////////////////////////////////////////////////////////////
412
// Remote counter method implementations
414
////////////////////////////////////////////////////////////////////////////////
416
int ns__inc(struct soap *soap, enum t__status &status)
417
{ Factory *factory = (Factory*)soap->user; // get factory from gSOAP environment
419
{ t__counter *counter = factory->counter(soap->header->h__handle);
425
status = FACTORY_INVALID;
428
status = FACTORY_INVALID;
432
////////////////////////////////////////////////////////////////////////////////
434
// Server-side base factory class methods
436
////////////////////////////////////////////////////////////////////////////////
446
void t__root::renew()
447
{ lease = time(NULL) + LEASETERM; // can adopt a leasing policy per class
450
////////////////////////////////////////////////////////////////////////////////
452
// Server-side adder class methods
454
////////////////////////////////////////////////////////////////////////////////
456
void t__adder::set(double val)
457
{ this->val = val; // copy data to update state
460
double t__adder::get()
464
void t__adder::add(double val)
468
////////////////////////////////////////////////////////////////////////////////
470
// Server-side counter class methods
472
////////////////////////////////////////////////////////////////////////////////
474
void t__counter::inc()