Author: abroekhuis
Date: Wed Aug  8 13:39:26 2012
New Revision: 1370759

URL: http://svn.apache.org/viewvc?rev=1370759&view=rev
Log:
Added bundle listener

Added:
    incubator/celix/trunk/framework/public/include/bundle_event.h
    incubator/celix/trunk/framework/public/include/bundle_listener.h
Modified:
    incubator/celix/trunk/framework/private/src/bundle_context.c
    incubator/celix/trunk/framework/private/src/framework.c
    incubator/celix/trunk/framework/public/include/bundle_context.h
    incubator/celix/trunk/framework/public/include/framework.h

Modified: incubator/celix/trunk/framework/private/src/bundle_context.c
URL: 
http://svn.apache.org/viewvc/incubator/celix/trunk/framework/private/src/bundle_context.c?rev=1370759&r1=1370758&r2=1370759&view=diff
==============================================================================
--- incubator/celix/trunk/framework/private/src/bundle_context.c (original)
+++ incubator/celix/trunk/framework/private/src/bundle_context.c Wed Aug  8 
13:39:26 2012
@@ -278,6 +278,30 @@ celix_status_t bundleContext_removeServi
     return status;
 }
 
+celix_status_t bundleContext_addBundleListener(BUNDLE_CONTEXT context, 
bundle_listener_t listener) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    if (context != NULL && listener != NULL) {
+        fw_addBundleListener(context->framework, context->bundle, listener);
+    } else {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+
+    return status;
+}
+
+celix_status_t bundleContext_removeBundleListener(BUNDLE_CONTEXT context, 
bundle_listener_t listener) {
+    celix_status_t status = CELIX_SUCCESS;
+
+    if (context != NULL && listener != NULL) {
+        fw_removeBundleListener(context->framework, context->bundle, listener);
+    } else {
+        status = CELIX_ILLEGAL_ARGUMENT;
+    }
+
+    return status;
+}
+
 celix_status_t bundleContext_getProperty(BUNDLE_CONTEXT context, const char 
*name, char **value) {
        celix_status_t status = CELIX_SUCCESS;
 

Modified: incubator/celix/trunk/framework/private/src/framework.c
URL: 
http://svn.apache.org/viewvc/incubator/celix/trunk/framework/private/src/framework.c?rev=1370759&r1=1370758&r2=1370759&view=diff
==============================================================================
--- incubator/celix/trunk/framework/private/src/framework.c (original)
+++ incubator/celix/trunk/framework/private/src/framework.c Wed Aug  8 13:39:26 
2012
@@ -65,6 +65,7 @@ struct framework {
        HASH_MAP installedBundleMap;
        HASH_MAP installRequestMap;
        ARRAY_LIST serviceListeners;
+       ARRAY_LIST bundleListeners;
 
        long nextBundleId;
        struct serviceRegistry * registry;
@@ -87,6 +88,11 @@ struct framework {
        apr_pool_t *mp;
 
        PROPERTIES configurationMap;
+
+       ARRAY_LIST requests;
+       apr_thread_cond_t *dispatcher;
+       apr_thread_mutex_t *dispatcherLock;
+       apr_thread_t *dispatcherThread;
 };
 
 struct activator {
@@ -117,6 +123,10 @@ celix_status_t fw_refreshBundle(FRAMEWOR
 
 celix_status_t fw_populateDependentGraph(FRAMEWORK framework, BUNDLE exporter, 
HASH_MAP *map);
 
+celix_status_t fw_fireBundleEvent(FRAMEWORK framework, bundle_event_type_e, 
BUNDLE bundle);
+static void *APR_THREAD_FUNC fw_eventDispatcher(apr_thread_t *thd, void *fw);
+celix_status_t fw_invokeBundleListener(FRAMEWORK framework, bundle_listener_t 
listener, bundle_event_t event, BUNDLE bundle);
+
 struct fw_refreshHelper {
     FRAMEWORK framework;
     BUNDLE bundle;
@@ -135,6 +145,33 @@ struct fw_serviceListener {
 
 typedef struct fw_serviceListener * FW_SERVICE_LISTENER;
 
+struct fw_bundleListener {
+       apr_pool_t *pool;
+       BUNDLE bundle;
+       bundle_listener_t listener;
+};
+
+typedef struct fw_bundleListener * fw_bundle_listener_t;
+
+enum event_type {
+       FRAMEWORK_EVENT_TYPE,
+       BUNDLE_EVENT_TYPE,
+       EVENT_TYPE_SERVICE,
+};
+
+typedef enum event_type event_type_e;
+
+struct request {
+       event_type_e type;
+       ARRAY_LIST listeners;
+
+       int eventType;
+       BUNDLE bundle;
+
+       char *filter;
+};
+
+typedef struct request *request_t;
 
 celix_status_t framework_create(FRAMEWORK *framework, apr_pool_t *memoryPool, 
PROPERTIES config) {
     celix_status_t status = CELIX_SUCCESS;
@@ -173,27 +210,39 @@ celix_status_t framework_create(FRAMEWOR
                                 if (apr_status != APR_SUCCESS) {
                                     status = CELIX_FRAMEWORK_EXCEPTION;
                                 } else {
-                                    (*framework)->bundle = bundle;
-
-                                    (*framework)->installedBundleMap = NULL;
-                                    (*framework)->registry = NULL;
-
-                                    (*framework)->interrupted = false;
-                                    (*framework)->shutdown = false;
-
-                                    (*framework)->globalLockWaitersList = NULL;
-                                    arrayList_create((*framework)->mp, 
&(*framework)->globalLockWaitersList);
-                                    (*framework)->globalLockCount = 0;
-                                    (*framework)->globalLockThread = 0;
-                                    (*framework)->nextBundleId = 1l;
-                                    (*framework)->cache = NULL;
-
-                                    (*framework)->installRequestMap = 
hashMap_create(string_hash, string_hash, string_equals, string_equals);
-                                    (*framework)->serviceListeners = NULL;
-                                    (*framework)->shutdownGate = NULL;
-                                    (*framework)->configurationMap = config;
-
-                                    status = 
bundle_setFramework((*framework)->bundle, (*framework));
+                                       apr_status_t apr_status = 
apr_thread_mutex_create(&(*framework)->dispatcherLock, 
APR_THREAD_MUTEX_UNNESTED, (*framework)->mp);
+                                       if (apr_status != CELIX_SUCCESS) {
+                                                                               
status = CELIX_FRAMEWORK_EXCEPTION;
+                                                                       } else {
+                                                                               
apr_status_t apr_status = apr_thread_cond_create(&(*framework)->dispatcher, 
(*framework)->mp);
+                                                                               
if (apr_status != APR_SUCCESS) {
+                                                                               
        status = CELIX_FRAMEWORK_EXCEPTION;
+                                                                               
} else {
+                                                                               
        (*framework)->bundle = bundle;
+
+                                                                               
        (*framework)->installedBundleMap = NULL;
+                                                                               
        (*framework)->registry = NULL;
+
+                                                                               
        (*framework)->interrupted = false;
+                                                                               
        (*framework)->shutdown = false;
+
+                                                                               
        (*framework)->globalLockWaitersList = NULL;
+                                                                               
        arrayList_create((*framework)->mp, 
&(*framework)->globalLockWaitersList);
+                                                                               
        (*framework)->globalLockCount = 0;
+                                                                               
        (*framework)->globalLockThread = 0;
+                                                                               
        (*framework)->nextBundleId = 1l;
+                                                                               
        (*framework)->cache = NULL;
+
+                                                                               
        (*framework)->installRequestMap = hashMap_create(string_hash, 
string_hash, string_equals, string_equals);
+                                                                               
        (*framework)->serviceListeners = NULL;
+                                                                               
        (*framework)->bundleListeners = NULL;
+                                                                               
        (*framework)->requests = NULL;
+                                                                               
        (*framework)->shutdownGate = NULL;
+                                                                               
        (*framework)->configurationMap = config;
+
+                                                                               
        status = bundle_setFramework((*framework)->bundle, (*framework));
+                                                                               
}
+                                                                       }
                                 }
                             }
                         }
@@ -244,6 +293,8 @@ celix_status_t framework_destroy(FRAMEWO
 
        arrayList_destroy(framework->globalLockWaitersList);
        arrayList_destroy(framework->serviceListeners);
+       arrayList_destroy(framework->bundleListeners);
+       arrayList_destroy(framework->requests);
 
        hashMap_destroy(framework->installedBundleMap, false, false);
 
@@ -266,6 +317,12 @@ celix_status_t fw_init(FRAMEWORK framewo
                return status;
        }
 
+       framework->requests = NULL;
+       arrayList_create(framework->mp, &framework->requests);
+       if (apr_thread_create(&framework->dispatcherThread, NULL, 
fw_eventDispatcher, framework, framework->mp) != APR_SUCCESS) {
+               return CELIX_FRAMEWORK_EXCEPTION;
+       }
+
        bundle_getState(framework->bundle, &state);
        if ((state == BUNDLE_INSTALLED) || (state == BUNDLE_RESOLVED)) {
            PROPERTIES props = properties_create();
@@ -391,6 +448,11 @@ celix_status_t fw_init(FRAMEWORK framewo
 
             framework->serviceListeners = NULL;
             arrayList_create(framework->mp, &framework->serviceListeners);
+            framework->bundleListeners = NULL;
+            arrayList_create(framework->mp, &framework->bundleListeners);
+            framework->requests = NULL;
+            arrayList_create(framework->mp, &framework->requests);
+
             framework_releaseBundleLock(framework, framework->bundle);
 
             status = CELIX_SUCCESS;
@@ -422,6 +484,7 @@ celix_status_t framework_start(FRAMEWORK
        }
 
        framework_releaseBundleLock(framework, framework->bundle);
+
        return CELIX_SUCCESS;
 }
 
@@ -690,6 +753,8 @@ celix_status_t fw_startBundle(FRAMEWORK 
                 }
 
                 framework_setBundleStateAndNotify(framework, bundle, 
BUNDLE_ACTIVE);
+
+                fw_fireBundleEvent(framework, BUNDLE_EVENT_STARTED, bundle);
                        }
 
                        break;
@@ -874,14 +939,14 @@ celix_status_t fw_uninstallBundle(FRAMEW
             }
 
             framework_setBundleStateAndNotify(framework, bundle, 
BUNDLE_INSTALLED);
-            // TODO: fw_fireBundleEvent(framework BUNDLE_EVENT_UNRESOLVED, 
bundle);
+            fw_fireBundleEvent(framework, BUNDLE_EVENT_UNRESOLVED, bundle);
 
             framework_setBundleStateAndNotify(framework, bundle, 
BUNDLE_UNINSTALLED);
             status = bundleArchive_setLastModified(archive, time(NULL));
         }
         framework_releaseBundleLock(framework, bundle);
 
-        // TODO: fw_fireBundleEvent(framework BUNDLE_EVENT_UNINSTALLED, 
bundle);
+        fw_fireBundleEvent(framework, BUNDLE_EVENT_UNINSTALLED, bundle);
 
         locked = framework_acquireGlobalLock(framework);
         if (locked) {
@@ -1320,6 +1385,44 @@ void fw_removeServiceListener(FRAMEWORK 
        }
 }
 
+celix_status_t fw_addBundleListener(FRAMEWORK framework, BUNDLE bundle, 
bundle_listener_t listener) {
+       celix_status_t status = CELIX_SUCCESS;
+
+       apr_pool_t *pool = NULL;
+       fw_bundle_listener_t bundleListener = NULL;
+
+       apr_pool_create(&pool, framework->mp);
+       bundleListener = apr_palloc(pool, sizeof(*bundleListener));
+       if (!bundleListener) {
+               status = CELIX_ENOMEM;
+       } else {
+               bundleListener->listener = listener;
+               bundleListener->bundle = bundle;
+               bundleListener->pool = pool;
+
+               arrayList_add(framework->bundleListeners, bundleListener);
+       }
+
+       return status;
+}
+
+celix_status_t fw_removeBundleListener(FRAMEWORK framework, BUNDLE bundle, 
bundle_listener_t listener) {
+       celix_status_t status = CELIX_SUCCESS;
+
+       int i;
+       fw_bundle_listener_t bundleListener;
+
+       for (i = 0; i < arrayList_size(framework->bundleListeners); i++) {
+               bundleListener = (fw_bundle_listener_t) 
arrayList_get(framework->bundleListeners, i);
+               if (bundleListener->listener == listener && 
bundleListener->bundle == bundle) {
+                       arrayList_remove(framework->bundleListeners, i);
+                       apr_pool_destroy(bundleListener->pool);
+               }
+       }
+
+       return status;
+}
+
 void fw_serviceChanged(FRAMEWORK framework, SERVICE_EVENT_TYPE eventType, 
SERVICE_REGISTRATION registration, PROPERTIES oldprops) {
        unsigned int i;
        FW_SERVICE_LISTENER element;
@@ -1782,6 +1885,105 @@ celix_status_t framework_getFrameworkBun
        return status;
 }
 
+celix_status_t fw_fireBundleEvent(FRAMEWORK framework, bundle_event_type_e 
eventType, BUNDLE bundle) {
+       celix_status_t status = CELIX_SUCCESS;
+
+       if ((eventType != BUNDLE_EVENT_STARTING)
+                       && (eventType != BUNDLE_EVENT_STOPPING)
+                       && (eventType != BUNDLE_EVENT_LAZY_ACTIVATION)) {
+               request_t request = malloc(sizeof(*request));
+               if (!request) {
+                       status = CELIX_ENOMEM;
+               } else {
+                       request->bundle = bundle;
+                       request->eventType = eventType;
+                       request->filter = NULL;
+                       request->listeners = framework->bundleListeners;
+                       request->type = BUNDLE_EVENT_TYPE;
+
+                       arrayList_add(framework->requests, request);
+                       if (apr_thread_mutex_lock(framework->dispatcherLock != 
APR_SUCCESS)) {
+                               status = CELIX_FRAMEWORK_EXCEPTION;
+                       } else {
+                               if 
(apr_thread_cond_broadcast(framework->dispatcher)) {
+                                       status = CELIX_FRAMEWORK_EXCEPTION;
+                               } else {
+                                       if 
(apr_thread_mutex_unlock(framework->dispatcherLock)) {
+                                               status = 
CELIX_FRAMEWORK_EXCEPTION;
+                                       }
+                               }
+                       }
+               }
+       }
+
+       return status;
+}
+
+static void *APR_THREAD_FUNC fw_eventDispatcher(apr_thread_t *thd, void *fw) {
+       FRAMEWORK framework = (FRAMEWORK) fw;
+       request_t request = NULL;
+
+       while (true) {
+               if (apr_thread_mutex_lock(framework->dispatcherLock) != 0) {
+                       celix_log("Error locking the dispatcher");
+                       return NULL;
+               }
+
+               int size = arrayList_size(framework->requests);
+               while (size == 0 && !framework->shutdown) {
+                       apr_status_t apr_status = 
apr_thread_cond_wait(framework->dispatcher, framework->dispatcherLock);
+                       // Ignore status and just keep waiting
+                       size = arrayList_size(framework->requests);
+               }
+
+               if (size == 0 && framework->shutdown) {
+                       apr_thread_exit(thd, APR_SUCCESS);
+                       return NULL;
+               }
+
+               request = arrayList_remove(framework->requests, 0);
+
+               apr_status_t status;
+               if ((status = 
apr_thread_mutex_unlock(framework->dispatcherLock)) != 0) {
+                       celix_log("Error unlocking the dispatcher.");
+                       apr_thread_exit(thd, status);
+                       return NULL;
+               }
+
+               if (request != NULL) {
+                       int i;
+                       int size = arrayList_size(request->listeners);
+                       for (i = 0; i < size; i++) {
+                               if (request->type == BUNDLE_EVENT_TYPE) {
+                                       fw_bundle_listener_t listener = 
arrayList_get(request->listeners, i);
+                                       bundle_event_t event = 
apr_palloc(listener->listener->pool, sizeof(*event));
+                                       event->bundle = request->bundle;
+                                       event->type = request->type;
+
+                                       fw_invokeBundleListener(framework, 
listener->listener, event, listener->bundle);
+                               }
+                       }
+               }
+       }
+
+       apr_thread_exit(thd, APR_SUCCESS);
+
+       return NULL;
+
+}
+
+celix_status_t fw_invokeBundleListener(FRAMEWORK framework, bundle_listener_t 
listener, bundle_event_t event, BUNDLE bundle) {
+       // We only support async bundle listeners for now
+       BUNDLE_STATE state;
+       bundle_getState(bundle, &state);
+       if (state == BUNDLE_STARTING || state == BUNDLE_ACTIVE) {
+
+               listener->bundleChanged(listener, event);
+       }
+
+       return CELIX_SUCCESS;
+}
+
 celix_status_t bundleActivator_start(void * userData, BUNDLE_CONTEXT context) {
        // nothing to do
        return CELIX_SUCCESS;

Modified: incubator/celix/trunk/framework/public/include/bundle_context.h
URL: 
http://svn.apache.org/viewvc/incubator/celix/trunk/framework/public/include/bundle_context.h?rev=1370759&r1=1370758&r2=1370759&view=diff
==============================================================================
--- incubator/celix/trunk/framework/public/include/bundle_context.h (original)
+++ incubator/celix/trunk/framework/public/include/bundle_context.h Wed Aug  8 
13:39:26 2012
@@ -35,6 +35,7 @@ typedef struct bundleContext *BUNDLE_CON
 
 #include "service_factory.h"
 #include "service_listener.h"
+#include "bundle_listener.h"
 #include "properties.h"
 #include "array_list.h"
 
@@ -65,6 +66,9 @@ celix_status_t bundleContext_getBundleBy
 celix_status_t bundleContext_addServiceListener(BUNDLE_CONTEXT context, 
SERVICE_LISTENER listener, char * filter);
 celix_status_t bundleContext_removeServiceListener(BUNDLE_CONTEXT context, 
SERVICE_LISTENER listener);
 
+celix_status_t bundleContext_addBundleListener(BUNDLE_CONTEXT context, 
bundle_listener_t listener);
+celix_status_t bundleContext_removeBundleListener(BUNDLE_CONTEXT context, 
bundle_listener_t listener);
+
 celix_status_t bundleContext_getProperty(BUNDLE_CONTEXT context, const char 
*name, char **value);
 
 #endif /* BUNDLE_CONTEXT_H_ */

Added: incubator/celix/trunk/framework/public/include/bundle_event.h
URL: 
http://svn.apache.org/viewvc/incubator/celix/trunk/framework/public/include/bundle_event.h?rev=1370759&view=auto
==============================================================================
--- incubator/celix/trunk/framework/public/include/bundle_event.h (added)
+++ incubator/celix/trunk/framework/public/include/bundle_event.h Wed Aug  8 
13:39:26 2012
@@ -0,0 +1,35 @@
+/*
+ * bundle_event.h
+ *
+ *  Created on: Jun 28, 2012
+ *      Author: alexander
+ */
+
+#ifndef BUNDLE_EVENT_H_
+#define BUNDLE_EVENT_H_
+
+typedef enum bundle_event_type bundle_event_type_e;
+typedef struct bundle_event *bundle_event_t;
+
+#include "service_reference.h"
+
+enum bundle_event_type
+{
+       BUNDLE_EVENT_INSTALLED = 0x00000001,
+       BUNDLE_EVENT_STARTED = 0x00000002,
+       BUNDLE_EVENT_STOPPED = 0x00000004,
+       BUNDLE_EVENT_UPDATED = 0x00000008,
+       BUNDLE_EVENT_UNINSTALLED = 0x00000010,
+       BUNDLE_EVENT_RESOLVED = 0x00000020,
+       BUNDLE_EVENT_UNRESOLVED = 0x00000040,
+       BUNDLE_EVENT_STARTING = 0x00000080,
+       BUNDLE_EVENT_STOPPING = 0x00000100,
+       BUNDLE_EVENT_LAZY_ACTIVATION = 0x00000200,
+};
+
+struct bundle_event {
+       BUNDLE bundle;
+       bundle_event_type_e type;
+};
+
+#endif /* BUNDLE_EVENT_H_ */

Added: incubator/celix/trunk/framework/public/include/bundle_listener.h
URL: 
http://svn.apache.org/viewvc/incubator/celix/trunk/framework/public/include/bundle_listener.h?rev=1370759&view=auto
==============================================================================
--- incubator/celix/trunk/framework/public/include/bundle_listener.h (added)
+++ incubator/celix/trunk/framework/public/include/bundle_listener.h Wed Aug  8 
13:39:26 2012
@@ -0,0 +1,51 @@
+/*
+ *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.
+ */
+/**
+ *
+ * @defgroup BundleListener Bundle Listener
+ * @ingroup framework
+ * @{
+ *
+ *  \author            Alexander Broekhuis
+ *  \date              June 28, 2012
+ *  \copyright Apache License, Version 2.0
+ */
+#ifndef BUNDLE_LISTENER_H_
+#define BUNDLE_LISTENER_H_
+
+#include <apr_general.h>
+
+typedef struct bundle_listener *bundle_listener_t;
+
+#include "celix_errno.h"
+#include "bundle_event.h"
+
+struct bundle_listener {
+       apr_pool_t *pool;
+       void * handle;
+       celix_status_t (*bundleChanged)(void * listener, bundle_event_t event);
+};
+
+
+
+#endif /* SERVICE_LISTENER_H_ */
+
+/**
+ * @}
+ */

Modified: incubator/celix/trunk/framework/public/include/framework.h
URL: 
http://svn.apache.org/viewvc/incubator/celix/trunk/framework/public/include/framework.h?rev=1370759&r1=1370758&r2=1370759&view=diff
==============================================================================
--- incubator/celix/trunk/framework/public/include/framework.h (original)
+++ incubator/celix/trunk/framework/public/include/framework.h Wed Aug  8 
13:39:26 2012
@@ -37,6 +37,7 @@ typedef struct framework * FRAMEWORK;
 #include "service_factory.h"
 #include "bundle_archive.h"
 #include "service_listener.h"
+#include "bundle_listener.h"
 #include "service_registration.h"
 #include "bundle_context.h"
 
@@ -70,6 +71,10 @@ celix_status_t fw_getBundleServicesInUse
 
 void fw_addServiceListener(FRAMEWORK framework, BUNDLE bundle, 
SERVICE_LISTENER listener, char * filter);
 void fw_removeServiceListener(FRAMEWORK framework, BUNDLE bundle, 
SERVICE_LISTENER listener);
+
+celix_status_t fw_addBundleListener(FRAMEWORK framework, BUNDLE bundle, 
bundle_listener_t listener);
+celix_status_t fw_removeBundleListener(FRAMEWORK framework, BUNDLE bundle, 
bundle_listener_t listener);
+
 void fw_serviceChanged(FRAMEWORK framework, SERVICE_EVENT_TYPE eventType, 
SERVICE_REGISTRATION registration, PROPERTIES oldprops);
 
 celix_status_t fw_isServiceAssignable(FRAMEWORK fw, BUNDLE requester, 
SERVICE_REFERENCE reference, bool *assignable);


Reply via email to