You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@etch.apache.org by jd...@apache.org on 2009/04/22 19:25:51 UTC
svn commit: r767594 [20/43] - in /incubator/etch/trunk/binding-c/runtime/c:
./ ext/ ext/hashtab/ ext/lib/ inc/ lib/ project/ project/$etchstop/
project/bin/ project/etch/ project/logcli/ project/logsrv/ project/notes/
project/test/ project/test/logcli/...
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_queue_apr.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,441 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_queue_apr.c
+ * based on apr_queue, modified by Cisco as follows:
+ * timeouts were added on the push and pop waits, and functions were modified
+ * to release their lock at a single exit point.
+ */
+
+#include "apr.h"
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "apu.h"
+#include "apr_portable.h"
+#include "apr_thread_mutex.h"
+#include "apr_thread_cond.h"
+#include "apr_errno.h"
+
+#include "etch_queue_apr.h" /* Cisco */
+
+/* #define QUEUE_DEBUG */
+
+#ifdef QUEUE_DEBUG
+static void Q_DBG(char*msg, etch_apr_queue_t *q) {
+ fprintf(stderr, "%ld\t#%d in %d out %d\t%s\n",
+ (size_t) apr_os_thread_current(), /* cast - Cisco */
+ q->nelts, q->in, q->out,
+ msg
+ );
+ fflush(stdout); /* Cisco */
+}
+#else
+#define Q_DBG(x,y)
+#endif
+
+
+/**
+ * Detects when the etch_apr_queue_t is full. This utility function is expected
+ * to be called from within critical sections, and is not threadsafe.
+ */
+#define etch_apr_queue_full(queue) ((queue)->nelts == (queue)->bounds)
+
+
+/**
+ * Detects when the etch_apr_queue_t is empty. This utility function is expected
+ * to be called from within critical sections, and is not threadsafe.
+ */
+#define etch_apr_queue_empty(queue) ((queue)->nelts == 0)
+
+
+/**
+ * Callback routine that is called to destroy this
+ * etch_apr_queue_t when its pool is destroyed.
+ */
+static apr_status_t etch_apr_queue_destroy(void *data)
+{
+ etch_apr_queue_t *queue = data;
+
+ apr_thread_cond_destroy(queue->not_empty);
+ apr_thread_cond_destroy(queue->not_full);
+ apr_thread_mutex_destroy(queue->one_big_mutex);
+
+ return APR_SUCCESS;
+}
+
+
+/**
+ * Initialize the etch_apr_queue_t.
+ */
+apr_status_t etch_apr_queue_create(etch_apr_queue_t **q,
+ unsigned int queue_capacity,
+ apr_pool_t *a)
+{
+ apr_status_t rv;
+ etch_apr_queue_t *queue;
+ queue = apr_palloc(a, sizeof(etch_apr_queue_t));
+ *q = queue;
+
+ /* nested doesn't work ;( */
+ rv = apr_thread_mutex_create(&queue->one_big_mutex,
+ APR_THREAD_MUTEX_UNNESTED,
+ a);
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ rv = apr_thread_cond_create(&queue->not_empty, a);
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ rv = apr_thread_cond_create(&queue->not_full, a);
+ if (rv != APR_SUCCESS)
+ return rv;
+
+ /* Set all the data in the queue to NULL */
+ queue->data = apr_pcalloc(a, queue_capacity * sizeof(void*));
+ queue->bounds = queue_capacity;
+ queue->nelts = 0;
+ queue->in = 0;
+ queue->out = 0;
+ queue->terminated = 0;
+ queue->full_waiters = 0;
+ queue->empty_waiters = 0;
+
+ apr_pool_cleanup_register(a, queue, etch_apr_queue_destroy, apr_pool_cleanup_null);
+
+ return APR_SUCCESS;
+}
+
+
+/**
+ * Push new data onto the queue. Blocks if the queue is full. Once
+ * the push operation has completed, it signals other threads waiting
+ * in apr_queue_pop() that they may continue consuming sockets.
+ * @param timeout added by Cisco. now uses apr_thread_cond_timewait().
+ * interval of time to wait. zero means forever, negative indicates no wait,
+ * otherwise wait time in *microseconds*.
+ * @return APR_SUCCESS, APR_EAGAIN, APR_EOF, APR_EINTR, APR_TIMEUP,
+ * or some APR error
+ */
+apr_status_t etch_apr_queue_push(etch_apr_queue_t *queue,
+ apr_interval_time_t timeout,
+ void *data)
+{
+ apr_status_t rv;
+
+ if (queue->terminated)
+ rv = APR_EOF; /* no more elements ever again */
+ else
+ if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+ {
+ do
+ { if (etch_apr_queue_full(queue))
+ {
+ if (!queue->terminated)
+ {
+ if (-1 == timeout)
+ { rv = APR_EAGAIN; /* asked to not wait */
+ break;
+ }
+
+ queue->full_waiters++;
+
+ if (0 == timeout)
+ rv = apr_thread_cond_wait(queue->not_full, queue->one_big_mutex);
+ else
+ rv = apr_thread_cond_timedwait(queue->not_full, queue->one_big_mutex, timeout);
+
+ queue->full_waiters--;
+ if (rv != APR_SUCCESS)
+ break;
+ }
+
+ /* If we wake up and it's still empty, then we were interrupted */
+ if (etch_apr_queue_full(queue))
+ {
+ Q_DBG("queue full (intr)", queue);
+ rv = queue->terminated? APR_EOF: APR_EINTR;
+ break;
+ }
+ }
+
+ queue->data[queue->in] = data;
+ queue->in = (queue->in + 1) % queue->bounds;
+ queue->nelts++;
+
+ if (queue->empty_waiters)
+ {
+ Q_DBG("sig !empty", queue);
+ rv = apr_thread_cond_signal(queue->not_empty);
+ }
+
+ } while(0);
+
+ apr_thread_mutex_unlock(queue->one_big_mutex);
+ }
+
+ return rv;
+}
+
+
+/**
+ * Push new data onto the queue. Blocks if the queue is full. Once
+ * the push operation has completed, it signals other threads waiting
+ * in apr_queue_pop() that they may continue consuming sockets.
+ */
+apr_status_t etch_apr_queue_trypush(etch_apr_queue_t *queue, void *data)
+{
+ apr_status_t rv;
+
+ if (queue->terminated)
+ rv = APR_EOF;
+ else
+ if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+ {
+ if (etch_apr_queue_full(queue))
+ rv = APR_EAGAIN;
+ else
+ { queue->data[queue->in] = data;
+ queue->in = (queue->in + 1) % queue->bounds;
+ queue->nelts++;
+
+ if (queue->empty_waiters)
+ {
+ Q_DBG("sig !empty", queue);
+ rv = apr_thread_cond_signal(queue->not_empty);
+ }
+ }
+
+ apr_thread_mutex_unlock(queue->one_big_mutex);
+ }
+
+ return rv;
+}
+
+
+/**
+ * not thread safe
+ */
+unsigned int etch_apr_queue_size(etch_apr_queue_t *queue) {
+ return queue->nelts;
+}
+
+
+/**
+ * Retrieves the next item from the queue. If there are no
+ * items available, it will block until one becomes available.
+ * Once retrieved, the item is placed into the address specified by
+ * 'data'.
+ * @param timeout added by Cisco. now uses apr_thread_cond_timewait().
+ * interval of time to wait. zero means forever, -1 means no wait,
+ * -2 means don't wait and ignore queue closed indicator,
+ * otherwise timeout is blocking time in microseconds.
+ * @return APR_SUCCESS, APR_EAGAIN, APR_EOF, APR_EINTR, APR_TIMEUP,
+ * or some APR error
+ */
+apr_status_t etch_apr_queue_pop(etch_apr_queue_t *queue,
+ apr_interval_time_t timeout,
+ void **data)
+{
+ apr_status_t rv;
+
+ if (queue->terminated) /* Cisco back door to clear closed queue */
+ { if (timeout != ETCHQUEUE_CLEARING_CLOSED_QUEUE)
+ return APR_EOF; /* no more elements ever again */
+ }
+
+ if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+ {
+ do
+ { /* Keep waiting until we wake up and find that the queue is not empty. */
+ if (etch_apr_queue_empty(queue))
+ {
+ if (-1 == timeout)
+ { rv = APR_EAGAIN; /* asked to not wait */
+ break;
+ }
+
+ if (!queue->terminated)
+ {
+ queue->empty_waiters++;
+
+ if (0 == timeout)
+ rv = apr_thread_cond_wait(queue->not_empty, queue->one_big_mutex);
+ else
+ rv = apr_thread_cond_timedwait(queue->not_empty, queue->one_big_mutex, timeout);
+
+ queue->empty_waiters--;
+
+ if (rv != APR_SUCCESS) /* rv will be APR_TIMEUP if timed out */
+ break;
+ }
+
+ /* If we wake up and it's still empty, then we were interrupted */
+ if (etch_apr_queue_empty(queue))
+ {
+ Q_DBG("queue empty (intr)", queue);
+ rv = queue->terminated? APR_EOF: APR_EINTR;
+ break;
+ }
+ }
+
+ *data = queue->data[queue->out];
+ queue->nelts--;
+
+ queue->out = (queue->out + 1) % queue->bounds;
+
+ if (queue->full_waiters)
+ {
+ Q_DBG("signal !full", queue);
+ rv = apr_thread_cond_signal(queue->not_full);
+ }
+
+ } while(0);
+
+ apr_thread_mutex_unlock(queue->one_big_mutex);
+ }
+
+ return rv;
+}
+
+
+/**
+ * Retrieves the next item from the queue. If there are no
+ * items available, return APR_EAGAIN. Once retrieved,
+ * the item is placed into the address specified by 'data'.
+ */
+apr_status_t etch_apr_queue_trypop(etch_apr_queue_t *queue, void **data)
+{
+ apr_status_t rv;
+
+ if (queue->terminated)
+ rv = APR_EOF; /* no more elements ever again */
+ else
+ if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+ {
+ if (etch_apr_queue_empty(queue))
+ rv = APR_EAGAIN;
+ else
+ { *data = queue->data[queue->out];
+ queue->nelts--;
+
+ queue->out = (queue->out + 1) % queue->bounds;
+
+ if (queue->full_waiters)
+ {
+ Q_DBG("signal !full", queue);
+ rv = apr_thread_cond_signal(queue->not_full);
+ }
+ }
+
+ apr_thread_mutex_unlock(queue->one_big_mutex);
+ }
+
+ return rv;
+}
+
+
+apr_status_t etch_apr_queue_interrupt_all(etch_apr_queue_t *queue)
+{
+ apr_status_t rv;
+ Q_DBG("intr all", queue);
+
+ if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+ {
+ apr_thread_cond_broadcast(queue->not_empty);
+ apr_thread_cond_broadcast(queue->not_full);
+
+ apr_thread_mutex_unlock(queue->one_big_mutex);
+ }
+
+ return rv;
+}
+
+
+/**
+ * etch_apr_queue_unsafe_interrupt_all()
+ * added by Cisco to opeate when lock already held since queue lock is not nestable.
+ */
+apr_status_t etch_apr_queue_unsafe_interrupt_all(etch_apr_queue_t *queue)
+{
+ Q_DBG("intr all", queue);
+
+ apr_thread_cond_broadcast(queue->not_empty);
+ apr_thread_cond_broadcast(queue->not_full);
+
+ return APR_SUCCESS;
+}
+
+
+apr_status_t etch_apr_queue_term(etch_apr_queue_t *queue)
+{
+ apr_status_t rv;
+
+ if (APR_SUCCESS == (rv = apr_thread_mutex_lock(queue->one_big_mutex)))
+ {
+ /* we must hold one_big_mutex when setting this... otherwise,
+ * we could end up setting it and waking everybody up just after a
+ * would-be popper checks it but right before they block
+ */
+ queue->terminated = 1;
+
+ apr_thread_mutex_unlock(queue->one_big_mutex);
+ }
+
+ return etch_apr_queue_interrupt_all(queue);
+}
+
+
+/**
+ * added by Cisco to close queue when lock already held
+ */
+apr_status_t etch_apr_queue_unsafeclose(etch_apr_queue_t *queue)
+{
+ queue->terminated = 1;
+ return etch_apr_queue_unsafe_interrupt_all(queue);
+}
+
+
+/**
+ * added by Cisco to access lock externally
+ */
+apr_status_t etch_apr_queue_lock(etch_apr_queue_t *queue)
+{
+ return apr_thread_mutex_lock(queue->one_big_mutex);
+}
+
+
+/**
+ * added by Cisco to access lock externally
+ */
+apr_status_t etch_apr_queue_unlock(etch_apr_queue_t *queue)
+{
+ return apr_thread_mutex_unlock(queue->one_big_mutex);
+}
+
+
+/**
+ * etch_apr_queue_trylock()
+ * added by Cisco to access lock externally
+ */
+int etch_apr_queue_trylock(etch_apr_queue_t *queue)
+{
+ return apr_thread_mutex_trylock(queue->one_big_mutex);
+}
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_remote.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,316 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_remote.c
+ * base methods for either type of remote
+ */
+
+#include "apr_time.h" /* some apr must be included first */
+#include "etch_remote.h"
+#include "etch_global.h"
+#include "etchexcp.h"
+#include "etch_url.h"
+#include "etchlog.h"
+
+#include <tchar.h>
+#include <stdio.h>
+#include <conio.h>
+char* ETCHREMO = "REMO";
+
+
+/**
+ * is_etch_remote()
+ */
+int is_etch_remote(void* x)
+{
+ int result = FALSE, objtype = x? ((objmask*)x)->obj_type: 0;
+ switch(objtype)
+ { case ETCHTYPEB_REMOTE: case ETCHTYPEB_REMOTECLIENT: case ETCHTYPEB_REMOTESERVER:
+ result = TRUE;
+ }
+ return result;
+}
+
+
+/**
+ * etchremote_new_message()
+ * instantiates a message to be sent via this.send() or this.begin_call().
+ * @param thisx this remote object.
+ * @param message_type type of message, caller retains.
+ * @return message object, or an etch object wrapping an exception.
+ */
+etch_message* etchremote_new_message (xxxx_remote* thisx, etch_type* message_type)
+{
+ etch_message* msg = new_message (message_type, ETCH_DEFSIZE, thisx->vf);
+
+ /* removed this throw because caller (remote) can't use the exception
+ * without rethrowing it to the mailbox object */
+ #if(0)
+ if (NULL == msg) /* warning this is not a usable message object */
+ msg = (etch_message*) throw_from(EXCPTYPE_ETCHRUNTIME, ETCHTYPEB_MESSAGE,
+ L"could not create message", ETCHEXCP_COPYTEXT);
+ #endif
+
+ return msg;
+}
+
+
+/**
+ * etchremote_send()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_send (xxxx_remote* thisx, etch_message* msg)
+{
+ int result = 0;
+ ETCH_ASSERT(is_etch_remote(thisx));
+
+ result = thisx->dsvc->itm->transport_message(thisx->dsvc, NULL, msg);
+
+ if (0 != result)
+ etchlog(ETCHREMO, ETCHLOG_ERROR, "remote server send failed for msg %x\n", msg);
+
+ return result;
+}
+
+
+/**
+ * etchremote_sendex()
+ * sends message to recipient without waiting for a response.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return etch_int32 whose value is 0 success, -1 failure, caller owns it.
+ * result object will wrap an exception if send was not successful.
+ */
+void* etchremote_sendex (xxxx_remote* thisx, etch_message* msg)
+{
+ etch_int32* resultobj = new_int32(0);
+
+ if (0 != (resultobj->value = etchremote_send (thisx, msg)))
+ etch_throw((objmask*)resultobj, EXCPTYPE_IO,
+ L"remote server send failed", ETCHEXCP_COPYTEXT);
+
+ return resultobj;
+}
+
+
+/**
+ * etchremote_begincall()
+ * sends message beginning a call sequence.
+ * @param thisx this remote object.
+ * @param msg message, caller relinquishes.
+ * @return in out parameter, a mailbox which can be used to retrieve the response.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_begincall (xxxx_remote* thisx, etch_message* msg, void** out)
+{
+ int result = 0;
+ ETCH_ASSERT(is_etch_remote(thisx));
+
+ result = thisx->dsvc->begin_call(thisx->dsvc, msg, out);
+
+ if (0 != result)
+ etchlog(ETCHREMO, ETCHLOG_ERROR, "could not create mailbox for msg %x\n", msg);
+
+ return result;
+}
+
+
+/**
+ * etchremote_endcall()
+ * finishes a call sequence by waiting for a response message.
+ * @param thisx this remote object.
+ * @param mbox a mailbox which will be used to read an expected message response.
+ * @param response_type the message type of the expected response.
+ * @return in out parameter, on success, the response objmask* masked object.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_endcall (xxxx_remote* thisx, i_mailbox* mbox, etch_type* response_type, void** out)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+
+ return thisx->dsvc->end_call(thisx->dsvc, mbox, response_type, out);
+}
+
+
+/**
+ * etchremote_transport_control()
+ * @param evt caller relinquishes
+ * @param value caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+int etchremote_transport_control (xxxx_remote* thisx, etch_event* evt, etch_int32* value)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+
+ return thisx->dsvc->itm->transport_control(thisx->dsvc, evt, value);
+}
+
+
+/**
+ * etchremote_transport_notify()
+ * @param evt caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+int etchremote_transport_notify (xxxx_remote* thisx, etch_event* evt)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+
+ return thisx->dsvc->itm->transport_notify(thisx->dsvc, evt);
+}
+
+
+/**
+ * etchremote_transport_query()
+ * @param query caller relinquishes
+ * @return 0 success, -1 failure.
+ */
+objmask* etchremote_transport_query (xxxx_remote* thisx, objmask* query)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+
+ return thisx->dsvc->itm->transport_query(thisx->dsvc, query);
+}
+
+
+/**
+ * etchremote_set_session()
+ * @param session caller retains
+ * @return 0 success, -1 failure.
+ */
+void etchremote_set_session (xxxx_remote* thisx, void* session)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+}
+
+
+/**
+ * etchremote_get_session()
+ * @param session caller retains
+ * @return 0 success, -1 failure.
+ */
+void* etchremote_get_session (xxxx_remote* thisx)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+ return thisx->dsvc->ism;
+}
+
+
+/**
+ * etchremote_start_waitup()
+ * start the transport and wait for it to come up.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_start_waitup (xxxx_remote* thisx, const int waitms)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+ ETCH_ASSERT(thisx->transport_control);
+
+ /* indicate to transport start whether this request is from a client
+ * (remote server) or a server (remote client) */
+ { const int is_client = thisx->remote_type == ETCH_REMOTETYPE_SERVER;
+ etch_int32* txvalue = is_client? new_int32(is_client): NULL;
+ etch_event* txevent = new_etch_event(CLASSID_CONTROL_START_WAITUP, waitms);
+
+ return thisx->transport_control (thisx, txevent, txvalue);
+ }
+}
+
+
+/**
+ * etchremote_stop_waitdown()
+ * stop the transport and wait for it to go down.
+ * @param thisx this remote object.
+ * @param waitms how long to wait, in milliseconds.
+ * @return 0 success, -1 failure.
+ */
+int etchremote_stop_waitdown (xxxx_remote* thisx, const int waitms)
+{
+ ETCH_ASSERT(is_etch_remote(thisx));
+ ETCH_ASSERT(thisx->transport_control);
+
+ /* indicate to transport start whether this request is from a client
+ * (remote server) or a server (remote client) */
+ { const int is_client = thisx->remote_type == ETCH_REMOTETYPE_SERVER;
+ etch_int32* txvalue = is_client? new_int32(is_client): NULL;
+ etch_event* txevent = new_etch_event(CLASSID_CONTROL_STOP_WAITDOWN, waitms);
+
+ #ifdef ETCH_SHORTCIRCUIT_CLIENT_DEMO
+ if (is_client) /* dead end chain here for client demo */
+ { ETCHOBJ_DESTROY(txevent);
+ ETCHOBJ_DESTROY(txvalue);
+ return -1;
+ }
+ #endif /* ETCH_SHORTCIRCUIT_CLIENT_DEMO */
+
+ return thisx->transport_control (thisx, txevent, txvalue);
+ }
+}
+
+
+/**
+ * new_etch_remote_base
+ * generic constructor for remote base
+ * @param thisx parent object such as remote server or client.
+ * @param objsize byte length of actual remote base object,
+ * specifying ETCH_DEFSIZE defaults to sizeof(xxxx_remote).
+ * @param class_id etch class id of this object.
+ * @param ids delivery service -- caller retains.
+ * @param vf default value factory -- caller retains.
+ * @param ixxxx service interface -- caller retains.
+ * @return xxxx_remote* mask over either remote type.
+ * fyi xxxx_remote typedefs to etch_remote.
+ */
+xxxx_remote* new_etch_remote_base (void* thisx,
+ const int objsize, const unsigned short class_id,
+ i_delivery_service* ids, etch_value_factory* vf, objmask* ixxxx)
+{
+ const int nbytes = objsize? objsize: sizeof(xxxx_remote);
+
+ xxxx_remote* remote = (xxxx_remote*) new_object (nbytes, ETCHTYPEB_REMOTE, class_id);
+
+ /* xxxx_remote instance data and methods */
+ remote->dsvc = ids;
+ remote->vf = vf;
+ remote->start_waitup = etchremote_start_waitup;
+ remote->stop_waitdown = etchremote_stop_waitdown;
+
+ /* transport methods */
+ remote->transport_control = etchremote_transport_control;
+ remote->transport_notify = etchremote_transport_notify;
+ remote->transport_query = etchremote_transport_query;
+ remote->set_session = etchremote_set_session;
+ remote->get_session = etchremote_get_session;
+
+ /* remote base */
+ remote->new_message = etchremote_new_message;
+ remote->send = etchremote_send;
+ remote->sendex = etchremote_sendex;
+ remote->begin_call = etchremote_begincall;
+ remote->end_call = etchremote_endcall;
+
+ return remote;
+}
+
+
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_serializer.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,900 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_serializer.c
+ */
+
+#include "etch_serializer.h"
+#include "etch_defvalufact.h"
+#include "etch_arrayval.h"
+#include "etch_encoding.h"
+#include "etch_syncobj.h"
+#include "etch_global.h"
+#include "etchexcp.h"
+#include "etchmap.h"
+#include "etchlog.h"
+char* ETCHIMPX = "IMPX";
+
+objmask* etchserializer_defexportval (etch_serializer* thisx, objmask* objval);
+objmask* etchserializer_defimportval (etch_serializer* thisx, objmask* structval);
+int destroy_etch_serializer(etch_serializer* thisx);
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * constructors/destructors
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * new_etch_serializer()
+ * etch_serializer constructor
+ */
+etch_serializer* new_etch_serializer(const int objsize)
+{
+ const int size = objsize? objsize: sizeof(etch_serializer);
+
+ etch_serializer* newobj = (etch_serializer*) new_object
+ (sizeof(etch_serializer), ETCHTYPEB_SERIALIZER, CLASSID_NONE);
+
+ newobj->destroy = destroy_etch_serializer;
+ newobj->import_value = etchserializer_defimportval;
+ newobj->export_value = etchserializer_defexportval;
+
+ return newobj;
+}
+
+
+/**
+ * destroy_etch_serializer()
+ * etch_serializer destructor
+ */
+int destroy_etch_serializer(etch_serializer* thisx)
+{
+ if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;
+
+ if (!is_etchobj_static_content(thisx))
+ {
+ if (thisx->impl)
+ { thisx->impl->destroy(thisx->impl);
+ thisx->impl = NULL;
+ }
+ }
+
+ return destroy_objectex((objmask*) thisx);
+}
+
+
+/**
+ * etch_serializer_init()
+ * generic static intitializer for import export helper serializers.
+ * caller retains ownership of *all* parameters to this method.
+ * @param obj_type type of the object being serialized
+ * @param keyname name of an existing etch_field which will key the import
+ * and export object in its serialization map.
+ * @param obj_class numeric etch object type and class id of the object
+ being serialized.
+ * @param c2tmap a vf's map of numeric class to object type associations.
+ * @param vtor the validator object used to vet objects of this type.
+ * @param new_szr a pointer to the constructor for serializers of the
+ * specified type.
+ */
+int etch_serializer_init(etch_type* obj_type, const wchar_t* keyname,
+ const unsigned obj_class, etch_hashtable* c2tmap, etch_validator* vtor,
+ etch_serializer_ctor new_szr)
+{
+ etch_serializer* newimpexhelper = NULL;
+ /* serializer instantiation is awkward, since we are installing serializers
+ * to singleton types, but the class to type map is not singleton.
+ * investigate, and if reasonable, move the c2t maintenance to a higher
+ * level, and invoke this code only once per type instantiation.
+ * unfortunately a type does not indicate its correpsonding class,
+ * i.e. we know a type is "foo", but the type does not know it maps to
+ * ETCHTYPE_FOO, CLASSID_FOO. so here, the serializers, in their ctors,
+ * determine that mapping, and pass that class here. ideally we can eliminate
+ * both the c2t and class parameters from the serializer initialization.
+ */
+
+ /* get reference to field key having specified name, not owned here */
+ etch_field* szr_key = etchtype_get_field_by_name (obj_type, keyname);
+ if (NULL == szr_key) return -1;
+
+ /* map this class identifier to associated type object */
+ class_to_type_map_put(c2tmap, obj_class, obj_type);
+
+ /* if the type's serializer is already instantiated, we don't want
+ * to do so again. this is the awkardness commented above. */
+ if (etchtype_get_component_type(obj_type)) return 0;
+
+ /* set component type for arrays of specified class */
+ etchtype_set_component_type(obj_type, obj_class);
+
+ /* instantiate the new import/export helper */
+ newimpexhelper = new_szr(obj_type, szr_key);
+
+ /* attach, and assign ownership of, the new helper object to the type */
+ etchtype_set_impexphelper(obj_type, newimpexhelper);
+
+ return NULL == vtor? 0: /* attach the supplied validator to the type */
+ etchtype_put_validator(obj_type, clone_field(szr_key), (objmask*) vtor);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * exception serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_exception_export_value()
+ * export value for any exception
+ * @param objval an etch_exception object. caller owns it,
+ * and presumably will destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+objmask* etchserializer_exception_export_value (etch_serializer* thisx, objmask* objval)
+{
+ int result = 0;
+ char* excpvalue = NULL;
+ const int THISINITSIZE = 2;
+ etch_string* stringobj = NULL;
+ etch_structvalue* structval = NULL;
+
+ etch_exception* excpobj = (etch_exception*) objval;
+ if (!is_etch_exception(excpobj))
+ { etchlog(ETCHIMPX, ETCHLOG_ERROR, "value is not exception\n");
+ return NULL;
+ }
+
+ /* we tostring() the exception, getting back a buffer which we own here.
+ * we pass ownership of that buffer to an etch_string, and then pass
+ * ownership of that etch_string to the returned structvalue. recall that
+ * a structvalue owns all its content memory, and assumes its keys and
+ * values are etch objects on which it will invoke destructors when it
+ * itself is destroyed. we clone a type key for a similar reason.
+ */
+ excpvalue = excp_tostringx(excpobj->value);
+ stringobj = new_string_from(excpvalue, ETCH_ENCODING_ASCII);
+ structval = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+ result = structvalue_put(structval, clone_field(thisx->field), (objmask*)stringobj);
+
+ return (objmask*) structval;
+}
+
+
+/**
+ * etchserializer_exception_import_value()
+ * import value for any exception.
+ * @param objval an etch_structvalue of appropriate type for the exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception.
+ *
+ * caller owns and must destroy the returned object.
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_exception_import_value
+ (etch_serializer* thisx, objmask* objval, excptype xtype)
+{
+ wchar_t* unistring = NULL;
+ etch_string* impstring = NULL;
+ etch_exception* exception = NULL;
+
+ etch_structvalue* structval = (etch_structvalue*) objval;
+ if (!is_etch_struct(structval)) return NULL;
+ if (!structvalue_is_type(structval, thisx->type)) return NULL;
+
+ /* fetch the exception string out of the struct. not owned here. */
+ impstring = (etch_string*) structvalue_get (structval, thisx->field);
+ if (!is_etch_string(impstring)) return NULL;
+
+ if (IS_ETCH_ENCODING_8BIT(impstring->encoding))
+ /* recall that we carry all non-internal strings as unicode.
+ * we own the returned unicode buffer for the moment. */
+ etch_ansi_to_unicode (&unistring, impstring->v.valc);
+ else /* todo figure a way to not re-allocate the string */
+ unistring = new_wchar (impstring->v.valw);
+
+ /* create an exception object from the deserialized string. this object
+ * manages the exception memory according to flags supplied it. we set
+ * such a flag here, ETCHEXCP_FREETEXT, indicating that the exception
+ * owns the text buffer we give it. thus we no longer own unistring */
+ exception = new_etch_exception (xtype, unistring, ETCHEXCP_FREETEXT);
+
+ return (objmask*) exception;
+}
+
+
+/**
+ * etchserializer_excp_import_value()
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception.
+ *
+ * caller owns and must destroy the returned object.
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_excp_import_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_GENERIC);
+}
+
+
+
+/**
+ * new_exception_serializer()
+ * etch_serializer_excp constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_exception_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_EXCP;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_exception_export_value;
+ newobj->import_value = etchserializer_excp_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_exception_init()
+ * static intitializer for runtime exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_exception_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* keyname = str_msg; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_EXCEPTION);
+
+ return etch_serializer_init(thistype, keyname, thisclass, c2tmap,
+ etchvtor_string_get(0), new_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * runtime exception serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_rtxcp_export_value()
+ * virtual export value for runtime exception
+ * @param objval a, etchexception blob, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+objmask* etchserializer_rtxcp_export_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_exception_export_value(thisx, objval);
+}
+
+
+/**
+ * etchserializer_rtxcp_import_value()
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return an opaque etch object containing the imported exception.
+ *
+ * caller owns and must destroy the returned object.
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_rtxcp_import_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_ETCHRUNTIME);
+}
+
+
+/**
+ * new_runtime_exception_serializer()
+ * etch_serializer_rtxcp constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_runtime_exception_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_RTXCP;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_rtxcp_export_value;
+ newobj->import_value = etchserializer_rtxcp_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_rtxcp_init()
+ * static intitializer for runtime exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_rtxcp_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* keyname = str_msg; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_RUNTIME_EXCEPTION);
+
+ return etch_serializer_init(thistype, keyname, thisclass, c2tmap,
+ etchvtor_string_get(0), new_runtime_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * auth exception serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_authxcp_export_value()
+ * virtual export value for auth exception
+ * @param objval a, etchexception blob, caller owns it and presumably will
+ * destroy it upon return from this method.
+ * @return the exported disposable structvalue object. caller must cast it.
+ */
+objmask* etchserializer_authxcp_export_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_exception_export_value(thisx, objval);
+}
+
+
+/**
+ * etchserializer_authxcp_import_value()
+ * virtual import value for runtime exception.
+ * @param objval an etch_structvalue of type etch runtime exception.
+ * caller retains ownership of this object as with all imports.
+ * @return a nonspecific etch object containing the imported exception.
+ *
+ * caller owns and must destroy the returned object.
+ * use: etch_exception* x = get_exception(returnedobj);
+ * to point into and inspect the exception.
+ */
+objmask* etchserializer_authxcp_import_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_exception_import_value(thisx, objval, EXCPTYPE_ETCHAUTH);
+}
+
+
+/**
+ * new_auth_exception_serializer()
+ * etch_serializer_auth exception constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_auth_exception_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_AUTHXCP;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_authxcp_export_value;
+ newobj->import_value = etchserializer_authxcp_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_authxcp_init()
+ * static intitializer for auth exception serializer.
+ * creates the impexp serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (runtime exception)
+ */
+int etch_serializer_authxcp_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* keyname = str_msg; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_EXCEPTION, CLASSID_AUTH_EXCEPTION);
+
+ return etch_serializer_init(thistype, keyname, thisclass, c2tmap,
+ etchvtor_string_get(0), new_auth_exception_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * list serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_list_export_value()
+ * virtual export value for list
+ * @param objval an etch_arraylist containing values to export to tdo.
+ * caller retains ownership of this object; this method however sets the readonly
+ * mark on this object, such that it will not destroy its content, which was
+ * assigned to the arraylist wrapped in the returned struct.
+ * the c binding internally models a list type as an etch_arraylist.
+ * @return the exported structvalue object, containing an etch_arraylist.
+ * since we can't pass around raw arrays as does the java binding in this case,
+ * this serializer chooses to use an arraylist as the export object type for lists.
+ * while it may seem convoluted that the exported from and exported to objects are
+ * the same object type (not the same object however), the reason is the vf export
+ * interface contract, i.e. caller relinquishes memory for the export from object,
+ * and acquires memory for the export to objects.
+ */
+objmask* etchserializer_list_export_value(etch_serializer* thisx, objmask* objval)
+{
+ int result = 0;
+ const int THISINITSIZE = 2;
+ etch_arraylist* listobj = NULL;
+ etch_arraylist* listnew = NULL;
+ etch_structvalue* outstruct = NULL;
+ if (!is_etch_arraylist(objval)) return NULL;
+
+ /* copy caller's list's content to a new list */
+ listobj = (etch_arraylist*) objval;
+ listnew = new_synchronized_arraylist_from(listobj);
+ /* value factory export_custom_value() will destroy() the export from object;
+ * we mark that object such that its content will not be destroyed with it */
+ listobj->is_readonly = TRUE;
+
+ /* assign ownership of the new list to the returned struct */
+ outstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+ result = structvalue_put(outstruct, clone_field(thisx->field), (objmask*) listnew);
+
+ return (objmask*) outstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_list_import_value()
+ * virtual import value for etch list.
+ * @param objval an etch_structvalue of type etch list.
+ * caller retains ownership of this object as with all imports.
+ * @return a *disposable* etch_arraylist containing the imported data objects.
+ *
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a
+ * synchronized etch_arraylist to the structvalue.
+ */
+objmask* etchserializer_list_import_value(etch_serializer* thisx, objmask* objval)
+{
+ etch_arraylist *inarray = NULL, *outarray = NULL;
+ etch_structvalue* instruct = (etch_structvalue*) objval;
+ if (!is_etch_struct(instruct)) return NULL;
+ if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+ /* fetch the arrayvalue from the struct. struct owns it. */
+ inarray = (etch_arraylist*) structvalue_get(instruct, thisx->field);
+ if (!is_etch_arraylist(inarray)) return NULL;
+
+ /* copy content to return list */
+ outarray = new_synchronized_arraylist_from(inarray);
+
+ /* value factory import_custom_value() will destroy() the import struct
+ * which will call destructors on its content. we mark the import list
+ * object such that its content will not be destroyed with it, since
+ * we just copied that content to the return list */
+ set_etchobj_static_content(inarray);
+
+ return (objmask*) outarray; /* caller owns the returned list */
+}
+
+
+/**
+ * new_list_serializer()
+ * etch_serializer_list constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_list_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_LIST;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_list_export_value;
+ newobj->import_value = etchserializer_list_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_list_init()
+ * static intitializer for list serializer.
+ * creates the list impex serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (list)
+ */
+int etch_serializer_list_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* key_name = str_values; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_ETCHLIST, CLASSID_ETCH_LIST);
+
+ return etch_serializer_init(thistype, key_name, thisclass, c2tmap,
+ etchvtor_object_get(1), new_list_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * map serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_map_export_value()
+ * virtual export value for etch map
+ * @param objval an etch_hashtable containing values to export. caller owns it,
+ * and presumably will destroy it on return from this method. this method marks
+ * this object such that its destructor will not destroy its content objects,
+ * ownership of which is transferred here to the returned arraylist.
+ * @return the exported structvalue object in which the lone entry is an
+ * etch_arraylist containing the map keys and values as consecutive entries.
+ * caller owns this returned structvalue.
+ */
+objmask* etchserializer_map_export_value(etch_serializer* thisx, objmask* objval)
+{
+ int result = 0, mapsize = 0, listsize = 0, is_expected_maptype = 0;
+ etch_iterator iterator;
+ const int THISINITSIZE = 2;
+ const int is_this_a_set = (thisx->type->id == builtins._mt__etch_set->id);
+ etch_hashtable* impmap = NULL;
+ etch_arraylist* explist = NULL;
+ etch_structvalue* expstruct = NULL;
+ if (!is_etch_hashtable(objval)) return NULL;
+
+ impmap = (etch_hashtable*) objval;
+ mapsize = etchmap_count(impmap);
+ listsize = is_this_a_set? mapsize: mapsize * 2;
+
+ /* the underlying hashtable for an etch map must be explicitly marked
+ * as having object-key, object-value content, since the export list
+ * content is object-key, object-value, object-key, object value, etc. */
+ is_expected_maptype = is_this_a_set?
+ impmap->content_type == ETCHHASHTABLE_CONTENT_OBJECT_NONE:
+ impmap->content_type == ETCHHASHTABLE_CONTENT_OBJECT_OBJECT;
+ if (!is_expected_maptype) return NULL;
+
+ /* create native array for export, marked such that
+ * destructors will be called on list content */
+ explist = new_synchronized_arraylist(listsize, 0);
+ explist->class_id = CLASSID_ETCH_ARRAYLIST;
+ explist->content_type = ETCHARRAYLIST_CONTENT_OBJECT;
+ explist->is_readonly = FALSE;
+ explist->content_obj_type = impmap->content_obj_type;
+ explist->content_class_id = impmap->content_class_id;
+
+ set_iterator(&iterator, impmap, &impmap->iterable);
+
+ while(iterator.has_next(&iterator)) /* copy map data to array */
+ {
+ arraylist_add(explist, iterator.current_key);
+ if (is_this_a_set); /* a set has only keys */
+ else arraylist_add(explist, iterator.current_value);
+ iterator.next(&iterator);
+ }
+
+ /* mark caller's map such that it will not destroy its content,
+ * ownership of which we just transferred to the export array */
+ impmap->is_readonly_keys = impmap->is_readonly_values = TRUE;
+ impmap->freehook = etch_noop_clear_handler;
+
+ expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+ /* here we assign ownership of the new arraylist to the struct */
+ result = structvalue_put(expstruct, clone_field(thisx->field), (objmask*)explist);
+
+ return (objmask*) expstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_map_import_value()
+ * virtual import value for etch map.
+ * @param objval an etch_structvalue of type etch map, wrapping a
+ * single entry of etch_arrayvalue, wrapping an etch_arraylist in which
+ * consecutive entries represent a map key and a map value. this method
+ * will mark the arraylist such that it will not destroy its object content.
+ * caller retains ownership of this object as with all imports.
+ * @return a disposable etch_hashtable containing the imported data objects.
+ * caller must cast it and destroy it.
+ *
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a
+ * synchronized etch_arraylist wrapped by an etch_arrayvalue, to the structvalue.
+ */
+objmask* etchserializer_map_import_value(etch_serializer* thisx, objmask* objval)
+{
+ int i = 0, result = 0, listcount = 0, mapsize = 0;
+ etch_hashtable* expmap = NULL;
+ etch_arraylist* implist = NULL;
+ etch_structvalue* impstruct = NULL;
+ const int is_this_a_set = thisx->type->id == builtins._mt__etch_set->id;
+ if (!is_etch_struct(objval)) return NULL;
+
+ impstruct = (etch_structvalue*) objval;
+ if (!structvalue_is_type(impstruct, thisx->type)) return NULL;
+
+ /* get the synchronized arraylist out of the struct and mark the list
+ * such that it no longer owns its object content, ownership of which we
+ * are transferring to the exported map.
+ */
+ implist = (etch_arraylist*) structvalue_get(impstruct, thisx->field);
+ if (!is_etch_arraylist(implist)) return NULL;
+ set_etchobj_static_content(implist);
+ listcount = implist->count;
+
+ /* instantiate a map configured appropriately for the import data */
+ /* todo code a new_synchronized_map() constructor and use it here */
+ if (is_this_a_set)
+ expmap = new_etch_set(listcount);
+ else expmap = new_etch_map(listcount / 2);
+ expmap->content_obj_type = implist->content_obj_type;
+ expmap->content_class_id = implist->content_class_id;
+
+ while(i < (const int) listcount) /* copy data objects to the map */
+ {
+ objmask* key = arraylist_get(implist, i++);
+ if (NULL == key) continue;
+
+ if (is_this_a_set)
+ result = etchmap_set_add(expmap, key);
+ else result = etchmap_map_add(expmap, key, arraylist_get(implist, i++));
+
+ if (-1 == result)
+ etchlog(ETCHIMPX, ETCHLOG_ERROR, "map insert error on key %u", key);
+ }
+
+ return (objmask*) expmap;
+}
+
+
+/**
+ * new_map_serializer()
+ * etch_serializer_map constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_map_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_MAP;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_map_export_value;
+ newobj->import_value = etchserializer_map_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_map_init()
+ * static intitializer for map serializer.
+ * creates the map serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (map)
+ */
+int etch_serializer_map_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* keyname = str_keys_values; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_ETCHMAP, CLASSID_ETCH_MAP);
+
+ return etch_serializer_init(thistype, keyname, thisclass, c2tmap,
+ etchvtor_object_get(1), new_map_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * set serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_set_export_value()
+ * virtual export value for etch set
+ * @param objval an etch_hashtable containing values to export. caller owns it,
+ * and presumably will destroy it on return from this method. this method marks
+ * the map object such that it will not destroy its content objects.
+ * @return the exported structvalue object in which the lone entry is an
+ * etch_arrayvalue containing the map keys
+ * caller owns memory for the returned object.
+ */
+objmask* etchserializer_set_export_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_map_export_value(thisx, objval); /* caller owns */
+}
+
+
+/**
+ * etchserializer_set_import_value()
+ * virtual import value for etch set.
+ * @param objval an etch_structvalue of type etch set, wrapping a single entry
+ * of etch_arrayvalue, wrapping an etch_arraylist containing the set values.
+ * this method will mark the arraylist such that it will not destroy its content.
+ * caller retains ownership of this object as with all imports.
+ * @return a disposable etch_hashtable containing the imported data objects.
+ * caller must cast it and destroy it.
+ * note that the c binding works a bit differently that does the java here.
+ * java tdi populates the structvalue with an object[]. in c the tdi inserts a
+ * synchronized etch_arraylist wrapped by an etch_arrayvalue, to the structvalue.
+ */
+objmask* etchserializer_set_import_value(etch_serializer* thisx, objmask* objval)
+{
+ return etchserializer_map_import_value(thisx, objval);
+}
+
+
+/**
+ * new_set_serializer()
+ * etch_serializer_set constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_set_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_SET;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_set_export_value;
+ newobj->import_value = etchserializer_set_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_set_init()
+ * static intitializer for set serializer.
+ * creates the set serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (set)
+ */
+int etch_serializer_set_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* keyname = str_keys; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_HASHTABLE, CLASSID_ETCH_SET);
+
+ return etch_serializer_init(thistype, keyname, thisclass, c2tmap,
+ etchvtor_object_get(1), new_set_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * date serializer
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+/**
+ * etchserializer_date_export_value()
+ * virtual export value for date
+ * @param objval an etch_date object for export to tdo.
+ * caller retains ownership of this object.
+ * @return the exported structvalue object. caller owns it and must cast it.
+ */
+objmask* etchserializer_date_export_value(etch_serializer* thisx, objmask* objval)
+{
+ const int THISINITSIZE = 2;
+ etch_structvalue* expstruct = NULL;
+ if (!is_etch_date(objval)) return NULL;
+
+ expstruct = new_structvalue((etch_type*) thisx->type, THISINITSIZE);
+
+ /* assign ownership of the wrapped 64-bit integer to the struct */
+ structvalue_put(expstruct, clone_field(thisx->field),
+ (objmask*) new_int64(((etch_date*)objval)->value));
+
+ return (objmask*) expstruct; /* caller owns this structvalue */
+}
+
+
+/**
+ * etchserializer_date_import_value()
+ * virtual import value for etch date.
+ * @param objval an etch_structvalue of type etch date.
+ * caller retains ownership of this object as with all imports.
+ * @return a *disposable* etch_date object
+ */
+objmask* etchserializer_date_import_value(etch_serializer* thisx, objmask* objval)
+{
+ etch_date* outdate = NULL;
+ etch_int64* timeval = NULL;
+ etch_structvalue* instruct = NULL;
+ if (!is_etch_struct(objval)) return NULL;
+
+ instruct = (etch_structvalue*) objval;
+ if (!structvalue_is_type(instruct, thisx->type)) return NULL;
+
+ /* fetch the arrayvalue out of the struct. struct owns it */
+ timeval = (etch_int64*) structvalue_get(instruct, thisx->field);
+ if (!is_etch_int64(timeval)) return NULL;
+
+ outdate = new_date();
+ outdate->value = (time_t) timeval->value;
+
+ return (objmask*) outdate; /* caller owns this object */
+}
+
+
+/**
+ * new_date_serializer()
+ * etch_serializer_date constructor
+ * @param type - not owned
+ * @param field - not owned
+ */
+etch_serializer* new_date_serializer(etch_type* type, etch_field* field)
+{
+ etch_serializer* newobj = new_etch_serializer(ETCH_DEFSIZE);
+
+ newobj->class_id = CLASSID_SERIALIZER_DATE;
+ newobj->type = type; /* not owned */
+ newobj->field = field; /* not owned */
+
+ newobj->export_value = etchserializer_date_export_value;
+ newobj->import_value = etchserializer_date_import_value;
+
+ return newobj;
+}
+
+
+/**
+ * etch_serializer_date_init()
+ * static intitializer for date serializer.
+ * creates the date serializer and installs it to the supplied type.
+ * @param thistype type of the serializer (date)
+ */
+int etch_serializer_date_init(etch_type* thistype, etch_hashtable* c2tmap)
+{
+ const wchar_t* keyname = str_date_time; /* vf static constant */
+ const unsigned thisclass
+ = ETCHMAKECLASS(ETCHTYPEB_PRIMITIVE, CLASSID_DATE);
+
+ return etch_serializer_init(thistype, keyname, thisclass, c2tmap,
+ etchvtor_int64_get(0), new_date_serializer);
+}
+
+
+/* - - - - - - - - - - - - - - - - - -
+ * misc
+ * - - - - - - - - - - - - - - - - - -
+ */
+
+ objmask* etchserializer_defexportval(etch_serializer* s, objmask* x)
+{
+ return NULL;
+}
+
+objmask* etchserializer_defimportval (etch_serializer* s, objmask* x)
+{
+ return NULL;
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sessionint.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,222 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_sessionint.c
+ * session interface
+ */
+
+#include "etch_sessionint.h"
+#include "etch_defvalufact.h"
+#include "etch_message.h"
+#include "etch_global.h"
+#include "etchlog.h"
+
+int etchsession_def_session_control (void*, void*, void*);
+int etchsession_def_session_notify (void*, void*);
+void* etchsession_def_session_query (void*, void*);
+
+char* ETCHDSIF = "DSIF";
+
+
+/**
+ * new_default_sessson_interface
+ * return a session interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_session* new_default_session_interface(void* thisx)
+{
+ i_session* newi = etch_malloc(sizeof(i_session), ETCHTYPEB_RAWOBJECT);
+ newi->session_control = etchsession_def_session_control;
+ newi->session_notify = etchsession_def_session_notify;
+ newi->session_query = etchsession_def_session_query;
+ newi->thisx = thisx;
+ return newi;
+}
+
+
+/**
+ * new_session_interface
+ * return a session interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_session* new_session_interface(void* thisx,
+ etch_session_control sc, etch_session_notify sn, etch_session_query sq)
+{
+ i_session* newi = new_default_session_interface(thisx);
+ if (sc) newi->session_control = sc;
+ if (sn) newi->session_notify = sn;
+ if (sq) newi->session_query = sq;
+ return newi;
+}
+
+
+/**
+ * clone_session()
+ */
+i_session* clone_session(void* thisx, const i_session* thatsession)
+{
+ i_session* newsession = thatsession? new_default_session_interface(thisx): NULL;
+
+ if (newsession)
+ memcpy(newsession, thatsession, sizeof(i_session));
+
+ return newsession;
+}
+
+
+/**
+ * new_default_objsessson_interface
+ * return an objsession interface populated with defaults for virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_objsession* new_default_objsession_interface (void* thisx)
+{
+ i_objsession* newi = etch_malloc(sizeof(i_objsession), ETCHTYPEB_RAWOBJECT);
+ newi->_session_control = etchsession_def_session_control;
+ newi->_session_notify = etchsession_def_session_notify;
+ newi->_session_query = etchsession_def_session_query;
+ newi->thisx = thisx;
+ return newi;
+}
+
+
+/**
+ * new_objsession_interface
+ * return an objsession interface populated with specified virtuals.
+ * caller owns returned object, not an etch object, use etch_free() to destroy.
+ */
+i_objsession* new_objsession_interface (void* thisx,
+ etch_session_control sc, etch_session_notify sn, etch_session_query sq)
+{
+ return (i_objsession*) new_session_interface(thisx, sc, sn, sq);
+}
+
+
+/**
+ * etchsession_get_objinfo()
+ * extract object info from the object passed to session methods.
+ */
+void etchsession_get_objinfo (etch_objsession_objinfo* p, void* evt)
+{
+ memset(p, 0, sizeof(etch_objsession_objinfo));
+ if (NULL == evt) return;
+ p->obj = (objmask*) evt;
+ p->obj_type = ((objmask*) evt)->obj_type;
+ p->class_id = ((objmask*) evt)->class_id;
+
+ if (is_etch_unwantedmsg (p->obj))
+ { p->msg = (objmask*) ((etch_unwanted_message*) p->obj)->message;
+ p->whofrom = ((etch_unwanted_message*) p->obj)->whofrom;
+ }
+ else
+ if (is_etch_message (p->obj))
+ p->msg = p->obj;
+
+ if (is_etch_message (p->msg))
+ {
+ p->is_message = TRUE;
+ p->msg_aname = message_aname ((etch_message*) p->msg);
+
+ if (is_exception(p->msg))
+ { p->is_exception = TRUE;
+ p->exception = get_exception_from ((objmask*) p->msg);
+ }
+ else
+ { p->resobj = message_get ((etch_message*) p->msg, builtins._mf_result);
+ if (is_exception(p->resobj))
+ { p->is_exception = TRUE;
+ p->exception = get_exception_from ((objmask*) p->resobj);
+ }
+ }
+ }
+}
+
+
+/**
+ * etchsession_destroy_objparam()
+ * identify, log and destroy the specified session parameter object.
+ */
+void etchsession_destroy_objparam (void* evt, char* caller)
+{
+ char *msgmask = 0, *descrip = 0, *SESSION_ = "session_";
+ etch_objsession_objinfo objinfo;
+ if (NULL == evt) return;
+
+ etchsession_get_objinfo (&objinfo, evt);
+
+ if (objinfo.is_message)
+ {
+ if (objinfo.is_exception)
+ { msgmask = "%s%s disposing '%s'\n";
+ descrip = objinfo.exception? ((etchexception*) objinfo.exception)->ansitext: 0;
+ }
+ else
+ { msgmask = "%s%s disposing message '%s'\n";
+ descrip = objinfo.msg_aname;
+ }
+
+ if (!descrip) descrip = "?";
+ etchlog(ETCHDSIF, ETCHLOG_DEBUG, msgmask, SESSION_, caller, descrip);
+ }
+ else
+ { msgmask = "%s%s disposing type %x class %x\n";
+ etchlog(ETCHDSIF, ETCHLOG_XDEBUG, msgmask, SESSION_, caller,
+ objinfo.obj_type, objinfo.class_id);
+ }
+
+ ETCHOBJ_DESTROY(objinfo.obj);
+}
+
+
+/**
+ * etchsession_def_session_control()
+ * @param obj caller this.
+ * @param evt some etch object or null.
+ * @param v some etch object or null.
+ */
+int etchsession_def_session_control (void* obj, void* evt, void* v)
+{
+ etchsession_destroy_objparam (evt, "control");
+ ETCHOBJ_DESTROY(((objmask*)v));
+ return 0;
+}
+
+
+/**
+ * etchsession_def_session_notify()
+ * @param obj caller this.
+ * @param evt some etch object or null.
+ */
+int etchsession_def_session_notify (void* obj, void* evt)
+{
+ etchsession_destroy_objparam (evt, "notify");
+ return 0;
+}
+
+
+/**
+ * etchsession_def_session_query()
+ * @param obj caller this.
+ * @param query some etch object or null.
+ */
+void* etchsession_def_session_query (void* obj, void* query)
+{
+ etchsession_destroy_objparam (obj, "query");
+ return NULL;
+}
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_simpletimer.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,165 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_simpletimer.c
+ * thread-per-use one-shot relative timer
+ * this should be replaced with a timer pool implementation when development resources permit
+ */
+
+#include "apr_network_io.h"
+#include "etch_simpletimer.h"
+#include "etchmutex.h"
+#include "etch_global.h"
+#include "etchexcp.h"
+#include "etchlog.h"
+
+typedef struct etch_timerdata
+{
+ void* userdata;
+ int durationms;
+ int is_started;
+ etch_timer_callback usercallback;
+
+} etch_timerdata;
+
+void etch_timerproc(void* data);
+etch_timerdata* new_timerdata(const int, void*, etch_timer_callback);
+
+
+
+/**
+ * new_timer()
+ * etch_timer constructor
+ * @param durationms timer duration in milliseconds.
+ * @param passthrudata user data to be returned in expiration callback.
+ * caller retains ownership of this memory.
+ * @param callback expiration callback void (*callback) (void*, int);
+ * in which creator's passthrudata is passed as the first parameter, and the timeout
+ * reason passed in parameter 2 (reason value 0 is signaled, 1 is timeout, -1 error).
+ * @return the timer object. caller owns this object but must not destroy it until
+ * after the expiration callback has completed and returned.
+ */
+etch_timer* new_timer(const int durationms, void* passthrudata, etch_timer_callback callback)
+{
+ etch_thread* timer_thread = NULL;
+ etch_timerdata* timerdata = NULL;
+ if (NULL == callback || durationms <= 0) return NULL;
+ timerdata = new_timerdata(durationms, passthrudata, callback);
+
+ /* create thread in wait state */
+ if (NULL == (timer_thread = new_thread(etch_timerproc, timerdata)))
+ etch_free(timerdata);
+ else /* timerdata wrapper freed in etch_timerproc */
+ { timer_thread->params.is_own_data = FALSE;
+ /* semikludge to complete thread start and thus avoid crash in the
+ * event timer is destroyed without having been started.
+ * surely there is a cleaner way to do this. */
+ etch_sleep(1);
+ }
+
+ return timer_thread;
+}
+
+
+/**
+ * etch_timer_start()
+ * start the specified timer. a timer must always be explicitly started.
+ */
+int etch_timer_start(etch_timer* timer_thread)
+{
+ int result = -1;
+ etch_threadparams* params = timer_thread? &timer_thread->params: NULL;
+ etch_timerdata* timerdata = params? (etch_timerdata*) params->data: NULL;
+
+ if (timerdata)
+ if (0 == (result = timer_thread->start(timer_thread)))
+ timerdata->is_started = TRUE;
+
+ return result;
+}
+
+
+/**
+ * etch_timer_stop()
+ * signal specified timer to stop waiting and exit its thread.
+ */
+int etch_timer_stop(etch_timer* timer_thread)
+{
+ int result = -1;
+ etchwait* waiter;
+ if (NULL == timer_thread) return -1;
+ waiter = timer_thread->params.waitobj;
+
+ if (waiter && timer_thread->params.threadstate == ETCH_THREADSTATE_STARTED)
+ result = waiter->signal(waiter);
+
+ return result;
+}
+
+
+/* - - - - - - -
+ * private
+ * - - - - - - -
+ */
+
+/**
+ * new_timerdata()
+ * create timer thread data
+ */
+struct etch_timerdata* new_timerdata(const int durationms, void* passthrudata,
+ etch_timer_callback callback)
+{
+ etch_timerdata* timerdata = etch_malloc(sizeof(etch_timerdata), 0);
+ timerdata->userdata = passthrudata;
+ timerdata->durationms = durationms;
+ timerdata->usercallback = callback;
+ timerdata->is_started = FALSE;
+ return timerdata;
+}
+
+
+/**
+ * etch_timerproc()
+ * timer thread procedure
+ */
+void etch_timerproc(void* data)
+{
+ etch_threadparams* params = (etch_threadparams*) data;
+ etch_timerdata* timerdata = (etch_timerdata*) params->data;
+ etch_timer_callback usercallback = timerdata->usercallback;
+ etch_thread* threadx = params->etchobj;
+ const int durationms = timerdata->durationms;
+ void* userdata = timerdata->userdata;
+ int result = 0;
+ ETCH_ASSERT(usercallback);
+
+ if (NULL == threadx->params.waitobj)
+ threadx->params.waitobj = new_wait(params->libdata->mempool);
+
+ /* start timer and wait for expiration or signal */
+ result = threadx->params.waitobj->timed_wait
+ (threadx->params.waitobj, durationms); // BUG FIX was * 1000
+
+ ETCHOBJ_FREE(params->data); /* etch_timerdata wrapper */
+ ETCHOBJ_DESTROY(threadx->params.waitobj);
+
+ /* pass ownership of userdata back to user */
+ usercallback(userdata, result);
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_sourceint.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,96 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_sourceint.c
+ * source interface
+ */
+
+#include "etch_sourceint.h"
+#include "etch_global.h"
+void* etch_source_def_get_handler (void* thisx);
+void etch_source_def_set_handler (void* thisx, void* handler);
+int destroy_i_source(i_source*);
+
+
+/**
+ * new_default_source_interface
+ * return a source interface populated with defaults for virtuals.
+ * this interface *is* an etch object, use destroy()
+ */
+i_source* new_default_source_interface()
+{
+ i_source* newi = (i_source*) new_object(sizeof(i_source),
+ ETCHTYPEB_SOURCE, CLASSID_SOURCE);
+
+ newi->destroy = destroy_i_source;
+ newi->get_handler = etch_source_def_get_handler;
+ newi->set_handler = etch_source_def_set_handler;
+ newi->itransport = new_default_transport_interface();
+ return newi;
+}
+
+
+/**
+ * new_source_interface
+ * return a source interface populated with specified virtuals.
+ * this interface object *is* an etch object, use destroy()
+ */
+i_source* new_source_interface(void* thisx,
+ etch_source_get_handler gh, etch_source_set_handler sh, i_transport* xp)
+{
+ i_source* newi = (i_source*) new_object(sizeof(i_source),
+ ETCHTYPEB_SOURCE, CLASSID_SOURCE);
+
+ newi->destroy = destroy_i_source;
+ newi->get_handler = gh? gh: etch_source_def_get_handler;
+ newi->set_handler = sh? sh: etch_source_def_set_handler;
+ newi->itransport = xp? xp: new_default_transport_interface();
+ newi->thisx = thisx;
+ return newi;
+}
+
+
+/**
+ * destroy_i_source
+ * i_source destructor
+ */
+int destroy_i_source(i_source* thisx)
+{
+ if (NULL == thisx) return -1;
+ if (thisx->refcount > 0 && --thisx->refcount > 0) return -1;
+
+ if (!is_etchobj_static_content(thisx))
+ { etch_free(thisx->itransport);
+ }
+
+ return destroy_objectex((objmask*)thisx);
+}
+
+
+void* etch_source_def_get_handler (void* thisx)
+{
+ return NULL;
+}
+
+
+void etch_source_def_set_handler (void* thisx, void* handler)
+{
+
+}
+
Added: incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c
URL: http://svn.apache.org/viewvc/incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c?rev=767594&view=auto
==============================================================================
--- incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c (added)
+++ incubator/etch/trunk/binding-c/runtime/c/src/support/etch_stop.c Wed Apr 22 17:25:43 2009
@@ -0,0 +1,101 @@
+/* $Id$
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version
+ * 2.0 (the "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+ * etch_stop.c
+ */
+
+#include <stdio.h>
+#include <conio.h>
+#include <apr_general.h>
+#include <apr_network_io.h>
+#include <apr_strings.h>
+#define ETCHSTOP_SOCK_TIMEOUT (APR_USEC_PER_SEC * 5)
+int waitforkey(const int, const int);
+
+
+/**
+ * main
+ */
+int main(int argc, char * argv[])
+{
+ apr_sockaddr_t *sa = 0;
+ apr_socket_t *s = 0;
+ apr_pool_t *mp = 0;
+ int arc = 0, result = -1;
+ const char* DATALENGTHONE = "$"; /* server used to assume that payload length 1 means shutdown */
+ const char* OTHERDATA = "$BOGUSDATA";
+ const char* ETCH_SHUTDOWNSIGNAL = "$ETCHQUIT"; /* server now recognizes this string defined in etchdefs.h */
+ const int IS_WAITKEY = TRUE;
+
+ const char* SERVERIP = "127.0.0.1";
+ const int SERVERPORT = 4004;
+
+ char* serverdata = (char*) ETCH_SHUTDOWNSIGNAL; /* the string for this compile */
+ apr_size_t datalen = strlen(serverdata);
+
+ do
+ { if (0 != (arc = apr_initialize())) break;
+ if (0 != (arc = apr_pool_create(&mp, NULL))) break;
+
+ if (0 != (arc = apr_sockaddr_info_get(&sa, SERVERIP, APR_INET, SERVERPORT, 0, mp)))
+ { printf("STOP socket info request failed\n");
+ break;
+ }
+
+ if (0 != (arc = apr_socket_create(&s, sa->family, SOCK_STREAM, APR_PROTO_TCP, mp)))
+ { printf("STOP socket create request failed\n");
+ break;
+ }
+
+ apr_socket_opt_set(s, APR_SO_NONBLOCK, FALSE);
+ apr_socket_timeout_set(s, ETCHSTOP_SOCK_TIMEOUT);
+
+ if (0 != (arc = apr_socket_connect(s, sa)))
+ { printf("STOP could not connect to %s:%d\n", SERVERIP, SERVERPORT);
+ break;
+ }
+
+ printf("STOP connected to %s:%d\n", SERVERIP, SERVERPORT);
+
+ if (0 != (arc = apr_socket_send(s, serverdata, &datalen)))
+ { printf("STOP could not transmit to server\n");
+ break;
+ }
+
+ printf("STOP sent %d-byte request %s to server\n", datalen, serverdata);
+ result = 0;
+
+ } while(0);
+
+ if (s) apr_socket_close(s);
+ apr_terminate();
+
+ return waitforkey(IS_WAITKEY, result);
+}
+
+
+int waitforkey(const int is_waitkey_enabled, const int result)
+{
+ if (is_waitkey_enabled)
+ { printf("any key ...");
+ while(!_getch());
+ printf("\n");
+ }
+ return result;
+}
\ No newline at end of file